Merge tag 'drm-for-v4.9' of git://people.freedesktop.org/~airlied/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 12 Oct 2016 01:12:22 +0000 (18:12 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 12 Oct 2016 01:12:22 +0000 (18:12 -0700)
Pull drm updates from Dave Airlie:
 "Core:
   - Fence destaging work
   - DRIVER_LEGACY to split off legacy drm drivers
   - drm_mm refactoring
   - Splitting drm_crtc.c into chunks and documenting better
   - Display info fixes
   - rbtree support for prime buffer lookup
   - Simple VGA DAC driver

  Panel:
   - Add Nexus 7 panel
   - More simple panels

  i915:
   - Refactoring GEM naming
   - Refactored vma/active tracking
   - Lockless request lookups
   - Better stolen memory support
   - FBC fixes
   - SKL watermark fixes
   - VGPU improvements
   - dma-buf fencing support
   - Better DP dongle support

  amdgpu:
   - Powerplay for Iceland asics
   - Improved GPU reset support
   - UVD/VEC powergating support for CZ/ST
   - Preinitialised VRAM buffer support
   - Virtual display support
   - Initial SI support
   - GTT rework
   - PCI shutdown callback support
   - HPD IRQ storm fixes

  amdkfd:
   - bugfixes

  tilcdc:
   - Atomic modesetting support

  mediatek:
   - AAL + GAMMA engine support
   - Hook up gamma LUT
   - Temporal dithering support

  imx:
   - Pixel clock from devicetree
   - drm bridge support for LVDS bridges
   - active plane reconfiguration
   - VDIC deinterlacer support
   - Frame synchronisation unit support
   - Color space conversion support

  analogix:
   - PSR support
   - Better panel on/off support

  rockchip:
   - rk3399 vop/crtc support
   - PSR support

  vc4:
   - Interlaced vblank timing
   - 3D rendering CPU overhead reduction
   - HDMI output fixes

  tda998x:
   - HDMI audio ASoC support

  sunxi:
   - Allwinner A33 support
   - better TCON support

  msm:
   - DT binding cleanups
   - Explicit fence-fd support

  sti:
   - remove sti415/416 support

  etnaviv:
   - MMUv2 refactoring
   - GC3000 support

  exynos:
   - Refactoring HDMI DCC/PHY
   - G2D pm regression fix
   - Page fault issues with wait for vblank

  There is no nouveau work in this tree, as Ben didn't get a pull
  request in, and he was fighting moving to atomic and adding mst
  support, so maybe best it waits for a cycle"

* tag 'drm-for-v4.9' of git://people.freedesktop.org/~airlied/linux: (1412 commits)
  drm/crtc: constify drm_crtc_index parameter
  drm/i915: Fix conflict resolution from backmerge of v4.8-rc8 to drm-next
  drm/i915/guc: Unwind GuC workqueue reservation if request construction fails
  drm/i915: Reset the breadcrumbs IRQ more carefully
  drm/i915: Force relocations via cpu if we run out of idle aperture
  drm/i915: Distinguish last emitted request from last submitted request
  drm/i915: Allow DP to work w/o EDID
  drm/i915: Move long hpd handling into the hotplug work
  drm/i915/execlists: Reinitialise context image after GPU hang
  drm/i915: Use correct index for backtracking HUNG semaphores
  drm/i915: Unalias obj->phys_handle and obj->userptr
  drm/i915: Just clear the mmiodebug before a register access
  drm/i915/gen9: only add the planes actually affected by ddb changes
  drm/i915: Allow PCH DPLL sharing regardless of DPLL_SDVO_HIGH_SPEED
  drm/i915/bxt: Fix HDMI DPLL configuration
  drm/i915/gen9: fix the watermark res_blocks value
  drm/i915/gen9: fix plane_blocks_per_line on watermarks calculations
  drm/i915/gen9: minimum scanlines for Y tile is not always 4
  drm/i915/gen9: fix the WaWmMemoryReadLatency implementation
  drm/i915/kbl: KBL also needs to run the SAGV code
  ...

699 files changed:
Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/tda998x.txt
Documentation/devicetree/bindings/display/msm/hdmi.txt
Documentation/devicetree/bindings/display/panel/innolux,g101ice-l01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/jdi,lt070me05000.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt
Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt
Documentation/gpu/drm-internals.rst
Documentation/gpu/drm-kms-helpers.rst
Documentation/gpu/drm-kms.rst
Documentation/gpu/drm-mm.rst
Documentation/gpu/drm-uapi.rst
Documentation/gpu/i915.rst
Documentation/gpu/index.rst
Documentation/gpu/kms-properties.csv
Documentation/gpu/vgaarbiter.rst [new file with mode: 0644]
Documentation/sync_file.txt
Documentation/vgaarbiter.txt [deleted file]
MAINTAINERS
arch/arm/boot/dts/am335x-boneblack.dts
arch/x86/kernel/early-quirks.c
drivers/char/agp/intel-gtt.c
drivers/dma-buf/dma-buf.c
drivers/dma-buf/fence-array.c
drivers/dma-buf/reservation.c
drivers/dma-buf/sync_debug.c
drivers/dma-buf/sync_file.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdgpu/Kconfig
drivers/gpu/drm/amd/amdgpu/Makefile
drivers/gpu/drm/amd/amdgpu/ObjectID.h
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h
drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
drivers/gpu/drm/amd/amdgpu/amdgpu_test.c
drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
drivers/gpu/drm/amd/amdgpu/atombios_dp.c
drivers/gpu/drm/amd/amdgpu/atombios_i2c.c
drivers/gpu/drm/amd/amdgpu/ci_dpm.c
drivers/gpu/drm/amd/amdgpu/cik.c
drivers/gpu/drm/amd/amdgpu/cik_sdma.c
drivers/gpu/drm/amd/amdgpu/cikd.h
drivers/gpu/drm/amd/amdgpu/cz_dpm.c
drivers/gpu/drm/amd/amdgpu/cz_smc.c
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v10_0.h
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.h
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/dce_v6_0.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.h
drivers/gpu/drm/amd/amdgpu/dce_virtual.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/dce_virtual.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/fiji_dpm.c [deleted file]
drivers/gpu/drm/amd/amdgpu/fiji_smc.c [deleted file]
drivers/gpu/drm/amd/amdgpu/fiji_smum.h [deleted file]
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.h
drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/gmc_v6_0.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
drivers/gpu/drm/amd/amdgpu/iceland_dpm.c [deleted file]
drivers/gpu/drm/amd/amdgpu/iceland_smc.c [deleted file]
drivers/gpu/drm/amd/amdgpu/iceland_smum.h [deleted file]
drivers/gpu/drm/amd/amdgpu/kv_dpm.c
drivers/gpu/drm/amd/amdgpu/r600_dpm.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
drivers/gpu/drm/amd/amdgpu/si.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/si.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/si_dma.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/si_dma.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/si_dpm.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/si_dpm.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/si_ih.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/si_ih.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/si_smc.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/sislands_smc.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/tonga_dpm.c [deleted file]
drivers/gpu/drm/amd/amdgpu/tonga_ih.c
drivers/gpu/drm/amd/amdgpu/tonga_smc.c [deleted file]
drivers/gpu/drm/amd/amdgpu/tonga_smum.h [deleted file]
drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/amdgpu/vid.h
drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_process.c
drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_queue.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/include/amd_shared.h
drivers/gpu/drm/amd/include/asic_reg/si/clearstate_si.h [new file with mode: 0644]
drivers/gpu/drm/amd/include/asic_reg/si/si_reg.h [new file with mode: 0644]
drivers/gpu/drm/amd/include/asic_reg/si/sid.h [new file with mode: 0644]
drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_4_2_d.h
drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_5_0_d.h
drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_6_0_d.h
drivers/gpu/drm/amd/include/atombios.h
drivers/gpu/drm/amd/include/cgs_common.h [changed mode: 0644->0755]
drivers/gpu/drm/amd/powerplay/Kconfig [deleted file]
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
drivers/gpu/drm/amd/powerplay/eventmgr/psm.c
drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_clockpowergating.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_clockpowergating.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_dyn_defaults.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_powertune.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_powertune.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_thermal.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_thermal.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
drivers/gpu/drm/amd/powerplay/hwmgr/pptable_v1_0.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_dyn_defaults.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_dyn_defaults.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_pptable.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.h [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.c [deleted file]
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.h [deleted file]
drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h
drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
drivers/gpu/drm/amd/powerplay/inc/polaris10_pwrvirus.h
drivers/gpu/drm/amd/powerplay/inc/power_state.h
drivers/gpu/drm/amd/powerplay/inc/pp_debug.h
drivers/gpu/drm/amd/powerplay/inc/smu71.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/inc/smu71_discrete.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/inc/smu7_common.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/inc/smumgr.h
drivers/gpu/drm/amd/powerplay/smumgr/Makefile
drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c [changed mode: 0644->0755]
drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h
drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c
drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h
drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.h [new file with mode: 0644]
drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c
drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h
drivers/gpu/drm/arc/arcpgu_crtc.c
drivers/gpu/drm/arc/arcpgu_drv.c
drivers/gpu/drm/arm/hdlcd_drv.c
drivers/gpu/drm/arm/malidp_drv.c
drivers/gpu/drm/arm/malidp_drv.h
drivers/gpu/drm/arm/malidp_planes.c
drivers/gpu/drm/armada/armada_drv.c
drivers/gpu/drm/armada/armada_fbdev.c
drivers/gpu/drm/armada/armada_gem.c
drivers/gpu/drm/armada/armada_overlay.c
drivers/gpu/drm/ast/ast_fb.c
drivers/gpu/drm/ast/ast_ttm.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
drivers/gpu/drm/bochs/bochs.h
drivers/gpu/drm/bochs/bochs_drv.c
drivers/gpu/drm/bochs/bochs_kms.c
drivers/gpu/drm/bochs/bochs_mm.c
drivers/gpu/drm/bridge/Kconfig
drivers/gpu/drm/bridge/Makefile
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
drivers/gpu/drm/bridge/adv7511/adv7533.c
drivers/gpu/drm/bridge/analogix-anx78xx.c
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
drivers/gpu/drm/bridge/dumb-vga-dac.c [new file with mode: 0644]
drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c
drivers/gpu/drm/bridge/dw-hdmi.c
drivers/gpu/drm/bridge/nxp-ptn3460.c
drivers/gpu/drm/bridge/parade-ps8622.c
drivers/gpu/drm/bridge/tc358767.c
drivers/gpu/drm/cirrus/cirrus_drv.c
drivers/gpu/drm/cirrus/cirrus_fbdev.c
drivers/gpu/drm/cirrus/cirrus_ttm.c
drivers/gpu/drm/drm_agpsupport.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_auth.c
drivers/gpu/drm/drm_blend.c
drivers/gpu/drm/drm_bridge.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_color_mgmt.c [new file with mode: 0644]
drivers/gpu/drm/drm_connector.c [new file with mode: 0644]
drivers/gpu/drm/drm_context.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_crtc_helper_internal.h [new file with mode: 0644]
drivers/gpu/drm/drm_crtc_internal.h
drivers/gpu/drm/drm_dma.c
drivers/gpu/drm/drm_dp_aux_dev.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_encoder.c [new file with mode: 0644]
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_fourcc.c
drivers/gpu/drm/drm_framebuffer.c [new file with mode: 0644]
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_global.c
drivers/gpu/drm/drm_hashtab.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_internal.h
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_kms_helper_common.c
drivers/gpu/drm/drm_lock.c
drivers/gpu/drm/drm_mipi_dsi.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_mode_object.c [new file with mode: 0644]
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_modeset_helper.c [new file with mode: 0644]
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_plane.c [new file with mode: 0644]
drivers/gpu/drm/drm_plane_helper.c
drivers/gpu/drm/drm_platform.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/drm_property.c [new file with mode: 0644]
drivers/gpu/drm/drm_rect.c
drivers/gpu/drm/drm_scatter.c
drivers/gpu/drm/drm_simple_kms_helper.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/drm_vma_manager.c
drivers/gpu/drm/etnaviv/etnaviv_buffer.c
drivers/gpu/drm/etnaviv/etnaviv_drv.c
drivers/gpu/drm/etnaviv/etnaviv_drv.h
drivers/gpu/drm/etnaviv/etnaviv_dump.c
drivers/gpu/drm/etnaviv/etnaviv_gpu.c
drivers/gpu/drm/etnaviv/etnaviv_gpu.h
drivers/gpu/drm/etnaviv/etnaviv_iommu.c
drivers/gpu/drm/etnaviv/etnaviv_iommu.h
drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.h [deleted file]
drivers/gpu/drm/etnaviv/etnaviv_mmu.c
drivers/gpu/drm/etnaviv/etnaviv_mmu.h
drivers/gpu/drm/etnaviv/state_hi.xml.h
drivers/gpu/drm/exynos/exynos5433_drm_decon.c
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_dp.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
drivers/gpu/drm/fsl-dcu/fsl_tcon.c
drivers/gpu/drm/gma500/accel_2d.c
drivers/gpu/drm/gma500/cdv_intel_lvds.c
drivers/gpu/drm/gma500/framebuffer.c
drivers/gpu/drm/gma500/mdfld_dsi_output.c
drivers/gpu/drm/gma500/opregion.c
drivers/gpu/drm/gma500/psb_intel_lvds.c
drivers/gpu/drm/gma500/psb_intel_modes.c
drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
drivers/gpu/drm/i2c/Kconfig
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/i810/i810_drv.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_cmd_parser.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_batch_pool.c
drivers/gpu/drm/i915/i915_gem_batch_pool.h
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_debug.c [deleted file]
drivers/gpu/drm/i915/i915_gem_dmabuf.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_fence.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/i915_gem_render_state.c
drivers/gpu/drm/i915/i915_gem_render_state.h
drivers/gpu/drm/i915/i915_gem_request.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem_request.h [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem_shrinker.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_gem_userptr.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_guc_reg.h
drivers/gpu/drm/i915/i915_guc_submission.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_memcpy.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_mm.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_params.h
drivers/gpu/drm/i915/i915_pci.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/i915_sw_fence.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_sw_fence.h [new file with mode: 0644]
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/i915_vgpu.c
drivers/gpu/drm/i915/intel_atomic_plane.c
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_breadcrumbs.c
drivers/gpu/drm/i915/intel_color.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_csr.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_device_info.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_link_training.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/i915/intel_dpll_mgr.c
drivers/gpu/drm/i915/intel_dpll_mgr.h
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dsi.c
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_engine_cs.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_fbc.c
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_frontbuffer.c
drivers/gpu/drm/i915/intel_frontbuffer.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_guc.h
drivers/gpu/drm/i915/intel_guc_fwif.h
drivers/gpu/drm/i915/intel_guc_loader.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_hotplug.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_lrc.h
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_mocs.c
drivers/gpu/drm/i915/intel_mocs.h
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_psr.c
drivers/gpu/drm/i915/intel_renderstate.h
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/imx/imx-drm-core.c
drivers/gpu/drm/imx/imx-drm.h
drivers/gpu/drm/imx/imx-ldb.c
drivers/gpu/drm/imx/imx-tve.c
drivers/gpu/drm/imx/ipuv3-crtc.c
drivers/gpu/drm/imx/ipuv3-plane.c
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/mediatek/mtk_disp_ovl.c
drivers/gpu/drm/mediatek/mtk_disp_rdma.c
drivers/gpu/drm/mediatek/mtk_drm_crtc.c
drivers/gpu/drm/mediatek/mtk_drm_crtc.h
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
drivers/gpu/drm/mediatek/mtk_drm_drv.c
drivers/gpu/drm/mediatek/mtk_drm_plane.c
drivers/gpu/drm/mediatek/mtk_drm_plane.h
drivers/gpu/drm/mediatek/mtk_hdmi.c
drivers/gpu/drm/mga/mga_drv.c
drivers/gpu/drm/mgag200/mgag200_drv.c
drivers/gpu/drm/mgag200/mgag200_fb.c
drivers/gpu/drm/mgag200/mgag200_main.c
drivers/gpu/drm/mgag200/mgag200_ttm.c
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi_i2c.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
drivers/gpu/drm/omapdrm/dss/dss-of.c
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/omapdrm/omap_fb.c
drivers/gpu/drm/omapdrm/omap_plane.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-jdi-lt070me05000.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_draw.c
drivers/gpu/drm/qxl/qxl_drv.h
drivers/gpu/drm/qxl/qxl_fb.c
drivers/gpu/drm/qxl/qxl_object.c
drivers/gpu/drm/qxl/qxl_release.c
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/r128/r128_drv.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_acpi.c
drivers/gpu/drm/radeon/radeon_atpx_handler.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_dp_auxch.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770d.h
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/sislands_smc.h
drivers/gpu/drm/rcar-du/rcar_du_drv.c
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/rockchip/Makefile
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
drivers/gpu/drm/rockchip/rockchip_drm_fb.c
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
drivers/gpu/drm/rockchip/rockchip_drm_psr.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_psr.h [new file with mode: 0644]
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.h
drivers/gpu/drm/rockchip/rockchip_vop_reg.c
drivers/gpu/drm/rockchip/rockchip_vop_reg.h
drivers/gpu/drm/savage/savage_drv.c
drivers/gpu/drm/savage/savage_state.c
drivers/gpu/drm/sis/sis_drv.c
drivers/gpu/drm/sti/Kconfig
drivers/gpu/drm/sti/Makefile
drivers/gpu/drm/sti/sti_compositor.c
drivers/gpu/drm/sti/sti_compositor.h
drivers/gpu/drm/sti/sti_crtc.c
drivers/gpu/drm/sti/sti_cursor.c
drivers/gpu/drm/sti/sti_drv.c
drivers/gpu/drm/sti/sti_dvo.c
drivers/gpu/drm/sti/sti_gdp.c
drivers/gpu/drm/sti/sti_hda.c
drivers/gpu/drm/sti/sti_hdmi.c
drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c [deleted file]
drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h [deleted file]
drivers/gpu/drm/sti/sti_hqvdp.c
drivers/gpu/drm/sti/sti_mixer.c
drivers/gpu/drm/sti/sti_tvout.c
drivers/gpu/drm/sti/sti_vid.c
drivers/gpu/drm/sti/sti_vtac.c
drivers/gpu/drm/sti/sti_vtg.c
drivers/gpu/drm/sun4i/Makefile
drivers/gpu/drm/sun4i/sun4i_backend.c
drivers/gpu/drm/sun4i/sun4i_backend.h
drivers/gpu/drm/sun4i/sun4i_dotclock.c
drivers/gpu/drm/sun4i/sun4i_drv.c
drivers/gpu/drm/sun4i/sun4i_framebuffer.c
drivers/gpu/drm/sun4i/sun4i_layer.c
drivers/gpu/drm/sun4i/sun4i_rgb.c
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun4i_tcon.h
drivers/gpu/drm/sun4i/sun4i_tv.c
drivers/gpu/drm/sun4i/sun6i_drc.c [new file with mode: 0644]
drivers/gpu/drm/tdfx/tdfx_drv.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/gem.c
drivers/gpu/drm/tilcdc/Makefile
drivers/gpu/drm/tilcdc/tilcdc_crtc.c
drivers/gpu/drm/tilcdc/tilcdc_drv.c
drivers/gpu/drm/tilcdc/tilcdc_drv.h
drivers/gpu/drm/tilcdc/tilcdc_external.c
drivers/gpu/drm/tilcdc/tilcdc_external.h
drivers/gpu/drm/tilcdc/tilcdc_panel.c
drivers/gpu/drm/tilcdc/tilcdc_plane.c [new file with mode: 0644]
drivers/gpu/drm/tilcdc/tilcdc_regs.h
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c
drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_memory.c
drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/udl/udl_connector.c
drivers/gpu/drm/udl/udl_dmabuf.c
drivers/gpu/drm/udl/udl_drv.c
drivers/gpu/drm/udl/udl_drv.h
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/udl/udl_modeset.c
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/drm/vc4/vc4_dpi.c
drivers/gpu/drm/vc4/vc4_drv.c
drivers/gpu/drm/vc4/vc4_drv.h
drivers/gpu/drm/vc4/vc4_gem.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_kms.c
drivers/gpu/drm/vc4/vc4_plane.c
drivers/gpu/drm/vc4/vc4_regs.h
drivers/gpu/drm/vc4/vc4_render_cl.c
drivers/gpu/drm/vc4/vc4_validate.c
drivers/gpu/drm/vgem/vgem_drv.c
drivers/gpu/drm/via/via_drv.c
drivers/gpu/drm/virtio/virtgpu_display.c
drivers/gpu/drm/virtio/virtgpu_drm_bus.c
drivers/gpu/drm/virtio/virtgpu_drv.c
drivers/gpu/drm/virtio/virtgpu_drv.h
drivers/gpu/drm/virtio/virtgpu_fence.c
drivers/gpu/drm/virtio/virtgpu_ioctl.c
drivers/gpu/drm/virtio/virtgpu_kms.c
drivers/gpu/drm/virtio/virtgpu_plane.c
drivers/gpu/drm/vmwgfx/Kconfig
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
drivers/gpu/ipu-v3/Makefile
drivers/gpu/ipu-v3/ipu-common.c
drivers/gpu/ipu-v3/ipu-cpmem.c
drivers/gpu/ipu-v3/ipu-csi.c
drivers/gpu/ipu-v3/ipu-dmfc.c
drivers/gpu/ipu-v3/ipu-ic.c
drivers/gpu/ipu-v3/ipu-image-convert.c [new file with mode: 0644]
drivers/gpu/ipu-v3/ipu-prv.h
drivers/gpu/ipu-v3/ipu-vdi.c [new file with mode: 0644]
drivers/gpu/vga/vgaarb.c
include/drm/bridge/analogix_dp.h
include/drm/drmP.h
include/drm/drm_atomic.h
include/drm/drm_atomic_helper.h
include/drm/drm_blend.h [new file with mode: 0644]
include/drm/drm_bridge.h [new file with mode: 0644]
include/drm/drm_color_mgmt.h [new file with mode: 0644]
include/drm/drm_connector.h [new file with mode: 0644]
include/drm/drm_core.h [deleted file]
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_dp_aux_dev.h [deleted file]
include/drm/drm_dp_helper.h
include/drm/drm_edid.h
include/drm/drm_encoder.h [new file with mode: 0644]
include/drm/drm_fb_helper.h
include/drm/drm_fourcc.h
include/drm/drm_framebuffer.h [new file with mode: 0644]
include/drm/drm_gem.h
include/drm/drm_mipi_dsi.h
include/drm/drm_mm.h
include/drm/drm_mode_object.h [new file with mode: 0644]
include/drm/drm_modes.h
include/drm/drm_modeset_helper.h [new file with mode: 0644]
include/drm/drm_modeset_helper_vtables.h
include/drm/drm_plane.h [new file with mode: 0644]
include/drm/drm_plane_helper.h
include/drm/drm_property.h [new file with mode: 0644]
include/drm/drm_simple_kms_helper.h
include/drm/drm_vma_manager.h
include/drm/i2c/tda998x.h
include/drm/i915_drm.h
include/drm/i915_pciids.h
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/drm/ttm/ttm_memory.h
include/drm/ttm/ttm_placement.h
include/dt-bindings/display/tda998x.h [new file with mode: 0644]
include/linux/fence-array.h
include/linux/fence.h
include/linux/io-mapping.h
include/linux/sync_file.h
include/linux/vgaarb.h
include/uapi/drm/amdgpu_drm.h
include/uapi/drm/drm.h
include/uapi/drm/drm_mode.h
include/uapi/drm/i915_drm.h
include/uapi/drm/msm_drm.h
include/uapi/linux/Kbuild
include/uapi/linux/sync_file.h
include/video/imx-ipu-image-convert.h [new file with mode: 0644]
include/video/imx-ipu-v3.h

diff --git a/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt b/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt
new file mode 100644 (file)
index 0000000..003bc24
--- /dev/null
@@ -0,0 +1,48 @@
+Dumb RGB to VGA DAC bridge
+---------------------------
+
+This binding is aimed for dumb RGB to VGA DAC based bridges that do not require
+any configuration.
+
+Required properties:
+
+- compatible: Must be "dumb-vga-dac"
+
+Required nodes:
+
+This device has two video ports. Their connections are modelled using the OF
+graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 for RGB input
+- Video port 1 for VGA output
+
+
+Example
+-------
+
+bridge {
+       compatible = "dumb-vga-dac";
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+
+                       vga_bridge_in: endpoint {
+                               remote-endpoint = <&tcon0_out_vga>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       vga_bridge_out: endpoint {
+                               remote-endpoint = <&vga_con_in>;
+                       };
+               };
+       };
+};
index e178e6b..24cc246 100644 (file)
@@ -21,8 +21,19 @@ Optional properties:
   - video-ports: 24 bits value which defines how the video controller
        output is wired to the TDA998x input - default: <0x230145>
 
+  - audio-ports: array of 8-bit values, 2 values per one DAI[1].
+       The first value defines the DAI type: TDA998x_SPDIF or TDA998x_I2S[2].
+       The second value defines the tda998x AP_ENA reg content when the DAI
+       in question is used. The implementation allows one or two DAIs. If two
+       DAIs are defined, they must be of different type.
+
+[1] Documentation/sound/alsa/soc/DAI.txt
+[2] include/dt-bindings/display/tda998x.h
+
 Example:
 
+#include <dt-bindings/display/tda998x.h>
+
        tda998x: hdmi-encoder {
                compatible = "nxp,tda998x";
                reg = <0x70>;
@@ -30,4 +41,11 @@ Example:
                interrupts = <27 2>;            /* falling edge */
                pinctrl-0 = <&pmx_camera>;
                pinctrl-names = "default";
+               video-ports = <0x230145>;
+
+               #sound-dai-cells = <2>;
+                            /* DAI-format      AP_ENA reg value */
+               audio-ports = < TDA998x_SPDIF   0x04
+                               TDA998x_I2S     0x03>;
+
        };
index b63f614..2ad5789 100644 (file)
@@ -14,17 +14,16 @@ Required properties:
 - power-domains: Should be <&mmcc MDSS_GDSC>.
 - clocks: device clocks
   See ../clocks/clock-bindings.txt for details.
-- qcom,hdmi-tx-ddc-clk-gpio: ddc clk pin
-- qcom,hdmi-tx-ddc-data-gpio: ddc data pin
-- qcom,hdmi-tx-hpd-gpio: hpd pin
 - core-vdda-supply: phandle to supply regulator
 - hdmi-mux-supply: phandle to mux regulator
 - phys: the phandle for the HDMI PHY device
 - phy-names: the name of the corresponding PHY device
 
 Optional properties:
-- qcom,hdmi-tx-mux-en-gpio: hdmi mux enable pin
-- qcom,hdmi-tx-mux-sel-gpio: hdmi mux select pin
+- hpd-gpios: hpd pin
+- qcom,hdmi-tx-mux-en-gpios: hdmi mux enable pin
+- qcom,hdmi-tx-mux-sel-gpios: hdmi mux select pin
+- qcom,hdmi-tx-mux-lpm-gpios: hdmi mux lpm pin
 - power-domains: reference to the power domain(s), if available.
 - pinctrl-names: the pin control state names; should contain "default"
 - pinctrl-0: the default pinctrl state (active)
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,g101ice-l01.txt b/Documentation/devicetree/bindings/display/panel/innolux,g101ice-l01.txt
new file mode 100644 (file)
index 0000000..9e75904
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux Corporation 10.1" G101ICE-L01 WXGA (1280x800) LVDS panel
+
+Required properties:
+- compatible: should be "innolux,g101ice-l01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/jdi,lt070me05000.txt b/Documentation/devicetree/bindings/display/panel/jdi,lt070me05000.txt
new file mode 100644 (file)
index 0000000..4989c91
--- /dev/null
@@ -0,0 +1,31 @@
+JDI model LT070ME05000 1200x1920 7" DSI Panel
+
+Required properties:
+- compatible: should be "jdi,lt070me05000"
+- vddp-supply: phandle of the regulator that provides the supply voltage
+  Power IC supply (3-5V)
+- iovcc-supply: phandle of the regulator that provides the supply voltage
+  IOVCC , power supply for LCM (1.8V)
+- enable-gpios: phandle of gpio for enable line
+  LED_EN, LED backlight enable, High active
+- reset-gpios: phandle of gpio for reset line
+  This should be 8mA, gpio can be configured using mux, pinctrl, pinctrl-names
+  XRES, Reset, Low active
+- dcdc-en-gpios: phandle of the gpio for power ic line
+  Power IC supply enable, High active
+
+Example:
+
+       dsi0: qcom,mdss_dsi@4700000 {
+               panel@0 {
+                       compatible = "jdi,lt070me05000";
+                       reg = <0>;
+
+                       vddp-supply = <&pm8921_l17>;
+                       iovcc-supply = <&pm8921_lvs7>;
+
+                       enable-gpios = <&pm8921_gpio 36 GPIO_ACTIVE_HIGH>;
+                       reset-gpios = <&tlmm_pinmux 54 GPIO_ACTIVE_LOW>;
+                       dcdc-en-gpios = <&pm8921_gpio 23 GPIO_ACTIVE_HIGH>;
+               };
+       };
index 5489b59..9eb3f0a 100644 (file)
@@ -6,8 +6,10 @@ buffer to an external LCD interface.
 
 Required properties:
 - compatible: value should be one of the following
-               "rockchip,rk3288-vop";
                "rockchip,rk3036-vop";
+               "rockchip,rk3288-vop";
+               "rockchip,rk3399-vop-big";
+               "rockchip,rk3399-vop-lit";
 
 - interrupts: should contain a list of all VOP IP block interrupts in the
                 order: VSYNC, LCD_SYSTEM. The interrupt specifier
index df8f4ae..b95696d 100644 (file)
@@ -26,13 +26,14 @@ TCON
 The TCON acts as a timing controller for RGB, LVDS and TV interfaces.
 
 Required properties:
- - compatible: value should be "allwinner,sun5i-a13-tcon".
+ - compatible: value must be either:
+   * allwinner,sun5i-a13-tcon
+   * allwinner,sun8i-a33-tcon
  - reg: base address and size of memory-mapped region
  - interrupts: interrupt associated to this IP
  - clocks: phandles to the clocks feeding the TCON. Three are needed:
    - 'ahb': the interface clocks
    - 'tcon-ch0': The clock driving the TCON channel 0
-   - 'tcon-ch1': The clock driving the TCON channel 1
  - resets: phandles to the reset controllers driving the encoder
    - "lcd": the reset line for the TCON channel 0
 
@@ -49,6 +50,33 @@ Required properties:
   second the block connected to the TCON channel 1 (usually the TV
   encoder)
 
+On the A13, there is one more clock required:
+   - 'tcon-ch1': The clock driving the TCON channel 1
+
+DRC
+---
+
+The DRC (Dynamic Range Controller), found in the latest Allwinner SoCs
+(A31, A23, A33), allows to dynamically adjust pixel
+brightness/contrast based on histogram measurements for LCD content
+adaptive backlight control.
+
+
+Required properties:
+  - compatible: value must be one of:
+    * allwinner,sun8i-a33-drc
+  - reg: base address and size of the memory-mapped region.
+  - interrupts: interrupt associated to this IP
+  - clocks: phandles to the clocks feeding the DRC
+    * ahb: the DRC interface clock
+    * mod: the DRC module clock
+    * ram: the DRC DRAM clock
+  - clock-names: the clock names mentioned above
+  - resets: phandles to the reset line driving the DRC
+
+- ports: A ports node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt. The
+  first port should be the input endpoints, the second one the outputs
 
 Display Engine Backend
 ----------------------
@@ -59,6 +87,7 @@ system.
 Required properties:
   - compatible: value must be one of:
     * allwinner,sun5i-a13-display-backend
+    * allwinner,sun8i-a33-display-backend
   - reg: base address and size of the memory-mapped region.
   - clocks: phandles to the clocks feeding the frontend and backend
     * ahb: the backend interface clock
@@ -71,6 +100,14 @@ Required properties:
   Documentation/devicetree/bindings/media/video-interfaces.txt. The
   first port should be the input endpoints, the second one the output
 
+On the A33, some additional properties are required:
+  - reg needs to have an additional region corresponding to the SAT
+  - reg-names need to be set, with "be" and "sat"
+  - clocks and clock-names need to have a phandle to the SAT bus
+    clocks, whose name will be "sat"
+  - resets and reset-names need to have a phandle to the SAT bus
+    resets, whose name will be "sat"
+
 Display Engine Frontend
 -----------------------
 
@@ -80,6 +117,7 @@ deinterlacing and color space conversion.
 Required properties:
   - compatible: value must be one of:
     * allwinner,sun5i-a13-display-frontend
+    * allwinner,sun8i-a33-display-frontend
   - reg: base address and size of the memory-mapped region.
   - interrupts: interrupt associated to this IP
   - clocks: phandles to the clocks feeding the frontend and backend
@@ -104,6 +142,7 @@ extra node.
 Required properties:
   - compatible: value must be one of:
     * allwinner,sun5i-a13-display-engine
+    * allwinner,sun8i-a33-display-engine
 
   - allwinner,pipelines: list of phandle to the display engine
     frontends available.
index 2136ee8..a83abd7 100644 (file)
@@ -17,6 +17,18 @@ Optional properties:
    the lcd controller.
  - max-pixelclock: The maximum pixel clock that can be supported
    by the lcd controller in KHz.
+ - blue-and-red-wiring: Recognized values "straight" or "crossed".
+   This property deals with the LCDC revision 2 (found on AM335x)
+   color errata [1].
+    - "straight" indicates normal wiring that supports RGB565,
+      BGR888, and XBGR8888 color formats.
+    - "crossed" indicates wiring that has blue and red wires
+      crossed. This setup supports BGR565, RGB888 and XRGB8888
+      formats.
+    - If the property is not present or its value is not recognized
+      the legacy mode is assumed. This configuration supports RGB565,
+      RGB888 and XRGB8888 formats. However, depending on wiring, the red
+      and blue colors are swapped in either 16 or 24-bit color modes.
 
 Optional nodes:
 
@@ -24,6 +36,18 @@ Optional nodes:
    binding follows Documentation/devicetree/bindings/graph.txt and
    suppors a single port with a single endpoint.
 
+ - See also Documentation/devicetree/bindings/display/tilcdc/panel.txt and
+   Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting
+   tfp410 DVI encoder or lcd panel to lcdc
+
+[1] There is an errata about AM335x color wiring. For 16-bit color mode
+    the wires work as they should (LCD_DATA[0:4] is for Blue[3:7]),
+    but for 24 bit color modes the wiring of blue and red components is
+    crossed and LCD_DATA[0:4] is for Red[3:7] and LCD_DATA[11:15] is
+    for Blue[3-7]. For more details see section 3.1.1 in AM335x
+    Silicon Errata:
+    http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sprz360
+
 Example:
 
        fb: fb@4830e000 {
@@ -33,6 +57,8 @@ Example:
                interrupts = <36>;
                ti,hwmods = "lcdc";
 
+               blue-and-red-wiring = "crossed";
+
                port {
                        lcdc_0: endpoint@0 {
                                remote-endpoint = <&hdmi_0>;
index 3bb2613..37284bc 100644 (file)
@@ -53,9 +53,12 @@ u32 driver_features;
 DRIVER_USE_AGP
     Driver uses AGP interface, the DRM core will manage AGP resources.
 
-DRIVER_REQUIRE_AGP
-    Driver needs AGP interface to function. AGP initialization failure
-    will become a fatal error.
+DRIVER_LEGACY
+    Denote a legacy driver using shadow attach. Don't use.
+
+DRIVER_KMS_LEGACY_CONTEXT
+    Used only by nouveau for backwards compatibility with existing userspace.
+    Don't use.
 
 DRIVER_PCI_DMA
     Driver is capable of PCI DMA, mapping of PCI DMA buffers to
index 0b302fe..bb4254d 100644 (file)
@@ -2,38 +2,45 @@
 Mode Setting Helper Functions
 =============================
 
-The plane, CRTC, encoder and connector functions provided by the drivers
-implement the DRM API. They're called by the DRM core and ioctl handlers
-to handle device state changes and configuration request. As
-implementing those functions often requires logic not specific to
-drivers, mid-layer helper functions are available to avoid duplicating
-boilerplate code.
-
-The DRM core contains one mid-layer implementation. The mid-layer
-provides implementations of several plane, CRTC, encoder and connector
-functions (called from the top of the mid-layer) that pre-process
-requests and call lower-level functions provided by the driver (at the
-bottom of the mid-layer). For instance, the
-:c:func:`drm_crtc_helper_set_config()` function can be used to
-fill the :c:type:`struct drm_crtc_funcs <drm_crtc_funcs>`
-set_config field. When called, it will split the set_config operation
-in smaller, simpler operations and call the driver to handle them.
-
-To use the mid-layer, drivers call
-:c:func:`drm_crtc_helper_add()`,
-:c:func:`drm_encoder_helper_add()` and
-:c:func:`drm_connector_helper_add()` functions to install their
-mid-layer bottom operations handlers, and fill the :c:type:`struct
-drm_crtc_funcs <drm_crtc_funcs>`, :c:type:`struct
-drm_encoder_funcs <drm_encoder_funcs>` and :c:type:`struct
-drm_connector_funcs <drm_connector_funcs>` structures with
-pointers to the mid-layer top API functions. Installing the mid-layer
-bottom operation handlers is best done right after registering the
-corresponding KMS object.
-
-The mid-layer is not split between CRTC, encoder and connector
-operations. To use it, a driver must provide bottom functions for all of
-the three KMS entities.
+The DRM subsystem aims for a strong separation between core code and helper
+libraries. Core code takes care of general setup and teardown and decoding
+userspace requests to kernel internal objects. Everything else is handled by a
+large set of helper libraries, which can be combined freely to pick and choose
+for each driver what fits, and avoid shared code where special behaviour is
+needed.
+
+This distinction between core code and helpers is especially strong in the
+modesetting code, where there's a shared userspace ABI for all drivers. This is
+in contrast to the render side, where pretty much everything (with very few
+exceptions) can be considered optional helper code.
+
+There are a few areas these helpers can grouped into:
+
+* Helpers to implement modesetting. The important ones here are the atomic
+  helpers. Old drivers still often use the legacy CRTC helpers. They both share
+  the same set of common helper vtables. For really simple drivers (anything
+  that would have been a great fit in the deprecated fbdev subsystem) there's
+  also the simple display pipe helpers.
+
+* There's a big pile of helpers for handling outputs. First the generic bridge
+  helpers for handling encoder and transcoder IP blocks. Second the panel helpers
+  for handling panel-related information and logic. Plus then a big set of
+  helpers for the various sink standards (DisplayPort, HDMI, MIPI DSI). Finally
+  there's also generic helpers for handling output probing, and for dealing with
+  EDIDs.
+
+* The last group of helpers concerns itself with the frontend side of a display
+  pipeline: Planes, handling rectangles for visibility checking and scissoring,
+  flip queues and assorted bits.
+
+Modeset Helper Reference for Common Vtables
+===========================================
+
+.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h
+   :internal:
+
+.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h
+   :doc: overview
 
 Atomic Modeset Helper Functions Reference
 =========================================
@@ -62,33 +69,27 @@ Atomic State Reset and Initialization
 .. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c
    :export:
 
-Modeset Helper Reference for Common Vtables
-===========================================
-
-.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h
-   :internal:
-
-.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h
-   :doc: overview
-
 Legacy CRTC/Modeset Helper Functions Reference
 ==============================================
 
 .. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c
-   :export:
+   :doc: overview
 
 .. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c
-   :doc: overview
+   :export:
 
-Output Probing Helper Functions Reference
-=========================================
+Simple KMS Helper Reference
+===========================
 
-.. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c
-   :doc: output probing helper overview
+.. kernel-doc:: include/drm/drm_simple_kms_helper.h
+   :internal:
 
-.. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c
+.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c
    :export:
 
+.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c
+   :doc: overview
+
 fbdev Helper Functions Reference
 ================================
 
@@ -110,6 +111,43 @@ Framebuffer CMA Helper Functions Reference
 .. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c
    :export:
 
+Bridges
+=======
+
+Overview
+--------
+
+.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
+   :doc: overview
+
+Default bridge callback sequence
+--------------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
+   :doc: bridge callbacks
+
+
+Bridge Helper Reference
+-------------------------
+
+.. kernel-doc:: include/drm/drm_bridge.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
+   :export:
+
+Panel Helper Reference
+======================
+
+.. kernel-doc:: include/drm/drm_panel.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_panel.c
+   :export:
+
+.. kernel-doc:: drivers/gpu/drm/drm_panel.c
+   :doc: drm panel
+
 Display Port Helper Functions Reference
 =======================================
 
@@ -158,9 +196,21 @@ MIPI DSI Helper Functions Reference
 .. kernel-doc:: drivers/gpu/drm/drm_mipi_dsi.c
    :export:
 
+Output Probing Helper Functions Reference
+=========================================
+
+.. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c
+   :doc: output probing helper overview
+
+.. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c
+   :export:
+
 EDID Helper Functions Reference
 ===============================
 
+.. kernel-doc:: include/drm/drm_edid.h
+   :internal:
+
 .. kernel-doc:: drivers/gpu/drm/drm_edid.c
    :export:
 
@@ -176,18 +226,6 @@ Rectangle Utilities Reference
 .. kernel-doc:: drivers/gpu/drm/drm_rect.c
    :export:
 
-Flip-work Helper Reference
-==========================
-
-.. kernel-doc:: include/drm/drm_flip_work.h
-   :doc: flip utils
-
-.. kernel-doc:: include/drm/drm_flip_work.h
-   :internal:
-
-.. kernel-doc:: drivers/gpu/drm/drm_flip_work.c
-   :export:
-
 HDMI Infoframes Helper Reference
 ================================
 
@@ -202,59 +240,40 @@ libraries and hence is also included here.
 .. kernel-doc:: drivers/video/hdmi.c
    :export:
 
-Plane Helper Reference
-======================
-
-.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c
-   :export:
-
-.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c
-   :doc: overview
+Flip-work Helper Reference
+==========================
 
-Tile group
-----------
+.. kernel-doc:: include/drm/drm_flip_work.h
+   :doc: flip utils
 
-.. kernel-doc:: drivers/gpu/drm/drm_crtc.c
-   :doc: Tile group
+.. kernel-doc:: include/drm/drm_flip_work.h
+   :internal:
 
-Bridges
-=======
+.. kernel-doc:: drivers/gpu/drm/drm_flip_work.c
+   :export:
 
-Overview
---------
+Plane Helper Reference
+======================
 
-.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
+.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c
    :doc: overview
 
-Default bridge callback sequence
---------------------------------
-
-.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
-   :doc: bridge callbacks
-
-.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
+.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c
    :export:
 
-Panel Helper Reference
-======================
-
-.. kernel-doc:: include/drm/drm_panel.h
-   :internal:
+Tile group
+==========
 
-.. kernel-doc:: drivers/gpu/drm/drm_panel.c
-   :export:
+# FIXME: This should probably be moved into a property documentation section
 
-.. kernel-doc:: drivers/gpu/drm/drm_panel.c
-   :doc: drm panel
+.. kernel-doc:: drivers/gpu/drm/drm_crtc.c
+   :doc: Tile group
 
-Simple KMS Helper Reference
-===========================
+Auxiliary Modeset Helpers
+=========================
 
-.. kernel-doc:: include/drm/drm_simple_kms_helper.h
-   :internal:
+.. kernel-doc:: drivers/gpu/drm/drm_modeset_helper.c
+   :doc: aux kms helpers
 
-.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c
+.. kernel-doc:: drivers/gpu/drm/drm_modeset_helper.c
    :export:
-
-.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c
-   :doc: overview
index 8dfa4b2..53b872c 100644 (file)
@@ -2,9 +2,6 @@
 Kernel Mode Setting (KMS)
 =========================
 
-Mode Setting
-============
-
 Drivers must initialize the mode setting core by calling
 :c:func:`drm_mode_config_init()` on the DRM device. The function
 initializes the :c:type:`struct drm_device <drm_device>`
@@ -18,60 +15,59 @@ be setup by initializing the following fields.
 -  struct drm_mode_config_funcs \*funcs;
    Mode setting functions.
 
-Display Modes Function Reference
---------------------------------
+Modeset Base Object Abstraction
+===============================
 
-.. kernel-doc:: include/drm/drm_modes.h
+.. kernel-doc:: include/drm/drm_mode_object.h
    :internal:
 
-.. kernel-doc:: drivers/gpu/drm/drm_modes.c
+.. kernel-doc:: drivers/gpu/drm/drm_mode_object.c
+   :export:
+
+KMS Data Structures
+===================
+
+.. kernel-doc:: include/drm/drm_crtc.h
+   :internal:
+
+KMS API Functions
+=================
+
+.. kernel-doc:: drivers/gpu/drm/drm_crtc.c
    :export:
 
 Atomic Mode Setting Function Reference
---------------------------------------
+======================================
 
 .. kernel-doc:: drivers/gpu/drm/drm_atomic.c
    :export:
 
-.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
+.. kernel-doc:: include/drm/drm_atomic.h
    :internal:
 
 Frame Buffer Abstraction
-------------------------
-
-Frame buffers are abstract memory objects that provide a source of
-pixels to scanout to a CRTC. Applications explicitly request the
-creation of frame buffers through the DRM_IOCTL_MODE_ADDFB(2) ioctls
-and receive an opaque handle that can be passed to the KMS CRTC control,
-plane configuration and page flip functions.
-
-Frame buffers rely on the underneath memory manager for low-level memory
-operations. When creating a frame buffer applications pass a memory
-handle (or a list of memory handles for multi-planar formats) through
-the ``drm_mode_fb_cmd2`` argument. For drivers using GEM as their
-userspace buffer management interface this would be a GEM handle.
-Drivers are however free to use their own backing storage object
-handles, e.g. vmwgfx directly exposes special TTM handles to userspace
-and so expects TTM handles in the create ioctl and not GEM handles.
-
-The lifetime of a drm framebuffer is controlled with a reference count,
-drivers can grab additional references with
-:c:func:`drm_framebuffer_reference()`and drop them again with
-:c:func:`drm_framebuffer_unreference()`. For driver-private
-framebuffers for which the last reference is never dropped (e.g. for the
-fbdev framebuffer when the struct :c:type:`struct drm_framebuffer
-<drm_framebuffer>` is embedded into the fbdev helper struct)
-drivers can manually clean up a framebuffer at module unload time with
-:c:func:`drm_framebuffer_unregister_private()`.
+========================
+
+.. kernel-doc:: drivers/gpu/drm/drm_framebuffer.c
+   :doc: overview
+
+Frame Buffer Functions Reference
+--------------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_framebuffer.c
+   :export:
+
+.. kernel-doc:: include/drm/drm_framebuffer.h
+   :internal:
 
 DRM Format Handling
--------------------
+===================
 
 .. kernel-doc:: drivers/gpu/drm/drm_fourcc.c
    :export:
 
 Dumb Buffer Objects
--------------------
+===================
 
 The KMS API doesn't standardize backing storage object creation and
 leaves it to driver-specific ioctls. Furthermore actually creating a
@@ -114,14 +110,59 @@ Note that dumb objects may not be used for gpu acceleration, as has been
 attempted on some ARM embedded platforms. Such drivers really must have
 a hardware-specific ioctl to allocate suitable buffer objects.
 
-Output Polling
---------------
+Plane Abstraction
+=================
+
+.. kernel-doc:: drivers/gpu/drm/drm_plane.c
+   :doc: overview
+
+Plane Functions Reference
+-------------------------
+
+.. kernel-doc:: include/drm/drm_plane.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_plane.c
+   :export:
+
+Display Modes Function Reference
+================================
+
+.. kernel-doc:: include/drm/drm_modes.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_modes.c
+   :export:
 
-void (\*output_poll_changed)(struct drm_device \*dev);
-This operation notifies the driver that the status of one or more
-connectors has changed. Drivers that use the fb helper can just call the
-:c:func:`drm_fb_helper_hotplug_event()` function to handle this
-operation.
+Connector Abstraction
+=====================
+
+.. kernel-doc:: drivers/gpu/drm/drm_connector.c
+   :doc: overview
+
+Connector Functions Reference
+-----------------------------
+
+.. kernel-doc:: include/drm/drm_connector.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_connector.c
+   :export:
+
+Encoder Abstraction
+===================
+
+.. kernel-doc:: drivers/gpu/drm/drm_encoder.c
+   :doc: overview
+
+Encoder Functions Reference
+---------------------------
+
+.. kernel-doc:: include/drm/drm_encoder.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_encoder.c
+   :export:
 
 KMS Initialization and Cleanup
 ==============================
@@ -151,250 +192,6 @@ allocated and zeroed by the driver, possibly as part of a larger
 structure, and registered with a call to :c:func:`drm_crtc_init()`
 with a pointer to CRTC functions.
 
-Planes (:c:type:`struct drm_plane <drm_plane>`)
------------------------------------------------
-
-A plane represents an image source that can be blended with or overlayed
-on top of a CRTC during the scanout process. Planes are associated with
-a frame buffer to crop a portion of the image memory (source) and
-optionally scale it to a destination size. The result is then blended
-with or overlayed on top of a CRTC.
-
-The DRM core recognizes three types of planes:
-
--  DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC.
-   Primary planes are the planes operated upon by CRTC modesetting and
-   flipping operations described in the page_flip hook in
-   :c:type:`struct drm_crtc_funcs <drm_crtc_funcs>`.
--  DRM_PLANE_TYPE_CURSOR represents a "cursor" plane for a CRTC.
-   Cursor planes are the planes operated upon by the
-   DRM_IOCTL_MODE_CURSOR and DRM_IOCTL_MODE_CURSOR2 ioctls.
--  DRM_PLANE_TYPE_OVERLAY represents all non-primary, non-cursor
-   planes. Some drivers refer to these types of planes as "sprites"
-   internally.
-
-For compatibility with legacy userspace, only overlay planes are made
-available to userspace by default. Userspace clients may set the
-DRM_CLIENT_CAP_UNIVERSAL_PLANES client capability bit to indicate
-that they wish to receive a universal plane list containing all plane
-types.
-
-Plane Initialization
-~~~~~~~~~~~~~~~~~~~~
-
-To create a plane, a KMS drivers allocates and zeroes an instances of
-:c:type:`struct drm_plane <drm_plane>` (possibly as part of a
-larger structure) and registers it with a call to
-:c:func:`drm_universal_plane_init()`. The function takes a
-bitmask of the CRTCs that can be associated with the plane, a pointer to
-the plane functions, a list of format supported formats, and the type of
-plane (primary, cursor, or overlay) being initialized.
-
-Cursor and overlay planes are optional. All drivers should provide one
-primary plane per CRTC (although this requirement may change in the
-future); drivers that do not wish to provide special handling for
-primary planes may make use of the helper functions described in ? to
-create and register a primary plane with standard capabilities.
-
-Encoders (:c:type:`struct drm_encoder <drm_encoder>`)
------------------------------------------------------
-
-An encoder takes pixel data from a CRTC and converts it to a format
-suitable for any attached connectors. On some devices, it may be
-possible to have a CRTC send data to more than one encoder. In that
-case, both encoders would receive data from the same scanout buffer,
-resulting in a "cloned" display configuration across the connectors
-attached to each encoder.
-
-Encoder Initialization
-~~~~~~~~~~~~~~~~~~~~~~
-
-As for CRTCs, a KMS driver must create, initialize and register at least
-one :c:type:`struct drm_encoder <drm_encoder>` instance. The
-instance is allocated and zeroed by the driver, possibly as part of a
-larger structure.
-
-Drivers must initialize the :c:type:`struct drm_encoder
-<drm_encoder>` possible_crtcs and possible_clones fields before
-registering the encoder. Both fields are bitmasks of respectively the
-CRTCs that the encoder can be connected to, and sibling encoders
-candidate for cloning.
-
-After being initialized, the encoder must be registered with a call to
-:c:func:`drm_encoder_init()`. The function takes a pointer to the
-encoder functions and an encoder type. Supported types are
-
--  DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A
--  DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort
--  DRM_MODE_ENCODER_LVDS for display panels
--  DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video,
-   Component, SCART)
--  DRM_MODE_ENCODER_VIRTUAL for virtual machine displays
-
-Encoders must be attached to a CRTC to be used. DRM drivers leave
-encoders unattached at initialization time. Applications (or the fbdev
-compatibility layer when implemented) are responsible for attaching the
-encoders they want to use to a CRTC.
-
-Connectors (:c:type:`struct drm_connector <drm_connector>`)
------------------------------------------------------------
-
-A connector is the final destination for pixel data on a device, and
-usually connects directly to an external display device like a monitor
-or laptop panel. A connector can only be attached to one encoder at a
-time. The connector is also the structure where information about the
-attached display is kept, so it contains fields for display data, EDID
-data, DPMS & connection status, and information about modes supported on
-the attached displays.
-
-Connector Initialization
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Finally a KMS driver must create, initialize, register and attach at
-least one :c:type:`struct drm_connector <drm_connector>`
-instance. The instance is created as other KMS objects and initialized
-by setting the following fields.
-
-interlace_allowed
-    Whether the connector can handle interlaced modes.
-
-doublescan_allowed
-    Whether the connector can handle doublescan.
-
-display_info
-    Display information is filled from EDID information when a display
-    is detected. For non hot-pluggable displays such as flat panels in
-    embedded systems, the driver should initialize the
-    display_info.width_mm and display_info.height_mm fields with the
-    physical size of the display.
-
-polled
-    Connector polling mode, a combination of
-
-    DRM_CONNECTOR_POLL_HPD
-        The connector generates hotplug events and doesn't need to be
-        periodically polled. The CONNECT and DISCONNECT flags must not
-        be set together with the HPD flag.
-
-    DRM_CONNECTOR_POLL_CONNECT
-        Periodically poll the connector for connection.
-
-    DRM_CONNECTOR_POLL_DISCONNECT
-        Periodically poll the connector for disconnection.
-
-    Set to 0 for connectors that don't support connection status
-    discovery.
-
-The connector is then registered with a call to
-:c:func:`drm_connector_init()` with a pointer to the connector
-functions and a connector type, and exposed through sysfs with a call to
-:c:func:`drm_connector_register()`.
-
-Supported connector types are
-
--  DRM_MODE_CONNECTOR_VGA
--  DRM_MODE_CONNECTOR_DVII
--  DRM_MODE_CONNECTOR_DVID
--  DRM_MODE_CONNECTOR_DVIA
--  DRM_MODE_CONNECTOR_Composite
--  DRM_MODE_CONNECTOR_SVIDEO
--  DRM_MODE_CONNECTOR_LVDS
--  DRM_MODE_CONNECTOR_Component
--  DRM_MODE_CONNECTOR_9PinDIN
--  DRM_MODE_CONNECTOR_DisplayPort
--  DRM_MODE_CONNECTOR_HDMIA
--  DRM_MODE_CONNECTOR_HDMIB
--  DRM_MODE_CONNECTOR_TV
--  DRM_MODE_CONNECTOR_eDP
--  DRM_MODE_CONNECTOR_VIRTUAL
-
-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
-:c:func:`drm_mode_connector_attach_encoder()`. The driver must
-also set the :c:type:`struct drm_connector <drm_connector>`
-encoder field to point to the attached encoder.
-
-Finally, drivers must initialize the connectors state change detection
-with a call to :c:func:`drm_kms_helper_poll_init()`. If at least
-one connector is pollable but can't generate hotplug interrupts
-(indicated by the DRM_CONNECTOR_POLL_CONNECT and
-DRM_CONNECTOR_POLL_DISCONNECT connector flags), a delayed work will
-automatically be queued to periodically poll for changes. Connectors
-that can generate hotplug interrupts must be marked with the
-DRM_CONNECTOR_POLL_HPD flag instead, and their interrupt handler must
-call :c:func:`drm_helper_hpd_irq_event()`. The function will
-queue a delayed work to check the state of all connectors, but no
-periodic polling will be done.
-
-Connector Operations
-~~~~~~~~~~~~~~~~~~~~
-
-    **Note**
-
-    Unless otherwise state, all operations are mandatory.
-
-DPMS
-''''
-
-void (\*dpms)(struct drm_connector \*connector, int mode);
-The DPMS operation sets the power state of a connector. The mode
-argument is one of
-
--  DRM_MODE_DPMS_ON
-
--  DRM_MODE_DPMS_STANDBY
-
--  DRM_MODE_DPMS_SUSPEND
-
--  DRM_MODE_DPMS_OFF
-
-In all but DPMS_ON mode the encoder to which the connector is attached
-should put the display in low-power mode by driving its signals
-appropriately. If more than one connector is attached to the encoder
-care should be taken not to change the power state of other displays as
-a side effect. Low-power mode should be propagated to the encoders and
-CRTCs when all related connectors are put in low-power mode.
-
-Modes
-'''''
-
-int (\*fill_modes)(struct drm_connector \*connector, uint32_t
-max_width, uint32_t max_height);
-Fill the mode list with all supported modes for the connector. If the
-``max_width`` and ``max_height`` arguments are non-zero, the
-implementation must ignore all modes wider than ``max_width`` or higher
-than ``max_height``.
-
-The connector must also fill in this operation its display_info
-width_mm and height_mm fields with the connected display physical size
-in millimeters. The fields should be set to 0 if the value isn't known
-or is not applicable (for instance for projector devices).
-
-Connection Status
-'''''''''''''''''
-
-The connection status is updated through polling or hotplug events when
-supported (see ?). The status value is reported to userspace through
-ioctls and must not be used inside the driver, as it only gets
-initialized by a call to :c:func:`drm_mode_getconnector()` from
-userspace.
-
-enum drm_connector_status (\*detect)(struct drm_connector
-\*connector, bool force);
-Check to see if anything is attached to the connector. The ``force``
-parameter is set to false whilst polling or to true when checking the
-connector due to user request. ``force`` can be used by the driver to
-avoid expensive, destructive operations during automated probing.
-
-Return connector_status_connected if something is connected to the
-connector, connector_status_disconnected if nothing is connected and
-connector_status_unknown if the connection state isn't known.
-
-Drivers should only return connector_status_connected if the
-connection status has really been probed as connected. Connectors that
-can't detect the connection status, or failed connection status probes,
-should return connector_status_unknown.
 
 Cleanup
 -------
@@ -463,20 +260,8 @@ created for fetching EDID data and performing monitor detection. Once
 the process is complete, the new connector is registered with sysfs to
 make its properties available to applications.
 
-KMS API Functions
------------------
-
-.. kernel-doc:: drivers/gpu/drm/drm_crtc.c
-   :export:
-
-KMS Data Structures
--------------------
-
-.. kernel-doc:: include/drm/drm_crtc.h
-   :internal:
-
 KMS Locking
------------
+===========
 
 .. kernel-doc:: drivers/gpu/drm/drm_modeset_lock.c
    :doc: kms locking
@@ -490,90 +275,38 @@ KMS Locking
 KMS Properties
 ==============
 
-Drivers may need to expose additional parameters to applications than
-those described in the previous sections. KMS supports attaching
-properties to CRTCs, connectors and planes and offers a userspace API to
-list, get and set the property values.
-
-Properties are identified by a name that uniquely defines the property
-purpose, and store an associated value. For all property types except
-blob properties the value is a 64-bit unsigned integer.
-
-KMS differentiates between properties and property instances. Drivers
-first create properties and then create and associate individual
-instances of those properties to objects. A property can be instantiated
-multiple times and associated with different objects. Values are stored
-in property instances, and all other property information are stored in
-the property and shared between all instances of the property.
-
-Every property is created with a type that influences how the KMS core
-handles the property. Supported property types are
-
-DRM_MODE_PROP_RANGE
-    Range properties report their minimum and maximum admissible values.
-    The KMS core verifies that values set by application fit in that
-    range.
-
-DRM_MODE_PROP_ENUM
-    Enumerated properties take a numerical value that ranges from 0 to
-    the number of enumerated values defined by the property minus one,
-    and associate a free-formed string name to each value. Applications
-    can retrieve the list of defined value-name pairs and use the
-    numerical value to get and set property instance values.
-
-DRM_MODE_PROP_BITMASK
-    Bitmask properties are enumeration properties that additionally
-    restrict all enumerated values to the 0..63 range. Bitmask property
-    instance values combine one or more of the enumerated bits defined
-    by the property.
-
-DRM_MODE_PROP_BLOB
-    Blob properties store a binary blob without any format restriction.
-    The binary blobs are created as KMS standalone objects, and blob
-    property instance values store the ID of their associated blob
-    object.
-
-    Blob properties are only used for the connector EDID property and
-    cannot be created by drivers.
-
-To create a property drivers call one of the following functions
-depending on the property type. All property creation functions take
-property flags and name, as well as type-specific arguments.
-
--  struct drm_property \*drm_property_create_range(struct
-   drm_device \*dev, int flags, const char \*name, uint64_t min,
-   uint64_t max);
-   Create a range property with the given minimum and maximum values.
-
--  struct drm_property \*drm_property_create_enum(struct drm_device
-   \*dev, int flags, const char \*name, const struct
-   drm_prop_enum_list \*props, int num_values);
-   Create an enumerated property. The ``props`` argument points to an
-   array of ``num_values`` value-name pairs.
-
--  struct drm_property \*drm_property_create_bitmask(struct
-   drm_device \*dev, int flags, const char \*name, const struct
-   drm_prop_enum_list \*props, int num_values);
-   Create a bitmask property. The ``props`` argument points to an array
-   of ``num_values`` value-name pairs.
-
-Properties can additionally be created as immutable, in which case they
-will be read-only for applications but can be modified by the driver. To
-create an immutable property drivers must set the
-DRM_MODE_PROP_IMMUTABLE flag at property creation time.
-
-When no array of value-name pairs is readily available at property
-creation time for enumerated or range properties, drivers can create the
-property using the :c:func:`drm_property_create()` function and
-manually add enumeration value-name pairs by calling the
-:c:func:`drm_property_add_enum()` function. Care must be taken to
-properly specify the property type through the ``flags`` argument.
-
-After creating properties drivers can attach property instances to CRTC,
-connector and plane objects by calling the
-:c:func:`drm_object_attach_property()`. The function takes a
-pointer to the target object, a pointer to the previously created
-property and an initial instance value.
+Property Types and Blob Property Support
+----------------------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_property.c
+   :doc: overview
+
+.. kernel-doc:: include/drm/drm_property.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_property.c
+   :export:
+
+Plane Composition Properties
+----------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_blend.c
+   :doc: overview
+
+.. kernel-doc:: drivers/gpu/drm/drm_blend.c
+   :export:
+
+Color Management Properties
+---------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c
+   :doc: overview
+
+.. kernel-doc:: include/drm/drm_color_mgmt.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c
+   :export:
 
 Existing KMS Properties
 -----------------------
index 59f9822..bca8085 100644 (file)
@@ -26,12 +26,12 @@ TTM, but has no video RAM management capabilities and is thus limited to
 UMA devices.
 
 The Translation Table Manager (TTM)
------------------------------------
+===================================
 
 TTM design background and information belongs here.
 
 TTM initialization
-~~~~~~~~~~~~~~~~~~
+------------------
 
     **Warning**
 
@@ -77,7 +77,7 @@ object, ttm_global_item_ref() is used to create an initial reference
 count for the TTM, which will call your initialization function.
 
 The Graphics Execution Manager (GEM)
-------------------------------------
+====================================
 
 The GEM design approach has resulted in a memory manager that doesn't
 provide full coverage of all (or even all common) use cases in its
@@ -114,7 +114,7 @@ read & write, mapping, and domain ownership transfers are left to
 driver-specific ioctls.
 
 GEM Initialization
-~~~~~~~~~~~~~~~~~~
+------------------
 
 Drivers that use GEM must set the DRIVER_GEM bit in the struct
 :c:type:`struct drm_driver <drm_driver>` driver_features
@@ -132,7 +132,7 @@ typically not managed by GEM, and must be initialized separately into
 its own DRM MM object.
 
 GEM Objects Creation
-~~~~~~~~~~~~~~~~~~~~
+--------------------
 
 GEM splits creation of GEM objects and allocation of the memory that
 backs them in two distinct operations.
@@ -173,7 +173,7 @@ a call to :c:func:`drm_gem_private_object_init()` instead of
 must be managed by drivers.
 
 GEM Objects Lifetime
-~~~~~~~~~~~~~~~~~~~~
+--------------------
 
 All GEM objects are reference-counted by the GEM core. References can be
 acquired and release by :c:func:`calling
@@ -196,7 +196,7 @@ resources created by the GEM core, which need to be released with
 :c:func:`drm_gem_object_release()`.
 
 GEM Objects Naming
-~~~~~~~~~~~~~~~~~~
+------------------
 
 Communication between userspace and the kernel refers to GEM objects
 using local handles, global names or, more recently, file descriptors.
@@ -245,7 +245,7 @@ Furthermore PRIME also allows cross-device buffer sharing since it is
 based on dma-bufs.
 
 GEM Objects Mapping
-~~~~~~~~~~~~~~~~~~~
+-------------------
 
 Because mapping operations are fairly heavyweight GEM favours
 read/write-like access to buffers, implemented through driver-specific
@@ -304,7 +304,7 @@ Drivers that want to map the GEM object upfront instead of handling page
 faults can implement their own mmap file operation handler.
 
 Memory Coherency
-~~~~~~~~~~~~~~~~
+----------------
 
 When mapped to the device or used in a command buffer, backing pages for
 an object are flushed to memory and marked write combined so as to be
@@ -320,7 +320,7 @@ blocks the client and waits for rendering to complete before performing
 any necessary flushing operations).
 
 Command Execution
-~~~~~~~~~~~~~~~~~
+-----------------
 
 Perhaps the most important GEM function for GPU devices is providing a
 command execution interface to clients. Client programs construct
@@ -348,8 +348,20 @@ GEM Function Reference
 .. kernel-doc:: include/drm/drm_gem.h
    :internal:
 
+GEM CMA Helper Functions Reference
+----------------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
+   :doc: cma helpers
+
+.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
+   :export:
+
+.. kernel-doc:: include/drm/drm_gem_cma_helper.h
+   :internal:
+
 VMA Offset Manager
-------------------
+==================
 
 .. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c
    :doc: vma offset manager
@@ -361,14 +373,14 @@ VMA Offset Manager
    :internal:
 
 PRIME Buffer Sharing
---------------------
+====================
 
 PRIME is the cross device buffer sharing framework in drm, originally
 created for the OPTIMUS range of multi-gpu platforms. To userspace PRIME
 buffers are dma-buf based file descriptors.
 
 Overview and Driver Interface
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-----------------------------
 
 Similar to GEM global names, PRIME file descriptors are also used to
 share buffer objects across processes. They offer additional security:
@@ -406,7 +418,7 @@ struct drm_gem_object \*obj, int flags); struct drm_gem_object \*
 support PRIME.
 
 PRIME Helper Functions
-~~~~~~~~~~~~~~~~~~~~~~
+----------------------
 
 .. kernel-doc:: drivers/gpu/drm/drm_prime.c
    :doc: PRIME Helpers
@@ -418,16 +430,16 @@ PRIME Function References
    :export:
 
 DRM MM Range Allocator
-----------------------
+======================
 
 Overview
-~~~~~~~~
+--------
 
 .. kernel-doc:: drivers/gpu/drm/drm_mm.c
    :doc: Overview
 
 LRU Scan/Eviction Support
-~~~~~~~~~~~~~~~~~~~~~~~~~
+-------------------------
 
 .. kernel-doc:: drivers/gpu/drm/drm_mm.c
    :doc: lru scan roaster
@@ -440,15 +452,3 @@ DRM MM Range Allocator Function References
 
 .. kernel-doc:: include/drm/drm_mm.h
    :internal:
-
-CMA Helper Functions Reference
-------------------------------
-
-.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
-   :doc: cma helpers
-
-.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
-   :export:
-
-.. kernel-doc:: include/drm/drm_gem_cma_helper.h
-   :internal:
index 536bf3e..1ba301c 100644 (file)
@@ -33,6 +33,76 @@ Primary Nodes, DRM Master and Authentication
 .. kernel-doc:: include/drm/drm_auth.h
    :internal:
 
+Open-Source Userspace Requirements
+==================================
+
+The DRM subsystem has stricter requirements than most other kernel subsystems on
+what the userspace side for new uAPI needs to look like. This section here
+explains what exactly those requirements are, and why they exist.
+
+The short summary is that any addition of DRM uAPI requires corresponding
+open-sourced userspace patches, and those patches must be reviewed and ready for
+merging into a suitable and canonical upstream project.
+
+GFX devices (both display and render/GPU side) are really complex bits of
+hardware, with userspace and kernel by necessity having to work together really
+closely.  The interfaces, for rendering and modesetting, must be extremely wide
+and flexible, and therefore it is almost always impossible to precisely define
+them for every possible corner case. This in turn makes it really practically
+infeasible to differentiate between behaviour that's required by userspace, and
+which must not be changed to avoid regressions, and behaviour which is only an
+accidental artifact of the current implementation.
+
+Without access to the full source code of all userspace users that means it
+becomes impossible to change the implementation details, since userspace could
+depend upon the accidental behaviour of the current implementation in minute
+details. And debugging such regressions without access to source code is pretty
+much impossible. As a consequence this means:
+
+- The Linux kernel's "no regression" policy holds in practice only for
+  open-source userspace of the DRM subsystem. DRM developers are perfectly fine
+  if closed-source blob drivers in userspace use the same uAPI as the open
+  drivers, but they must do so in the exact same way as the open drivers.
+  Creative (ab)use of the interfaces will, and in the past routinely has, lead
+  to breakage.
+
+- Any new userspace interface must have an open-source implementation as
+  demonstration vehicle.
+
+The other reason for requiring open-source userspace is uAPI review. Since the
+kernel and userspace parts of a GFX stack must work together so closely, code
+review can only assess whether a new interface achieves its goals by looking at
+both sides. Making sure that the interface indeed covers the use-case fully
+leads to a few additional requirements:
+
+- The open-source userspace must not be a toy/test application, but the real
+  thing. Specifically it needs to handle all the usual error and corner cases.
+  These are often the places where new uAPI falls apart and hence essential to
+  assess the fitness of a proposed interface.
+
+- The userspace side must be fully reviewed and tested to the standards of that
+  userspace project. For e.g. mesa this means piglit testcases and review on the
+  mailing list. This is again to ensure that the new interface actually gets the
+  job done.
+
+- The userspace patches must be against the canonical upstream, not some vendor
+  fork. This is to make sure that no one cheats on the review and testing
+  requirements by doing a quick fork.
+
+- The kernel patch can only be merged after all the above requirements are met,
+  but it **must** be merged **before** the userspace patches land. uAPI always flows
+  from the kernel, doing things the other way round risks divergence of the uAPI
+  definitions and header files.
+
+These are fairly steep requirements, but have grown out from years of shared
+pain and experience with uAPI added hastily, and almost always regretted about
+just as fast. GFX devices change really fast, requiring a paradigm shift and
+entire new set of uAPI interfaces every few years at least. Together with the
+Linux kernel's guarantee to keep existing userspace running for 10+ years this
+is already rather painful for the DRM subsystem, with multiple different uAPIs
+for the same thing co-existing. If we add a few more complete mistakes into the
+mix every year it would be entirely unmanageable.
+
 Render nodes
 ============
 
@@ -86,6 +156,43 @@ other hand, a driver requires shared state between clients which is
 visible to user-space and accessible beyond open-file boundaries, they
 cannot support render nodes.
 
+Validating changes with IGT
+===========================
+
+There's a collection of tests that aims to cover the whole functionality of
+DRM drivers and that can be used to check that changes to DRM drivers or the
+core don't regress existing functionality. This test suite is called IGT and
+its code can be found in https://cgit.freedesktop.org/drm/igt-gpu-tools/.
+
+To build IGT, start by installing its build dependencies. In Debian-based
+systems::
+
+       # apt-get build-dep intel-gpu-tools
+
+And in Fedora-based systems::
+
+       # dnf builddep intel-gpu-tools
+
+Then clone the repository::
+
+       $ git clone git://anongit.freedesktop.org/drm/igt-gpu-tools
+
+Configure the build system and start the build::
+
+       $ cd igt-gpu-tools && ./autogen.sh && make -j6
+
+Download the piglit dependency::
+
+       $ ./scripts/run-tests.sh -d
+
+And run the tests::
+
+       $ ./scripts/run-tests.sh -t kms -t core -s
+
+run-tests.sh is a wrapper around piglit that will execute the tests matching
+the -t options. A report in HTML format will be available in
+./results/html/index.html. Results can be compared with piglit.
+
 VBlank event handling
 =====================
 
index 2fe5952..87aaffc 100644 (file)
@@ -70,6 +70,9 @@ Frontbuffer Tracking
 .. kernel-doc:: drivers/gpu/drm/i915/intel_frontbuffer.c
    :doc: frontbuffer tracking
 
+.. kernel-doc:: drivers/gpu/drm/i915/intel_frontbuffer.h
+   :internal:
+
 .. kernel-doc:: drivers/gpu/drm/i915/intel_frontbuffer.c
    :internal:
 
index 5ff3d2b..be0dafc 100644 (file)
@@ -12,6 +12,7 @@ Linux GPU Driver Developer's Guide
    drm-uapi
    i915
    vga-switcheroo
+   vgaarbiter
 
 .. only::  subproject
 
index 4c5ce3e..981873a 100644 (file)
@@ -1,23 +1,10 @@
 Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,Description/Restrictions
-DRM,Generic,“rotation”,BITMASK,"{ 0, ""rotate-0"" }, { 1, ""rotate-90"" }, { 2, ""rotate-180"" }, { 3, ""rotate-270"" }, { 4, ""reflect-x"" }, { 5, ""reflect-y"" }","CRTC, Plane",rotate-(degrees) rotates the image by the specified amount in degrees in counter clockwise direction. reflect-x and reflect-y reflects the image along the specified axis prior to rotation
 ,,“scaling mode”,ENUM,"{ ""None"", ""Full"", ""Center"", ""Full aspect"" }",Connector,"Supported by: amdgpu, gma500, i915, nouveau and radeon."
 ,Connector,“EDID”,BLOB | IMMUTABLE,0,Connector,Contains id of edid blob ptr object.
 ,,“DPMS”,ENUM,"{ “On”, “Standby”, “Suspend”, “Off” }",Connector,Contains DPMS operation mode value.
 ,,“PATH”,BLOB | IMMUTABLE,0,Connector,Contains topology path to a connector.
 ,,“TILE”,BLOB | IMMUTABLE,0,Connector,Contains tiling information for a connector.
 ,,“CRTC_ID”,OBJECT,DRM_MODE_OBJECT_CRTC,Connector,CRTC that connector is attached to (atomic)
-,Plane,“type”,ENUM | IMMUTABLE,"{ ""Overlay"", ""Primary"", ""Cursor"" }",Plane,Plane type
-,,“SRC_X”,RANGE,"Min=0, Max=UINT_MAX",Plane,Scanout source x coordinate in 16.16 fixed point (atomic)
-,,“SRC_Y”,RANGE,"Min=0, Max=UINT_MAX",Plane,Scanout source y coordinate in 16.16 fixed point (atomic)
-,,“SRC_W”,RANGE,"Min=0, Max=UINT_MAX",Plane,Scanout source width in 16.16 fixed point (atomic)
-,,“SRC_H”,RANGE,"Min=0, Max=UINT_MAX",Plane,Scanout source height in 16.16 fixed point (atomic)
-,,“CRTC_X”,SIGNED_RANGE,"Min=INT_MIN, Max=INT_MAX",Plane,Scanout CRTC (destination) x coordinate (atomic)
-,,“CRTC_Y”,SIGNED_RANGE,"Min=INT_MIN, Max=INT_MAX",Plane,Scanout CRTC (destination) y coordinate (atomic)
-,,“CRTC_W”,RANGE,"Min=0, Max=UINT_MAX",Plane,Scanout CRTC (destination) width (atomic)
-,,“CRTC_H”,RANGE,"Min=0, Max=UINT_MAX",Plane,Scanout CRTC (destination) height (atomic)
-,,“FB_ID”,OBJECT,DRM_MODE_OBJECT_FB,Plane,Scanout framebuffer (atomic)
-,,“CRTC_ID”,OBJECT,DRM_MODE_OBJECT_CRTC,Plane,CRTC that plane is attached to (atomic)
-,,“zpos”,RANGE,"Min=0, Max=UINT_MAX","Plane,Z-order of the plane.Planes with higher Z-order values are displayed on top, planes with identical Z-order values are display in an undefined order"
 ,DVI-I,“subconnector”,ENUM,"{ “Unknown”, “DVI-D”, “DVI-A” }",Connector,TBD
 ,,“select subconnector”,ENUM,"{ “Automatic”, “DVI-D”, “DVI-A” }",Connector,TBD
 ,TV,“subconnector”,ENUM,"{ ""Unknown"", ""Composite"", ""SVIDEO"", ""Component"", ""SCART"" }",Connector,TBD
@@ -36,12 +23,6 @@ DRM,Generic,“rotation”,BITMASK,"{ 0, ""rotate-0"" }, { 1, ""rotate-90"" }, {
 ,Virtual GPU,“suggested X”,RANGE,"Min=0, Max=0xffffffff",Connector,property to suggest an X offset for a connector
 ,,“suggested Y”,RANGE,"Min=0, Max=0xffffffff",Connector,property to suggest an Y offset for a connector
 ,Optional,"""aspect ratio""",ENUM,"{ ""None"", ""4:3"", ""16:9"" }",Connector,TDB
-,,“dirty”,ENUM | IMMUTABLE,"{ ""Off"", ""On"", ""Annotate"" }",Connector,TBD
-,,“DEGAMMA_LUT”,BLOB,0,CRTC,DRM property to set the degamma lookup table (LUT) mapping pixel data from the framebuffer before it is given to the transformation matrix. The data is an interpreted as an array of struct drm_color_lut elements. Hardware might choose not to use the full precision of the LUT elements nor use all the elements of the LUT (for example the hardware might choose to interpolate between LUT[0] and LUT[4]).
-,,“DEGAMMA_LUT_SIZE”,RANGE | IMMUTABLE,"Min=0, Max=UINT_MAX",CRTC,DRM property to gives the size of the lookup table to be set on the DEGAMMA_LUT property (the size depends on the underlying hardware).
-,,“CTM”,BLOB,0,CRTC,DRM property to set the current transformation matrix (CTM) apply to pixel data after the lookup through the degamma LUT and before the lookup through the gamma LUT. The data is an interpreted as a struct drm_color_ctm.
-,,“GAMMA_LUT”,BLOB,0,CRTC,DRM property to set the gamma lookup table (LUT) mapping pixel data after to the transformation matrix to data sent to the connector. The data is an interpreted as an array of struct drm_color_lut elements. Hardware might choose not to use the full precision of the LUT elements nor use all the elements of the LUT (for example the hardware might choose to interpolate between LUT[0] and LUT[4]).
-,,“GAMMA_LUT_SIZE”,RANGE | IMMUTABLE,"Min=0, Max=UINT_MAX",CRTC,DRM property to gives the size of the lookup table to be set on the GAMMA_LUT property (the size depends on the underlying hardware).
 i915,Generic,"""Broadcast RGB""",ENUM,"{ ""Automatic"", ""Full"", ""Limited 16:235"" }",Connector,"When this property is set to Limited 16:235 and CTM is set, the hardware will be programmed with the result of the multiplication of CTM by the limited range matrix to ensure the pixels normaly in the range 0..1.0 are remapped to the range 16/255..235/255."
 ,,“audio”,ENUM,"{ ""force-dvi"", ""off"", ""auto"", ""on"" }",Connector,TBD
 ,SDVO-TV,“mode”,ENUM,"{ ""NTSC_M"", ""NTSC_J"", ""NTSC_443"", ""PAL_B"" } etc.",Connector,TBD
@@ -95,7 +76,6 @@ armada,CRTC,"""CSC_YUV""",ENUM,"{ ""Auto"" , ""CCIR601"", ""CCIR709"" }",CRTC,TB
 ,,"""contrast""",RANGE,"Min=0, Max=0x7fff",Plane,TBD
 ,,"""saturation""",RANGE,"Min=0, Max=0x7fff",Plane,TBD
 exynos,CRTC,“mode”,ENUM,"{ ""normal"", ""blank"" }",CRTC,TBD
-,Overlay,“zpos”,RANGE,"Min=0, Max=MAX_PLANE-1",Plane,TBD
 i2c/ch7006_drv,Generic,“scale”,RANGE,"Min=0, Max=2",Connector,TBD
 ,TV,“mode”,ENUM,"{ ""PAL"", ""PAL-M"",""PAL-N""}, ”PAL-Nc"" , ""PAL-60"", ""NTSC-M"", ""NTSC-J"" }",Connector,TBD
 nouveau,NV10 Overlay,"""colorkey""",RANGE,"Min=0, Max=0x01ffffff",Plane,TBD
@@ -126,4 +106,3 @@ radeon,DVI-I,“coherent”,RANGE,"Min=0, Max=1",Connector,TBD
 ,FMT Dithering,“dither”,ENUM,"{ ""off"", ""on"" }",Connector,TBD
 rcar-du,Generic,"""alpha""",RANGE,"Min=0, Max=255",Plane,TBD
 ,,"""colorkey""",RANGE,"Min=0, Max=0x01ffffff",Plane,TBD
-,,"""zpos""",RANGE,"Min=1, Max=7",Plane,TBD
diff --git a/Documentation/gpu/vgaarbiter.rst b/Documentation/gpu/vgaarbiter.rst
new file mode 100644 (file)
index 0000000..0b41b05
--- /dev/null
@@ -0,0 +1,191 @@
+===========
+VGA Arbiter
+===========
+
+Graphic devices are accessed through ranges in I/O or memory space. While most
+modern devices allow relocation of such ranges, some "Legacy" VGA devices
+implemented on PCI will typically have the same "hard-decoded" addresses as
+they did on ISA. For more details see "PCI Bus Binding to IEEE Std 1275-1994
+Standard for Boot (Initialization Configuration) Firmware Revision 2.1"
+Section 7, Legacy Devices.
+
+The Resource Access Control (RAC) module inside the X server [0] existed for
+the legacy VGA arbitration task (besides other bus management tasks) when more
+than one legacy device co-exists on the same machine. But the problem happens
+when these devices are trying to be accessed by different userspace clients
+(e.g. two server in parallel). Their address assignments conflict. Moreover,
+ideally, being a userspace application, it is not the role of the X server to
+control bus resources. Therefore an arbitration scheme outside of the X server
+is needed to control the sharing of these resources. This document introduces
+the operation of the VGA arbiter implemented for the Linux kernel.
+
+vgaarb kernel/userspace ABI
+---------------------------
+
+The vgaarb is a module of the Linux Kernel. When it is initially loaded, it
+scans all PCI devices and adds the VGA ones inside the arbitration. The
+arbiter then enables/disables the decoding on different devices of the VGA
+legacy instructions. Devices which do not want/need to use the arbiter may
+explicitly tell it by calling vga_set_legacy_decoding().
+
+The kernel exports a char device interface (/dev/vga_arbiter) to the clients,
+which has the following semantics:
+
+open
+        Opens a user instance of the arbiter. By default, it's attached to the
+        default VGA device of the system.
+
+close
+        Close a user instance. Release locks made by the user
+
+read
+        Return a string indicating the status of the target like:
+
+        "<card_ID>,decodes=<io_state>,owns=<io_state>,locks=<io_state> (ic,mc)"
+
+        An IO state string is of the form {io,mem,io+mem,none}, mc and
+        ic are respectively mem and io lock counts (for debugging/
+        diagnostic only). "decodes" indicate what the card currently
+        decodes, "owns" indicates what is currently enabled on it, and
+        "locks" indicates what is locked by this card. If the card is
+        unplugged, we get "invalid" then for card_ID and an -ENODEV
+        error is returned for any command until a new card is targeted.
+
+
+write
+        Write a command to the arbiter. List of commands:
+
+        target <card_ID>
+                switch target to card <card_ID> (see below)
+        lock <io_state>
+                acquires locks on target ("none" is an invalid io_state)
+        trylock <io_state>
+                non-blocking acquire locks on target (returns EBUSY if
+                unsuccessful)
+        unlock <io_state>
+                release locks on target
+        unlock all
+                release all locks on target held by this user (not implemented
+                yet)
+        decodes <io_state>
+                set the legacy decoding attributes for the card
+
+        poll
+                event if something changes on any card (not just the target)
+
+        card_ID is of the form "PCI:domain:bus:dev.fn". It can be set to "default"
+        to go back to the system default card (TODO: not implemented yet). Currently,
+        only PCI is supported as a prefix, but the userland API may support other bus
+        types in the future, even if the current kernel implementation doesn't.
+
+Note about locks:
+
+The driver keeps track of which user has which locks on which card. It
+supports stacking, like the kernel one. This complexifies the implementation
+a bit, but makes the arbiter more tolerant to user space problems and able
+to properly cleanup in all cases when a process dies.
+Currently, a max of 16 cards can have locks simultaneously issued from
+user space for a given user (file descriptor instance) of the arbiter.
+
+In the case of devices hot-{un,}plugged, there is a hook - pci_notify() - to
+notify them being added/removed in the system and automatically added/removed
+in the arbiter.
+
+There is also an in-kernel API of the arbiter in case DRM, vgacon, or other
+drivers want to use it.
+
+In-kernel interface
+-------------------
+
+.. kernel-doc:: include/linux/vgaarb.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/vga/vgaarb.c
+   :export:
+
+libpciaccess
+------------
+
+To use the vga arbiter char device it was implemented an API inside the
+libpciaccess library. One field was added to struct pci_device (each device
+on the system)::
+
+    /* the type of resource decoded by the device */
+    int vgaarb_rsrc;
+
+Besides it, in pci_system were added::
+
+    int vgaarb_fd;
+    int vga_count;
+    struct pci_device *vga_target;
+    struct pci_device *vga_default_dev;
+
+The vga_count is used to track how many cards are being arbitrated, so for
+instance, if there is only one card, then it can completely escape arbitration.
+
+These functions below acquire VGA resources for the given card and mark those
+resources as locked. If the resources requested are "normal" (and not legacy)
+resources, the arbiter will first check whether the card is doing legacy
+decoding for that type of resource. If yes, the lock is "converted" into a
+legacy resource lock. The arbiter will first look for all VGA cards that
+might conflict and disable their IOs and/or Memory access, including VGA
+forwarding on P2P bridges if necessary, so that the requested resources can
+be used. Then, the card is marked as locking these resources and the IO and/or
+Memory access is enabled on the card (including VGA forwarding on parent
+P2P bridges if any). In the case of vga_arb_lock(), the function will block
+if some conflicting card is already locking one of the required resources (or
+any resource on a different bus segment, since P2P bridges don't differentiate
+VGA memory and IO afaik). If the card already owns the resources, the function
+succeeds.  vga_arb_trylock() will return (-EBUSY) instead of blocking. Nested
+calls are supported (a per-resource counter is maintained).
+
+Set the target device of this client. ::
+
+    int  pci_device_vgaarb_set_target   (struct pci_device *dev);
+
+For instance, in x86 if two devices on the same bus want to lock different
+resources, both will succeed (lock). If devices are in different buses and
+trying to lock different resources, only the first who tried succeeds. ::
+
+    int  pci_device_vgaarb_lock         (void);
+    int  pci_device_vgaarb_trylock      (void);
+
+Unlock resources of device. ::
+
+    int  pci_device_vgaarb_unlock       (void);
+
+Indicates to the arbiter if the card decodes legacy VGA IOs, legacy VGA
+Memory, both, or none. All cards default to both, the card driver (fbdev for
+example) should tell the arbiter if it has disabled legacy decoding, so the
+card can be left out of the arbitration process (and can be safe to take
+interrupts at any time. ::
+
+    int  pci_device_vgaarb_decodes      (int new_vgaarb_rsrc);
+
+Connects to the arbiter device, allocates the struct ::
+
+    int  pci_device_vgaarb_init         (void);
+
+Close the connection ::
+
+    void pci_device_vgaarb_fini         (void);
+
+xf86VGAArbiter (X server implementation)
+----------------------------------------
+
+X server basically wraps all the functions that touch VGA registers somehow.
+
+References
+----------
+
+Benjamin Herrenschmidt (IBM?) started this work when he discussed such design
+with the Xorg community in 2005 [1, 2]. In the end of 2007, Paulo Zanoni and
+Tiago Vignatti (both of C3SL/Federal University of Paraná) proceeded his work
+enhancing the kernel code to adapt as a kernel module and also did the
+implementation of the user space side [3]. Now (2009) Tiago Vignatti and Dave
+Airlie finally put this work in shape and queued to Jesse Barnes' PCI tree.
+
+0) http://cgit.freedesktop.org/xorg/xserver/commit/?id=4b42448a2388d40f257774fbffdccaea87bd0347
+1) http://lists.freedesktop.org/archives/xorg/2005-March/006663.html
+2) http://lists.freedesktop.org/archives/xorg/2005-March/006745.html
+3) http://lists.freedesktop.org/archives/xorg/2007-October/029507.html
index e8e2eba..b63a685 100644 (file)
@@ -64,6 +64,20 @@ The sync_file fd now can be sent to userspace.
 If the creation process fail, or the sync_file needs to be released by any
 other reason fput(sync_file->file) should be used.
 
+Receiving Sync Files from Userspace
+-----------------------------------
+
+When userspace needs to send an in-fence to the driver it passes file descriptor
+of the Sync File to the kernel. The kernel can then retrieve the fences
+from it.
+
+Interface:
+       struct fence *sync_file_get_fence(int fd);
+
+
+The returned reference is owned by the caller and must be disposed of
+afterwards using fence_put(). In case of error, a NULL is returned instead.
+
 References:
 [1] struct sync_file in include/linux/sync_file.h
 [2] All interfaces mentioned above defined in include/linux/sync_file.h
diff --git a/Documentation/vgaarbiter.txt b/Documentation/vgaarbiter.txt
deleted file mode 100644 (file)
index 014423e..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-
-VGA Arbiter
-===========
-
-Graphic devices are accessed through ranges in I/O or memory space. While most
-modern devices allow relocation of such ranges, some "Legacy" VGA devices
-implemented on PCI will typically have the same "hard-decoded" addresses as
-they did on ISA. For more details see "PCI Bus Binding to IEEE Std 1275-1994
-Standard for Boot (Initialization Configuration) Firmware Revision 2.1"
-Section 7, Legacy Devices.
-
-The Resource Access Control (RAC) module inside the X server [0] existed for
-the legacy VGA arbitration task (besides other bus management tasks) when more
-than one legacy device co-exists on the same machine. But the problem happens
-when these devices are trying to be accessed by different userspace clients
-(e.g. two server in parallel). Their address assignments conflict. Moreover,
-ideally, being a userspace application, it is not the role of the X server to
-control bus resources. Therefore an arbitration scheme outside of the X server
-is needed to control the sharing of these resources. This document introduces
-the operation of the VGA arbiter implemented for the Linux kernel.
-
-----------------------------------------------------------------------------
-
-I.  Details and Theory of Operation
-        I.1 vgaarb
-        I.2 libpciaccess
-        I.3 xf86VGAArbiter (X server implementation)
-II. Credits
-III.References
-
-
-I. Details and Theory of Operation
-==================================
-
-I.1 vgaarb
-----------
-
-The vgaarb is a module of the Linux Kernel. When it is initially loaded, it
-scans all PCI devices and adds the VGA ones inside the arbitration. The
-arbiter then enables/disables the decoding on different devices of the VGA
-legacy instructions. Devices which do not want/need to use the arbiter may
-explicitly tell it by calling vga_set_legacy_decoding().
-
-The kernel exports a char device interface (/dev/vga_arbiter) to the clients,
-which has the following semantics:
-
- open       : open user instance of the arbiter. By default, it's attached to
-              the default VGA device of the system.
-
- close      : close user instance. Release locks made by the user
-
- read       : return a string indicating the status of the target like:
-
-              "<card_ID>,decodes=<io_state>,owns=<io_state>,locks=<io_state> (ic,mc)"
-
-              An IO state string is of the form {io,mem,io+mem,none}, mc and
-              ic are respectively mem and io lock counts (for debugging/
-              diagnostic only). "decodes" indicate what the card currently
-              decodes, "owns" indicates what is currently enabled on it, and
-              "locks" indicates what is locked by this card. If the card is
-              unplugged, we get "invalid" then for card_ID and an -ENODEV
-              error is returned for any command until a new card is targeted.
-
-
- write       : write a command to the arbiter. List of commands:
-
-  target <card_ID>   : switch target to card <card_ID> (see below)
-  lock <io_state>    : acquires locks on target ("none" is an invalid io_state)
-  trylock <io_state> : non-blocking acquire locks on target (returns EBUSY if
-                       unsuccessful)
-  unlock <io_state>  : release locks on target
-  unlock all         : release all locks on target held by this user (not
-                       implemented yet)
-  decodes <io_state> : set the legacy decoding attributes for the card
-
-  poll               : event if something changes on any card (not just the
-                       target)
-
-  card_ID is of the form "PCI:domain:bus:dev.fn". It can be set to "default"
-  to go back to the system default card (TODO: not implemented yet). Currently,
-  only PCI is supported as a prefix, but the userland API may support other bus
-  types in the future, even if the current kernel implementation doesn't.
-
-Note about locks:
-
-The driver keeps track of which user has which locks on which card. It
-supports stacking, like the kernel one. This complexifies the implementation
-a bit, but makes the arbiter more tolerant to user space problems and able
-to properly cleanup in all cases when a process dies.
-Currently, a max of 16 cards can have locks simultaneously issued from
-user space for a given user (file descriptor instance) of the arbiter.
-
-In the case of devices hot-{un,}plugged, there is a hook - pci_notify() - to
-notify them being added/removed in the system and automatically added/removed
-in the arbiter.
-
-There is also an in-kernel API of the arbiter in case DRM, vgacon, or other
-drivers want to use it.
-
-
-I.2 libpciaccess
-----------------
-
-To use the vga arbiter char device it was implemented an API inside the
-libpciaccess library. One field was added to struct pci_device (each device
-on the system):
-
-    /* the type of resource decoded by the device */
-    int vgaarb_rsrc;
-
-Besides it, in pci_system were added:
-
-    int vgaarb_fd;
-    int vga_count;
-    struct pci_device *vga_target;
-    struct pci_device *vga_default_dev;
-
-
-The vga_count is used to track how many cards are being arbitrated, so for
-instance, if there is only one card, then it can completely escape arbitration.
-
-
-These functions below acquire VGA resources for the given card and mark those
-resources as locked. If the resources requested are "normal" (and not legacy)
-resources, the arbiter will first check whether the card is doing legacy
-decoding for that type of resource. If yes, the lock is "converted" into a
-legacy resource lock. The arbiter will first look for all VGA cards that
-might conflict and disable their IOs and/or Memory access, including VGA
-forwarding on P2P bridges if necessary, so that the requested resources can
-be used. Then, the card is marked as locking these resources and the IO and/or
-Memory access is enabled on the card (including VGA forwarding on parent
-P2P bridges if any). In the case of vga_arb_lock(), the function will block
-if some conflicting card is already locking one of the required resources (or
-any resource on a different bus segment, since P2P bridges don't differentiate
-VGA memory and IO afaik). If the card already owns the resources, the function
-succeeds.  vga_arb_trylock() will return (-EBUSY) instead of blocking. Nested
-calls are supported (a per-resource counter is maintained).
-
-
-Set the target device of this client.
-    int  pci_device_vgaarb_set_target   (struct pci_device *dev);
-
-
-For instance, in x86 if two devices on the same bus want to lock different
-resources, both will succeed (lock). If devices are in different buses and
-trying to lock different resources, only the first who tried succeeds.
-    int  pci_device_vgaarb_lock         (void);
-    int  pci_device_vgaarb_trylock      (void);
-
-Unlock resources of device.
-    int  pci_device_vgaarb_unlock       (void);
-
-Indicates to the arbiter if the card decodes legacy VGA IOs, legacy VGA
-Memory, both, or none. All cards default to both, the card driver (fbdev for
-example) should tell the arbiter if it has disabled legacy decoding, so the
-card can be left out of the arbitration process (and can be safe to take
-interrupts at any time.
-    int  pci_device_vgaarb_decodes      (int new_vgaarb_rsrc);
-
-Connects to the arbiter device, allocates the struct
-    int  pci_device_vgaarb_init         (void);
-
-Close the connection
-    void pci_device_vgaarb_fini         (void);
-
-
-I.3 xf86VGAArbiter (X server implementation)
---------------------------------------------
-
-(TODO)
-
-X server basically wraps all the functions that touch VGA registers somehow.
-
-
-II. Credits
-===========
-
-Benjamin Herrenschmidt (IBM?) started this work when he discussed such design
-with the Xorg community in 2005 [1, 2]. In the end of 2007, Paulo Zanoni and
-Tiago Vignatti (both of C3SL/Federal University of Paraná) proceeded his work
-enhancing the kernel code to adapt as a kernel module and also did the
-implementation of the user space side [3]. Now (2009) Tiago Vignatti and Dave
-Airlie finally put this work in shape and queued to Jesse Barnes' PCI tree.
-
-
-III. References
-==============
-
-[0] http://cgit.freedesktop.org/xorg/xserver/commit/?id=4b42448a2388d40f257774fbffdccaea87bd0347
-[1] http://lists.freedesktop.org/archives/xorg/2005-March/006663.html
-[2] http://lists.freedesktop.org/archives/xorg/2005-March/006745.html
-[3] http://lists.freedesktop.org/archives/xorg/2007-October/029507.html
index dd78462..5e925a2 100644 (file)
@@ -4122,6 +4122,14 @@ S:       Orphan / Obsolete
 F:     drivers/gpu/drm/i810/
 F:     include/uapi/drm/i810_drm.h
 
+DRM DRIVERS FOR MEDIATEK
+M:     CK Hu <ck.hu@mediatek.com>
+M:     Philipp Zabel <p.zabel@pengutronix.de>
+L:     dri-devel@lists.freedesktop.org
+S:     Supported
+F:     drivers/gpu/drm/mediatek/
+F:     Documentation/devicetree/bindings/display/mediatek/
+
 DRM DRIVER FOR MSM ADRENO GPU
 M:     Rob Clark <robdclark@gmail.com>
 L:     linux-arm-msm@vger.kernel.org
index 55c0e95..6bbb1fe 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "am33xx.dtsi"
 #include "am335x-bone-common.dtsi"
+#include <dt-bindings/display/tda998x.h>
 
 / {
        model = "TI AM335x BeagleBone Black";
                        AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr0 */
                >;
        };
+
+       mcasp0_pins: mcasp0_pins {
+               pinctrl-single,pins = <
+                       AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLUP | MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
+                       AM33XX_IOPAD(0x99c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
+                       AM33XX_IOPAD(0x994, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
+                       AM33XX_IOPAD(0x990, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
+                       AM33XX_IOPAD(0x86c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */
+               >;
+       };
 };
 
 &lcdc {
 };
 
 &i2c0 {
-       tda19988 {
+       tda19988: tda19988 {
                compatible = "nxp,tda998x";
                reg = <0x70>;
+
                pinctrl-names = "default", "off";
                pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
                pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
 
-               port {
-                       hdmi_0: endpoint@0 {
-                               remote-endpoint = <&lcdc_0>;
+               #sound-dai-cells = <0>;
+               audio-ports = < TDA998x_I2S     0x03>;
+
+               ports {
+                       port@0 {
+                               hdmi_0: endpoint@0 {
+                                       remote-endpoint = <&lcdc_0>;
+                               };
                        };
                };
        };
 &rtc {
        system-power-controller;
 };
+
+&mcasp0        {
+       #sound-dai-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcasp0_pins>;
+       status = "okay";
+       op-mode = <0>;  /* MCASP_IIS_MODE */
+       tdm-slots = <2>;
+       serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
+                       0 0 1 0
+               >;
+       tx-num-evt = <32>;
+       rx-num-evt = <32>;
+};
+
+/ {
+       clk_mcasp0_fixed: clk_mcasp0_fixed {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <24576000>;
+       };
+
+       clk_mcasp0: clk_mcasp0 {
+               #clock-cells = <0>;
+               compatible = "gpio-gate-clock";
+               clocks = <&clk_mcasp0_fixed>;
+               enable-gpios = <&gpio1 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */
+       };
+
+       sound {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "TI BeagleBone Black";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,bitclock-master = <&dailink0_master>;
+               simple-audio-card,frame-master = <&dailink0_master>;
+
+               dailink0_master: simple-audio-card,cpu {
+                       sound-dai = <&mcasp0>;
+                       clocks = <&clk_mcasp0>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&tda19988>;
+               };
+       };
+};
index 18bb3a6..6a08e25 100644 (file)
@@ -317,16 +317,11 @@ static phys_addr_t __init i85x_stolen_base(int num, int slot, int func,
 static phys_addr_t __init i865_stolen_base(int num, int slot, int func,
                                           size_t stolen_size)
 {
-       u16 toud;
+       u16 toud = 0;
 
-       /*
-        * FIXME is the graphics stolen memory region
-        * always at TOUD? Ie. is it always the last
-        * one to be allocated by the BIOS?
-        */
        toud = read_pci_config_16(0, 0, 0, I865_TOUD);
 
-       return (phys_addr_t)toud << 16;
+       return (phys_addr_t)(toud << 16) + i845_tseg_size();
 }
 
 static phys_addr_t __init gen3_stolen_base(int num, int slot, int func,
@@ -512,8 +507,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
        INTEL_I915GM_IDS(&gen3_early_ops),
        INTEL_I945G_IDS(&gen3_early_ops),
        INTEL_I945GM_IDS(&gen3_early_ops),
-       INTEL_VLV_M_IDS(&gen6_early_ops),
-       INTEL_VLV_D_IDS(&gen6_early_ops),
+       INTEL_VLV_IDS(&gen6_early_ops),
        INTEL_PINEVIEW_IDS(&gen3_early_ops),
        INTEL_I965G_IDS(&gen3_early_ops),
        INTEL_G33_IDS(&gen3_early_ops),
@@ -526,10 +520,8 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
        INTEL_SNB_M_IDS(&gen6_early_ops),
        INTEL_IVB_M_IDS(&gen6_early_ops),
        INTEL_IVB_D_IDS(&gen6_early_ops),
-       INTEL_HSW_D_IDS(&gen6_early_ops),
-       INTEL_HSW_M_IDS(&gen6_early_ops),
-       INTEL_BDW_M_IDS(&gen8_early_ops),
-       INTEL_BDW_D_IDS(&gen8_early_ops),
+       INTEL_HSW_IDS(&gen6_early_ops),
+       INTEL_BDW_IDS(&gen8_early_ops),
        INTEL_CHV_IDS(&chv_early_ops),
        INTEL_SKL_IDS(&gen9_early_ops),
        INTEL_BXT_IDS(&gen9_early_ops),
index 4431129..0f7d28a 100644 (file)
@@ -845,6 +845,8 @@ void intel_gtt_insert_page(dma_addr_t addr,
                           unsigned int flags)
 {
        intel_private.driver->write_entry(addr, pg, flags);
+       if (intel_private.driver->chipset_flush)
+               intel_private.driver->chipset_flush();
 }
 EXPORT_SYMBOL(intel_gtt_insert_page);
 
index ddaee60..cf04d24 100644 (file)
@@ -586,6 +586,22 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
 }
 EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
 
+static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
+                                     enum dma_data_direction direction)
+{
+       bool write = (direction == DMA_BIDIRECTIONAL ||
+                     direction == DMA_TO_DEVICE);
+       struct reservation_object *resv = dmabuf->resv;
+       long ret;
+
+       /* Wait on any implicit rendering fences */
+       ret = reservation_object_wait_timeout_rcu(resv, write, true,
+                                                 MAX_SCHEDULE_TIMEOUT);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
 
 /**
  * dma_buf_begin_cpu_access - Must be called before accessing a dma_buf from the
@@ -608,6 +624,13 @@ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
        if (dmabuf->ops->begin_cpu_access)
                ret = dmabuf->ops->begin_cpu_access(dmabuf, direction);
 
+       /* Ensure that all fences are waited upon - but we first allow
+        * the native handler the chance to do so more efficiently if it
+        * chooses. A double invocation here will be reasonably cheap no-op.
+        */
+       if (ret == 0)
+               ret = __dma_buf_begin_cpu_access(dmabuf, direction);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
index a8731c8..f1989fc 100644 (file)
@@ -99,6 +99,7 @@ const struct fence_ops fence_array_ops = {
        .wait = fence_default_wait,
        .release = fence_array_release,
 };
+EXPORT_SYMBOL(fence_array_ops);
 
 /**
  * fence_array_create - Create a custom fence array
@@ -106,14 +107,14 @@ const struct fence_ops fence_array_ops = {
  * @fences:            [in]    array containing the fences
  * @context:           [in]    fence context to use
  * @seqno:             [in]    sequence number to use
- * @signal_on_any      [in]    signal on any fence in the array
+ * @signal_on_any:     [in]    signal on any fence in the array
  *
  * Allocate a fence_array object and initialize the base fence with fence_init().
  * In case of error it returns NULL.
  *
- * The caller should allocte the fences array with num_fences size
+ * The caller should allocate the fences array with num_fences size
  * and fill it with the fences it wants to add to the object. Ownership of this
- * array is take and fence_put() is used on each fence on release.
+ * array is taken and fence_put() is used on each fence on release.
  *
  * If @signal_on_any is true the fence array signals if any fence in the array
  * signals, otherwise it signals when all fences in the array signal.
index 9566a62..723d8af 100644 (file)
@@ -205,7 +205,7 @@ done:
  * @fence: the shared fence to add
  *
  * Add a fence to a shared slot, obj->lock must be held, and
- * reservation_object_reserve_shared_fence has been called.
+ * reservation_object_reserve_shared() has been called.
  */
 void reservation_object_add_shared_fence(struct reservation_object *obj,
                                         struct fence *fence)
index fab9520..2dd4c3d 100644 (file)
@@ -135,10 +135,16 @@ static void sync_print_sync_file(struct seq_file *s,
        int i;
 
        seq_printf(s, "[%p] %s: %s\n", sync_file, sync_file->name,
-                  sync_status_str(atomic_read(&sync_file->status)));
+                  sync_status_str(!fence_is_signaled(sync_file->fence)));
 
-       for (i = 0; i < sync_file->num_fences; ++i)
-               sync_print_fence(s, sync_file->cbs[i].fence, true);
+       if (fence_is_array(sync_file->fence)) {
+               struct fence_array *array = to_fence_array(sync_file->fence);
+
+               for (i = 0; i < array->num_fences; ++i)
+                       sync_print_fence(s, array->fences[i], true);
+       } else {
+               sync_print_fence(s, sync_file->fence, true);
+       }
 }
 
 static int sync_debugfs_show(struct seq_file *s, void *unused)
index 9aaa608..b29a9e8 100644 (file)
 
 static const struct file_operations sync_file_fops;
 
-static struct sync_file *sync_file_alloc(int size)
+static struct sync_file *sync_file_alloc(void)
 {
        struct sync_file *sync_file;
 
-       sync_file = kzalloc(size, GFP_KERNEL);
+       sync_file = kzalloc(sizeof(*sync_file), GFP_KERNEL);
        if (!sync_file)
                return NULL;
 
@@ -45,6 +45,8 @@ static struct sync_file *sync_file_alloc(int size)
 
        init_waitqueue_head(&sync_file->wq);
 
+       INIT_LIST_HEAD(&sync_file->cb.node);
+
        return sync_file;
 
 err:
@@ -54,14 +56,11 @@ err:
 
 static void fence_check_cb_func(struct fence *f, struct fence_cb *cb)
 {
-       struct sync_file_cb *check;
        struct sync_file *sync_file;
 
-       check = container_of(cb, struct sync_file_cb, cb);
-       sync_file = check->sync_file;
+       sync_file = container_of(cb, struct sync_file, cb);
 
-       if (atomic_dec_and_test(&sync_file->status))
-               wake_up_all(&sync_file->wq);
+       wake_up_all(&sync_file->wq);
 }
 
 /**
@@ -76,23 +75,17 @@ struct sync_file *sync_file_create(struct fence *fence)
 {
        struct sync_file *sync_file;
 
-       sync_file = sync_file_alloc(offsetof(struct sync_file, cbs[1]));
+       sync_file = sync_file_alloc();
        if (!sync_file)
                return NULL;
 
-       sync_file->num_fences = 1;
-       atomic_set(&sync_file->status, 1);
+       sync_file->fence = fence;
+
        snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d",
                 fence->ops->get_driver_name(fence),
                 fence->ops->get_timeline_name(fence), fence->context,
                 fence->seqno);
 
-       sync_file->cbs[0].fence = fence;
-       sync_file->cbs[0].sync_file = sync_file;
-       if (fence_add_callback(fence, &sync_file->cbs[0].cb,
-                              fence_check_cb_func))
-               atomic_dec(&sync_file->status);
-
        return sync_file;
 }
 EXPORT_SYMBOL(sync_file_create);
@@ -121,14 +114,73 @@ err:
        return NULL;
 }
 
-static void sync_file_add_pt(struct sync_file *sync_file, int *i,
-                            struct fence *fence)
+/**
+ * sync_file_get_fence - get the fence related to the sync_file fd
+ * @fd:                sync_file fd to get the fence from
+ *
+ * Ensures @fd references a valid sync_file and returns a fence that
+ * represents all fence in the sync_file. On error NULL is returned.
+ */
+struct fence *sync_file_get_fence(int fd)
+{
+       struct sync_file *sync_file;
+       struct fence *fence;
+
+       sync_file = sync_file_fdget(fd);
+       if (!sync_file)
+               return NULL;
+
+       fence = fence_get(sync_file->fence);
+       fput(sync_file->file);
+
+       return fence;
+}
+EXPORT_SYMBOL(sync_file_get_fence);
+
+static int sync_file_set_fence(struct sync_file *sync_file,
+                              struct fence **fences, int num_fences)
+{
+       struct fence_array *array;
+
+       /*
+        * The reference for the fences in the new sync_file and held
+        * in add_fence() during the merge procedure, so for num_fences == 1
+        * we already own a new reference to the fence. For num_fence > 1
+        * we own the reference of the fence_array creation.
+        */
+       if (num_fences == 1) {
+               sync_file->fence = fences[0];
+               kfree(fences);
+       } else {
+               array = fence_array_create(num_fences, fences,
+                                          fence_context_alloc(1), 1, false);
+               if (!array)
+                       return -ENOMEM;
+
+               sync_file->fence = &array->base;
+       }
+
+       return 0;
+}
+
+static struct fence **get_fences(struct sync_file *sync_file, int *num_fences)
+{
+       if (fence_is_array(sync_file->fence)) {
+               struct fence_array *array = to_fence_array(sync_file->fence);
+
+               *num_fences = array->num_fences;
+               return array->fences;
+       }
+
+       *num_fences = 1;
+       return &sync_file->fence;
+}
+
+static void add_fence(struct fence **fences, int *i, struct fence *fence)
 {
-       sync_file->cbs[*i].fence = fence;
-       sync_file->cbs[*i].sync_file = sync_file;
+       fences[*i] = fence;
 
-       if (!fence_add_callback(fence, &sync_file->cbs[*i].cb,
-                               fence_check_cb_func)) {
+       if (!fence_is_signaled(fence)) {
                fence_get(fence);
                (*i)++;
        }
@@ -147,16 +199,24 @@ static void sync_file_add_pt(struct sync_file *sync_file, int *i,
 static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
                                         struct sync_file *b)
 {
-       int num_fences = a->num_fences + b->num_fences;
        struct sync_file *sync_file;
-       int i, i_a, i_b;
-       unsigned long size = offsetof(struct sync_file, cbs[num_fences]);
+       struct fence **fences, **nfences, **a_fences, **b_fences;
+       int i, i_a, i_b, num_fences, a_num_fences, b_num_fences;
 
-       sync_file = sync_file_alloc(size);
+       sync_file = sync_file_alloc();
        if (!sync_file)
                return NULL;
 
-       atomic_set(&sync_file->status, num_fences);
+       a_fences = get_fences(a, &a_num_fences);
+       b_fences = get_fences(b, &b_num_fences);
+       if (a_num_fences > INT_MAX - b_num_fences)
+               return NULL;
+
+       num_fences = a_num_fences + b_num_fences;
+
+       fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
+       if (!fences)
+               goto err;
 
        /*
         * Assume sync_file a and b are both ordered and have no
@@ -165,55 +225,69 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
         * If a sync_file can only be created with sync_file_merge
         * and sync_file_create, this is a reasonable assumption.
         */
-       for (i = i_a = i_b = 0; i_a < a->num_fences && i_b < b->num_fences; ) {
-               struct fence *pt_a = a->cbs[i_a].fence;
-               struct fence *pt_b = b->cbs[i_b].fence;
+       for (i = i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
+               struct fence *pt_a = a_fences[i_a];
+               struct fence *pt_b = b_fences[i_b];
 
                if (pt_a->context < pt_b->context) {
-                       sync_file_add_pt(sync_file, &i, pt_a);
+                       add_fence(fences, &i, pt_a);
 
                        i_a++;
                } else if (pt_a->context > pt_b->context) {
-                       sync_file_add_pt(sync_file, &i, pt_b);
+                       add_fence(fences, &i, pt_b);
 
                        i_b++;
                } else {
                        if (pt_a->seqno - pt_b->seqno <= INT_MAX)
-                               sync_file_add_pt(sync_file, &i, pt_a);
+                               add_fence(fences, &i, pt_a);
                        else
-                               sync_file_add_pt(sync_file, &i, pt_b);
+                               add_fence(fences, &i, pt_b);
 
                        i_a++;
                        i_b++;
                }
        }
 
-       for (; i_a < a->num_fences; i_a++)
-               sync_file_add_pt(sync_file, &i, a->cbs[i_a].fence);
+       for (; i_a < a_num_fences; i_a++)
+               add_fence(fences, &i, a_fences[i_a]);
+
+       for (; i_b < b_num_fences; i_b++)
+               add_fence(fences, &i, b_fences[i_b]);
 
-       for (; i_b < b->num_fences; i_b++)
-               sync_file_add_pt(sync_file, &i, b->cbs[i_b].fence);
+       if (i == 0)
+               fences[i++] = fence_get(a_fences[0]);
 
-       if (num_fences > i)
-               atomic_sub(num_fences - i, &sync_file->status);
-       sync_file->num_fences = i;
+       if (num_fences > i) {
+               nfences = krealloc(fences, i * sizeof(*fences),
+                                 GFP_KERNEL);
+               if (!nfences)
+                       goto err;
+
+               fences = nfences;
+       }
+
+       if (sync_file_set_fence(sync_file, fences, i) < 0) {
+               kfree(fences);
+               goto err;
+       }
 
        strlcpy(sync_file->name, name, sizeof(sync_file->name));
        return sync_file;
+
+err:
+       fput(sync_file->file);
+       return NULL;
+
 }
 
 static void sync_file_free(struct kref *kref)
 {
        struct sync_file *sync_file = container_of(kref, struct sync_file,
                                                     kref);
-       int i;
-
-       for (i = 0; i < sync_file->num_fences; ++i) {
-               fence_remove_callback(sync_file->cbs[i].fence,
-                                     &sync_file->cbs[i].cb);
-               fence_put(sync_file->cbs[i].fence);
-       }
 
+       if (test_bit(POLL_ENABLED, &sync_file->fence->flags))
+               fence_remove_callback(sync_file->fence, &sync_file->cb);
+       fence_put(sync_file->fence);
        kfree(sync_file);
 }
 
@@ -228,17 +302,17 @@ static int sync_file_release(struct inode *inode, struct file *file)
 static unsigned int sync_file_poll(struct file *file, poll_table *wait)
 {
        struct sync_file *sync_file = file->private_data;
-       int status;
 
        poll_wait(file, &sync_file->wq, wait);
 
-       status = atomic_read(&sync_file->status);
+       if (!poll_does_not_wait(wait) &&
+           !test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) {
+               if (fence_add_callback(sync_file->fence, &sync_file->cb,
+                                      fence_check_cb_func) < 0)
+                       wake_up_all(&sync_file->wq);
+       }
 
-       if (!status)
-               return POLLIN;
-       if (status < 0)
-               return POLLERR;
-       return 0;
+       return fence_is_signaled(sync_file->fence) ? POLLIN : 0;
 }
 
 static long sync_file_ioctl_merge(struct sync_file *sync_file,
@@ -315,8 +389,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
 {
        struct sync_file_info info;
        struct sync_fence_info *fence_info = NULL;
+       struct fence **fences;
        __u32 size;
-       int ret, i;
+       int num_fences, ret, i;
 
        if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
                return -EFAULT;
@@ -324,6 +399,8 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
        if (info.flags || info.pad)
                return -EINVAL;
 
+       fences = get_fences(sync_file, &num_fences);
+
        /*
         * Passing num_fences = 0 means that userspace doesn't want to
         * retrieve any sync_fence_info. If num_fences = 0 we skip filling
@@ -333,16 +410,16 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
        if (!info.num_fences)
                goto no_fences;
 
-       if (info.num_fences < sync_file->num_fences)
+       if (info.num_fences < num_fences)
                return -EINVAL;
 
-       size = sync_file->num_fences * sizeof(*fence_info);
+       size = num_fences * sizeof(*fence_info);
        fence_info = kzalloc(size, GFP_KERNEL);
        if (!fence_info)
                return -ENOMEM;
 
-       for (i = 0; i < sync_file->num_fences; ++i)
-               sync_fill_fence_info(sync_file->cbs[i].fence, &fence_info[i]);
+       for (i = 0; i < num_fences; i++)
+               sync_fill_fence_info(fences[i], &fence_info[i]);
 
        if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info,
                         size)) {
@@ -352,11 +429,8 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
 
 no_fences:
        strlcpy(info.name, sync_file->name, sizeof(info.name));
-       info.status = atomic_read(&sync_file->status);
-       if (info.status >= 0)
-               info.status = !info.status;
-
-       info.num_fences = sync_file->num_fences;
+       info.status = fence_is_signaled(sync_file->fence);
+       info.num_fences = num_fences;
 
        if (copy_to_user((void __user *)arg, &info, sizeof(info)))
                ret = -EFAULT;
index fc35731..483059a 100644 (file)
@@ -108,33 +108,13 @@ config DRM_KMS_CMA_HELPER
 
 source "drivers/gpu/drm/i2c/Kconfig"
 
-config DRM_TDFX
-       tristate "3dfx Banshee/Voodoo3+"
-       depends on DRM && PCI
-       help
-         Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
-         graphics card.  If M is selected, the module will be called tdfx.
-
 source "drivers/gpu/drm/arm/Kconfig"
 
-config DRM_R128
-       tristate "ATI Rage 128"
-       depends on DRM && PCI
-       select FW_LOADER
-       help
-         Choose this option if you have an ATI Rage 128 graphics card.  If M
-         is selected, the module will be called r128.  AGP support for
-         this card is strongly suggested (unless you have a PCI version).
-
 config DRM_RADEON
        tristate "ATI Radeon"
        depends on DRM && PCI
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
        select FW_LOADER
         select DRM_KMS_HELPER
-       select DRM_KMS_FB_HELPER
         select DRM_TTM
        select POWER_SUPPLY
        select HWMON
@@ -153,12 +133,8 @@ source "drivers/gpu/drm/radeon/Kconfig"
 config DRM_AMDGPU
        tristate "AMD GPU"
        depends on DRM && PCI
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
        select FW_LOADER
         select DRM_KMS_HELPER
-       select DRM_KMS_FB_HELPER
         select DRM_TTM
        select POWER_SUPPLY
        select HWMON
@@ -171,55 +147,11 @@ config DRM_AMDGPU
          If M is selected, the module will be called amdgpu.
 
 source "drivers/gpu/drm/amd/amdgpu/Kconfig"
-source "drivers/gpu/drm/amd/powerplay/Kconfig"
-
-source "drivers/gpu/drm/amd/acp/Kconfig"
 
 source "drivers/gpu/drm/nouveau/Kconfig"
 
-config DRM_I810
-       tristate "Intel I810"
-       # !PREEMPT because of missing ioctl locking
-       depends on DRM && AGP && AGP_INTEL && (!PREEMPT || BROKEN)
-       help
-         Choose this option if you have an Intel I810 graphics card.  If M is
-         selected, the module will be called i810.  AGP support is required
-         for this driver to work.
-
 source "drivers/gpu/drm/i915/Kconfig"
 
-config DRM_MGA
-       tristate "Matrox g200/g400"
-       depends on DRM && PCI
-       select FW_LOADER
-       help
-         Choose this option if you have a Matrox G200, G400 or G450 graphics
-         card.  If M is selected, the module will be called mga.  AGP
-         support is required for this driver to work.
-
-config DRM_SIS
-       tristate "SiS video cards"
-       depends on DRM && AGP
-       depends on FB_SIS || FB_SIS=n
-       help
-         Choose this option if you have a SiS 630 or compatible video
-          chipset. If M is selected the module will be called sis. AGP
-          support is required for this driver to work.
-
-config DRM_VIA
-       tristate "Via unichrome video cards"
-       depends on DRM && PCI
-       help
-         Choose this option if you have a Via unichrome or compatible video
-         chipset. If M is selected the module will be called via.
-
-config DRM_SAVAGE
-       tristate "Savage video cards"
-       depends on DRM && PCI
-       help
-         Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
-         chipset. If M is selected the module will be called savage.
-
 config DRM_VGEM
        tristate "Virtual GEM provider"
        depends on DRM
@@ -290,3 +222,81 @@ source "drivers/gpu/drm/arc/Kconfig"
 source "drivers/gpu/drm/hisilicon/Kconfig"
 
 source "drivers/gpu/drm/mediatek/Kconfig"
+
+# Keep legacy drivers last
+
+menuconfig DRM_LEGACY
+       bool "Enable legacy drivers (DANGEROUS)"
+       depends on DRM
+       help
+         Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous
+         APIs to user-space, which can be used to circumvent access
+         restrictions and other security measures. For backwards compatibility
+         those drivers are still available, but their use is highly
+         inadvisable and might harm your system.
+
+         You are recommended to use the safe modeset-only drivers instead, and
+         perform 3D emulation in user-space.
+
+         Unless you have strong reasons to go rogue, say "N".
+
+if DRM_LEGACY
+
+config DRM_TDFX
+       tristate "3dfx Banshee/Voodoo3+"
+       depends on DRM && PCI
+       help
+         Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
+         graphics card.  If M is selected, the module will be called tdfx.
+
+config DRM_R128
+       tristate "ATI Rage 128"
+       depends on DRM && PCI
+       select FW_LOADER
+       help
+         Choose this option if you have an ATI Rage 128 graphics card.  If M
+         is selected, the module will be called r128.  AGP support for
+         this card is strongly suggested (unless you have a PCI version).
+
+config DRM_I810
+       tristate "Intel I810"
+       # !PREEMPT because of missing ioctl locking
+       depends on DRM && AGP && AGP_INTEL && (!PREEMPT || BROKEN)
+       help
+         Choose this option if you have an Intel I810 graphics card.  If M is
+         selected, the module will be called i810.  AGP support is required
+         for this driver to work.
+
+config DRM_MGA
+       tristate "Matrox g200/g400"
+       depends on DRM && PCI
+       select FW_LOADER
+       help
+         Choose this option if you have a Matrox G200, G400 or G450 graphics
+         card.  If M is selected, the module will be called mga.  AGP
+         support is required for this driver to work.
+
+config DRM_SIS
+       tristate "SiS video cards"
+       depends on DRM && AGP
+       depends on FB_SIS || FB_SIS=n
+       help
+         Choose this option if you have a SiS 630 or compatible video
+         chipset. If M is selected the module will be called sis. AGP
+         support is required for this driver to work.
+
+config DRM_VIA
+       tristate "Via unichrome video cards"
+       depends on DRM && PCI
+       help
+         Choose this option if you have a Via unichrome or compatible video
+         chipset. If M is selected the module will be called via.
+
+config DRM_SAVAGE
+       tristate "Savage video cards"
+       depends on DRM && PCI
+       help
+         Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
+         chipset. If M is selected the module will be called savage.
+
+endif # DRM_LEGACY
index 0238bf8..25c7204 100644 (file)
@@ -12,7 +12,10 @@ drm-y       :=       drm_auth.o drm_bufs.o drm_cache.o \
                drm_info.o drm_debugfs.o drm_encoder_slave.o \
                drm_trace_points.o drm_global.o drm_prime.o \
                drm_rect.o drm_vma_manager.o drm_flip_work.o \
-               drm_modeset_lock.o drm_atomic.o drm_bridge.o
+               drm_modeset_lock.o drm_atomic.o drm_bridge.o \
+               drm_framebuffer.o drm_connector.o drm_blend.o \
+               drm_encoder.o drm_mode_object.o drm_property.o \
+               drm_plane.o drm_color_mgmt.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
@@ -24,7 +27,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
                drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
                drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
-               drm_simple_kms_helper.o drm_blend.o
+               drm_simple_kms_helper.o drm_modeset_helper.o
 
 drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
 drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
@@ -46,7 +49,7 @@ obj-$(CONFIG_DRM_RADEON)+= radeon/
 obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/
 obj-$(CONFIG_DRM_MGA)  += mga/
 obj-$(CONFIG_DRM_I810) += i810/
-obj-$(CONFIG_DRM_I915)  += i915/
+obj-$(CONFIG_DRM_I915) += i915/
 obj-$(CONFIG_DRM_MGAG200) += mgag200/
 obj-$(CONFIG_DRM_VC4)  += vc4/
 obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/
index 7335c04..61360e2 100644 (file)
@@ -1,3 +1,10 @@
+config DRM_AMDGPU_SI
+       bool "Enable amdgpu support for SI parts"
+       depends on DRM_AMDGPU
+       help
+         Choose this option if you want to enable experimental support
+         for SI asics.
+
 config DRM_AMDGPU_CIK
        bool "Enable amdgpu support for CIK parts"
        depends on DRM_AMDGPU
@@ -25,3 +32,4 @@ config DRM_AMDGPU_GART_DEBUGFS
          Selecting this option creates a debugfs file to inspect the mapped
          pages. Uses more memory for housekeeping, enable only for debugging.
 
+source "drivers/gpu/drm/amd/acp/Kconfig"
index c7fcdce..248a05d 100644 (file)
@@ -23,13 +23,16 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
        amdgpu_pm.o atombios_dp.o amdgpu_afmt.o amdgpu_trace_points.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_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
+       amdgpu_gtt_mgr.o
 
 # add asic specific block
 amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
        ci_smc.o ci_dpm.o dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o \
        amdgpu_amdkfd_gfx_v7.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
 
@@ -50,15 +53,13 @@ amdgpu-y += \
 amdgpu-y += \
        amdgpu_dpm.o \
        amdgpu_powerplay.o \
-       cz_smc.o cz_dpm.o \
-       tonga_smc.o tonga_dpm.o \
-       fiji_smc.o fiji_dpm.o \
-       iceland_smc.o iceland_dpm.o
+       cz_smc.o cz_dpm.o
 
 # add DCE block
 amdgpu-y += \
        dce_v10_0.o \
-       dce_v11_0.o
+       dce_v11_0.o \
+       dce_virtual.o
 
 # add GFX block
 amdgpu-y += \
@@ -110,14 +111,10 @@ amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o
 amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o
 amdgpu-$(CONFIG_MMU_NOTIFIER) += amdgpu_mn.o
 
-ifneq ($(CONFIG_DRM_AMD_POWERPLAY),)
-
 include $(FULL_AMD_PATH)/powerplay/Makefile
 
 amdgpu-y += $(AMD_POWERPLAY_FILES)
 
-endif
-
 obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o
 
 CFLAGS_amdgpu_trace_points.o := -I$(src)
index 0619269..b8d6667 100644 (file)
@@ -90,6 +90,7 @@
 #define ENCODER_OBJECT_ID_INTERNAL_VCE            0x24
 #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY3        0x25
 #define ENCODER_OBJECT_ID_INTERNAL_AMCLK          0x27
+#define ENCODER_OBJECT_ID_VIRTUAL                 0x28
 
 #define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO    0xFF
 
 #define CONNECTOR_OBJECT_ID_eDP                   0x14
 #define CONNECTOR_OBJECT_ID_MXM                   0x15
 #define CONNECTOR_OBJECT_ID_LVDS_eDP              0x16
+#define CONNECTOR_OBJECT_ID_VIRTUAL               0x17
 
 /* deleted */
 
 #define GRAPH_OBJECT_ENUM_ID5                     0x05
 #define GRAPH_OBJECT_ENUM_ID6                     0x06
 #define GRAPH_OBJECT_ENUM_ID7                     0x07
+#define GRAPH_OBJECT_ENUM_VIRTUAL                 0x08
 
 /****************************************************/
 /* Graphics Object ID Bit definition                */
                                                   GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                   ENCODER_OBJECT_ID_HDMI_ANX9805 << OBJECT_ID_SHIFT)
 
+#define ENCODER_VIRTUAL_ENUM_VIRTUAL            ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+                                                  GRAPH_OBJECT_ENUM_VIRTUAL << ENUM_ID_SHIFT |\
+                                                  ENCODER_OBJECT_ID_VIRTUAL << OBJECT_ID_SHIFT)
+
 /****************************************************/
 /* Connector Object ID definition - Shared with BIOS */
 /****************************************************/
index 700c56b..039b57e 100644 (file)
 #include "amdgpu_ih.h"
 #include "amdgpu_irq.h"
 #include "amdgpu_ucode.h"
+#include "amdgpu_ttm.h"
 #include "amdgpu_gds.h"
 #include "amd_powerplay.h"
 #include "amdgpu_acp.h"
 
 #include "gpu_scheduler.h"
+#include "amdgpu_virt.h"
 
 /*
  * Modules parameters.
@@ -63,6 +65,7 @@
 extern int amdgpu_modeset;
 extern int amdgpu_vram_limit;
 extern int amdgpu_gart_size;
+extern int amdgpu_moverate;
 extern int amdgpu_benchmarking;
 extern int amdgpu_testing;
 extern int amdgpu_audio;
@@ -91,6 +94,9 @@ extern unsigned amdgpu_pcie_lane_cap;
 extern unsigned amdgpu_cg_mask;
 extern unsigned amdgpu_pg_mask;
 extern char *amdgpu_disable_cu;
+extern int amdgpu_sclk_deep_sleep_en;
+extern char *amdgpu_virtual_display;
+extern unsigned amdgpu_pp_feature_mask;
 
 #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS         3000
 #define AMDGPU_MAX_USEC_TIMEOUT                        100000  /* 100 ms */
@@ -105,7 +111,7 @@ extern char *amdgpu_disable_cu;
 #define AMDGPU_MAX_RINGS                       16
 #define AMDGPU_MAX_GFX_RINGS                   1
 #define AMDGPU_MAX_COMPUTE_RINGS               8
-#define AMDGPU_MAX_VCE_RINGS                   2
+#define AMDGPU_MAX_VCE_RINGS                   3
 
 /* max number of IP instances */
 #define AMDGPU_MAX_SDMA_INSTANCES              2
@@ -248,10 +254,9 @@ struct amdgpu_vm_pte_funcs {
                         uint64_t pe, uint64_t src,
                         unsigned count);
        /* write pte one entry at a time with addr mapping */
-       void (*write_pte)(struct amdgpu_ib *ib,
-                         const dma_addr_t *pages_addr, uint64_t pe,
-                         uint64_t addr, unsigned count,
-                         uint32_t incr, uint32_t flags);
+       void (*write_pte)(struct amdgpu_ib *ib, uint64_t pe,
+                         uint64_t value, unsigned count,
+                         uint32_t incr);
        /* for linear pte/pde updates without addr mapping */
        void (*set_pte_pde)(struct amdgpu_ib *ib,
                            uint64_t pe,
@@ -316,6 +321,10 @@ struct amdgpu_ring_funcs {
        /* note usage for clock and power gating */
        void (*begin_use)(struct amdgpu_ring *ring);
        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);
+       unsigned (*get_emit_ib_size) (struct amdgpu_ring *ring);
+       unsigned (*get_dma_frame_size) (struct amdgpu_ring *ring);
 };
 
 /*
@@ -396,48 +405,8 @@ int amdgpu_fence_wait_empty(struct amdgpu_ring *ring);
 unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring);
 
 /*
- * TTM.
+ * BO.
  */
-
-#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;
-       struct ttm_bo_device            bdev;
-       bool                            mem_global_referenced;
-       bool                            initialized;
-
-#if defined(CONFIG_DEBUG_FS)
-       struct dentry                   *vram;
-       struct dentry                   *gtt;
-#endif
-
-       /* buffer handling */
-       const struct amdgpu_buffer_funcs        *buffer_funcs;
-       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;
-};
-
-int amdgpu_copy_buffer(struct amdgpu_ring *ring,
-                      uint64_t src_offset,
-                      uint64_t dst_offset,
-                      uint32_t byte_count,
-                      struct reservation_object *resv,
-                      struct fence **fence);
-int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma);
-
 struct amdgpu_bo_list_entry {
        struct amdgpu_bo                *robj;
        struct ttm_validate_buffer      tv;
@@ -476,8 +445,6 @@ struct amdgpu_bo_va {
 #define AMDGPU_GEM_DOMAIN_MAX          0x3
 
 struct amdgpu_bo {
-       /* Protected by gem.mutex */
-       struct list_head                list;
        /* Protected by tbo.reserved */
        u32                             prefered_domains;
        u32                             allowed_domains;
@@ -500,10 +467,12 @@ struct amdgpu_bo {
        struct amdgpu_device            *adev;
        struct drm_gem_object           gem_base;
        struct amdgpu_bo                *parent;
+       struct amdgpu_bo                *shadow;
 
        struct ttm_bo_kmap_obj          dma_buf_vmap;
        struct amdgpu_mn                *mn;
        struct list_head                mn_list;
+       struct list_head                shadow_list;
 };
 #define gem_to_amdgpu_bo(gobj) container_of((gobj), struct amdgpu_bo, gem_base)
 
@@ -653,6 +622,7 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
 int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
                     int pages, struct page **pagelist,
                     dma_addr_t *dma_addr, uint32_t flags);
+int amdgpu_ttm_recover_gart(struct amdgpu_device *adev);
 
 /*
  * GPU MC structures, functions & helpers
@@ -679,6 +649,8 @@ struct amdgpu_mc {
        uint32_t                fw_version;
        struct amdgpu_irq_src   vm_fault;
        uint32_t                vram_type;
+       uint32_t                srbm_soft_reset;
+       struct amdgpu_mode_mc_save save;
 };
 
 /*
@@ -723,13 +695,14 @@ void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev,
  */
 
 struct amdgpu_flip_work {
-       struct work_struct              flip_work;
+       struct delayed_work             flip_work;
        struct work_struct              unpin_work;
        struct amdgpu_device            *adev;
        int                             crtc_id;
+       u32                             target_vblank;
        uint64_t                        base;
        struct drm_pending_vblank_event *event;
-       struct amdgpu_bo                *old_rbo;
+       struct amdgpu_bo                *old_abo;
        struct fence                    *excl;
        unsigned                        shared_count;
        struct fence                    **shared;
@@ -817,13 +790,17 @@ struct amdgpu_ring {
 /* maximum number of VMIDs */
 #define AMDGPU_NUM_VM  16
 
+/* Maximum number of PTEs the hardware can write with one command */
+#define AMDGPU_VM_MAX_UPDATE_SIZE      0x3FFFF
+
 /* number of entries in page table */
 #define AMDGPU_VM_PTE_COUNT (1 << amdgpu_vm_block_size)
 
 /* PTBs (Page Table Blocks) need to be aligned to 32K */
 #define AMDGPU_VM_PTB_ALIGN_SIZE   32768
-#define AMDGPU_VM_PTB_ALIGN_MASK (AMDGPU_VM_PTB_ALIGN_SIZE - 1)
-#define AMDGPU_VM_PTB_ALIGN(a) (((a) + AMDGPU_VM_PTB_ALIGN_MASK) & ~AMDGPU_VM_PTB_ALIGN_MASK)
+
+/* LOG2 number of continuous pages for the fragment field */
+#define AMDGPU_LOG2_PAGES_PER_FRAG 4
 
 #define AMDGPU_PTE_VALID       (1 << 0)
 #define AMDGPU_PTE_SYSTEM      (1 << 1)
@@ -835,10 +812,7 @@ struct amdgpu_ring {
 #define AMDGPU_PTE_READABLE    (1 << 5)
 #define AMDGPU_PTE_WRITEABLE   (1 << 6)
 
-/* PTE (Page Table Entry) fragment field for different page sizes */
-#define AMDGPU_PTE_FRAG_4KB    (0 << 7)
-#define AMDGPU_PTE_FRAG_64KB   (4 << 7)
-#define AMDGPU_LOG2_PAGES_PER_FRAG 4
+#define AMDGPU_PTE_FRAG(x)     ((x & 0x1f) << 7)
 
 /* How to programm VM fault handling */
 #define AMDGPU_VM_FAULT_STOP_NEVER     0
@@ -848,6 +822,7 @@ struct amdgpu_ring {
 struct amdgpu_vm_pt {
        struct amdgpu_bo_list_entry     entry;
        uint64_t                        addr;
+       uint64_t                        shadow_addr;
 };
 
 struct amdgpu_vm {
@@ -950,7 +925,6 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
                      struct amdgpu_job *job);
 int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job);
 void amdgpu_vm_reset_id(struct amdgpu_device *adev, unsigned vm_id);
-uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr);
 int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
                                    struct amdgpu_vm *vm);
 int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
@@ -959,7 +933,7 @@ int amdgpu_vm_clear_invalids(struct amdgpu_device *adev, struct amdgpu_vm *vm,
                             struct amdgpu_sync *sync);
 int amdgpu_vm_bo_update(struct amdgpu_device *adev,
                        struct amdgpu_bo_va *bo_va,
-                       struct ttm_mem_reg *mem);
+                       bool clear);
 void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
                             struct amdgpu_bo *bo);
 struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
@@ -994,6 +968,7 @@ struct amdgpu_ctx {
        spinlock_t              ring_lock;
        struct fence            **fences;
        struct amdgpu_ctx_ring  rings[AMDGPU_MAX_RINGS];
+       bool preamble_presented;
 };
 
 struct amdgpu_ctx_mgr {
@@ -1197,6 +1172,10 @@ struct amdgpu_gfx {
        unsigned                        ce_ram_size;
        struct amdgpu_cu_info           cu_info;
        const struct amdgpu_gfx_funcs   *funcs;
+
+       /* reset mask */
+       uint32_t                        grbm_soft_reset;
+       uint32_t                        srbm_soft_reset;
 };
 
 int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm,
@@ -1249,11 +1228,16 @@ struct amdgpu_cs_parser {
        struct fence                    *fence;
        uint64_t                        bytes_moved_threshold;
        uint64_t                        bytes_moved;
+       struct amdgpu_bo_list_entry     *evictable;
 
        /* user fence */
        struct amdgpu_bo_list_entry     uf_entry;
 };
 
+#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 */
+
 struct amdgpu_job {
        struct amd_sched_job    base;
        struct amdgpu_device    *adev;
@@ -1262,9 +1246,10 @@ struct amdgpu_job {
        struct amdgpu_sync      sync;
        struct amdgpu_ib        *ibs;
        struct fence            *fence; /* the hw fence */
+       uint32_t                preamble_status;
        uint32_t                num_ibs;
        void                    *owner;
-       uint64_t                ctx;
+       uint64_t                fence_ctx; /* the fence_context this job uses */
        bool                    vm_needs_flush;
        unsigned                vm_id;
        uint64_t                vm_pd_addr;
@@ -1685,6 +1670,7 @@ struct amdgpu_uvd {
        bool                    address_64_bit;
        bool                    use_ctx_buf;
        struct amd_sched_entity entity;
+       uint32_t                srbm_soft_reset;
 };
 
 /*
@@ -1711,6 +1697,8 @@ struct amdgpu_vce {
        struct amdgpu_irq_src   irq;
        unsigned                harvest_config;
        struct amd_sched_entity entity;
+       uint32_t                srbm_soft_reset;
+       unsigned                num_rings;
 };
 
 /*
@@ -1728,9 +1716,14 @@ struct amdgpu_sdma_instance {
 
 struct amdgpu_sdma {
        struct amdgpu_sdma_instance instance[AMDGPU_MAX_SDMA_INSTANCES];
+#ifdef CONFIG_DRM_AMDGPU_SI
+       //SI DMA has a difference trap irq number for the second engine
+       struct amdgpu_irq_src   trap_irq_1;
+#endif
        struct amdgpu_irq_src   trap_irq;
        struct amdgpu_irq_src   illegal_inst_irq;
        int                     num_instances;
+       uint32_t                    srbm_soft_reset;
 };
 
 /*
@@ -1832,6 +1825,7 @@ 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);
@@ -1841,8 +1835,9 @@ struct amdgpu_asic_funcs {
        /* MM block clocks */
        int (*set_uvd_clocks)(struct amdgpu_device *adev, u32 vclk, u32 dclk);
        int (*set_vce_clocks)(struct amdgpu_device *adev, u32 evclk, u32 ecclk);
-       /* query virtual capabilities */
-       u32 (*get_virtual_caps)(struct amdgpu_device *adev);
+       /* static power management */
+       int (*get_pcie_lanes)(struct amdgpu_device *adev);
+       void (*set_pcie_lanes)(struct amdgpu_device *adev, int lanes);
 };
 
 /*
@@ -1935,16 +1930,6 @@ struct amdgpu_atcs {
 struct cgs_device *amdgpu_cgs_create_device(struct amdgpu_device *adev);
 void amdgpu_cgs_destroy_device(struct cgs_device *cgs_device);
 
-
-/* GPU virtualization */
-#define AMDGPU_VIRT_CAPS_SRIOV_EN       (1 << 0)
-#define AMDGPU_VIRT_CAPS_IS_VF          (1 << 1)
-struct amdgpu_virtualization {
-       bool supports_sr_iov;
-       bool is_virtual;
-       u32 caps;
-};
-
 /*
  * Core structure, functions and helpers.
  */
@@ -1958,6 +1943,8 @@ struct amdgpu_ip_block_status {
        bool valid;
        bool sw;
        bool hw;
+       bool late_initialized;
+       bool hang;
 };
 
 struct amdgpu_device {
@@ -2016,6 +2003,8 @@ struct amdgpu_device {
        spinlock_t pcie_idx_lock;
        amdgpu_rreg_t                   pcie_rreg;
        amdgpu_wreg_t                   pcie_wreg;
+       amdgpu_rreg_t                   pciep_rreg;
+       amdgpu_wreg_t                   pciep_wreg;
        /* protects concurrent UVD register access */
        spinlock_t uvd_ctx_idx_lock;
        amdgpu_rreg_t                   uvd_ctx_rreg;
@@ -2056,7 +2045,16 @@ struct amdgpu_device {
        atomic64_t                      num_evictions;
        atomic_t                        gpu_reset_counter;
 
+       /* data for buffer migration throttling */
+       struct {
+               spinlock_t              lock;
+               s64                     last_update_us;
+               s64                     accum_us; /* accumulated microseconds */
+               u32                     log2_max_MBps;
+       } mm_stats;
+
        /* display */
+       bool                            enable_virtual_display;
        struct amdgpu_mode_info         mode_info;
        struct work_struct              hotplug_work;
        struct amdgpu_irq_src           crtc_irq;
@@ -2119,6 +2117,14 @@ struct amdgpu_device {
        struct kfd_dev          *kfd;
 
        struct amdgpu_virtualization virtualization;
+
+       /* link all shadow bo */
+       struct list_head                shadow_list;
+       struct mutex                    shadow_list_lock;
+       /* link all gtt */
+       spinlock_t                      gtt_list_lock;
+       struct list_head                gtt_list;
+
 };
 
 bool amdgpu_device_is_px(struct drm_device *dev);
@@ -2151,6 +2157,8 @@ void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v);
 #define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)
 #define RREG32_PCIE(reg) adev->pcie_rreg(adev, (reg))
 #define WREG32_PCIE(reg, v) adev->pcie_wreg(adev, (reg), (v))
+#define RREG32_PCIE_PORT(reg) adev->pciep_rreg(adev, (reg))
+#define WREG32_PCIE_PORT(reg, v) adev->pciep_wreg(adev, (reg), (v))
 #define RREG32_SMC(reg) adev->smc_rreg(adev, (reg))
 #define WREG32_SMC(reg, v) adev->smc_wreg(adev, (reg), (v))
 #define RREG32_UVD_CTX(reg) adev->uvd_ctx_rreg(adev, (reg))
@@ -2194,6 +2202,9 @@ void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v);
 #define REG_GET_FIELD(value, reg, field)                               \
        (((value) & REG_FIELD_MASK(reg, field)) >> REG_FIELD_SHIFT(reg, field))
 
+#define WREG32_FIELD(reg, field, val)  \
+       WREG32(mm##reg, (RREG32(mm##reg) & ~REG_FIELD_MASK(reg, field)) | (val) << REG_FIELD_SHIFT(reg, field))
+
 /*
  * BIOS helpers.
  */
@@ -2237,14 +2248,17 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
 #define amdgpu_asic_get_xclk(adev) (adev)->asic_funcs->get_xclk((adev))
 #define amdgpu_asic_set_uvd_clocks(adev, v, d) (adev)->asic_funcs->set_uvd_clocks((adev), (v), (d))
 #define amdgpu_asic_set_vce_clocks(adev, ev, ec) (adev)->asic_funcs->set_vce_clocks((adev), (ev), (ec))
-#define amdgpu_asic_get_virtual_caps(adev) ((adev)->asic_funcs->get_virtual_caps((adev)))
+#define amdgpu_get_pcie_lanes(adev) (adev)->asic_funcs->get_pcie_lanes((adev))
+#define amdgpu_set_pcie_lanes(adev, l) (adev)->asic_funcs->set_pcie_lanes((adev), (l))
+#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))
 #define amdgpu_vm_copy_pte(adev, ib, pe, src, count) ((adev)->vm_manager.vm_pte_funcs->copy_pte((ib), (pe), (src), (count)))
-#define amdgpu_vm_write_pte(adev, ib, pa, pe, addr, count, incr, flags) ((adev)->vm_manager.vm_pte_funcs->write_pte((ib), (pa), (pe), (addr), (count), (incr), (flags)))
+#define amdgpu_vm_write_pte(adev, ib, pe, value, count, incr) ((adev)->vm_manager.vm_pte_funcs->write_pte((ib), (pe), (value), (count), (incr)))
 #define amdgpu_vm_set_pte_pde(adev, ib, pe, addr, count, incr, flags) ((adev)->vm_manager.vm_pte_funcs->set_pte_pde((ib), (pe), (addr), (count), (incr), (flags)))
 #define amdgpu_ring_parse_cs(r, p, ib) ((r)->funcs->parse_cs((p), (ib)))
 #define amdgpu_ring_test_ring(r) (r)->funcs->test_ring((r))
@@ -2259,9 +2273,13 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
 #define amdgpu_ring_emit_gds_switch(r, v, db, ds, wb, ws, ab, as) (r)->funcs->emit_gds_switch((r), (v), (db), (ds), (wb), (ws), (ab), (as))
 #define amdgpu_ring_emit_hdp_flush(r) (r)->funcs->emit_hdp_flush((r))
 #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_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))
+#define amdgpu_ring_get_emit_ib_size(r) (r)->funcs->get_emit_ib_size((r))
+#define amdgpu_ring_get_dma_frame_size(r) (r)->funcs->get_dma_frame_size((r))
 #define amdgpu_ih_get_wptr(adev) (adev)->irq.ih_funcs->get_wptr((adev))
 #define amdgpu_ih_decode_iv(adev, iv) (adev)->irq.ih_funcs->decode_iv((adev), (iv))
 #define amdgpu_ih_set_rptr(adev) (adev)->irq.ih_funcs->set_rptr((adev))
@@ -2293,6 +2311,11 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
 #define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev))
 #define amdgpu_gfx_select_se_sh(adev, se, sh, instance) (adev)->gfx.funcs->select_se_sh((adev), (se), (sh), (instance))
 
+#define amdgpu_dpm_read_sensor(adev, idx, value) \
+       ((adev)->pp_enabled ? \
+               (adev)->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, (idx), (value)) : \
+               -EINVAL)
+
 #define amdgpu_dpm_get_temperature(adev) \
        ((adev)->pp_enabled ?                                           \
              (adev)->powerplay.pp_funcs->get_temperature((adev)->powerplay.pp_handle) : \
@@ -2344,11 +2367,6 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
              (adev)->powerplay.pp_funcs->powergate_vce((adev)->powerplay.pp_handle, (g)) : \
              (adev)->pm.funcs->powergate_vce((adev), (g)))
 
-#define amdgpu_dpm_debugfs_print_current_performance_level(adev, m) \
-       ((adev)->pp_enabled ?                                           \
-             (adev)->powerplay.pp_funcs->print_current_performance_level((adev)->powerplay.pp_handle, (m)) : \
-             (adev)->pm.funcs->debugfs_print_current_performance_level((adev), (m)))
-
 #define amdgpu_dpm_get_current_power_state(adev) \
        (adev)->powerplay.pp_funcs->get_current_power_state((adev)->powerplay.pp_handle)
 
@@ -2389,6 +2407,7 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
 
 /* Common functions */
 int amdgpu_gpu_reset(struct amdgpu_device *adev);
+bool amdgpu_need_backup(struct amdgpu_device *adev);
 void amdgpu_pci_config_reset(struct amdgpu_device *adev);
 bool amdgpu_card_posted(struct amdgpu_device *adev);
 void amdgpu_update_display_priority(struct amdgpu_device *adev);
@@ -2397,7 +2416,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data);
 int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
                       u32 ip_instance, u32 ring,
                       struct amdgpu_ring **out_ring);
-void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *rbo, u32 domain);
+void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain);
 bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo);
 int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages);
 int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
@@ -2414,6 +2433,10 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
 void amdgpu_vram_location(struct amdgpu_device *adev, struct amdgpu_mc *mc, u64 base);
 void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc);
 void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size);
+u64 amdgpu_ttm_get_gtt_mem_size(struct amdgpu_device *adev);
+int amdgpu_ttm_global_init(struct amdgpu_device *adev);
+int amdgpu_ttm_init(struct amdgpu_device *adev);
+void amdgpu_ttm_fini(struct amdgpu_device *adev);
 void amdgpu_program_register_sequence(struct amdgpu_device *adev,
                                             const u32 *registers,
                                             const u32 array_size);
@@ -2425,11 +2448,13 @@ void amdgpu_register_atpx_handler(void);
 void amdgpu_unregister_atpx_handler(void);
 bool amdgpu_has_atpx_dgpu_power_cntl(void);
 bool amdgpu_is_atpx_hybrid(void);
+bool amdgpu_atpx_dgpu_req_power_for_displays(void);
 #else
 static inline void amdgpu_register_atpx_handler(void) {}
 static inline void amdgpu_unregister_atpx_handler(void) {}
 static inline bool amdgpu_has_atpx_dgpu_power_cntl(void) { return false; }
 static inline bool amdgpu_is_atpx_hybrid(void) { return false; }
+static inline bool amdgpu_atpx_dgpu_req_power_for_displays(void) { return false; }
 #endif
 
 /*
@@ -2446,8 +2471,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
                                 struct drm_file *file_priv);
 void amdgpu_driver_preclose_kms(struct drm_device *dev,
                                struct drm_file *file_priv);
-int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon);
-int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
+int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon);
+int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon);
 u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
 int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe);
 void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe);
@@ -2493,6 +2518,7 @@ static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
 struct amdgpu_bo_va_mapping *
 amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
                       uint64_t addr, struct amdgpu_bo **bo);
+int amdgpu_cs_sysvm_access_required(struct amdgpu_cs_parser *parser);
 
 #include "amdgpu_object.h"
 #endif
index 5cd7b73..5796539 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/acpi.h>
 #include <linux/slab.h>
 #include <linux/power_supply.h>
+#include <linux/pm_runtime.h>
 #include <acpi/video.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
@@ -333,6 +334,16 @@ int amdgpu_atif_handler(struct amdgpu_device *adev,
 #endif
                }
        }
+       if (req.pending & ATIF_DGPU_DISPLAY_EVENT) {
+               if ((adev->flags & AMD_IS_PX) &&
+                   amdgpu_atpx_dgpu_req_power_for_displays()) {
+                       pm_runtime_get_sync(adev->ddev->dev);
+                       /* Just fire off a uevent and let userspace tell us what to do */
+                       drm_helper_hpd_irq_event(adev->ddev);
+                       pm_runtime_mark_last_busy(adev->ddev->dev);
+                       pm_runtime_put_autosuspend(adev->ddev->dev);
+               }
+       }
        /* TODO: check other events */
 
        /* We've handled the event, stop the notifier chain. The ACPI interface
index d080d08..dba8a5b 100644 (file)
@@ -143,14 +143,6 @@ int amdgpu_amdkfd_resume(struct amdgpu_device *rdev)
        return r;
 }
 
-u32 pool_to_domain(enum kgd_memory_pool p)
-{
-       switch (p) {
-       case KGD_POOL_FRAMEBUFFER: return AMDGPU_GEM_DOMAIN_VRAM;
-       default: return AMDGPU_GEM_DOMAIN_GTT;
-       }
-}
-
 int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
                        void **mem_obj, uint64_t *gpu_addr,
                        void **cpu_ptr)
index 362bedc..1a0a5f7 100644 (file)
@@ -103,11 +103,11 @@ static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
                                uint32_t pipe_id, uint32_t queue_id);
 
 static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
-                               unsigned int timeout, uint32_t pipe_id,
+                               unsigned int utimeout, uint32_t pipe_id,
                                uint32_t queue_id);
 static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd);
 static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
-                               unsigned int timeout);
+                               unsigned int utimeout);
 static int kgd_address_watch_disable(struct kgd_dev *kgd);
 static int kgd_address_watch_execute(struct kgd_dev *kgd,
                                        unsigned int watch_point_id,
@@ -437,11 +437,12 @@ static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
 }
 
 static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
-                               unsigned int timeout, uint32_t pipe_id,
+                               unsigned int utimeout, uint32_t pipe_id,
                                uint32_t queue_id)
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
        uint32_t temp;
+       int timeout = utimeout;
 
        acquire_queue(kgd, pipe_id, queue_id);
        WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, 0);
@@ -452,9 +453,8 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
                temp = RREG32(mmCP_HQD_ACTIVE);
                if (temp & CP_HQD_ACTIVE__ACTIVE_MASK)
                        break;
-               if (timeout == 0) {
-                       pr_err("kfd: cp queue preemption time out (%dms)\n",
-                               temp);
+               if (timeout <= 0) {
+                       pr_err("kfd: cp queue preemption time out.\n");
                        release_queue(kgd);
                        return -ETIME;
                }
@@ -467,12 +467,13 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
 }
 
 static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
-                               unsigned int timeout)
+                               unsigned int utimeout)
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
        struct cik_sdma_rlc_registers *m;
        uint32_t sdma_base_addr;
        uint32_t temp;
+       int timeout = utimeout;
 
        m = get_sdma_mqd(mqd);
        sdma_base_addr = get_sdma_base_addr(m);
@@ -485,7 +486,7 @@ static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
                temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS);
                if (temp & SDMA0_STATUS_REG__RB_CMD_IDLE__SHIFT)
                        break;
-               if (timeout == 0)
+               if (timeout <= 0)
                        return -ETIME;
                msleep(20);
                timeout -= 20;
index 04b744d..6697612 100644 (file)
@@ -62,10 +62,10 @@ static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
                uint32_t pipe_id, uint32_t queue_id);
 static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd);
 static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
-                               unsigned int timeout, uint32_t pipe_id,
+                               unsigned int utimeout, uint32_t pipe_id,
                                uint32_t queue_id);
 static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
-                               unsigned int timeout);
+                               unsigned int utimeout);
 static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid);
 static int kgd_address_watch_disable(struct kgd_dev *kgd);
 static int kgd_address_watch_execute(struct kgd_dev *kgd,
@@ -349,11 +349,12 @@ static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
 }
 
 static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
-                               unsigned int timeout, uint32_t pipe_id,
+                               unsigned int utimeout, uint32_t pipe_id,
                                uint32_t queue_id)
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
        uint32_t temp;
+       int timeout = utimeout;
 
        acquire_queue(kgd, pipe_id, queue_id);
 
@@ -363,9 +364,8 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
                temp = RREG32(mmCP_HQD_ACTIVE);
                if (temp & CP_HQD_ACTIVE__ACTIVE_MASK)
                        break;
-               if (timeout == 0) {
-                       pr_err("kfd: cp queue preemption time out (%dms)\n",
-                               temp);
+               if (timeout <= 0) {
+                       pr_err("kfd: cp queue preemption time out.\n");
                        release_queue(kgd);
                        return -ETIME;
                }
@@ -378,12 +378,13 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
 }
 
 static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
-                               unsigned int timeout)
+                               unsigned int utimeout)
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
        struct cik_sdma_rlc_registers *m;
        uint32_t sdma_base_addr;
        uint32_t temp;
+       int timeout = utimeout;
 
        m = get_sdma_mqd(mqd);
        sdma_base_addr = get_sdma_base_addr(m);
@@ -396,7 +397,7 @@ static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
                temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS);
                if (temp & SDMA0_STATUS_REG__RB_CMD_IDLE__SHIFT)
                        break;
-               if (timeout == 0)
+               if (timeout <= 0)
                        return -ETIME;
                msleep(20);
                timeout -= 20;
index fe872b8..8e6bf54 100644 (file)
@@ -259,6 +259,33 @@ static const int object_connector_convert[] = {
        DRM_MODE_CONNECTOR_Unknown
 };
 
+bool amdgpu_atombios_has_dce_engine_info(struct amdgpu_device *adev)
+{
+       struct amdgpu_mode_info *mode_info = &adev->mode_info;
+       struct atom_context *ctx = mode_info->atom_context;
+       int index = GetIndexIntoMasterTable(DATA, Object_Header);
+       u16 size, data_offset;
+       u8 frev, crev;
+       ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
+       ATOM_OBJECT_HEADER *obj_header;
+
+       if (!amdgpu_atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))
+               return false;
+
+       if (crev < 2)
+               return false;
+
+       obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
+       path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
+           (ctx->bios + data_offset +
+            le16_to_cpu(obj_header->usDisplayPathTableOffset));
+
+       if (path_obj->ucNumOfDispPath)
+               return true;
+       else
+               return false;
+}
+
 bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev)
 {
        struct amdgpu_mode_info *mode_info = &adev->mode_info;
@@ -964,6 +991,48 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
                return -EINVAL;
 
        switch (crev) {
+       case 2:
+       case 3:
+       case 5:
+               /* r6xx, r7xx, evergreen, ni, si.
+                * TODO: add support for asic_type <= CHIP_RV770*/
+               if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {
+                       args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
+
+                       amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+                       dividers->post_div = args.v3.ucPostDiv;
+                       dividers->enable_post_div = (args.v3.ucCntlFlag &
+                                                    ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
+                       dividers->enable_dithen = (args.v3.ucCntlFlag &
+                                                  ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
+                       dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
+                       dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
+                       dividers->ref_div = args.v3.ucRefDiv;
+                       dividers->vco_mode = (args.v3.ucCntlFlag &
+                                             ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
+               } else {
+                       /* for SI we use ComputeMemoryClockParam for memory plls */
+                       if (adev->asic_type >= CHIP_TAHITI)
+                               return -EINVAL;
+                       args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
+                       if (strobe_mode)
+                               args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
+
+                       amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+                       dividers->post_div = args.v5.ucPostDiv;
+                       dividers->enable_post_div = (args.v5.ucCntlFlag &
+                                                    ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
+                       dividers->enable_dithen = (args.v5.ucCntlFlag &
+                                                  ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
+                       dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv);
+                       dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac);
+                       dividers->ref_div = args.v5.ucRefDiv;
+                       dividers->vco_mode = (args.v5.ucCntlFlag &
+                                             ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
+               }
+               break;
        case 4:
                /* fusion */
                args.v4.ulClock = cpu_to_le32(clock);   /* 10 khz */
@@ -1108,6 +1177,32 @@ void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev,
        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+void amdgpu_atombios_get_default_voltages(struct amdgpu_device *adev,
+                                         u16 *vddc, u16 *vddci, u16 *mvdd)
+{
+       struct amdgpu_mode_info *mode_info = &adev->mode_info;
+       int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+       u8 frev, crev;
+       u16 data_offset;
+       union firmware_info *firmware_info;
+
+       *vddc = 0;
+       *vddci = 0;
+       *mvdd = 0;
+
+       if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+                                  &frev, &crev, &data_offset)) {
+               firmware_info =
+                       (union firmware_info *)(mode_info->atom_context->bios +
+                                               data_offset);
+               *vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
+               if ((frev == 2) && (crev >= 2)) {
+                       *vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);
+                       *mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage);
+               }
+       }
+}
+
 union set_voltage {
        struct _SET_VOLTAGE_PS_ALLOCATION alloc;
        struct _SET_VOLTAGE_PARAMETERS v1;
@@ -1115,6 +1210,52 @@ union set_voltage {
        struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;
 };
 
+int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type,
+                            u16 voltage_id, u16 *voltage)
+{
+       union set_voltage args;
+       int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
+       u8 frev, crev;
+
+       if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+               return -EINVAL;
+
+       switch (crev) {
+       case 1:
+               return -EINVAL;
+       case 2:
+               args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;
+               args.v2.ucVoltageMode = 0;
+               args.v2.usVoltageLevel = 0;
+
+               amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+               *voltage = le16_to_cpu(args.v2.usVoltageLevel);
+               break;
+       case 3:
+               args.v3.ucVoltageType = voltage_type;
+               args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;
+               args.v3.usVoltageLevel = cpu_to_le16(voltage_id);
+
+               amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+               *voltage = le16_to_cpu(args.v3.usVoltageLevel);
+               break;
+       default:
+               DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int amdgpu_atombios_get_leakage_vddc_based_on_leakage_idx(struct amdgpu_device *adev,
+                                                     u16 *voltage,
+                                                     u16 leakage_idx)
+{
+       return amdgpu_atombios_get_max_vddc(adev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage);
+}
+
 void amdgpu_atombios_set_voltage(struct amdgpu_device *adev,
                                 u16 voltage_level,
                                 u8 voltage_type)
@@ -1335,6 +1476,50 @@ static ATOM_VOLTAGE_OBJECT_V3 *amdgpu_atombios_lookup_voltage_object_v3(ATOM_VOL
        return NULL;
 }
 
+int amdgpu_atombios_get_svi2_info(struct amdgpu_device *adev,
+                             u8 voltage_type,
+                             u8 *svd_gpio_id, u8 *svc_gpio_id)
+{
+       int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+       u8 frev, crev;
+       u16 data_offset, size;
+       union voltage_object_info *voltage_info;
+       union voltage_object *voltage_object = NULL;
+
+       if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,
+                                  &frev, &crev, &data_offset)) {
+               voltage_info = (union voltage_object_info *)
+                       (adev->mode_info.atom_context->bios + data_offset);
+
+               switch (frev) {
+               case 3:
+                       switch (crev) {
+                       case 1:
+                               voltage_object = (union voltage_object *)
+                                       amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,
+                                                                     voltage_type,
+                                                                     VOLTAGE_OBJ_SVID2);
+                               if (voltage_object) {
+                                       *svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId;
+                                       *svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId;
+                               } else {
+                                       return -EINVAL;
+                               }
+                               break;
+                       default:
+                               DRM_ERROR("unknown voltage object table\n");
+                               return -EINVAL;
+                       }
+                       break;
+               default:
+                       DRM_ERROR("unknown voltage object table\n");
+                       return -EINVAL;
+               }
+
+       }
+       return 0;
+}
+
 bool
 amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev,
                                u8 voltage_type, u8 voltage_mode)
index 8c2e696..1735615 100644 (file)
@@ -140,6 +140,8 @@ struct amdgpu_i2c_bus_rec amdgpu_atombios_lookup_i2c_gpio(struct amdgpu_device *
                                                          uint8_t id);
 void amdgpu_atombios_i2c_init(struct amdgpu_device *adev);
 
+bool amdgpu_atombios_has_dce_engine_info(struct amdgpu_device *adev);
+
 bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev);
 
 int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev);
@@ -206,5 +208,19 @@ void amdgpu_atombios_scratch_regs_save(struct amdgpu_device *adev);
 void amdgpu_atombios_scratch_regs_restore(struct amdgpu_device *adev);
 
 void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);
-
+int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type,
+                            u16 voltage_id, u16 *voltage);
+int amdgpu_atombios_get_leakage_vddc_based_on_leakage_idx(struct amdgpu_device *adev,
+                                                     u16 *voltage,
+                                                     u16 leakage_idx);
+void amdgpu_atombios_get_default_voltages(struct amdgpu_device *adev,
+                                         u16 *vddc, u16 *vddci, u16 *mvdd);
+int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+                                      u8 clock_type,
+                                      u32 clock,
+                                      bool strobe_mode,
+                                      struct atom_clock_dividers *dividers);
+int amdgpu_atombios_get_svi2_info(struct amdgpu_device *adev,
+                             u8 voltage_type,
+                             u8 *svd_gpio_id, u8 *svc_gpio_id);
 #endif
index 10b5ddf..dae35a9 100644 (file)
@@ -29,6 +29,7 @@ struct amdgpu_atpx {
        acpi_handle handle;
        struct amdgpu_atpx_functions functions;
        bool is_hybrid;
+       bool dgpu_req_power_for_displays;
 };
 
 static struct amdgpu_atpx_priv {
@@ -73,6 +74,10 @@ bool amdgpu_is_atpx_hybrid(void) {
        return amdgpu_atpx_priv.atpx.is_hybrid;
 }
 
+bool amdgpu_atpx_dgpu_req_power_for_displays(void) {
+       return amdgpu_atpx_priv.atpx.dgpu_req_power_for_displays;
+}
+
 /**
  * amdgpu_atpx_call - call an ATPX method
  *
@@ -204,6 +209,10 @@ static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx)
                atpx->is_hybrid = true;
        }
 
+       atpx->dgpu_req_power_for_displays = false;
+       if (valid_bits & ATPX_DGPU_REQ_POWER_FOR_DISPLAYS)
+               atpx->dgpu_req_power_for_displays = true;
+
        return 0;
 }
 
index 33e47a4..3453052 100644 (file)
@@ -39,7 +39,8 @@ static int amdgpu_benchmark_do_move(struct amdgpu_device *adev, unsigned size,
        start_jiffies = jiffies;
        for (i = 0; i < n; i++) {
                struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
-               r = amdgpu_copy_buffer(ring, saddr, daddr, size, NULL, &fence);
+               r = amdgpu_copy_buffer(ring, saddr, daddr, size, NULL, &fence,
+                                      false);
                if (r)
                        goto exit_do_move;
                r = fence_wait(fence, false);
index bc0440f..7a8bfa3 100644 (file)
@@ -616,7 +616,7 @@ static int amdgpu_cgs_irq_put(struct cgs_device *cgs_device, unsigned src_id, un
        return amdgpu_irq_put(adev, adev->irq.sources[src_id], type);
 }
 
-int amdgpu_cgs_set_clockgating_state(struct cgs_device *cgs_device,
+static int amdgpu_cgs_set_clockgating_state(struct cgs_device *cgs_device,
                                  enum amd_ip_block_type block_type,
                                  enum amd_clockgating_state state)
 {
@@ -637,7 +637,7 @@ int amdgpu_cgs_set_clockgating_state(struct cgs_device *cgs_device,
        return r;
 }
 
-int amdgpu_cgs_set_powergating_state(struct cgs_device *cgs_device,
+static int amdgpu_cgs_set_powergating_state(struct cgs_device *cgs_device,
                                  enum amd_ip_block_type block_type,
                                  enum amd_powergating_state state)
 {
@@ -711,6 +711,47 @@ static int amdgpu_cgs_rel_firmware(struct cgs_device *cgs_device, enum cgs_ucode
        return -EINVAL;
 }
 
+static uint16_t amdgpu_get_firmware_version(struct cgs_device *cgs_device,
+                                       enum cgs_ucode_id type)
+{
+       CGS_FUNC_ADEV;
+       uint16_t fw_version;
+
+       switch (type) {
+               case CGS_UCODE_ID_SDMA0:
+                       fw_version = adev->sdma.instance[0].fw_version;
+                       break;
+               case CGS_UCODE_ID_SDMA1:
+                       fw_version = adev->sdma.instance[1].fw_version;
+                       break;
+               case CGS_UCODE_ID_CP_CE:
+                       fw_version = adev->gfx.ce_fw_version;
+                       break;
+               case CGS_UCODE_ID_CP_PFP:
+                       fw_version = adev->gfx.pfp_fw_version;
+                       break;
+               case CGS_UCODE_ID_CP_ME:
+                       fw_version = adev->gfx.me_fw_version;
+                       break;
+               case CGS_UCODE_ID_CP_MEC:
+                       fw_version = adev->gfx.mec_fw_version;
+                       break;
+               case CGS_UCODE_ID_CP_MEC_JT1:
+                       fw_version = adev->gfx.mec_fw_version;
+                       break;
+               case CGS_UCODE_ID_CP_MEC_JT2:
+                       fw_version = adev->gfx.mec_fw_version;
+                       break;
+               case CGS_UCODE_ID_RLC_G:
+                       fw_version = adev->gfx.rlc_fw_version;
+                       break;
+               default:
+                       DRM_ERROR("firmware type %d do not have version\n", type);
+                       fw_version = 0;
+       }
+       return fw_version;
+}
+
 static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
                                        enum cgs_ucode_id type,
                                        struct cgs_firmware_info *info)
@@ -741,6 +782,7 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
                info->mc_addr = gpu_addr;
                info->image_size = data_size;
                info->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
+               info->fw_version = amdgpu_get_firmware_version(cgs_device, type);
                info->feature_version = (uint16_t)le32_to_cpu(header->ucode_feature_version);
        } else {
                char fw_name[30] = {0};
@@ -848,6 +890,12 @@ static int amdgpu_cgs_query_system_info(struct cgs_device *cgs_device,
        case CGS_SYSTEM_INFO_GFX_SE_INFO:
                sys_info->value = adev->gfx.config.max_shader_engines;
                break;
+       case CGS_SYSTEM_INFO_PCIE_SUB_SYS_ID:
+               sys_info->value = adev->pdev->subsystem_device;
+               break;
+       case CGS_SYSTEM_INFO_PCIE_SUB_SYS_VENDOR_ID:
+               sys_info->value = adev->pdev->subsystem_vendor;
+               break;
        default:
                return -ENODEV;
        }
index ff0b55a..2e3a054 100644 (file)
@@ -168,12 +168,12 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
                }
 
                /* Any defined maximum tmds clock limit we must not exceed? */
-               if (connector->max_tmds_clock > 0) {
+               if (connector->display_info.max_tmds_clock > 0) {
                        /* mode_clock is clock in kHz for mode to be modeset on this connector */
                        mode_clock = amdgpu_connector->pixelclock_for_modeset;
 
                        /* Maximum allowable input clock in kHz */
-                       max_tmds_clock = connector->max_tmds_clock * 1000;
+                       max_tmds_clock = connector->display_info.max_tmds_clock;
 
                        DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
                                  connector->name, mode_clock, max_tmds_clock);
@@ -769,8 +769,10 @@ static void amdgpu_connector_destroy(struct drm_connector *connector)
 {
        struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-       if (amdgpu_connector->ddc_bus->has_aux)
+       if (amdgpu_connector->ddc_bus->has_aux) {
                drm_dp_aux_unregister(&amdgpu_connector->ddc_bus->aux);
+               amdgpu_connector->ddc_bus->has_aux = false;
+       }
        amdgpu_connector_free_edid(connector);
        kfree(amdgpu_connector->con_priv);
        drm_connector_unregister(connector);
@@ -1504,6 +1506,88 @@ static const struct drm_connector_funcs amdgpu_connector_edp_funcs = {
        .force = amdgpu_connector_dvi_force,
 };
 
+static struct drm_encoder *
+amdgpu_connector_virtual_encoder(struct drm_connector *connector)
+{
+       int enc_id = connector->encoder_ids[0];
+       struct drm_encoder *encoder;
+       int i;
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
+
+               encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
+               if (!encoder)
+                       continue;
+
+               if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL)
+                       return encoder;
+       }
+
+       /* pick the first one */
+       if (enc_id)
+               return drm_encoder_find(connector->dev, enc_id);
+       return NULL;
+}
+
+static int amdgpu_connector_virtual_get_modes(struct drm_connector *connector)
+{
+       struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
+
+       if (encoder) {
+               amdgpu_connector_add_common_modes(encoder, connector);
+       }
+
+       return 0;
+}
+
+static int amdgpu_connector_virtual_mode_valid(struct drm_connector *connector,
+                                          struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static int
+amdgpu_connector_virtual_dpms(struct drm_connector *connector, int mode)
+{
+       return 0;
+}
+
+static enum drm_connector_status
+
+amdgpu_connector_virtual_detect(struct drm_connector *connector, bool force)
+{
+       return connector_status_connected;
+}
+
+static int
+amdgpu_connector_virtual_set_property(struct drm_connector *connector,
+                                 struct drm_property *property,
+                                 uint64_t val)
+{
+       return 0;
+}
+
+static void amdgpu_connector_virtual_force(struct drm_connector *connector)
+{
+       return;
+}
+
+static const struct drm_connector_helper_funcs amdgpu_connector_virtual_helper_funcs = {
+       .get_modes = amdgpu_connector_virtual_get_modes,
+       .mode_valid = amdgpu_connector_virtual_mode_valid,
+       .best_encoder = amdgpu_connector_virtual_encoder,
+};
+
+static const struct drm_connector_funcs amdgpu_connector_virtual_funcs = {
+       .dpms = amdgpu_connector_virtual_dpms,
+       .detect = amdgpu_connector_virtual_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = amdgpu_connector_virtual_set_property,
+       .destroy = amdgpu_connector_destroy,
+       .force = amdgpu_connector_virtual_force,
+};
+
 void
 amdgpu_connector_add(struct amdgpu_device *adev,
                      uint32_t connector_id,
@@ -1888,6 +1972,17 @@ amdgpu_connector_add(struct amdgpu_device *adev,
                        connector->interlace_allowed = false;
                        connector->doublescan_allowed = false;
                        break;
+               case DRM_MODE_CONNECTOR_VIRTUAL:
+                       amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
+                       if (!amdgpu_dig_connector)
+                               goto failed;
+                       amdgpu_connector->con_priv = amdgpu_dig_connector;
+                       drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_virtual_funcs, connector_type);
+                       drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_virtual_helper_funcs);
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = false;
+                       connector->doublescan_allowed = false;
+                       break;
                }
        }
 
index 0307ff5..b0f6e69 100644 (file)
@@ -91,6 +91,7 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
                                      uint32_t *offset)
 {
        struct drm_gem_object *gobj;
+       unsigned long size;
 
        gobj = drm_gem_object_lookup(p->filp, data->handle);
        if (gobj == NULL)
@@ -101,6 +102,11 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
        p->uf_entry.tv.bo = &p->uf_entry.robj->tbo;
        p->uf_entry.tv.shared = true;
        p->uf_entry.user_pages = NULL;
+
+       size = amdgpu_bo_size(p->uf_entry.robj);
+       if (size != PAGE_SIZE || (data->offset + 8) > size)
+               return -EINVAL;
+
        *offset = data->offset;
 
        drm_gem_object_unreference_unlocked(gobj);
@@ -235,70 +241,212 @@ free_chunk:
        return ret;
 }
 
-/* Returns how many bytes TTM can move per IB.
+/* Convert microseconds to bytes. */
+static u64 us_to_bytes(struct amdgpu_device *adev, s64 us)
+{
+       if (us <= 0 || !adev->mm_stats.log2_max_MBps)
+               return 0;
+
+       /* Since accum_us is incremented by a million per second, just
+        * multiply it by the number of MB/s to get the number of bytes.
+        */
+       return us << adev->mm_stats.log2_max_MBps;
+}
+
+static s64 bytes_to_us(struct amdgpu_device *adev, u64 bytes)
+{
+       if (!adev->mm_stats.log2_max_MBps)
+               return 0;
+
+       return bytes >> adev->mm_stats.log2_max_MBps;
+}
+
+/* Returns how many bytes TTM can move right now. If no bytes can be moved,
+ * it returns 0. If it returns non-zero, it's OK to move at least one buffer,
+ * which means it can go over the threshold once. If that happens, the driver
+ * will be in debt and no other buffer migrations can be done until that debt
+ * is repaid.
+ *
+ * This approach allows moving a buffer of any size (it's important to allow
+ * that).
+ *
+ * The currency is simply time in microseconds and it increases as the clock
+ * ticks. The accumulated microseconds (us) are converted to bytes and
+ * returned.
  */
 static u64 amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev)
 {
-       u64 real_vram_size = adev->mc.real_vram_size;
-       u64 vram_usage = atomic64_read(&adev->vram_usage);
+       s64 time_us, increment_us;
+       u64 max_bytes;
+       u64 free_vram, total_vram, used_vram;
 
-       /* This function is based on the current VRAM usage.
+       /* Allow a maximum of 200 accumulated ms. This is basically per-IB
+        * throttling.
         *
-        * - If all of VRAM is free, allow relocating the number of bytes that
-        *   is equal to 1/4 of the size of VRAM for this IB.
+        * It means that in order to get full max MBps, at least 5 IBs per
+        * second must be submitted and not more than 200ms apart from each
+        * other.
+        */
+       const s64 us_upper_bound = 200000;
 
-        * - If more than one half of VRAM is occupied, only allow relocating
-        *   1 MB of data for this IB.
-        *
-        * - From 0 to one half of used VRAM, the threshold decreases
-        *   linearly.
-        *         __________________
-        * 1/4 of -|\               |
-        * VRAM    | \              |
-        *         |  \             |
-        *         |   \            |
-        *         |    \           |
-        *         |     \          |
-        *         |      \         |
-        *         |       \________|1 MB
-        *         |----------------|
-        *    VRAM 0 %             100 %
-        *         used            used
-        *
-        * Note: It's a threshold, not a limit. The threshold must be crossed
-        * for buffer relocations to stop, so any buffer of an arbitrary size
-        * can be moved as long as the threshold isn't crossed before
-        * the relocation takes place. We don't want to disable buffer
-        * relocations completely.
+       if (!adev->mm_stats.log2_max_MBps)
+               return 0;
+
+       total_vram = adev->mc.real_vram_size - adev->vram_pin_size;
+       used_vram = atomic64_read(&adev->vram_usage);
+       free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram;
+
+       spin_lock(&adev->mm_stats.lock);
+
+       /* Increase the amount of accumulated us. */
+       time_us = ktime_to_us(ktime_get());
+       increment_us = time_us - adev->mm_stats.last_update_us;
+       adev->mm_stats.last_update_us = time_us;
+       adev->mm_stats.accum_us = min(adev->mm_stats.accum_us + increment_us,
+                                      us_upper_bound);
+
+       /* This prevents the short period of low performance when the VRAM
+        * usage is low and the driver is in debt or doesn't have enough
+        * accumulated us to fill VRAM quickly.
         *
-        * The idea is that buffers should be placed in VRAM at creation time
-        * and TTM should only do a minimum number of relocations during
-        * command submission. In practice, you need to submit at least
-        * a dozen IBs to move all buffers to VRAM if they are in GTT.
+        * The situation can occur in these cases:
+        * - a lot of VRAM is freed by userspace
+        * - the presence of a big buffer causes a lot of evictions
+        *   (solution: split buffers into smaller ones)
         *
-        * Also, things can get pretty crazy under memory pressure and actual
-        * VRAM usage can change a lot, so playing safe even at 50% does
-        * consistently increase performance.
+        * If 128 MB or 1/8th of VRAM is free, start filling it now by setting
+        * accum_us to a positive number.
+        */
+       if (free_vram >= 128 * 1024 * 1024 || free_vram >= total_vram / 8) {
+               s64 min_us;
+
+               /* Be more aggresive on dGPUs. Try to fill a portion of free
+                * VRAM now.
+                */
+               if (!(adev->flags & AMD_IS_APU))
+                       min_us = bytes_to_us(adev, free_vram / 4);
+               else
+                       min_us = 0; /* Reset accum_us on APUs. */
+
+               adev->mm_stats.accum_us = max(min_us, adev->mm_stats.accum_us);
+       }
+
+       /* This returns 0 if the driver is in debt to disallow (optional)
+        * buffer moves.
+        */
+       max_bytes = us_to_bytes(adev, adev->mm_stats.accum_us);
+
+       spin_unlock(&adev->mm_stats.lock);
+       return max_bytes;
+}
+
+/* Report how many bytes have really been moved for the last command
+ * submission. This can result in a debt that can stop buffer migrations
+ * temporarily.
+ */
+static void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev,
+                                        u64 num_bytes)
+{
+       spin_lock(&adev->mm_stats.lock);
+       adev->mm_stats.accum_us -= bytes_to_us(adev, num_bytes);
+       spin_unlock(&adev->mm_stats.lock);
+}
+
+static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
+                                struct amdgpu_bo *bo)
+{
+       u64 initial_bytes_moved;
+       uint32_t domain;
+       int r;
+
+       if (bo->pin_count)
+               return 0;
+
+       /* Don't move this buffer if we have depleted our allowance
+        * to move it. Don't move anything if the threshold is zero.
         */
+       if (p->bytes_moved < p->bytes_moved_threshold)
+               domain = bo->prefered_domains;
+       else
+               domain = bo->allowed_domains;
+
+retry:
+       amdgpu_ttm_placement_from_domain(bo, domain);
+       initial_bytes_moved = atomic64_read(&bo->adev->num_bytes_moved);
+       r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+       p->bytes_moved += atomic64_read(&bo->adev->num_bytes_moved) -
+               initial_bytes_moved;
+
+       if (unlikely(r == -ENOMEM) && domain != bo->allowed_domains) {
+               domain = bo->allowed_domains;
+               goto retry;
+       }
 
-       u64 half_vram = real_vram_size >> 1;
-       u64 half_free_vram = vram_usage >= half_vram ? 0 : half_vram - vram_usage;
-       u64 bytes_moved_threshold = half_free_vram >> 1;
-       return max(bytes_moved_threshold, 1024*1024ull);
+       return r;
 }
 
-int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p,
+/* Last resort, try to evict something from the current working set */
+static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p,
+                               struct amdgpu_bo_list_entry *lobj)
+{
+       uint32_t domain = lobj->robj->allowed_domains;
+       int r;
+
+       if (!p->evictable)
+               return false;
+
+       for (;&p->evictable->tv.head != &p->validated;
+            p->evictable = list_prev_entry(p->evictable, tv.head)) {
+
+               struct amdgpu_bo_list_entry *candidate = p->evictable;
+               struct amdgpu_bo *bo = candidate->robj;
+               u64 initial_bytes_moved;
+               uint32_t other;
+
+               /* If we reached our current BO we can forget it */
+               if (candidate == lobj)
+                       break;
+
+               other = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
+
+               /* Check if this BO is in one of the domains we need space for */
+               if (!(other & domain))
+                       continue;
+
+               /* Check if we can move this BO somewhere else */
+               other = bo->allowed_domains & ~domain;
+               if (!other)
+                       continue;
+
+               /* Good we can try to move this BO somewhere else */
+               amdgpu_ttm_placement_from_domain(bo, other);
+               initial_bytes_moved = atomic64_read(&bo->adev->num_bytes_moved);
+               r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+               p->bytes_moved += atomic64_read(&bo->adev->num_bytes_moved) -
+                       initial_bytes_moved;
+
+               if (unlikely(r))
+                       break;
+
+               p->evictable = list_prev_entry(p->evictable, tv.head);
+               list_move(&candidate->tv.head, &p->validated);
+
+               return true;
+       }
+
+       return false;
+}
+
+static int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p,
                            struct list_head *validated)
 {
        struct amdgpu_bo_list_entry *lobj;
-       u64 initial_bytes_moved;
        int r;
 
        list_for_each_entry(lobj, validated, tv.head) {
                struct amdgpu_bo *bo = lobj->robj;
                bool binding_userptr = false;
                struct mm_struct *usermm;
-               uint32_t domain;
 
                usermm = amdgpu_ttm_tt_get_usermm(bo->tbo.ttm);
                if (usermm && usermm != current->mm)
@@ -313,35 +461,19 @@ int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p,
                        binding_userptr = true;
                }
 
-               if (bo->pin_count)
-                       continue;
-
-               /* Avoid moving this one if we have moved too many buffers
-                * for this IB already.
-                *
-                * Note that this allows moving at least one buffer of
-                * any size, because it doesn't take the current "bo"
-                * into account. We don't want to disallow buffer moves
-                * completely.
-                */
-               if (p->bytes_moved <= p->bytes_moved_threshold)
-                       domain = bo->prefered_domains;
-               else
-                       domain = bo->allowed_domains;
-
-       retry:
-               amdgpu_ttm_placement_from_domain(bo, domain);
-               initial_bytes_moved = atomic64_read(&bo->adev->num_bytes_moved);
-               r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
-               p->bytes_moved += atomic64_read(&bo->adev->num_bytes_moved) -
-                              initial_bytes_moved;
+               if (p->evictable == lobj)
+                       p->evictable = NULL;
 
-               if (unlikely(r)) {
-                       if (r != -ERESTARTSYS && domain != bo->allowed_domains) {
-                               domain = bo->allowed_domains;
-                               goto retry;
-                       }
+               do {
+                       r = amdgpu_cs_bo_validate(p, bo);
+               } while (r == -ENOMEM && amdgpu_cs_try_evict(p, lobj));
+               if (r)
                        return r;
+
+               if (bo->shadow) {
+                       r = amdgpu_cs_bo_validate(p, bo);
+                       if (r)
+                               return r;
                }
 
                if (binding_userptr) {
@@ -386,8 +518,10 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
 
                r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true,
                                           &duplicates);
-               if (unlikely(r != 0))
+               if (unlikely(r != 0)) {
+                       DRM_ERROR("ttm_eu_reserve_buffers failed.\n");
                        goto error_free_pages;
+               }
 
                /* Without a BO list we don't have userptr BOs */
                if (!p->bo_list)
@@ -427,9 +561,10 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
                /* Unreserve everything again. */
                ttm_eu_backoff_reservation(&p->ticket, &p->validated);
 
-               /* We tried to often, just abort */
+               /* We tried too many times, just abort */
                if (!--tries) {
                        r = -EDEADLK;
+                       DRM_ERROR("deadlock in %s\n", __func__);
                        goto error_free_pages;
                }
 
@@ -441,11 +576,13 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
                                                         sizeof(struct page*));
                        if (!e->user_pages) {
                                r = -ENOMEM;
+                               DRM_ERROR("calloc failure in %s\n", __func__);
                                goto error_free_pages;
                        }
 
                        r = amdgpu_ttm_tt_get_user_pages(ttm, e->user_pages);
                        if (r) {
+                               DRM_ERROR("amdgpu_ttm_tt_get_user_pages failed.\n");
                                drm_free_large(e->user_pages);
                                e->user_pages = NULL;
                                goto error_free_pages;
@@ -460,14 +597,23 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
 
        p->bytes_moved_threshold = amdgpu_cs_get_threshold_for_moves(p->adev);
        p->bytes_moved = 0;
+       p->evictable = list_last_entry(&p->validated,
+                                      struct amdgpu_bo_list_entry,
+                                      tv.head);
 
        r = amdgpu_cs_list_validate(p, &duplicates);
-       if (r)
+       if (r) {
+               DRM_ERROR("amdgpu_cs_list_validate(duplicates) failed.\n");
                goto error_validate;
+       }
 
        r = amdgpu_cs_list_validate(p, &p->validated);
-       if (r)
+       if (r) {
+               DRM_ERROR("amdgpu_cs_list_validate(validated) failed.\n");
                goto error_validate;
+       }
+
+       amdgpu_cs_report_moved_bytes(p->adev, p->bytes_moved);
 
        fpriv->vm.last_eviction_counter =
                atomic64_read(&p->adev->num_evictions);
@@ -499,8 +645,12 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
                }
        }
 
-       if (p->uf_entry.robj)
-               p->job->uf_addr += amdgpu_bo_gpu_offset(p->uf_entry.robj);
+       if (!r && p->uf_entry.robj) {
+               struct amdgpu_bo *uf = p->uf_entry.robj;
+
+               r = amdgpu_ttm_bind(&uf->tbo, &uf->tbo.mem);
+               p->job->uf_addr += amdgpu_bo_gpu_offset(uf);
+       }
 
 error_validate:
        if (r) {
@@ -617,7 +767,7 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
                        if (bo_va == NULL)
                                continue;
 
-                       r = amdgpu_vm_bo_update(adev, bo_va, &bo->tbo.mem);
+                       r = amdgpu_vm_bo_update(adev, bo_va, false);
                        if (r)
                                return r;
 
@@ -710,6 +860,14 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
                if (r)
                        return r;
 
+               if (ib->flags & AMDGPU_IB_FLAG_PREAMBLE) {
+                       parser->job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT;
+                       if (!parser->ctx->preamble_presented) {
+                               parser->job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT_FIRST;
+                               parser->ctx->preamble_presented = true;
+                       }
+               }
+
                if (parser->job->ring && parser->job->ring != ring)
                        return -EINVAL;
 
@@ -849,7 +1007,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
        }
 
        job->owner = p->filp;
-       job->ctx = entity->fence_context;
+       job->fence_ctx = entity->fence_context;
        p->fence = fence_get(&job->base.s_fence->finished);
        cs->out.handle = amdgpu_ctx_add_fence(p->ctx, ring, p->fence);
        job->uf_sequence = cs->out.handle;
@@ -1015,3 +1173,29 @@ amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
 
        return NULL;
 }
+
+/**
+ * amdgpu_cs_sysvm_access_required - make BOs accessible by the system VM
+ *
+ * @parser: command submission parser context
+ *
+ * Helper for UVD/VCE VM emulation, make sure BOs are accessible by the system VM.
+ */
+int amdgpu_cs_sysvm_access_required(struct amdgpu_cs_parser *parser)
+{
+       unsigned i;
+       int r;
+
+       if (!parser->bo_list)
+               return 0;
+
+       for (i = 0; i < parser->bo_list->num_entries; i++) {
+               struct amdgpu_bo *bo = parser->bo_list->array[i].robj;
+
+               r = amdgpu_ttm_bind(&bo->tbo, &bo->tbo.mem);
+               if (unlikely(r))
+                       return r;
+       }
+
+       return 0;
+}
index 17e1362..e203e55 100644 (file)
@@ -60,6 +60,7 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, struct amdgpu_ctx *ctx)
                        amd_sched_entity_fini(&adev->rings[j]->sched,
                                              &ctx->rings[j].entity);
                kfree(ctx->fences);
+               ctx->fences = NULL;
                return r;
        }
        return 0;
@@ -77,6 +78,7 @@ static void amdgpu_ctx_fini(struct amdgpu_ctx *ctx)
                for (j = 0; j < amdgpu_sched_jobs; ++j)
                        fence_put(ctx->rings[i].fences[j]);
        kfree(ctx->fences);
+       ctx->fences = NULL;
 
        for (i = 0; i < adev->num_rings; i++)
                amd_sched_entity_fini(&adev->rings[i]->sched,
index 39c01b9..7dbe85d 100644 (file)
 #include "atom.h"
 #include "amdgpu_atombios.h"
 #include "amd_pcie.h"
+#ifdef CONFIG_DRM_AMDGPU_SI
+#include "si.h"
+#endif
 #ifdef CONFIG_DRM_AMDGPU_CIK
 #include "cik.h"
 #endif
 #include "vi.h"
 #include "bif/bif_4_1_d.h"
+#include <linux/pci.h>
+#include <linux/firmware.h>
 
 static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev);
 static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev);
 
 static const char *amdgpu_asic_name[] = {
+       "TAHITI",
+       "PITCAIRN",
+       "VERDE",
+       "OLAND",
+       "HAINAN",
        "BONAIRE",
        "KAVERI",
        "KABINI",
@@ -101,7 +111,7 @@ void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v,
                    bool always_indirect)
 {
        trace_amdgpu_mm_wreg(adev->pdev->device, reg, v);
-       
+
        if ((reg * 4) < adev->rmmio_size && !always_indirect)
                writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
        else {
@@ -642,6 +652,46 @@ bool amdgpu_card_posted(struct amdgpu_device *adev)
 
 }
 
+static bool amdgpu_vpost_needed(struct amdgpu_device *adev)
+{
+       if (amdgpu_sriov_vf(adev))
+               return false;
+
+       if (amdgpu_passthrough(adev)) {
+               /* for FIJI: In whole GPU pass-through virtualization case
+                * old smc fw won't clear some registers (e.g. MEM_SIZE, BIOS_SCRATCH)
+                * so amdgpu_card_posted return false and driver will incorrectly skip vPost.
+                * but if we force vPost do in pass-through case, the driver reload will hang.
+                * whether doing vPost depends on amdgpu_card_posted if smc version is above
+                * 00160e00 for FIJI.
+                */
+               if (adev->asic_type == CHIP_FIJI) {
+                       int err;
+                       uint32_t fw_ver;
+                       err = request_firmware(&adev->pm.fw, "amdgpu/fiji_smc.bin", adev->dev);
+                       /* force vPost if error occured */
+                       if (err)
+                               return true;
+
+                       fw_ver = *((uint32_t *)adev->pm.fw->data + 69);
+                       if (fw_ver >= 0x00160e00)
+                               return !amdgpu_card_posted(adev);
+               }
+       } else {
+               /* in bare-metal case, amdgpu_card_posted return false
+                * after system reboot/boot, and return true if driver
+                * reloaded.
+                * we shouldn't do vPost after driver reload otherwise GPU
+                * could hang.
+                */
+               if (amdgpu_card_posted(adev))
+                       return false;
+       }
+
+       /* we assume vPost is neede for all other cases */
+       return true;
+}
+
 /**
  * amdgpu_dummy_page_init - init dummy page used by the driver
  *
@@ -1026,7 +1076,7 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
                /* don't suspend or resume card normally */
                dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
 
-               amdgpu_resume_kms(dev, true, true);
+               amdgpu_device_resume(dev, true, true);
 
                dev->pdev->d3_delay = d3_delay;
 
@@ -1036,7 +1086,7 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
                printk(KERN_INFO "amdgpu: switched off\n");
                drm_kms_helper_poll_disable(dev);
                dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
-               amdgpu_suspend_kms(dev, true, true);
+               amdgpu_device_suspend(dev, true, true);
                dev->switch_power_state = DRM_SWITCH_POWER_OFF;
        }
 }
@@ -1181,10 +1231,38 @@ int amdgpu_ip_block_version_cmp(struct amdgpu_device *adev,
        return 1;
 }
 
+static void amdgpu_whether_enable_virtual_display(struct amdgpu_device *adev)
+{
+       adev->enable_virtual_display = false;
+
+       if (amdgpu_virtual_display) {
+               struct drm_device *ddev = adev->ddev;
+               const char *pci_address_name = pci_name(ddev->pdev);
+               char *pciaddstr, *pciaddstr_tmp, *pciaddname;
+
+               pciaddstr = kstrdup(amdgpu_virtual_display, GFP_KERNEL);
+               pciaddstr_tmp = pciaddstr;
+               while ((pciaddname = strsep(&pciaddstr_tmp, ";"))) {
+                       if (!strcmp(pci_address_name, pciaddname)) {
+                               adev->enable_virtual_display = true;
+                               break;
+                       }
+               }
+
+               DRM_INFO("virtual display string:%s, %s:virtual_display:%d\n",
+                                amdgpu_virtual_display, pci_address_name,
+                                adev->enable_virtual_display);
+
+               kfree(pciaddstr);
+       }
+}
+
 static int amdgpu_early_init(struct amdgpu_device *adev)
 {
        int i, r;
 
+       amdgpu_whether_enable_virtual_display(adev);
+
        switch (adev->asic_type) {
        case CHIP_TOPAZ:
        case CHIP_TONGA:
@@ -1202,6 +1280,18 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
                if (r)
                        return r;
                break;
+#ifdef CONFIG_DRM_AMDGPU_SI
+       case CHIP_VERDE:
+       case CHIP_TAHITI:
+       case CHIP_PITCAIRN:
+       case CHIP_OLAND:
+       case CHIP_HAINAN:
+               adev->family = AMDGPU_FAMILY_SI;
+               r = si_set_ip_blocks(adev);
+               if (r)
+                       return r;
+               break;
+#endif
 #ifdef CONFIG_DRM_AMDGPU_CIK
        case CHIP_BONAIRE:
        case CHIP_HAWAII:
@@ -1318,6 +1408,9 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
        for (i = 0; i < adev->num_ip_blocks; i++) {
                if (!adev->ip_block_status[i].valid)
                        continue;
+               if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_UVD ||
+                       adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_VCE)
+                       continue;
                /* enable clockgating to save power */
                r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
                                                                    AMD_CG_STATE_GATE);
@@ -1331,6 +1424,7 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
                                DRM_ERROR("late_init of IP block <%s> failed %d\n", adev->ip_blocks[i].funcs->name, r);
                                return r;
                        }
+                       adev->ip_block_status[i].late_initialized = true;
                }
        }
 
@@ -1376,8 +1470,11 @@ static int amdgpu_fini(struct amdgpu_device *adev)
        }
 
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
+               if (!adev->ip_block_status[i].late_initialized)
+                       continue;
                if (adev->ip_blocks[i].funcs->late_fini)
                        adev->ip_blocks[i].funcs->late_fini((void *)adev);
+               adev->ip_block_status[i].late_initialized = false;
        }
 
        return 0;
@@ -1433,13 +1530,10 @@ static int amdgpu_resume(struct amdgpu_device *adev)
        return 0;
 }
 
-static bool amdgpu_device_is_virtual(void)
+static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev)
 {
-#ifdef CONFIG_X86
-       return boot_cpu_has(X86_FEATURE_HYPERVISOR);
-#else
-       return false;
-#endif
+       if (amdgpu_atombios_has_gpu_virtualization_table(adev))
+               adev->virtualization.virtual_caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
 }
 
 /**
@@ -1461,6 +1555,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
 {
        int r, i;
        bool runtime = false;
+       u32 max_MBps;
 
        adev->shutdown = false;
        adev->dev = &pdev->dev;
@@ -1484,6 +1579,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        adev->smc_wreg = &amdgpu_invalid_wreg;
        adev->pcie_rreg = &amdgpu_invalid_rreg;
        adev->pcie_wreg = &amdgpu_invalid_wreg;
+       adev->pciep_rreg = &amdgpu_invalid_rreg;
+       adev->pciep_wreg = &amdgpu_invalid_wreg;
        adev->uvd_ctx_rreg = &amdgpu_invalid_rreg;
        adev->uvd_ctx_wreg = &amdgpu_invalid_wreg;
        adev->didt_rreg = &amdgpu_invalid_rreg;
@@ -1520,9 +1617,22 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        spin_lock_init(&adev->didt_idx_lock);
        spin_lock_init(&adev->gc_cac_idx_lock);
        spin_lock_init(&adev->audio_endpt_idx_lock);
+       spin_lock_init(&adev->mm_stats.lock);
+
+       INIT_LIST_HEAD(&adev->shadow_list);
+       mutex_init(&adev->shadow_list_lock);
+
+       INIT_LIST_HEAD(&adev->gtt_list);
+       spin_lock_init(&adev->gtt_list_lock);
+
+       if (adev->asic_type >= CHIP_BONAIRE) {
+               adev->rmmio_base = pci_resource_start(adev->pdev, 5);
+               adev->rmmio_size = pci_resource_len(adev->pdev, 5);
+       } else {
+               adev->rmmio_base = pci_resource_start(adev->pdev, 2);
+               adev->rmmio_size = pci_resource_len(adev->pdev, 2);
+       }
 
-       adev->rmmio_base = pci_resource_start(adev->pdev, 5);
-       adev->rmmio_size = pci_resource_len(adev->pdev, 5);
        adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size);
        if (adev->rmmio == NULL) {
                return -ENOMEM;
@@ -1530,8 +1640,9 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)adev->rmmio_base);
        DRM_INFO("register mmio size: %u\n", (unsigned)adev->rmmio_size);
 
-       /* doorbell bar mapping */
-       amdgpu_doorbell_init(adev);
+       if (adev->asic_type >= CHIP_BONAIRE)
+               /* doorbell bar mapping */
+               amdgpu_doorbell_init(adev);
 
        /* io port mapping */
        for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -1579,25 +1690,24 @@ int amdgpu_device_init(struct amdgpu_device *adev,
                goto failed;
        }
 
-       /* See if the asic supports SR-IOV */
-       adev->virtualization.supports_sr_iov =
-               amdgpu_atombios_has_gpu_virtualization_table(adev);
-
-       /* Check if we are executing in a virtualized environment */
-       adev->virtualization.is_virtual = amdgpu_device_is_virtual();
-       adev->virtualization.caps = amdgpu_asic_get_virtual_caps(adev);
+       /* detect if we are with an SRIOV vbios */
+       amdgpu_device_detect_sriov_bios(adev);
 
        /* Post card if necessary */
-       if (!amdgpu_card_posted(adev) ||
-           (adev->virtualization.is_virtual &&
-            !(adev->virtualization.caps & AMDGPU_VIRT_CAPS_SRIOV_EN))) {
+       if (amdgpu_vpost_needed(adev)) {
                if (!adev->bios) {
-                       dev_err(adev->dev, "Card not posted and no BIOS - ignoring\n");
+                       dev_err(adev->dev, "no vBIOS found\n");
                        r = -EINVAL;
                        goto failed;
                }
-               DRM_INFO("GPU not posted. posting now...\n");
-               amdgpu_atom_asic_init(adev->mode_info.atom_context);
+               DRM_INFO("GPU posting now...\n");
+               r = amdgpu_atom_asic_init(adev->mode_info.atom_context);
+               if (r) {
+                       dev_err(adev->dev, "gpu post error!\n");
+                       goto failed;
+               }
+       } else {
+               DRM_INFO("GPU post is not needed\n");
        }
 
        /* Initialize clocks */
@@ -1628,6 +1738,14 @@ int amdgpu_device_init(struct amdgpu_device *adev,
 
        adev->accel_working = true;
 
+       /* Initialize the buffer migration limit. */
+       if (amdgpu_moverate >= 0)
+               max_MBps = amdgpu_moverate;
+       else
+               max_MBps = 8; /* Allow 8 MB/s. */
+       /* Get a log2 for easy divisions. */
+       adev->mm_stats.log2_max_MBps = ilog2(max(1u, max_MBps));
+
        amdgpu_fbdev_init(adev);
 
        r = amdgpu_ib_pool_init(adev);
@@ -1732,7 +1850,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
        adev->rio_mem = NULL;
        iounmap(adev->rmmio);
        adev->rmmio = NULL;
-       amdgpu_doorbell_fini(adev);
+       if (adev->asic_type >= CHIP_BONAIRE)
+               amdgpu_doorbell_fini(adev);
        amdgpu_debugfs_regs_cleanup(adev);
        amdgpu_debugfs_remove_files(adev);
 }
@@ -1742,7 +1861,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
  * Suspend & resume.
  */
 /**
- * amdgpu_suspend_kms - initiate device suspend
+ * amdgpu_device_suspend - initiate device suspend
  *
  * @pdev: drm dev pointer
  * @state: suspend state
@@ -1751,7 +1870,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
  * Returns 0 for success or an error on failure.
  * Called at driver suspend.
  */
-int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
+int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
 {
        struct amdgpu_device *adev;
        struct drm_crtc *crtc;
@@ -1819,6 +1938,10 @@ int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
                /* Shut down the device */
                pci_disable_device(dev->pdev);
                pci_set_power_state(dev->pdev, PCI_D3hot);
+       } else {
+               r = amdgpu_asic_reset(adev);
+               if (r)
+                       DRM_ERROR("amdgpu asic reset failed\n");
        }
 
        if (fbcon) {
@@ -1830,7 +1953,7 @@ int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
 }
 
 /**
- * amdgpu_resume_kms - initiate device resume
+ * amdgpu_device_resume - initiate device resume
  *
  * @pdev: drm dev pointer
  *
@@ -1838,7 +1961,7 @@ int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
  * Returns 0 for success or an error on failure.
  * Called at driver resume.
  */
-int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
+int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
 {
        struct drm_connector *connector;
        struct amdgpu_device *adev = dev->dev_private;
@@ -1848,22 +1971,26 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       if (fbcon) {
+       if (fbcon)
                console_lock();
-       }
+
        if (resume) {
                pci_set_power_state(dev->pdev, PCI_D0);
                pci_restore_state(dev->pdev);
-               if (pci_enable_device(dev->pdev)) {
+               r = pci_enable_device(dev->pdev);
+               if (r) {
                        if (fbcon)
                                console_unlock();
-                       return -1;
+                       return r;
                }
        }
 
        /* post card */
-       if (!amdgpu_card_posted(adev))
-               amdgpu_atom_asic_init(adev->mode_info.atom_context);
+       if (!amdgpu_card_posted(adev) || !resume) {
+               r = amdgpu_atom_asic_init(adev->mode_info.atom_context);
+               if (r)
+                       DRM_ERROR("amdgpu asic init failed\n");
+       }
 
        r = amdgpu_resume(adev);
        if (r)
@@ -1937,6 +2064,126 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        return 0;
 }
 
+static bool amdgpu_check_soft_reset(struct amdgpu_device *adev)
+{
+       int i;
+       bool asic_hang = false;
+
+       for (i = 0; i < adev->num_ip_blocks; i++) {
+               if (!adev->ip_block_status[i].valid)
+                       continue;
+               if (adev->ip_blocks[i].funcs->check_soft_reset)
+                       adev->ip_blocks[i].funcs->check_soft_reset(adev);
+               if (adev->ip_block_status[i].hang) {
+                       DRM_INFO("IP block:%d is hang!\n", i);
+                       asic_hang = true;
+               }
+       }
+       return asic_hang;
+}
+
+static int amdgpu_pre_soft_reset(struct amdgpu_device *adev)
+{
+       int i, r = 0;
+
+       for (i = 0; i < adev->num_ip_blocks; i++) {
+               if (!adev->ip_block_status[i].valid)
+                       continue;
+               if (adev->ip_block_status[i].hang &&
+                   adev->ip_blocks[i].funcs->pre_soft_reset) {
+                       r = adev->ip_blocks[i].funcs->pre_soft_reset(adev);
+                       if (r)
+                               return r;
+               }
+       }
+
+       return 0;
+}
+
+static bool amdgpu_need_full_reset(struct amdgpu_device *adev)
+{
+       if (adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang ||
+           adev->ip_block_status[AMD_IP_BLOCK_TYPE_SMC].hang ||
+           adev->ip_block_status[AMD_IP_BLOCK_TYPE_ACP].hang ||
+           adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang) {
+               DRM_INFO("Some block need full reset!\n");
+               return true;
+       }
+       return false;
+}
+
+static int amdgpu_soft_reset(struct amdgpu_device *adev)
+{
+       int i, r = 0;
+
+       for (i = 0; i < adev->num_ip_blocks; i++) {
+               if (!adev->ip_block_status[i].valid)
+                       continue;
+               if (adev->ip_block_status[i].hang &&
+                   adev->ip_blocks[i].funcs->soft_reset) {
+                       r = adev->ip_blocks[i].funcs->soft_reset(adev);
+                       if (r)
+                               return r;
+               }
+       }
+
+       return 0;
+}
+
+static int amdgpu_post_soft_reset(struct amdgpu_device *adev)
+{
+       int i, r = 0;
+
+       for (i = 0; i < adev->num_ip_blocks; i++) {
+               if (!adev->ip_block_status[i].valid)
+                       continue;
+               if (adev->ip_block_status[i].hang &&
+                   adev->ip_blocks[i].funcs->post_soft_reset)
+                       r = adev->ip_blocks[i].funcs->post_soft_reset(adev);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
+bool amdgpu_need_backup(struct amdgpu_device *adev)
+{
+       if (adev->flags & AMD_IS_APU)
+               return false;
+
+       return amdgpu_lockup_timeout > 0 ? true : false;
+}
+
+static int amdgpu_recover_vram_from_shadow(struct amdgpu_device *adev,
+                                          struct amdgpu_ring *ring,
+                                          struct amdgpu_bo *bo,
+                                          struct fence **fence)
+{
+       uint32_t domain;
+       int r;
+
+       if (!bo->shadow)
+               return 0;
+
+       r = amdgpu_bo_reserve(bo, false);
+       if (r)
+               return r;
+       domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
+       /* if bo has been evicted, then no need to recover */
+       if (domain == AMDGPU_GEM_DOMAIN_VRAM) {
+               r = amdgpu_bo_restore_from_shadow(adev, ring, bo,
+                                                NULL, fence, true);
+               if (r) {
+                       DRM_ERROR("recover page table failed!\n");
+                       goto err;
+               }
+       }
+err:
+       amdgpu_bo_unreserve(bo);
+       return r;
+}
+
 /**
  * amdgpu_gpu_reset - reset the asic
  *
@@ -1949,6 +2196,12 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev)
 {
        int i, r;
        int resched;
+       bool need_full_reset;
+
+       if (!amdgpu_check_soft_reset(adev)) {
+               DRM_INFO("No hardware hang detected. Did some blocks stall?\n");
+               return 0;
+       }
 
        atomic_inc(&adev->gpu_reset_counter);
 
@@ -1967,40 +2220,93 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev)
        /* after all hw jobs are reset, hw fence is meaningless, so force_completion */
        amdgpu_fence_driver_force_completion(adev);
 
-       /* save scratch */
-       amdgpu_atombios_scratch_regs_save(adev);
-       r = amdgpu_suspend(adev);
+       need_full_reset = amdgpu_need_full_reset(adev);
 
-retry:
-       /* Disable fb access */
-       if (adev->mode_info.num_crtc) {
-               struct amdgpu_mode_mc_save save;
-               amdgpu_display_stop_mc_access(adev, &save);
-               amdgpu_wait_for_idle(adev, AMD_IP_BLOCK_TYPE_GMC);
+       if (!need_full_reset) {
+               amdgpu_pre_soft_reset(adev);
+               r = amdgpu_soft_reset(adev);
+               amdgpu_post_soft_reset(adev);
+               if (r || amdgpu_check_soft_reset(adev)) {
+                       DRM_INFO("soft reset failed, will fallback to full reset!\n");
+                       need_full_reset = true;
+               }
        }
 
-       r = amdgpu_asic_reset(adev);
-       /* post card */
-       amdgpu_atom_asic_init(adev->mode_info.atom_context);
+       if (need_full_reset) {
+               /* save scratch */
+               amdgpu_atombios_scratch_regs_save(adev);
+               r = amdgpu_suspend(adev);
 
-       if (!r) {
-               dev_info(adev->dev, "GPU reset succeeded, trying to resume\n");
-               r = amdgpu_resume(adev);
+retry:
+               /* Disable fb access */
+               if (adev->mode_info.num_crtc) {
+                       struct amdgpu_mode_mc_save save;
+                       amdgpu_display_stop_mc_access(adev, &save);
+                       amdgpu_wait_for_idle(adev, AMD_IP_BLOCK_TYPE_GMC);
+               }
+
+               r = amdgpu_asic_reset(adev);
+               /* post card */
+               amdgpu_atom_asic_init(adev->mode_info.atom_context);
+
+               if (!r) {
+                       dev_info(adev->dev, "GPU reset succeeded, trying to resume\n");
+                       r = amdgpu_resume(adev);
+               }
+               /* restore scratch */
+               amdgpu_atombios_scratch_regs_restore(adev);
        }
-       /* restore scratch */
-       amdgpu_atombios_scratch_regs_restore(adev);
        if (!r) {
+               amdgpu_irq_gpu_reset_resume_helper(adev);
+               if (need_full_reset && amdgpu_need_backup(adev)) {
+                       r = amdgpu_ttm_recover_gart(adev);
+                       if (r)
+                               DRM_ERROR("gart recovery failed!!!\n");
+               }
                r = amdgpu_ib_ring_tests(adev);
                if (r) {
                        dev_err(adev->dev, "ib ring test failed (%d).\n", r);
                        r = amdgpu_suspend(adev);
+                       need_full_reset = true;
                        goto retry;
                }
+               /**
+                * recovery vm page tables, since we cannot depend on VRAM is
+                * consistent after gpu full reset.
+                */
+               if (need_full_reset && amdgpu_need_backup(adev)) {
+                       struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
+                       struct amdgpu_bo *bo, *tmp;
+                       struct fence *fence = NULL, *next = NULL;
+
+                       DRM_INFO("recover vram bo from shadow\n");
+                       mutex_lock(&adev->shadow_list_lock);
+                       list_for_each_entry_safe(bo, tmp, &adev->shadow_list, shadow_list) {
+                               amdgpu_recover_vram_from_shadow(adev, ring, bo, &next);
+                               if (fence) {
+                                       r = fence_wait(fence, false);
+                                       if (r) {
+                                               WARN(r, "recovery from shadow isn't comleted\n");
+                                               break;
+                                       }
+                               }
 
+                               fence_put(fence);
+                               fence = next;
+                       }
+                       mutex_unlock(&adev->shadow_list_lock);
+                       if (fence) {
+                               r = fence_wait(fence, false);
+                               if (r)
+                                       WARN(r, "recovery from shadow isn't comleted\n");
+                       }
+                       fence_put(fence);
+               }
                for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                        struct amdgpu_ring *ring = adev->rings[i];
                        if (!ring)
                                continue;
+
                        amd_sched_job_recovery(&ring->sched);
                        kthread_unpark(ring->sched.thread);
                }
@@ -2020,7 +2326,6 @@ retry:
                /* bad news, how to tell it to userspace ? */
                dev_info(adev->dev, "GPU reset failed\n");
        }
-       amdgpu_irq_gpu_reset_resume_helper(adev);
 
        return r;
 }
@@ -2178,22 +2483,26 @@ static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf,
        struct amdgpu_device *adev = f->f_inode->i_private;
        ssize_t result = 0;
        int r;
-       bool use_bank;
+       bool pm_pg_lock, use_bank;
        unsigned instance_bank, sh_bank, se_bank;
 
        if (size & 0x3 || *pos & 0x3)
                return -EINVAL;
 
+       /* are we reading registers for which a PG lock is necessary? */
+       pm_pg_lock = (*pos >> 23) & 1;
+
        if (*pos & (1ULL << 62)) {
                se_bank = (*pos >> 24) & 0x3FF;
                sh_bank = (*pos >> 34) & 0x3FF;
                instance_bank = (*pos >> 44) & 0x3FF;
                use_bank = 1;
-               *pos &= 0xFFFFFF;
        } else {
                use_bank = 0;
        }
 
+       *pos &= 0x3FFFF;
+
        if (use_bank) {
                if (sh_bank >= adev->gfx.config.max_sh_per_se ||
                    se_bank >= adev->gfx.config.max_shader_engines)
@@ -2203,6 +2512,9 @@ static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf,
                                        sh_bank, instance_bank);
        }
 
+       if (pm_pg_lock)
+               mutex_lock(&adev->pm.mutex);
+
        while (size) {
                uint32_t value;
 
@@ -2228,6 +2540,9 @@ end:
                mutex_unlock(&adev->grbm_idx_mutex);
        }
 
+       if (pm_pg_lock)
+               mutex_unlock(&adev->pm.mutex);
+
        return result;
 }
 
@@ -2385,7 +2700,7 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf,
        while (size) {
                uint32_t value;
 
-               value = RREG32_SMC(*pos >> 2);
+               value = RREG32_SMC(*pos);
                r = put_user(value, (uint32_t *)buf);
                if (r)
                        return r;
@@ -2416,7 +2731,7 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user *
                if (r)
                        return r;
 
-               WREG32_SMC(*pos >> 2, value);
+               WREG32_SMC(*pos, value);
 
                result += 4;
                buf += 4;
@@ -2438,12 +2753,12 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
        if (size & 0x3 || *pos & 0x3)
                return -EINVAL;
 
-       config = kmalloc(256 * sizeof(*config), GFP_KERNEL);
+       config = kmalloc_array(256, sizeof(*config), GFP_KERNEL);
        if (!config)
                return -ENOMEM;
 
        /* version, increment each time something is added */
-       config[no_regs++] = 0;
+       config[no_regs++] = 2;
        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;
@@ -2468,6 +2783,15 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
        config[no_regs++] = adev->gfx.config.gb_addr_config;
        config[no_regs++] = adev->gfx.config.num_rbs;
 
+       /* rev==1 */
+       config[no_regs++] = adev->rev_id;
+       config[no_regs++] = adev->pg_flags;
+       config[no_regs++] = adev->cg_flags;
+
+       /* rev==2 */
+       config[no_regs++] = adev->family;
+       config[no_regs++] = adev->external_rev_id;
+
        while (size && (*pos < no_regs * 4)) {
                uint32_t value;
 
@@ -2488,6 +2812,29 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
        return result;
 }
 
+static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf,
+                                       size_t size, loff_t *pos)
+{
+       struct amdgpu_device *adev = f->f_inode->i_private;
+       int idx, r;
+       int32_t value;
+
+       if (size != 4 || *pos & 0x3)
+               return -EINVAL;
+
+       /* convert offset to sensor number */
+       idx = *pos >> 2;
+
+       if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->read_sensor)
+               r = adev->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, idx, &value);
+       else
+               return -EINVAL;
+
+       if (!r)
+               r = put_user(value, (int32_t *)buf);
+
+       return !r ? 4 : r;
+}
 
 static const struct file_operations amdgpu_debugfs_regs_fops = {
        .owner = THIS_MODULE,
@@ -2520,12 +2867,19 @@ static const struct file_operations amdgpu_debugfs_gca_config_fops = {
        .llseek = default_llseek
 };
 
+static const struct file_operations amdgpu_debugfs_sensors_fops = {
+       .owner = THIS_MODULE,
+       .read = amdgpu_debugfs_sensor_read,
+       .llseek = default_llseek
+};
+
 static const struct file_operations *debugfs_regs[] = {
        &amdgpu_debugfs_regs_fops,
        &amdgpu_debugfs_regs_didt_fops,
        &amdgpu_debugfs_regs_pcie_fops,
        &amdgpu_debugfs_regs_smc_fops,
        &amdgpu_debugfs_gca_config_fops,
+       &amdgpu_debugfs_sensors_fops,
 };
 
 static const char *debugfs_regs_names[] = {
@@ -2534,6 +2888,7 @@ static const char *debugfs_regs_names[] = {
        "amdgpu_regs_pcie",
        "amdgpu_regs_smc",
        "amdgpu_gca_config",
+       "amdgpu_sensors",
 };
 
 static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
index 76f9602..083e2b4 100644 (file)
@@ -41,7 +41,7 @@ static void amdgpu_flip_callback(struct fence *f, struct fence_cb *cb)
                container_of(cb, struct amdgpu_flip_work, cb);
 
        fence_put(f);
-       schedule_work(&work->flip_work);
+       schedule_work(&work->flip_work.work);
 }
 
 static bool amdgpu_flip_handle_fence(struct amdgpu_flip_work *work,
@@ -63,16 +63,17 @@ static bool amdgpu_flip_handle_fence(struct amdgpu_flip_work *work,
 
 static void amdgpu_flip_work_func(struct work_struct *__work)
 {
+       struct delayed_work *delayed_work =
+               container_of(__work, struct delayed_work, work);
        struct amdgpu_flip_work *work =
-               container_of(__work, struct amdgpu_flip_work, flip_work);
+               container_of(delayed_work, struct amdgpu_flip_work, flip_work);
        struct amdgpu_device *adev = work->adev;
        struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id];
 
        struct drm_crtc *crtc = &amdgpuCrtc->base;
        unsigned long flags;
-       unsigned i, repcnt = 4;
-       int vpos, hpos, stat, min_udelay = 0;
-       struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
+       unsigned i;
+       int vpos, hpos;
 
        if (amdgpu_flip_handle_fence(work, &work->excl))
                return;
@@ -81,55 +82,23 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
                if (amdgpu_flip_handle_fence(work, &work->shared[i]))
                        return;
 
-       /* We borrow the event spin lock for protecting flip_status */
-       spin_lock_irqsave(&crtc->dev->event_lock, flags);
-
-       /* If this happens to execute within the "virtually extended" vblank
-        * interval before the start of the real vblank interval then it needs
-        * to delay programming the mmio flip until the real vblank is entered.
-        * This prevents completing a flip too early due to the way we fudge
-        * our vblank counter and vblank timestamps in order to work around the
-        * problem that the hw fires vblank interrupts before actual start of
-        * vblank (when line buffer refilling is done for a frame). It
-        * complements the fudging logic in amdgpu_get_crtc_scanoutpos() for
-        * timestamping and amdgpu_get_vblank_counter_kms() for vblank counts.
-        *
-        * In practice this won't execute very often unless on very fast
-        * machines because the time window for this to happen is very small.
+       /* Wait until we're out of the vertical blank period before the one
+        * targeted by the flip
         */
-       while (amdgpuCrtc->enabled && --repcnt) {
-               /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
-                * start in hpos, and to the "fudged earlier" vblank start in
-                * vpos.
-                */
-               stat = amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id,
-                                                 GET_DISTANCE_TO_VBLANKSTART,
-                                                 &vpos, &hpos, NULL, NULL,
-                                                 &crtc->hwmode);
-
-               if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
-                   (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
-                   !(vpos >= 0 && hpos <= 0))
-                       break;
-
-               /* Sleep at least until estimated real start of hw vblank */
-               min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
-               if (min_udelay > vblank->framedur_ns / 2000) {
-                       /* Don't wait ridiculously long - something is wrong */
-                       repcnt = 0;
-                       break;
-               }
-               spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
-               usleep_range(min_udelay, 2 * min_udelay);
-               spin_lock_irqsave(&crtc->dev->event_lock, flags);
+       if (amdgpuCrtc->enabled &&
+           (amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id, 0,
+                                       &vpos, &hpos, NULL, NULL,
+                                       &crtc->hwmode)
+            & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
+           (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
+           (int)(work->target_vblank -
+                 amdgpu_get_vblank_counter_kms(adev->ddev, amdgpuCrtc->crtc_id)) > 0) {
+               schedule_delayed_work(&work->flip_work, usecs_to_jiffies(1000));
+               return;
        }
 
-       if (!repcnt)
-               DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
-                                "framedur %d, linedur %d, stat %d, vpos %d, "
-                                "hpos %d\n", work->crtc_id, min_udelay,
-                                vblank->framedur_ns / 1000,
-                                vblank->linedur_ns / 1000, stat, vpos, hpos);
+       /* We borrow the event spin lock for protecting flip_status */
+       spin_lock_irqsave(&crtc->dev->event_lock, flags);
 
        /* Do the flip (mmio) */
        adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base, work->async);
@@ -154,25 +123,25 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
        int r;
 
        /* unpin of the old buffer */
-       r = amdgpu_bo_reserve(work->old_rbo, false);
+       r = amdgpu_bo_reserve(work->old_abo, false);
        if (likely(r == 0)) {
-               r = amdgpu_bo_unpin(work->old_rbo);
+               r = amdgpu_bo_unpin(work->old_abo);
                if (unlikely(r != 0)) {
                        DRM_ERROR("failed to unpin buffer after flip\n");
                }
-               amdgpu_bo_unreserve(work->old_rbo);
+               amdgpu_bo_unreserve(work->old_abo);
        } else
                DRM_ERROR("failed to reserve buffer after flip\n");
 
-       amdgpu_bo_unref(&work->old_rbo);
+       amdgpu_bo_unref(&work->old_abo);
        kfree(work->shared);
        kfree(work);
 }
 
-int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
-                         struct drm_framebuffer *fb,
-                         struct drm_pending_vblank_event *event,
-                         uint32_t page_flip_flags)
+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 drm_device *dev = crtc->dev;
        struct amdgpu_device *adev = dev->dev_private;
@@ -181,7 +150,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
        struct amdgpu_framebuffer *new_amdgpu_fb;
        struct drm_gem_object *obj;
        struct amdgpu_flip_work *work;
-       struct amdgpu_bo *new_rbo;
+       struct amdgpu_bo *new_abo;
        unsigned long flags;
        u64 tiling_flags;
        u64 base;
@@ -191,7 +160,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
        if (work == NULL)
                return -ENOMEM;
 
-       INIT_WORK(&work->flip_work, amdgpu_flip_work_func);
+       INIT_DELAYED_WORK(&work->flip_work, amdgpu_flip_work_func);
        INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func);
 
        work->event = event;
@@ -204,28 +173,28 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
        obj = old_amdgpu_fb->obj;
 
        /* take a reference to the old object */
-       work->old_rbo = gem_to_amdgpu_bo(obj);
-       amdgpu_bo_ref(work->old_rbo);
+       work->old_abo = gem_to_amdgpu_bo(obj);
+       amdgpu_bo_ref(work->old_abo);
 
        new_amdgpu_fb = to_amdgpu_framebuffer(fb);
        obj = new_amdgpu_fb->obj;
-       new_rbo = gem_to_amdgpu_bo(obj);
+       new_abo = gem_to_amdgpu_bo(obj);
 
        /* pin the new buffer */
-       r = amdgpu_bo_reserve(new_rbo, false);
+       r = amdgpu_bo_reserve(new_abo, false);
        if (unlikely(r != 0)) {
-               DRM_ERROR("failed to reserve new rbo buffer before flip\n");
+               DRM_ERROR("failed to reserve new abo buffer before flip\n");
                goto cleanup;
        }
 
-       r = amdgpu_bo_pin_restricted(new_rbo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, &base);
+       r = amdgpu_bo_pin_restricted(new_abo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, &base);
        if (unlikely(r != 0)) {
                r = -EINVAL;
-               DRM_ERROR("failed to pin new rbo buffer before flip\n");
+               DRM_ERROR("failed to pin new abo buffer before flip\n");
                goto unreserve;
        }
 
-       r = reservation_object_get_fences_rcu(new_rbo->tbo.resv, &work->excl,
+       r = reservation_object_get_fences_rcu(new_abo->tbo.resv, &work->excl,
                                              &work->shared_count,
                                              &work->shared);
        if (unlikely(r != 0)) {
@@ -233,16 +202,12 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
                goto unpin;
        }
 
-       amdgpu_bo_get_tiling_flags(new_rbo, &tiling_flags);
-       amdgpu_bo_unreserve(new_rbo);
+       amdgpu_bo_get_tiling_flags(new_abo, &tiling_flags);
+       amdgpu_bo_unreserve(new_abo);
 
        work->base = base;
-
-       r = drm_crtc_vblank_get(crtc);
-       if (r) {
-               DRM_ERROR("failed to get vblank before flip\n");
-               goto pflip_cleanup;
-       }
+       work->target_vblank = target - drm_crtc_vblank_count(crtc) +
+               amdgpu_get_vblank_counter_kms(dev, work->crtc_id);
 
        /* we borrow the event spin lock for protecting flip_wrok */
        spin_lock_irqsave(&crtc->dev->event_lock, flags);
@@ -250,7 +215,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
                DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
                spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
                r = -EBUSY;
-               goto vblank_cleanup;
+               goto pflip_cleanup;
        }
 
        amdgpu_crtc->pflip_status = AMDGPU_FLIP_PENDING;
@@ -262,26 +227,23 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
        /* update crtc fb */
        crtc->primary->fb = fb;
        spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
-       amdgpu_flip_work_func(&work->flip_work);
+       amdgpu_flip_work_func(&work->flip_work.work);
        return 0;
 
-vblank_cleanup:
-       drm_crtc_vblank_put(crtc);
-
 pflip_cleanup:
-       if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) {
-               DRM_ERROR("failed to reserve new rbo in error path\n");
+       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_rbo) != 0)) {
-               DRM_ERROR("failed to unpin new rbo in error path\n");
+       if (unlikely(amdgpu_bo_unpin(new_abo) != 0)) {
+               DRM_ERROR("failed to unpin new abo in error path\n");
        }
 unreserve:
-       amdgpu_bo_unreserve(new_rbo);
+       amdgpu_bo_unreserve(new_abo);
 
 cleanup:
-       amdgpu_bo_unref(&work->old_rbo);
+       amdgpu_bo_unref(&work->old_abo);
        fence_put(work->excl);
        for (i = 0; i < work->shared_count; ++i)
                fence_put(work->shared[i]);
@@ -335,7 +297,7 @@ int amdgpu_crtc_set_config(struct drm_mode_set *set)
        return ret;
 }
 
-static const char *encoder_names[38] = {
+static const char *encoder_names[41] = {
        "NONE",
        "INTERNAL_LVDS",
        "INTERNAL_TMDS1",
@@ -374,6 +336,9 @@ static const char *encoder_names[38] = {
        "TRAVIS",
        "INTERNAL_VCE",
        "INTERNAL_UNIPHY3",
+       "HDMI_ANX9805",
+       "INTERNAL_AMCLK",
+       "VIRTUAL",
 };
 
 static const char *hpd_names[6] = {
index 9aa533c..71ed27e 100644 (file)
  * - 3.2.0 - GFX8: Uses EOP_TC_WB_ACTION_EN, so UMDs don't have to do the same
  *           at the end of IBs.
  * - 3.3.0 - Add VM support for UVD on supported hardware.
+ * - 3.4.0 - Add AMDGPU_INFO_NUM_EVICTIONS.
+ * - 3.5.0 - Add support for new UVD_NO_OP register.
+ * - 3.6.0 - kmd involves use CONTEXT_CONTROL in ring buffer.
+ * - 3.7.0 - Add support for VCE clock list packet
+ * - 3.8.0 - Add support raster config init in the kernel
  */
 #define KMS_DRIVER_MAJOR       3
-#define KMS_DRIVER_MINOR       3
+#define KMS_DRIVER_MINOR       8
 #define KMS_DRIVER_PATCHLEVEL  0
 
 int amdgpu_vram_limit = 0;
 int amdgpu_gart_size = -1; /* auto */
+int amdgpu_moverate = -1; /* auto */
 int amdgpu_benchmarking = 0;
 int amdgpu_testing = 0;
 int amdgpu_audio = -1;
@@ -84,11 +90,14 @@ int amdgpu_sched_jobs = 32;
 int amdgpu_sched_hw_submission = 2;
 int amdgpu_powerplay = -1;
 int amdgpu_powercontainment = 1;
+int amdgpu_sclk_deep_sleep_en = 1;
 unsigned amdgpu_pcie_gen_cap = 0;
 unsigned amdgpu_pcie_lane_cap = 0;
 unsigned amdgpu_cg_mask = 0xffffffff;
 unsigned amdgpu_pg_mask = 0xffffffff;
 char *amdgpu_disable_cu = NULL;
+char *amdgpu_virtual_display = NULL;
+unsigned amdgpu_pp_feature_mask = 0xffffffff;
 
 MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");
 module_param_named(vramlimit, amdgpu_vram_limit, int, 0600);
@@ -96,6 +105,9 @@ module_param_named(vramlimit, amdgpu_vram_limit, int, 0600);
 MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32, 64, etc., -1 = auto)");
 module_param_named(gartsize, amdgpu_gart_size, int, 0600);
 
+MODULE_PARM_DESC(moverate, "Maximum buffer migration rate in MB/s. (32, 64, etc., -1=auto, 0=1=disabled)");
+module_param_named(moverate, amdgpu_moverate, int, 0600);
+
 MODULE_PARM_DESC(benchmark, "Run benchmark");
 module_param_named(benchmark, amdgpu_benchmarking, int, 0444);
 
@@ -162,13 +174,17 @@ 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);
 
-#ifdef CONFIG_DRM_AMD_POWERPLAY
 MODULE_PARM_DESC(powerplay, "Powerplay component (1 = enable, 0 = disable, -1 = auto (default))");
 module_param_named(powerplay, amdgpu_powerplay, int, 0444);
 
 MODULE_PARM_DESC(powercontainment, "Power Containment (1 = enable (default), 0 = disable)");
 module_param_named(powercontainment, amdgpu_powercontainment, int, 0444);
-#endif
+
+MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))");
+module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, int, 0444);
+
+MODULE_PARM_DESC(sclkdeepsleep, "SCLK Deep Sleep (1 = enable (default), 0 = disable)");
+module_param_named(sclkdeepsleep, amdgpu_sclk_deep_sleep_en, int, 0444);
 
 MODULE_PARM_DESC(pcie_gen_cap, "PCIE Gen Caps (0: autodetect (default))");
 module_param_named(pcie_gen_cap, amdgpu_pcie_gen_cap, uint, 0444);
@@ -185,7 +201,84 @@ module_param_named(pg_mask, amdgpu_pg_mask, uint, 0444);
 MODULE_PARM_DESC(disable_cu, "Disable CUs (se.sh.cu,...)");
 module_param_named(disable_cu, amdgpu_disable_cu, charp, 0444);
 
+MODULE_PARM_DESC(virtual_display, "Enable virtual display feature (the virtual_display will be set like xxxx:xx:xx.x;xxxx:xx:xx.x)");
+module_param_named(virtual_display, amdgpu_virtual_display, charp, 0444);
+
 static const struct pci_device_id pciidlist[] = {
+#ifdef  CONFIG_DRM_AMDGPU_SI
+       {0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x6784, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x6788, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x678A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x6790, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x6791, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x6792, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x679B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
+       {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|AMD_IS_MOBILITY},
+       {0x1002, 0x6801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|AMD_IS_MOBILITY},
+       {0x1002, 0x6802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|AMD_IS_MOBILITY},
+       {0x1002, 0x6806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN},
+       {0x1002, 0x6808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN},
+       {0x1002, 0x6809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN},
+       {0x1002, 0x6810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN},
+       {0x1002, 0x6811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN},
+       {0x1002, 0x6816, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN},
+       {0x1002, 0x6817, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN},
+       {0x1002, 0x6818, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN},
+       {0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN},
+       {0x1002, 0x6600, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6602, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6603, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6604, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6605, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6606, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6607, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND},
+       {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND},
+       {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND},
+       {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND},
+       {0x1002, 0x6617, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6620, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|AMD_IS_MOBILITY},
+       {0x1002, 0x6631, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND},
+       {0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6821, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6822, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6823, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6824, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6826, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6827, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x682A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x682C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|AMD_IS_MOBILITY},
+       {0x1002, 0x6835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x6837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x6838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x6839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x683B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x683D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x683F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE},
+       {0x1002, 0x6660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|AMD_IS_MOBILITY},
+       {0x1002, 0x6663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|AMD_IS_MOBILITY},
+       {0x1002, 0x6664, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|AMD_IS_MOBILITY},
+       {0x1002, 0x6665, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|AMD_IS_MOBILITY},
+       {0x1002, 0x6667, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|AMD_IS_MOBILITY},
+       {0x1002, 0x666F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|AMD_IS_MOBILITY},
+#endif
 #ifdef CONFIG_DRM_AMDGPU_CIK
        /* Kaveri */
        {0x1002, 0x1304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU},
@@ -341,7 +434,7 @@ static int amdgpu_kick_out_firmware_fb(struct pci_dev *pdev)
 #ifdef CONFIG_X86
        primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 #endif
-       remove_conflicting_framebuffers(ap, "amdgpudrmfb", primary);
+       drm_fb_helper_remove_conflicting_framebuffers(ap, "amdgpudrmfb", primary);
        kfree(ap);
 
        return 0;
@@ -383,32 +476,70 @@ amdgpu_pci_remove(struct pci_dev *pdev)
        drm_put_dev(dev);
 }
 
+static void
+amdgpu_pci_shutdown(struct pci_dev *pdev)
+{
+       /* if we are running in a VM, make sure the device
+        * torn down properly on reboot/shutdown.
+        * unfortunately we can't detect certain
+        * hypervisors so just do this all the time.
+        */
+       amdgpu_pci_remove(pdev);
+}
+
 static int amdgpu_pmops_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
+
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       return amdgpu_suspend_kms(drm_dev, true, true);
+       return amdgpu_device_suspend(drm_dev, true, true);
 }
 
 static int amdgpu_pmops_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       return amdgpu_resume_kms(drm_dev, true, true);
+
+       /* GPU comes up enabled by the bios on resume */
+       if (amdgpu_device_is_px(drm_dev)) {
+               pm_runtime_disable(dev);
+               pm_runtime_set_active(dev);
+               pm_runtime_enable(dev);
+       }
+
+       return amdgpu_device_resume(drm_dev, true, true);
 }
 
 static int amdgpu_pmops_freeze(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
+
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       return amdgpu_suspend_kms(drm_dev, false, true);
+       return amdgpu_device_suspend(drm_dev, false, true);
 }
 
 static int amdgpu_pmops_thaw(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
+
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       return amdgpu_device_resume(drm_dev, false, true);
+}
+
+static int amdgpu_pmops_poweroff(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       return amdgpu_device_suspend(drm_dev, true, true);
+}
+
+static int amdgpu_pmops_restore(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       return amdgpu_resume_kms(drm_dev, false, true);
+       return amdgpu_device_resume(drm_dev, false, true);
 }
 
 static int amdgpu_pmops_runtime_suspend(struct device *dev)
@@ -426,7 +557,7 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
        drm_kms_helper_poll_disable(drm_dev);
        vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
 
-       ret = amdgpu_suspend_kms(drm_dev, false, false);
+       ret = amdgpu_device_suspend(drm_dev, false, false);
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_ignore_hotplug(pdev);
@@ -459,7 +590,7 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
                return ret;
        pci_set_master(pdev);
 
-       ret = amdgpu_resume_kms(drm_dev, false, false);
+       ret = amdgpu_device_resume(drm_dev, false, false);
        drm_kms_helper_poll_enable(drm_dev);
        vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
        drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
@@ -513,8 +644,8 @@ static const struct dev_pm_ops amdgpu_pm_ops = {
        .resume = amdgpu_pmops_resume,
        .freeze = amdgpu_pmops_freeze,
        .thaw = amdgpu_pmops_thaw,
-       .poweroff = amdgpu_pmops_freeze,
-       .restore = amdgpu_pmops_resume,
+       .poweroff = amdgpu_pmops_poweroff,
+       .restore = amdgpu_pmops_restore,
        .runtime_suspend = amdgpu_pmops_runtime_suspend,
        .runtime_resume = amdgpu_pmops_runtime_resume,
        .runtime_idle = amdgpu_pmops_runtime_idle,
@@ -596,6 +727,7 @@ static struct pci_driver amdgpu_kms_pci_driver = {
        .id_table = pciidlist,
        .probe = amdgpu_pci_probe,
        .remove = amdgpu_pci_remove,
+       .shutdown = amdgpu_pci_shutdown,
        .driver.pm = &amdgpu_pm_ops,
 };
 
index 9191467..9fb8aa4 100644 (file)
@@ -25,7 +25,7 @@
  */
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/fb.h>
+#include <linux/pm_runtime.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
@@ -48,8 +48,35 @@ struct amdgpu_fbdev {
        struct amdgpu_device *adev;
 };
 
+static int
+amdgpufb_open(struct fb_info *info, int user)
+{
+       struct amdgpu_fbdev *rfbdev = info->par;
+       struct amdgpu_device *adev = rfbdev->adev;
+       int ret = pm_runtime_get_sync(adev->ddev->dev);
+       if (ret < 0 && ret != -EACCES) {
+               pm_runtime_mark_last_busy(adev->ddev->dev);
+               pm_runtime_put_autosuspend(adev->ddev->dev);
+               return ret;
+       }
+       return 0;
+}
+
+static int
+amdgpufb_release(struct fb_info *info, int user)
+{
+       struct amdgpu_fbdev *rfbdev = info->par;
+       struct amdgpu_device *adev = rfbdev->adev;
+
+       pm_runtime_mark_last_busy(adev->ddev->dev);
+       pm_runtime_put_autosuspend(adev->ddev->dev);
+       return 0;
+}
+
 static struct fb_ops amdgpufb_ops = {
        .owner = THIS_MODULE,
+       .fb_open = amdgpufb_open,
+       .fb_release = amdgpufb_release,
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
        .fb_fillrect = drm_fb_helper_cfb_fillrect,
@@ -88,14 +115,14 @@ int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tile
 
 static void amdgpufb_destroy_pinned_object(struct drm_gem_object *gobj)
 {
-       struct amdgpu_bo *rbo = gem_to_amdgpu_bo(gobj);
+       struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj);
        int ret;
 
-       ret = amdgpu_bo_reserve(rbo, false);
+       ret = amdgpu_bo_reserve(abo, false);
        if (likely(ret == 0)) {
-               amdgpu_bo_kunmap(rbo);
-               amdgpu_bo_unpin(rbo);
-               amdgpu_bo_unreserve(rbo);
+               amdgpu_bo_kunmap(abo);
+               amdgpu_bo_unpin(abo);
+               amdgpu_bo_unreserve(abo);
        }
        drm_gem_object_unreference_unlocked(gobj);
 }
@@ -106,7 +133,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,
 {
        struct amdgpu_device *adev = rfbdev->adev;
        struct drm_gem_object *gobj = NULL;
-       struct amdgpu_bo *rbo = NULL;
+       struct amdgpu_bo *abo = NULL;
        bool fb_tiled = false; /* useful for testing */
        u32 tiling_flags = 0;
        int ret;
@@ -132,30 +159,30 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,
                       aligned_size);
                return -ENOMEM;
        }
-       rbo = gem_to_amdgpu_bo(gobj);
+       abo = gem_to_amdgpu_bo(gobj);
 
        if (fb_tiled)
                tiling_flags = AMDGPU_TILING_SET(ARRAY_MODE, GRPH_ARRAY_2D_TILED_THIN1);
 
-       ret = amdgpu_bo_reserve(rbo, false);
+       ret = amdgpu_bo_reserve(abo, false);
        if (unlikely(ret != 0))
                goto out_unref;
 
        if (tiling_flags) {
-               ret = amdgpu_bo_set_tiling_flags(rbo,
+               ret = amdgpu_bo_set_tiling_flags(abo,
                                                 tiling_flags);
                if (ret)
                        dev_err(adev->dev, "FB failed to set tiling flags\n");
        }
 
 
-       ret = amdgpu_bo_pin_restricted(rbo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, NULL);
+       ret = amdgpu_bo_pin_restricted(abo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, NULL);
        if (ret) {
-               amdgpu_bo_unreserve(rbo);
+               amdgpu_bo_unreserve(abo);
                goto out_unref;
        }
-       ret = amdgpu_bo_kmap(rbo, NULL);
-       amdgpu_bo_unreserve(rbo);
+       ret = amdgpu_bo_kmap(abo, NULL);
+       amdgpu_bo_unreserve(abo);
        if (ret) {
                goto out_unref;
        }
@@ -177,7 +204,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
        struct drm_framebuffer *fb = NULL;
        struct drm_mode_fb_cmd2 mode_cmd;
        struct drm_gem_object *gobj = NULL;
-       struct amdgpu_bo *rbo = NULL;
+       struct amdgpu_bo *abo = NULL;
        int ret;
        unsigned long tmp;
 
@@ -196,7 +223,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
                return ret;
        }
 
-       rbo = gem_to_amdgpu_bo(gobj);
+       abo = gem_to_amdgpu_bo(gobj);
 
        /* okay we have an object now allocate the framebuffer */
        info = drm_fb_helper_alloc_fbi(helper);
@@ -219,7 +246,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
        /* setup helper */
        rfbdev->helper.fb = fb;
 
-       memset_io(rbo->kptr, 0x0, amdgpu_bo_size(rbo));
+       memset_io(abo->kptr, 0x0, amdgpu_bo_size(abo));
 
        strcpy(info->fix.id, "amdgpudrmfb");
 
@@ -228,11 +255,11 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
        info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
        info->fbops = &amdgpufb_ops;
 
-       tmp = amdgpu_bo_gpu_offset(rbo) - adev->mc.vram_start;
+       tmp = amdgpu_bo_gpu_offset(abo) - adev->mc.vram_start;
        info->fix.smem_start = adev->mc.aper_base + tmp;
-       info->fix.smem_len = amdgpu_bo_size(rbo);
-       info->screen_base = rbo->kptr;
-       info->screen_size = amdgpu_bo_size(rbo);
+       info->fix.smem_len = amdgpu_bo_size(abo);
+       info->screen_base = abo->kptr;
+       info->screen_size = amdgpu_bo_size(abo);
 
        drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
 
@@ -249,7 +276,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
 
        DRM_INFO("fb mappable at 0x%lX\n",  info->fix.smem_start);
        DRM_INFO("vram apper at 0x%lX\n",  (unsigned long)adev->mc.aper_base);
-       DRM_INFO("size %lu\n", (unsigned long)amdgpu_bo_size(rbo));
+       DRM_INFO("size %lu\n", (unsigned long)amdgpu_bo_size(abo));
        DRM_INFO("fb depth is %d\n", fb->depth);
        DRM_INFO("   pitch is %d\n", fb->pitches[0]);
 
@@ -259,7 +286,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
 out_destroy_fbi:
        drm_fb_helper_release_fbi(helper);
 out_unref:
-       if (rbo) {
+       if (abo) {
 
        }
        if (fb && ret) {
index 0b109ae..3a2e42f 100644 (file)
@@ -454,6 +454,7 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
                for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j)
                        fence_put(ring->fence_drv.fences[j]);
                kfree(ring->fence_drv.fences);
+               ring->fence_drv.fences = NULL;
                ring->fence_drv.initialized = false;
        }
 }
index 0feea34..21a1242 100644 (file)
@@ -238,7 +238,7 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
        t = offset / AMDGPU_GPU_PAGE_SIZE;
        p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE);
        for (i = 0; i < pages; i++, p++) {
-#ifdef CONFIG_AMDGPU_GART_DEBUGFS
+#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
                adev->gart.pages[p] = NULL;
 #endif
                page_base = adev->dummy_page.addr;
@@ -286,7 +286,7 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
        p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE);
 
        for (i = 0; i < pages; i++, p++) {
-#ifdef CONFIG_AMDGPU_GART_DEBUGFS
+#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
                adev->gart.pages[p] = pagelist[i];
 #endif
                if (adev->gart.ptr) {
@@ -331,7 +331,7 @@ int amdgpu_gart_init(struct amdgpu_device *adev)
        DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
                 adev->gart.num_cpu_pages, adev->gart.num_gpu_pages);
 
-#ifdef CONFIG_AMDGPU_GART_DEBUGFS
+#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
        /* Allocate pages table */
        adev->gart.pages = vzalloc(sizeof(void *) * adev->gart.num_cpu_pages);
        if (adev->gart.pages == NULL) {
@@ -357,7 +357,7 @@ void amdgpu_gart_fini(struct amdgpu_device *adev)
                amdgpu_gart_unbind(adev, 0, adev->gart.num_cpu_pages);
        }
        adev->gart.ready = false;
-#ifdef CONFIG_AMDGPU_GART_DEBUGFS
+#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
        vfree(adev->gart.pages);
        adev->gart.pages = NULL;
 #endif
index 503d540..e73728d 100644 (file)
 #define AMDGPU_GWS_SHIFT       PAGE_SHIFT
 #define AMDGPU_OA_SHIFT                PAGE_SHIFT
 
-#define AMDGPU_PL_GDS          TTM_PL_PRIV0
-#define AMDGPU_PL_GWS          TTM_PL_PRIV1
-#define AMDGPU_PL_OA           TTM_PL_PRIV2
-
-#define AMDGPU_PL_FLAG_GDS             TTM_PL_FLAG_PRIV0
-#define AMDGPU_PL_FLAG_GWS             TTM_PL_FLAG_PRIV1
-#define AMDGPU_PL_FLAG_OA              TTM_PL_FLAG_PRIV2
-
 struct amdgpu_ring;
 struct amdgpu_bo;
 
index 88fbed2..a7ea9a3 100644 (file)
@@ -118,23 +118,23 @@ void amdgpu_gem_force_release(struct amdgpu_device *adev)
  */
 int amdgpu_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv)
 {
-       struct amdgpu_bo *rbo = gem_to_amdgpu_bo(obj);
-       struct amdgpu_device *adev = rbo->adev;
+       struct amdgpu_bo *abo = gem_to_amdgpu_bo(obj);
+       struct amdgpu_device *adev = abo->adev;
        struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
        struct amdgpu_vm *vm = &fpriv->vm;
        struct amdgpu_bo_va *bo_va;
        int r;
-       r = amdgpu_bo_reserve(rbo, false);
+       r = amdgpu_bo_reserve(abo, false);
        if (r)
                return r;
 
-       bo_va = amdgpu_vm_bo_find(vm, rbo);
+       bo_va = amdgpu_vm_bo_find(vm, abo);
        if (!bo_va) {
-               bo_va = amdgpu_vm_bo_add(adev, vm, rbo);
+               bo_va = amdgpu_vm_bo_add(adev, vm, abo);
        } else {
                ++bo_va->ref_count;
        }
-       amdgpu_bo_unreserve(rbo);
+       amdgpu_bo_unreserve(abo);
        return 0;
 }
 
@@ -528,7 +528,7 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
                goto error_unreserve;
 
        if (operation == AMDGPU_VA_OP_MAP)
-               r = amdgpu_vm_bo_update(adev, bo_va, &bo_va->bo->tbo.mem);
+               r = amdgpu_vm_bo_update(adev, bo_va, false);
 
 error_unreserve:
        ttm_eu_backoff_reservation(&ticket, &list);
@@ -547,7 +547,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
        struct drm_gem_object *gobj;
        struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_fpriv *fpriv = filp->driver_priv;
-       struct amdgpu_bo *rbo;
+       struct amdgpu_bo *abo;
        struct amdgpu_bo_va *bo_va;
        struct ttm_validate_buffer tv, tv_pd;
        struct ww_acquire_ctx ticket;
@@ -587,10 +587,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
        gobj = drm_gem_object_lookup(filp, args->handle);
        if (gobj == NULL)
                return -ENOENT;
-       rbo = gem_to_amdgpu_bo(gobj);
+       abo = gem_to_amdgpu_bo(gobj);
        INIT_LIST_HEAD(&list);
        INIT_LIST_HEAD(&duplicates);
-       tv.bo = &rbo->tbo;
+       tv.bo = &abo->tbo;
        tv.shared = true;
        list_add(&tv.head, &list);
 
@@ -604,7 +604,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
                return r;
        }
 
-       bo_va = amdgpu_vm_bo_find(&fpriv->vm, rbo);
+       bo_va = amdgpu_vm_bo_find(&fpriv->vm, abo);
        if (!bo_va) {
                ttm_eu_backoff_reservation(&ticket, &list);
                drm_gem_object_unreference_unlocked(gobj);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
new file mode 100644 (file)
index 0000000..f86c844
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ *
+ * Authors: Christian König
+ */
+
+#include <drm/drmP.h>
+#include "amdgpu.h"
+
+struct amdgpu_gtt_mgr {
+       struct drm_mm mm;
+       spinlock_t lock;
+       uint64_t available;
+};
+
+/**
+ * amdgpu_gtt_mgr_init - init GTT manager and DRM MM
+ *
+ * @man: TTM memory type manager
+ * @p_size: maximum size of GTT
+ *
+ * Allocate and initialize the GTT manager.
+ */
+static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
+                              unsigned long p_size)
+{
+       struct amdgpu_gtt_mgr *mgr;
+
+       mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+       if (!mgr)
+               return -ENOMEM;
+
+       drm_mm_init(&mgr->mm, 0, p_size);
+       spin_lock_init(&mgr->lock);
+       mgr->available = p_size;
+       man->priv = mgr;
+       return 0;
+}
+
+/**
+ * amdgpu_gtt_mgr_fini - free and destroy GTT manager
+ *
+ * @man: TTM memory type manager
+ *
+ * Destroy and free the GTT manager, returns -EBUSY if ranges are still
+ * allocated inside it.
+ */
+static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man)
+{
+       struct amdgpu_gtt_mgr *mgr = man->priv;
+
+       spin_lock(&mgr->lock);
+       if (!drm_mm_clean(&mgr->mm)) {
+               spin_unlock(&mgr->lock);
+               return -EBUSY;
+       }
+
+       drm_mm_takedown(&mgr->mm);
+       spin_unlock(&mgr->lock);
+       kfree(mgr);
+       man->priv = NULL;
+       return 0;
+}
+
+/**
+ * amdgpu_gtt_mgr_alloc - allocate new ranges
+ *
+ * @man: TTM memory type manager
+ * @tbo: TTM BO we need this range for
+ * @place: placement flags and restrictions
+ * @mem: the resulting mem object
+ *
+ * Allocate the address space for a node.
+ */
+int amdgpu_gtt_mgr_alloc(struct ttm_mem_type_manager *man,
+                        struct ttm_buffer_object *tbo,
+                        const struct ttm_place *place,
+                        struct ttm_mem_reg *mem)
+{
+       struct amdgpu_gtt_mgr *mgr = man->priv;
+       struct drm_mm_node *node = mem->mm_node;
+       enum drm_mm_search_flags sflags = DRM_MM_SEARCH_BEST;
+       enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT;
+       unsigned long fpfn, lpfn;
+       int r;
+
+       if (node->start != AMDGPU_BO_INVALID_OFFSET)
+               return 0;
+
+       if (place)
+               fpfn = place->fpfn;
+       else
+               fpfn = 0;
+
+       if (place && place->lpfn)
+               lpfn = place->lpfn;
+       else
+               lpfn = man->size;
+
+       if (place && place->flags & TTM_PL_FLAG_TOPDOWN) {
+               sflags = DRM_MM_SEARCH_BELOW;
+               aflags = DRM_MM_CREATE_TOP;
+       }
+
+       spin_lock(&mgr->lock);
+       r = drm_mm_insert_node_in_range_generic(&mgr->mm, node, mem->num_pages,
+                                               mem->page_alignment, 0,
+                                               fpfn, lpfn, sflags, aflags);
+       spin_unlock(&mgr->lock);
+
+       if (!r) {
+               mem->start = node->start;
+               if (&tbo->mem == mem)
+                       tbo->offset = (tbo->mem.start << PAGE_SHIFT) +
+                           tbo->bdev->man[tbo->mem.mem_type].gpu_offset;
+       }
+
+       return r;
+}
+
+/**
+ * amdgpu_gtt_mgr_new - allocate a new node
+ *
+ * @man: TTM memory type manager
+ * @tbo: TTM BO we need this range for
+ * @place: placement flags and restrictions
+ * @mem: the resulting mem object
+ *
+ * Dummy, allocate the node but no space for it yet.
+ */
+static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man,
+                             struct ttm_buffer_object *tbo,
+                             const struct ttm_place *place,
+                             struct ttm_mem_reg *mem)
+{
+       struct amdgpu_gtt_mgr *mgr = man->priv;
+       struct drm_mm_node *node;
+       int r;
+
+       spin_lock(&mgr->lock);
+       if (mgr->available < mem->num_pages) {
+               spin_unlock(&mgr->lock);
+               return 0;
+       }
+       mgr->available -= mem->num_pages;
+       spin_unlock(&mgr->lock);
+
+       node = kzalloc(sizeof(*node), GFP_KERNEL);
+       if (!node)
+               return -ENOMEM;
+
+       node->start = AMDGPU_BO_INVALID_OFFSET;
+       mem->mm_node = node;
+
+       if (place->fpfn || place->lpfn || place->flags & TTM_PL_FLAG_TOPDOWN) {
+               r = amdgpu_gtt_mgr_alloc(man, tbo, place, mem);
+               if (unlikely(r)) {
+                       kfree(node);
+                       mem->mm_node = NULL;
+               }
+       } else {
+               mem->start = node->start;
+       }
+
+       return 0;
+}
+
+/**
+ * amdgpu_gtt_mgr_del - free ranges
+ *
+ * @man: TTM memory type manager
+ * @tbo: TTM BO we need this range for
+ * @place: placement flags and restrictions
+ * @mem: TTM memory object
+ *
+ * Free the allocated GTT again.
+ */
+static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man,
+                              struct ttm_mem_reg *mem)
+{
+       struct amdgpu_gtt_mgr *mgr = man->priv;
+       struct drm_mm_node *node = mem->mm_node;
+
+       if (!node)
+               return;
+
+       spin_lock(&mgr->lock);
+       if (node->start != AMDGPU_BO_INVALID_OFFSET)
+               drm_mm_remove_node(node);
+       mgr->available += mem->num_pages;
+       spin_unlock(&mgr->lock);
+
+       kfree(node);
+       mem->mm_node = NULL;
+}
+
+/**
+ * amdgpu_gtt_mgr_debug - dump VRAM table
+ *
+ * @man: TTM memory type manager
+ * @prefix: text prefix
+ *
+ * Dump the table content using printk.
+ */
+static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man,
+                                 const char *prefix)
+{
+       struct amdgpu_gtt_mgr *mgr = man->priv;
+
+       spin_lock(&mgr->lock);
+       drm_mm_debug_table(&mgr->mm, prefix);
+       spin_unlock(&mgr->lock);
+}
+
+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
+};
index 31a6763..91d3673 100644 (file)
@@ -158,8 +158,8 @@ static const struct i2c_algorithm amdgpu_atombios_i2c_algo = {
 };
 
 struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
-                                           struct amdgpu_i2c_bus_rec *rec,
-                                           const char *name)
+                                         const struct amdgpu_i2c_bus_rec *rec,
+                                         const char *name)
 {
        struct amdgpu_i2c_chan *i2c;
        int ret;
@@ -186,10 +186,8 @@ struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
                         "AMDGPU i2c hw bus %s", name);
                i2c->adapter.algo = &amdgpu_atombios_i2c_algo;
                ret = i2c_add_adapter(&i2c->adapter);
-               if (ret) {
-                       DRM_ERROR("Failed to register hw i2c %s\n", name);
+               if (ret)
                        goto out_free;
-               }
        } else {
                /* set the amdgpu bit adapter */
                snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
@@ -222,6 +220,7 @@ void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c)
 {
        if (!i2c)
                return;
+       WARN_ON(i2c->has_aux);
        i2c_del_adapter(&i2c->adapter);
        kfree(i2c);
 }
@@ -251,8 +250,8 @@ void amdgpu_i2c_fini(struct amdgpu_device *adev)
 
 /* Add additional buses */
 void amdgpu_i2c_add(struct amdgpu_device *adev,
-                    struct amdgpu_i2c_bus_rec *rec,
-                    const char *name)
+                   const struct amdgpu_i2c_bus_rec *rec,
+                   const char *name)
 {
        struct drm_device *dev = adev->ddev;
        int i;
@@ -268,7 +267,7 @@ void amdgpu_i2c_add(struct amdgpu_device *adev,
 /* looks up bus based on id */
 struct amdgpu_i2c_chan *
 amdgpu_i2c_lookup(struct amdgpu_device *adev,
-                  struct amdgpu_i2c_bus_rec *i2c_bus)
+                 const struct amdgpu_i2c_bus_rec *i2c_bus)
 {
        int i;
 
@@ -338,7 +337,7 @@ static void amdgpu_i2c_put_byte(struct amdgpu_i2c_chan *i2c_bus,
 
 /* ddc router switching */
 void
-amdgpu_i2c_router_select_ddc_port(struct amdgpu_connector *amdgpu_connector)
+amdgpu_i2c_router_select_ddc_port(const struct amdgpu_connector *amdgpu_connector)
 {
        u8 val;
 
@@ -367,7 +366,7 @@ amdgpu_i2c_router_select_ddc_port(struct amdgpu_connector *amdgpu_connector)
 
 /* clock/data router switching */
 void
-amdgpu_i2c_router_select_cd_port(struct amdgpu_connector *amdgpu_connector)
+amdgpu_i2c_router_select_cd_port(const struct amdgpu_connector *amdgpu_connector)
 {
        u8 val;
 
index d81e19b..63c2ff7 100644 (file)
 #define __AMDGPU_I2C_H__
 
 struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
-                                           struct amdgpu_i2c_bus_rec *rec,
-                                           const char *name);
+                                         const struct amdgpu_i2c_bus_rec *rec,
+                                         const char *name);
 void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c);
 void amdgpu_i2c_init(struct amdgpu_device *adev);
 void amdgpu_i2c_fini(struct amdgpu_device *adev);
 void amdgpu_i2c_add(struct amdgpu_device *adev,
-                    struct amdgpu_i2c_bus_rec *rec,
-                    const char *name);
+                   const struct amdgpu_i2c_bus_rec *rec,
+                   const char *name);
 struct amdgpu_i2c_chan *
 amdgpu_i2c_lookup(struct amdgpu_device *adev,
-                  struct amdgpu_i2c_bus_rec *i2c_bus);
+                 const struct amdgpu_i2c_bus_rec *i2c_bus);
 void
-amdgpu_i2c_router_select_ddc_port(struct amdgpu_connector *amdgpu_connector);
+amdgpu_i2c_router_select_ddc_port(const struct amdgpu_connector *connector);
 void
-amdgpu_i2c_router_select_cd_port(struct amdgpu_connector *amdgpu_connector);
+amdgpu_i2c_router_select_cd_port(const struct amdgpu_connector *connector);
 
 #endif
index ec1282a..6a6c86c 100644 (file)
@@ -124,7 +124,8 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
        bool skip_preamble, need_ctx_switch;
        unsigned patch_offset = ~0;
        struct amdgpu_vm *vm;
-       uint64_t ctx;
+       uint64_t fence_ctx;
+       uint32_t status = 0, alloc_size;
 
        unsigned i;
        int r = 0;
@@ -135,14 +136,14 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
        /* ring tests don't use a job */
        if (job) {
                vm = job->vm;
-               ctx = job->ctx;
+               fence_ctx = job->fence_ctx;
        } else {
                vm = NULL;
-               ctx = 0;
+               fence_ctx = 0;
        }
 
        if (!ring->ready) {
-               dev_err(adev->dev, "couldn't schedule ib\n");
+               dev_err(adev->dev, "couldn't schedule ib on ring <%s>\n", ring->name);
                return -EINVAL;
        }
 
@@ -151,7 +152,10 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
                return -EINVAL;
        }
 
-       r = amdgpu_ring_alloc(ring, 256 * num_ibs);
+       alloc_size = amdgpu_ring_get_dma_frame_size(ring) +
+               num_ibs * amdgpu_ring_get_emit_ib_size(ring);
+
+       r = amdgpu_ring_alloc(ring, alloc_size);
        if (r) {
                dev_err(adev->dev, "scheduling IB failed (%d).\n", r);
                return r;
@@ -174,13 +178,22 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
        /* always set cond_exec_polling to CONTINUE */
        *ring->cond_exe_cpu_addr = 1;
 
-       skip_preamble = ring->current_ctx == ctx;
-       need_ctx_switch = ring->current_ctx != ctx;
+       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;
+               amdgpu_ring_emit_cntxcntl(ring, status);
+       }
+
        for (i = 0; i < num_ibs; ++i) {
                ib = &ibs[i];
 
                /* drop preamble IBs if we don't have a context switch */
-               if ((ib->flags & AMDGPU_IB_FLAG_PREAMBLE) && skip_preamble)
+               if ((ib->flags & AMDGPU_IB_FLAG_PREAMBLE) &&
+                       skip_preamble &&
+                       !(status & AMDGPU_PREAMBLE_IB_PRESENT_FIRST))
                        continue;
 
                amdgpu_ring_emit_ib(ring, ib, job ? job->vm_id : 0,
@@ -209,7 +222,9 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
        if (patch_offset != ~0 && ring->funcs->patch_cond_exec)
                amdgpu_ring_patch_cond_exec(ring, patch_offset);
 
-       ring->current_ctx = ctx;
+       ring->current_ctx = fence_ctx;
+       if (ring->funcs->emit_switch_buffer)
+               amdgpu_ring_emit_switch_buffer(ring);
        amdgpu_ring_commit(ring);
        return 0;
 }
index 534fc04..3ab4c65 100644 (file)
@@ -40,32 +40,15 @@ static int amdgpu_ih_ring_alloc(struct amdgpu_device *adev)
 
        /* Allocate ring buffer */
        if (adev->irq.ih.ring_obj == NULL) {
-               r = amdgpu_bo_create(adev, adev->irq.ih.ring_size,
-                                    PAGE_SIZE, true,
-                                    AMDGPU_GEM_DOMAIN_GTT, 0,
-                                    NULL, NULL, &adev->irq.ih.ring_obj);
+               r = amdgpu_bo_create_kernel(adev, adev->irq.ih.ring_size,
+                                           PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT,
+                                           &adev->irq.ih.ring_obj,
+                                           &adev->irq.ih.gpu_addr,
+                                           (void **)&adev->irq.ih.ring);
                if (r) {
                        DRM_ERROR("amdgpu: failed to create ih ring buffer (%d).\n", r);
                        return r;
                }
-               r = amdgpu_bo_reserve(adev->irq.ih.ring_obj, false);
-               if (unlikely(r != 0))
-                       return r;
-               r = amdgpu_bo_pin(adev->irq.ih.ring_obj,
-                                 AMDGPU_GEM_DOMAIN_GTT,
-                                 &adev->irq.ih.gpu_addr);
-               if (r) {
-                       amdgpu_bo_unreserve(adev->irq.ih.ring_obj);
-                       DRM_ERROR("amdgpu: failed to pin ih ring buffer (%d).\n", r);
-                       return r;
-               }
-               r = amdgpu_bo_kmap(adev->irq.ih.ring_obj,
-                                  (void **)&adev->irq.ih.ring);
-               amdgpu_bo_unreserve(adev->irq.ih.ring_obj);
-               if (r) {
-                       DRM_ERROR("amdgpu: failed to map ih ring buffer (%d).\n", r);
-                       return r;
-               }
        }
        return 0;
 }
@@ -136,8 +119,6 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, unsigned ring_size,
  */
 void amdgpu_ih_ring_fini(struct amdgpu_device *adev)
 {
-       int r;
-
        if (adev->irq.ih.use_bus_addr) {
                if (adev->irq.ih.ring) {
                        /* add 8 bytes for the rptr/wptr shadows and
@@ -149,17 +130,9 @@ void amdgpu_ih_ring_fini(struct amdgpu_device *adev)
                        adev->irq.ih.ring = NULL;
                }
        } else {
-               if (adev->irq.ih.ring_obj) {
-                       r = amdgpu_bo_reserve(adev->irq.ih.ring_obj, false);
-                       if (likely(r == 0)) {
-                               amdgpu_bo_kunmap(adev->irq.ih.ring_obj);
-                               amdgpu_bo_unpin(adev->irq.ih.ring_obj);
-                               amdgpu_bo_unreserve(adev->irq.ih.ring_obj);
-                       }
-                       amdgpu_bo_unref(&adev->irq.ih.ring_obj);
-                       adev->irq.ih.ring = NULL;
-                       adev->irq.ih.ring_obj = NULL;
-               }
+               amdgpu_bo_free_kernel(&adev->irq.ih.ring_obj,
+                                     &adev->irq.ih.gpu_addr,
+                                     (void **)&adev->irq.ih.ring);
                amdgpu_wb_free(adev, adev->irq.ih.wptr_offs);
                amdgpu_wb_free(adev, adev->irq.ih.rptr_offs);
        }
index 7ef0935..f016464 100644 (file)
@@ -70,6 +70,7 @@ struct amdgpu_irq {
        /* gen irq stuff */
        struct irq_domain               *domain; /* GPU irq controller domain */
        unsigned                        virq[AMDGPU_MAX_IRQ_SRC_ID];
+       uint32_t                        srbm_soft_reset;
 };
 
 void amdgpu_irq_preinstall(struct drm_device *dev);
index 6674d40..8c58079 100644 (file)
@@ -91,7 +91,7 @@ void amdgpu_job_free_resources(struct amdgpu_job *job)
                amdgpu_ib_free(job->adev, &job->ibs[i], f);
 }
 
-void amdgpu_job_free_cb(struct amd_sched_job *s_job)
+static void amdgpu_job_free_cb(struct amd_sched_job *s_job)
 {
        struct amdgpu_job *job = container_of(s_job, struct amdgpu_job, base);
 
@@ -124,7 +124,7 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct amdgpu_ring *ring,
                return r;
 
        job->owner = owner;
-       job->ctx = entity->fence_context;
+       job->fence_ctx = entity->fence_context;
        *f = fence_get(&job->base.s_fence->finished);
        amdgpu_job_free_resources(job);
        amd_sched_entity_push_job(&job->base);
index d942654..c2c7fb1 100644 (file)
@@ -292,14 +292,14 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        type = AMD_IP_BLOCK_TYPE_UVD;
                        ring_mask = adev->uvd.ring.ready ? 1 : 0;
                        ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
-                       ib_size_alignment = 8;
+                       ib_size_alignment = 16;
                        break;
                case AMDGPU_HW_IP_VCE:
                        type = AMD_IP_BLOCK_TYPE_VCE;
-                       for (i = 0; i < AMDGPU_MAX_VCE_RINGS; i++)
+                       for (i = 0; i < adev->vce.num_rings; i++)
                                ring_mask |= ((adev->vce.ring[i].ready ? 1 : 0) << i);
                        ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
-                       ib_size_alignment = 8;
+                       ib_size_alignment = 1;
                        break;
                default:
                        return -EINVAL;
@@ -373,6 +373,9 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
        case AMDGPU_INFO_NUM_BYTES_MOVED:
                ui64 = atomic64_read(&adev->num_bytes_moved);
                return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
+       case AMDGPU_INFO_NUM_EVICTIONS:
+               ui64 = atomic64_read(&adev->num_evictions);
+               return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
        case AMDGPU_INFO_VRAM_USAGE:
                ui64 = atomic64_read(&adev->vram_usage);
                return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
@@ -539,12 +542,16 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
                return r;
 
        fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
-       if (unlikely(!fpriv))
-               return -ENOMEM;
+       if (unlikely(!fpriv)) {
+               r = -ENOMEM;
+               goto out_suspend;
+       }
 
        r = amdgpu_vm_init(adev, &fpriv->vm);
-       if (r)
-               goto error_free;
+       if (r) {
+               kfree(fpriv);
+               goto out_suspend;
+       }
 
        mutex_init(&fpriv->bo_list_lock);
        idr_init(&fpriv->bo_list_handles);
@@ -553,12 +560,9 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
 
        file_priv->driver_priv = fpriv;
 
+out_suspend:
        pm_runtime_mark_last_busy(dev->dev);
        pm_runtime_put_autosuspend(dev->dev);
-       return 0;
-
-error_free:
-       kfree(fpriv);
 
        return r;
 }
@@ -597,6 +601,9 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
 
        kfree(fpriv);
        file_priv->driver_priv = NULL;
+
+       pm_runtime_mark_last_busy(dev->dev);
+       pm_runtime_put_autosuspend(dev->dev);
 }
 
 /**
@@ -611,6 +618,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
 void amdgpu_driver_preclose_kms(struct drm_device *dev,
                                struct drm_file *file_priv)
 {
+       pm_runtime_get_sync(dev->dev);
 }
 
 /*
index 6b1d7d3..7b0eff7 100644 (file)
@@ -39,6 +39,8 @@
 #include <drm/drm_plane_helper.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/hrtimer.h>
+#include "amdgpu_irq.h"
 
 struct amdgpu_bo;
 struct amdgpu_device;
@@ -339,6 +341,8 @@ struct amdgpu_mode_info {
        int                     num_dig; /* number of dig blocks */
        int                     disp_priority;
        const struct amdgpu_display_funcs *funcs;
+       struct hrtimer vblank_timer;
+       enum amdgpu_interrupt_state vsync_timer_enabled;
 };
 
 #define AMDGPU_MAX_BL_LEVEL 0xFF
@@ -587,10 +591,10 @@ int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tile
 void amdgpu_print_display_setup(struct drm_device *dev);
 int amdgpu_modeset_create_props(struct amdgpu_device *adev);
 int amdgpu_crtc_set_config(struct drm_mode_set *set);
-int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
-                         struct drm_framebuffer *fb,
-                         struct drm_pending_vblank_event *event,
-                         uint32_t page_flip_flags);
+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);
 extern const struct drm_mode_config_funcs amdgpu_mode_funcs;
 
 #endif
index 6f0873c..aa074fa 100644 (file)
 #include "amdgpu_trace.h"
 
 
-int amdgpu_ttm_init(struct amdgpu_device *adev);
-void amdgpu_ttm_fini(struct amdgpu_device *adev);
 
 static u64 amdgpu_get_vis_part_size(struct amdgpu_device *adev,
                                                struct ttm_mem_reg *mem)
 {
-       u64 ret = 0;
-       if (mem->start << PAGE_SHIFT < adev->mc.visible_vram_size) {
-               ret = (u64)((mem->start << PAGE_SHIFT) + mem->size) >
-                          adev->mc.visible_vram_size ?
-                          adev->mc.visible_vram_size - (mem->start << PAGE_SHIFT) :
-                          mem->size;
-       }
-       return ret;
+       if (mem->start << PAGE_SHIFT >= adev->mc.visible_vram_size)
+               return 0;
+
+       return ((mem->start << PAGE_SHIFT) + mem->size) >
+               adev->mc.visible_vram_size ?
+               adev->mc.visible_vram_size - (mem->start << PAGE_SHIFT) :
+               mem->size;
 }
 
 static void amdgpu_update_memory_usage(struct amdgpu_device *adev,
@@ -99,6 +96,11 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
 
        drm_gem_object_release(&bo->gem_base);
        amdgpu_bo_unref(&bo->parent);
+       if (!list_empty(&bo->shadow_list)) {
+               mutex_lock(&bo->adev->shadow_list_lock);
+               list_del_init(&bo->shadow_list);
+               mutex_unlock(&bo->adev->shadow_list_lock);
+       }
        kfree(bo->metadata);
        kfree(bo);
 }
@@ -112,90 +114,99 @@ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
 
 static void amdgpu_ttm_placement_init(struct amdgpu_device *adev,
                                      struct ttm_placement *placement,
-                                     struct ttm_place *placements,
+                                     struct ttm_place *places,
                                      u32 domain, u64 flags)
 {
-       u32 c = 0, i;
-
-       placement->placement = placements;
-       placement->busy_placement = placements;
+       u32 c = 0;
 
        if (domain & AMDGPU_GEM_DOMAIN_VRAM) {
+               unsigned visible_pfn = adev->mc.visible_vram_size >> PAGE_SHIFT;
+
                if (flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS &&
-                       adev->mc.visible_vram_size < adev->mc.real_vram_size) {
-                       placements[c].fpfn =
-                               adev->mc.visible_vram_size >> PAGE_SHIFT;
-                       placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
-                               TTM_PL_FLAG_VRAM | TTM_PL_FLAG_TOPDOWN;
+                   !(flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) &&
+                   adev->mc.visible_vram_size < adev->mc.real_vram_size) {
+                       places[c].fpfn = visible_pfn;
+                       places[c].lpfn = 0;
+                       places[c].flags = TTM_PL_FLAG_WC |
+                               TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM |
+                               TTM_PL_FLAG_TOPDOWN;
+                       c++;
                }
-               placements[c].fpfn = 0;
-               placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
+
+               places[c].fpfn = 0;
+               places[c].lpfn = 0;
+               places[c].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
                        TTM_PL_FLAG_VRAM;
-               if (!(flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED))
-                       placements[c - 1].flags |= TTM_PL_FLAG_TOPDOWN;
+               if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
+                       places[c].lpfn = visible_pfn;
+               else
+                       places[c].flags |= TTM_PL_FLAG_TOPDOWN;
+               c++;
        }
 
        if (domain & AMDGPU_GEM_DOMAIN_GTT) {
-               if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) {
-                       placements[c].fpfn = 0;
-                       placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT |
+               places[c].fpfn = 0;
+               places[c].lpfn = 0;
+               places[c].flags = TTM_PL_FLAG_TT;
+               if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC)
+                       places[c].flags |= TTM_PL_FLAG_WC |
                                TTM_PL_FLAG_UNCACHED;
-               } else {
-                       placements[c].fpfn = 0;
-                       placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT;
-               }
+               else
+                       places[c].flags |= TTM_PL_FLAG_CACHED;
+               c++;
        }
 
        if (domain & AMDGPU_GEM_DOMAIN_CPU) {
-               if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) {
-                       placements[c].fpfn = 0;
-                       placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_SYSTEM |
+               places[c].fpfn = 0;
+               places[c].lpfn = 0;
+               places[c].flags = TTM_PL_FLAG_SYSTEM;
+               if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC)
+                       places[c].flags |= TTM_PL_FLAG_WC |
                                TTM_PL_FLAG_UNCACHED;
-               } else {
-                       placements[c].fpfn = 0;
-                       placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM;
-               }
+               else
+                       places[c].flags |= TTM_PL_FLAG_CACHED;
+               c++;
        }
 
        if (domain & AMDGPU_GEM_DOMAIN_GDS) {
-               placements[c].fpfn = 0;
-               placements[c++].flags = TTM_PL_FLAG_UNCACHED |
-                       AMDGPU_PL_FLAG_GDS;
+               places[c].fpfn = 0;
+               places[c].lpfn = 0;
+               places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GDS;
+               c++;
        }
+
        if (domain & AMDGPU_GEM_DOMAIN_GWS) {
-               placements[c].fpfn = 0;
-               placements[c++].flags = TTM_PL_FLAG_UNCACHED |
-                       AMDGPU_PL_FLAG_GWS;
+               places[c].fpfn = 0;
+               places[c].lpfn = 0;
+               places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GWS;
+               c++;
        }
+
        if (domain & AMDGPU_GEM_DOMAIN_OA) {
-               placements[c].fpfn = 0;
-               placements[c++].flags = TTM_PL_FLAG_UNCACHED |
-                       AMDGPU_PL_FLAG_OA;
+               places[c].fpfn = 0;
+               places[c].lpfn = 0;
+               places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_OA;
+               c++;
        }
 
        if (!c) {
-               placements[c].fpfn = 0;
-               placements[c++].flags = TTM_PL_MASK_CACHING |
-                       TTM_PL_FLAG_SYSTEM;
+               places[c].fpfn = 0;
+               places[c].lpfn = 0;
+               places[c].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               c++;
        }
+
        placement->num_placement = c;
-       placement->num_busy_placement = c;
+       placement->placement = places;
 
-       for (i = 0; i < c; i++) {
-               if ((flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) &&
-                       (placements[i].flags & TTM_PL_FLAG_VRAM) &&
-                       !placements[i].fpfn)
-                       placements[i].lpfn =
-                               adev->mc.visible_vram_size >> PAGE_SHIFT;
-               else
-                       placements[i].lpfn = 0;
-       }
+       placement->num_busy_placement = c;
+       placement->busy_placement = places;
 }
 
-void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *rbo, u32 domain)
+void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
 {
-       amdgpu_ttm_placement_init(rbo->adev, &rbo->placement,
-                                 rbo->placements, domain, rbo->flags);
+       amdgpu_ttm_placement_init(abo->adev, &abo->placement,
+                                 abo->placements, domain, abo->flags);
 }
 
 static void amdgpu_fill_placement_to_bo(struct amdgpu_bo *bo,
@@ -211,6 +222,98 @@ static void amdgpu_fill_placement_to_bo(struct amdgpu_bo *bo,
        bo->placement.busy_placement = bo->placements;
 }
 
+/**
+ * amdgpu_bo_create_kernel - create BO for kernel use
+ *
+ * @adev: amdgpu device object
+ * @size: size for the new BO
+ * @align: alignment for the new BO
+ * @domain: where to place it
+ * @bo_ptr: resulting BO
+ * @gpu_addr: GPU addr of the pinned BO
+ * @cpu_addr: optional CPU address mapping
+ *
+ * Allocates and pins a BO for kernel internal use.
+ *
+ * Returns 0 on success, negative error code otherwise.
+ */
+int amdgpu_bo_create_kernel(struct amdgpu_device *adev,
+                           unsigned long size, int align,
+                           u32 domain, struct amdgpu_bo **bo_ptr,
+                           u64 *gpu_addr, void **cpu_addr)
+{
+       int r;
+
+       r = amdgpu_bo_create(adev, size, align, true, domain,
+                            AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
+                            NULL, NULL, bo_ptr);
+       if (r) {
+               dev_err(adev->dev, "(%d) failed to allocate kernel bo\n", r);
+               return r;
+       }
+
+       r = amdgpu_bo_reserve(*bo_ptr, false);
+       if (r) {
+               dev_err(adev->dev, "(%d) failed to reserve kernel bo\n", r);
+               goto error_free;
+       }
+
+       r = amdgpu_bo_pin(*bo_ptr, domain, gpu_addr);
+       if (r) {
+               dev_err(adev->dev, "(%d) kernel bo pin failed\n", r);
+               goto error_unreserve;
+       }
+
+       if (cpu_addr) {
+               r = amdgpu_bo_kmap(*bo_ptr, cpu_addr);
+               if (r) {
+                       dev_err(adev->dev, "(%d) kernel bo map failed\n", r);
+                       goto error_unreserve;
+               }
+       }
+
+       amdgpu_bo_unreserve(*bo_ptr);
+
+       return 0;
+
+error_unreserve:
+       amdgpu_bo_unreserve(*bo_ptr);
+
+error_free:
+       amdgpu_bo_unref(bo_ptr);
+
+       return r;
+}
+
+/**
+ * amdgpu_bo_free_kernel - free BO for kernel use
+ *
+ * @bo: amdgpu BO to free
+ *
+ * unmaps and unpin a BO for kernel internal use.
+ */
+void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr,
+                          void **cpu_addr)
+{
+       if (*bo == NULL)
+               return;
+
+       if (likely(amdgpu_bo_reserve(*bo, false) == 0)) {
+               if (cpu_addr)
+                       amdgpu_bo_kunmap(*bo);
+
+               amdgpu_bo_unpin(*bo);
+               amdgpu_bo_unreserve(*bo);
+       }
+       amdgpu_bo_unref(bo);
+
+       if (gpu_addr)
+               *gpu_addr = 0;
+
+       if (cpu_addr)
+               *cpu_addr = NULL;
+}
+
 int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
                                unsigned long size, int byte_align,
                                bool kernel, u32 domain, u64 flags,
@@ -249,7 +352,7 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
                return r;
        }
        bo->adev = adev;
-       INIT_LIST_HEAD(&bo->list);
+       INIT_LIST_HEAD(&bo->shadow_list);
        INIT_LIST_HEAD(&bo->va);
        bo->prefered_domains = domain & (AMDGPU_GEM_DOMAIN_VRAM |
                                         AMDGPU_GEM_DOMAIN_GTT |
@@ -277,11 +380,79 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
        if (unlikely(r != 0)) {
                return r;
        }
+
+       if (flags & AMDGPU_GEM_CREATE_VRAM_CLEARED &&
+           bo->tbo.mem.placement & TTM_PL_FLAG_VRAM) {
+               struct fence *fence;
+
+               if (adev->mman.buffer_funcs_ring == NULL ||
+                  !adev->mman.buffer_funcs_ring->ready) {
+                       r = -EBUSY;
+                       goto fail_free;
+               }
+
+               r = amdgpu_bo_reserve(bo, false);
+               if (unlikely(r != 0))
+                       goto fail_free;
+
+               amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM);
+               r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+               if (unlikely(r != 0))
+                       goto fail_unreserve;
+
+               amdgpu_fill_buffer(bo, 0, bo->tbo.resv, &fence);
+               amdgpu_bo_fence(bo, fence, false);
+               amdgpu_bo_unreserve(bo);
+               fence_put(bo->tbo.moving);
+               bo->tbo.moving = fence_get(fence);
+               fence_put(fence);
+       }
        *bo_ptr = bo;
 
        trace_amdgpu_bo_create(bo);
 
        return 0;
+
+fail_unreserve:
+       amdgpu_bo_unreserve(bo);
+fail_free:
+       amdgpu_bo_unref(&bo);
+       return r;
+}
+
+static int amdgpu_bo_create_shadow(struct amdgpu_device *adev,
+                                  unsigned long size, int byte_align,
+                                  struct amdgpu_bo *bo)
+{
+       struct ttm_placement placement = {0};
+       struct ttm_place placements[AMDGPU_GEM_DOMAIN_MAX + 1];
+       int r;
+
+       if (bo->shadow)
+               return 0;
+
+       bo->flags |= AMDGPU_GEM_CREATE_SHADOW;
+       memset(&placements, 0,
+              (AMDGPU_GEM_DOMAIN_MAX + 1) * sizeof(struct ttm_place));
+
+       amdgpu_ttm_placement_init(adev, &placement,
+                                 placements, AMDGPU_GEM_DOMAIN_GTT,
+                                 AMDGPU_GEM_CREATE_CPU_GTT_USWC);
+
+       r = amdgpu_bo_create_restricted(adev, size, byte_align, true,
+                                       AMDGPU_GEM_DOMAIN_GTT,
+                                       AMDGPU_GEM_CREATE_CPU_GTT_USWC,
+                                       NULL, &placement,
+                                       bo->tbo.resv,
+                                       &bo->shadow);
+       if (!r) {
+               bo->shadow->parent = amdgpu_bo_ref(bo);
+               mutex_lock(&adev->shadow_list_lock);
+               list_add_tail(&bo->shadow_list, &adev->shadow_list);
+               mutex_unlock(&adev->shadow_list_lock);
+       }
+
+       return r;
 }
 
 int amdgpu_bo_create(struct amdgpu_device *adev,
@@ -293,6 +464,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
 {
        struct ttm_placement placement = {0};
        struct ttm_place placements[AMDGPU_GEM_DOMAIN_MAX + 1];
+       int r;
 
        memset(&placements, 0,
               (AMDGPU_GEM_DOMAIN_MAX + 1) * sizeof(struct ttm_place));
@@ -300,9 +472,83 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
        amdgpu_ttm_placement_init(adev, &placement,
                                  placements, domain, flags);
 
-       return amdgpu_bo_create_restricted(adev, size, byte_align, kernel,
-                                          domain, flags, sg, &placement,
-                                          resv, bo_ptr);
+       r = amdgpu_bo_create_restricted(adev, size, byte_align, kernel,
+                                       domain, flags, sg, &placement,
+                                       resv, bo_ptr);
+       if (r)
+               return r;
+
+       if (amdgpu_need_backup(adev) && (flags & AMDGPU_GEM_CREATE_SHADOW)) {
+               r = amdgpu_bo_create_shadow(adev, size, byte_align, (*bo_ptr));
+               if (r)
+                       amdgpu_bo_unref(bo_ptr);
+       }
+
+       return r;
+}
+
+int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
+                              struct amdgpu_ring *ring,
+                              struct amdgpu_bo *bo,
+                              struct reservation_object *resv,
+                              struct fence **fence,
+                              bool direct)
+
+{
+       struct amdgpu_bo *shadow = bo->shadow;
+       uint64_t bo_addr, shadow_addr;
+       int r;
+
+       if (!shadow)
+               return -EINVAL;
+
+       bo_addr = amdgpu_bo_gpu_offset(bo);
+       shadow_addr = amdgpu_bo_gpu_offset(bo->shadow);
+
+       r = reservation_object_reserve_shared(bo->tbo.resv);
+       if (r)
+               goto err;
+
+       r = amdgpu_copy_buffer(ring, bo_addr, shadow_addr,
+                              amdgpu_bo_size(bo), resv, fence,
+                              direct);
+       if (!r)
+               amdgpu_bo_fence(bo, *fence, true);
+
+err:
+       return r;
+}
+
+int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev,
+                                 struct amdgpu_ring *ring,
+                                 struct amdgpu_bo *bo,
+                                 struct reservation_object *resv,
+                                 struct fence **fence,
+                                 bool direct)
+
+{
+       struct amdgpu_bo *shadow = bo->shadow;
+       uint64_t bo_addr, shadow_addr;
+       int r;
+
+       if (!shadow)
+               return -EINVAL;
+
+       bo_addr = amdgpu_bo_gpu_offset(bo);
+       shadow_addr = amdgpu_bo_gpu_offset(bo->shadow);
+
+       r = reservation_object_reserve_shared(bo->tbo.resv);
+       if (r)
+               goto err;
+
+       r = amdgpu_copy_buffer(ring, shadow_addr, bo_addr,
+                              amdgpu_bo_size(bo), resv, fence,
+                              direct);
+       if (!r)
+               amdgpu_bo_fence(bo, *fence, true);
+
+err:
+       return r;
 }
 
 int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
@@ -380,16 +626,17 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
                return -EINVAL;
 
        if (bo->pin_count) {
+               uint32_t mem_type = bo->tbo.mem.mem_type;
+
+               if (domain != amdgpu_mem_type_to_domain(mem_type))
+                       return -EINVAL;
+
                bo->pin_count++;
                if (gpu_addr)
                        *gpu_addr = amdgpu_bo_gpu_offset(bo);
 
                if (max_offset != 0) {
-                       u64 domain_start;
-                       if (domain == AMDGPU_GEM_DOMAIN_VRAM)
-                               domain_start = bo->adev->mc.vram_start;
-                       else
-                               domain_start = bo->adev->mc.gtt_start;
+                       u64 domain_start = bo->tbo.bdev->man[mem_type].gpu_offset;
                        WARN_ON_ONCE(max_offset <
                                     (amdgpu_bo_gpu_offset(bo) - domain_start));
                }
@@ -401,7 +648,8 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
                /* force to pin into visible video ram */
                if ((bo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
                    !(bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) &&
-                   (!max_offset || max_offset > bo->adev->mc.visible_vram_size)) {
+                   (!max_offset || max_offset >
+                    bo->adev->mc.visible_vram_size)) {
                        if (WARN_ON_ONCE(min_offset >
                                         bo->adev->mc.visible_vram_size))
                                return -EINVAL;
@@ -420,19 +668,28 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
        }
 
        r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
-       if (likely(r == 0)) {
-               bo->pin_count = 1;
-               if (gpu_addr != NULL)
-                       *gpu_addr = amdgpu_bo_gpu_offset(bo);
-               if (domain == AMDGPU_GEM_DOMAIN_VRAM) {
-                       bo->adev->vram_pin_size += amdgpu_bo_size(bo);
-                       if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)
-                               bo->adev->invisible_pin_size += amdgpu_bo_size(bo);
-               } else
-                       bo->adev->gart_pin_size += amdgpu_bo_size(bo);
-       } else {
+       if (unlikely(r)) {
                dev_err(bo->adev->dev, "%p pin failed\n", bo);
+               goto error;
+       }
+       r = amdgpu_ttm_bind(&bo->tbo, &bo->tbo.mem);
+       if (unlikely(r)) {
+               dev_err(bo->adev->dev, "%p bind failed\n", bo);
+               goto error;
        }
+
+       bo->pin_count = 1;
+       if (gpu_addr != NULL)
+               *gpu_addr = amdgpu_bo_gpu_offset(bo);
+       if (domain == AMDGPU_GEM_DOMAIN_VRAM) {
+               bo->adev->vram_pin_size += amdgpu_bo_size(bo);
+               if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)
+                       bo->adev->invisible_pin_size += amdgpu_bo_size(bo);
+       } else if (domain == AMDGPU_GEM_DOMAIN_GTT) {
+               bo->adev->gart_pin_size += amdgpu_bo_size(bo);
+       }
+
+error:
        return r;
 }
 
@@ -457,16 +714,20 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo)
                bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
        }
        r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
-       if (likely(r == 0)) {
-               if (bo->tbo.mem.mem_type == TTM_PL_VRAM) {
-                       bo->adev->vram_pin_size -= amdgpu_bo_size(bo);
-                       if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)
-                               bo->adev->invisible_pin_size -= amdgpu_bo_size(bo);
-               } else
-                       bo->adev->gart_pin_size -= amdgpu_bo_size(bo);
-       } else {
+       if (unlikely(r)) {
                dev_err(bo->adev->dev, "%p validate failed for unpin\n", bo);
+               goto error;
        }
+
+       if (bo->tbo.mem.mem_type == TTM_PL_VRAM) {
+               bo->adev->vram_pin_size -= amdgpu_bo_size(bo);
+               if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)
+                       bo->adev->invisible_pin_size -= amdgpu_bo_size(bo);
+       } else if (bo->tbo.mem.mem_type == TTM_PL_TT) {
+               bo->adev->gart_pin_size -= amdgpu_bo_size(bo);
+       }
+
+error:
        return r;
 }
 
@@ -588,23 +849,23 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
 void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
                           struct ttm_mem_reg *new_mem)
 {
-       struct amdgpu_bo *rbo;
+       struct amdgpu_bo *abo;
        struct ttm_mem_reg *old_mem = &bo->mem;
 
        if (!amdgpu_ttm_bo_is_amdgpu_bo(bo))
                return;
 
-       rbo = container_of(bo, struct amdgpu_bo, tbo);
-       amdgpu_vm_bo_invalidate(rbo->adev, rbo);
+       abo = container_of(bo, struct amdgpu_bo, tbo);
+       amdgpu_vm_bo_invalidate(abo->adev, abo);
 
        /* update statistics */
        if (!new_mem)
                return;
 
        /* move_notify is called before move happens */
-       amdgpu_update_memory_usage(rbo->adev, &bo->mem, new_mem);
+       amdgpu_update_memory_usage(abo->adev, &bo->mem, new_mem);
 
-       trace_amdgpu_ttm_bo_move(rbo, new_mem->mem_type, old_mem->mem_type);
+       trace_amdgpu_ttm_bo_move(abo, new_mem->mem_type, old_mem->mem_type);
 }
 
 int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
@@ -637,7 +898,8 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
        for (i = 0; i < abo->placement.num_placement; i++) {
                /* Force into visible VRAM */
                if ((abo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
-                   (!abo->placements[i].lpfn || abo->placements[i].lpfn > lpfn))
+                   (!abo->placements[i].lpfn ||
+                    abo->placements[i].lpfn > lpfn))
                        abo->placements[i].lpfn = lpfn;
        }
        r = ttm_bo_validate(bo, &abo->placement, false, false);
@@ -674,3 +936,24 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct fence *fence,
        else
                reservation_object_add_excl_fence(resv, fence);
 }
+
+/**
+ * amdgpu_bo_gpu_offset - return GPU offset of bo
+ * @bo:        amdgpu object for which we query the offset
+ *
+ * Returns current GPU offset of the object.
+ *
+ * Note: object should either be pinned or reserved when calling this
+ * function, it might be useful to add check for this for debugging.
+ */
+u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
+{
+       WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM);
+       WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_TT &&
+                    !amdgpu_ttm_is_bound(bo->tbo.ttm));
+       WARN_ON_ONCE(!ww_mutex_is_locked(&bo->tbo.resv->lock) &&
+                    !bo->pin_count);
+       WARN_ON_ONCE(bo->tbo.mem.start == AMDGPU_BO_INVALID_OFFSET);
+
+       return bo->tbo.offset;
+}
index bdb01d9..8255034 100644 (file)
@@ -31,6 +31,8 @@
 #include <drm/amdgpu_drm.h>
 #include "amdgpu.h"
 
+#define AMDGPU_BO_INVALID_OFFSET       LONG_MAX
+
 /**
  * amdgpu_mem_type_to_domain - return domain corresponding to mem_type
  * @mem_type:  ttm memory type
@@ -85,21 +87,6 @@ static inline void amdgpu_bo_unreserve(struct amdgpu_bo *bo)
        ttm_bo_unreserve(&bo->tbo);
 }
 
-/**
- * amdgpu_bo_gpu_offset - return GPU offset of bo
- * @bo:        amdgpu object for which we query the offset
- *
- * Returns current GPU offset of the object.
- *
- * Note: object should either be pinned or reserved when calling this
- * function, it might be useful to add check for this for debugging.
- */
-static inline u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
-{
-       WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM);
-       return bo->tbo.offset;
-}
-
 static inline unsigned long amdgpu_bo_size(struct amdgpu_bo *bo)
 {
        return bo->tbo.num_pages << PAGE_SHIFT;
@@ -139,6 +126,12 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
                                struct ttm_placement *placement,
                                struct reservation_object *resv,
                                struct amdgpu_bo **bo_ptr);
+int amdgpu_bo_create_kernel(struct amdgpu_device *adev,
+                           unsigned long size, int align,
+                           u32 domain, struct amdgpu_bo **bo_ptr,
+                           u64 *gpu_addr, void **cpu_addr);
+void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr,
+                          void **cpu_addr);
 int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr);
 void amdgpu_bo_kunmap(struct amdgpu_bo *bo);
 struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo);
@@ -165,6 +158,19 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
 int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
 void amdgpu_bo_fence(struct amdgpu_bo *bo, struct fence *fence,
                     bool shared);
+u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo);
+int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
+                              struct amdgpu_ring *ring,
+                              struct amdgpu_bo *bo,
+                              struct reservation_object *resv,
+                              struct fence **fence, bool direct);
+int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev,
+                                 struct amdgpu_ring *ring,
+                                 struct amdgpu_bo *bo,
+                                 struct reservation_object *resv,
+                                 struct fence **fence,
+                                 bool direct);
+
 
 /*
  * sub allocation
index d153149..8e67c12 100644 (file)
@@ -25,6 +25,7 @@
 #include "amdgpu.h"
 #include "atom.h"
 #include "atombios_encoders.h"
+#include "amdgpu_pll.h"
 #include <asm/div64.h>
 #include <linux/gcd.h>
 
index 5cc7052..accc908 100644 (file)
@@ -1103,54 +1103,46 @@ force:
 
 void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
 {
-       if (adev->pp_enabled)
+       if (adev->pp_enabled || adev->pm.funcs->powergate_uvd) {
+               /* enable/disable UVD */
+               mutex_lock(&adev->pm.mutex);
                amdgpu_dpm_powergate_uvd(adev, !enable);
-       else {
-               if (adev->pm.funcs->powergate_uvd) {
+               mutex_unlock(&adev->pm.mutex);
+       } else {
+               if (enable) {
                        mutex_lock(&adev->pm.mutex);
-                       /* enable/disable UVD */
-                       amdgpu_dpm_powergate_uvd(adev, !enable);
+                       adev->pm.dpm.uvd_active = true;
+                       adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
                        mutex_unlock(&adev->pm.mutex);
                } else {
-                       if (enable) {
-                               mutex_lock(&adev->pm.mutex);
-                               adev->pm.dpm.uvd_active = true;
-                               adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
-                               mutex_unlock(&adev->pm.mutex);
-                       } else {
-                               mutex_lock(&adev->pm.mutex);
-                               adev->pm.dpm.uvd_active = false;
-                               mutex_unlock(&adev->pm.mutex);
-                       }
-                       amdgpu_pm_compute_clocks(adev);
+                       mutex_lock(&adev->pm.mutex);
+                       adev->pm.dpm.uvd_active = false;
+                       mutex_unlock(&adev->pm.mutex);
                }
-
+               amdgpu_pm_compute_clocks(adev);
        }
 }
 
 void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
 {
-       if (adev->pp_enabled)
+       if (adev->pp_enabled || adev->pm.funcs->powergate_vce) {
+               /* enable/disable VCE */
+               mutex_lock(&adev->pm.mutex);
                amdgpu_dpm_powergate_vce(adev, !enable);
-       else {
-               if (adev->pm.funcs->powergate_vce) {
+               mutex_unlock(&adev->pm.mutex);
+       } else {
+               if (enable) {
                        mutex_lock(&adev->pm.mutex);
-                       amdgpu_dpm_powergate_vce(adev, !enable);
+                       adev->pm.dpm.vce_active = true;
+                       /* XXX select vce level based on ring/task */
+                       adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL;
                        mutex_unlock(&adev->pm.mutex);
                } else {
-                       if (enable) {
-                               mutex_lock(&adev->pm.mutex);
-                               adev->pm.dpm.vce_active = true;
-                               /* XXX select vce level based on ring/task */
-                               adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL;
-                               mutex_unlock(&adev->pm.mutex);
-                       } else {
-                               mutex_lock(&adev->pm.mutex);
-                               adev->pm.dpm.vce_active = false;
-                               mutex_unlock(&adev->pm.mutex);
-                       }
-                       amdgpu_pm_compute_clocks(adev);
+                       mutex_lock(&adev->pm.mutex);
+                       adev->pm.dpm.vce_active = false;
+                       mutex_unlock(&adev->pm.mutex);
                }
+               amdgpu_pm_compute_clocks(adev);
        }
 }
 
@@ -1330,6 +1322,64 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
  */
 #if defined(CONFIG_DEBUG_FS)
 
+static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *adev)
+{
+       int32_t value;
+
+       /* sanity check PP is enabled */
+       if (!(adev->powerplay.pp_funcs &&
+             adev->powerplay.pp_funcs->read_sensor))
+             return -EINVAL;
+
+       /* GPU Clocks */
+       seq_printf(m, "GFX Clocks and Power:\n");
+       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK, &value))
+               seq_printf(m, "\t%u MHz (MCLK)\n", value/100);
+       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK, &value))
+               seq_printf(m, "\t%u MHz (SCLK)\n", value/100);
+       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX, &value))
+               seq_printf(m, "\t%u mV (VDDGFX)\n", value);
+       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, &value))
+               seq_printf(m, "\t%u mV (VDDNB)\n", value);
+       seq_printf(m, "\n");
+
+       /* GPU Temp */
+       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, &value))
+               seq_printf(m, "GPU Temperature: %u C\n", value/1000);
+
+       /* GPU Load */
+       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD, &value))
+               seq_printf(m, "GPU Load: %u %%\n", value);
+       seq_printf(m, "\n");
+
+       /* UVD clocks */
+       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_POWER, &value)) {
+               if (!value) {
+                       seq_printf(m, "UVD: Disabled\n");
+               } else {
+                       seq_printf(m, "UVD: Enabled\n");
+                       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_DCLK, &value))
+                               seq_printf(m, "\t%u MHz (DCLK)\n", value/100);
+                       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_VCLK, &value))
+                               seq_printf(m, "\t%u MHz (VCLK)\n", value/100);
+               }
+       }
+       seq_printf(m, "\n");
+
+       /* VCE clocks */
+       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_POWER, &value)) {
+               if (!value) {
+                       seq_printf(m, "VCE: Disabled\n");
+               } else {
+                       seq_printf(m, "VCE: Enabled\n");
+                       if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_ECCLK, &value))
+                               seq_printf(m, "\t%u MHz (ECCLK)\n", value/100);
+               }
+       }
+
+       return 0;
+}
+
 static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -1345,11 +1395,11 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
             (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
                seq_printf(m, "PX asic powered off\n");
        } else if (adev->pp_enabled) {
-               amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
+               return amdgpu_debugfs_pm_info_pp(m, adev);
        } else {
                mutex_lock(&adev->pm.mutex);
                if (adev->pm.funcs->debugfs_print_current_performance_level)
-                       amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
+                       adev->pm.funcs->debugfs_print_current_performance_level(adev, m);
                else
                        seq_printf(m, "Debugfs support not implemented for this asic\n");
                mutex_unlock(&adev->pm.mutex);
index c5738a2..7532ff8 100644 (file)
@@ -30,6 +30,7 @@
 #include "amdgpu_pm.h"
 #include <drm/amdgpu_drm.h>
 #include "amdgpu_powerplay.h"
+#include "si_dpm.h"
 #include "cik_dpm.h"
 #include "vi_dpm.h"
 
@@ -41,7 +42,6 @@ static int amdgpu_powerplay_init(struct amdgpu_device *adev)
        amd_pp = &(adev->powerplay);
 
        if (adev->pp_enabled) {
-#ifdef CONFIG_DRM_AMD_POWERPLAY
                struct amd_pp_init *pp_init;
 
                pp_init = kzalloc(sizeof(struct amd_pp_init), GFP_KERNEL);
@@ -52,15 +52,21 @@ static int amdgpu_powerplay_init(struct amdgpu_device *adev)
                pp_init->chip_family = adev->family;
                pp_init->chip_id = adev->asic_type;
                pp_init->device = amdgpu_cgs_create_device(adev);
-               pp_init->powercontainment_enabled = amdgpu_powercontainment;
-
                ret = amd_powerplay_init(pp_init, amd_pp);
                kfree(pp_init);
-#endif
        } 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:
@@ -72,15 +78,6 @@ static int amdgpu_powerplay_init(struct amdgpu_device *adev)
                        amd_pp->ip_funcs = &kv_dpm_ip_funcs;
                        break;
 #endif
-               case CHIP_TOPAZ:
-                       amd_pp->ip_funcs = &iceland_dpm_ip_funcs;
-                       break;
-               case CHIP_TONGA:
-                       amd_pp->ip_funcs = &tonga_dpm_ip_funcs;
-                       break;
-               case CHIP_FIJI:
-                       amd_pp->ip_funcs = &fiji_dpm_ip_funcs;
-                       break;
                case CHIP_CARRIZO:
                case CHIP_STONEY:
                        amd_pp->ip_funcs = &cz_dpm_ip_funcs;
@@ -98,19 +95,17 @@ static int amdgpu_pp_early_init(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        int ret = 0;
 
-#ifdef CONFIG_DRM_AMD_POWERPLAY
        switch (adev->asic_type) {
        case CHIP_POLARIS11:
        case CHIP_POLARIS10:
-               adev->pp_enabled = true;
-               break;
        case CHIP_TONGA:
        case CHIP_FIJI:
-               adev->pp_enabled = (amdgpu_powerplay == 0) ? false : true;
+       case CHIP_TOPAZ:
+               adev->pp_enabled = true;
                break;
        case CHIP_CARRIZO:
        case CHIP_STONEY:
-               adev->pp_enabled = (amdgpu_powerplay > 0) ? true : false;
+               adev->pp_enabled = (amdgpu_powerplay == 0) ? false : true;
                break;
        /* These chips don't have powerplay implemenations */
        case CHIP_BONAIRE:
@@ -118,14 +113,10 @@ static int amdgpu_pp_early_init(void *handle)
        case CHIP_KABINI:
        case CHIP_MULLINS:
        case CHIP_KAVERI:
-       case CHIP_TOPAZ:
        default:
                adev->pp_enabled = false;
                break;
        }
-#else
-       adev->pp_enabled = false;
-#endif
 
        ret = amdgpu_powerplay_init(adev);
        if (ret)
@@ -147,12 +138,11 @@ static int amdgpu_pp_late_init(void *handle)
                ret = adev->powerplay.ip_funcs->late_init(
                                        adev->powerplay.pp_handle);
 
-#ifdef CONFIG_DRM_AMD_POWERPLAY
        if (adev->pp_enabled && adev->pm.dpm_enabled) {
                amdgpu_pm_sysfs_init(adev);
                amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_COMPLETE_INIT, NULL, NULL);
        }
-#endif
+
        return ret;
 }
 
@@ -165,10 +155,8 @@ static int amdgpu_pp_sw_init(void *handle)
                ret = adev->powerplay.ip_funcs->sw_init(
                                        adev->powerplay.pp_handle);
 
-#ifdef CONFIG_DRM_AMD_POWERPLAY
        if (adev->pp_enabled)
                adev->pm.dpm_enabled = true;
-#endif
 
        return ret;
 }
@@ -219,7 +207,6 @@ static int amdgpu_pp_hw_fini(void *handle)
 
 static void amdgpu_pp_late_fini(void *handle)
 {
-#ifdef CONFIG_DRM_AMD_POWERPLAY
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        if (adev->pp_enabled) {
@@ -230,7 +217,6 @@ static void amdgpu_pp_late_fini(void *handle)
        if (adev->powerplay.ip_funcs->late_fini)
                adev->powerplay.ip_funcs->late_fini(
                          adev->powerplay.pp_handle);
-#endif
 }
 
 static int amdgpu_pp_suspend(void *handle)
index 85aeb0a..e1fa873 100644 (file)
@@ -222,33 +222,16 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
 
        /* Allocate ring buffer */
        if (ring->ring_obj == NULL) {
-               r = amdgpu_bo_create(adev, ring->ring_size, PAGE_SIZE, true,
-                                    AMDGPU_GEM_DOMAIN_GTT, 0,
-                                    NULL, NULL, &ring->ring_obj);
+               r = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
+                                           AMDGPU_GEM_DOMAIN_GTT,
+                                           &ring->ring_obj,
+                                           &ring->gpu_addr,
+                                           (void **)&ring->ring);
                if (r) {
                        dev_err(adev->dev, "(%d) ring create failed\n", r);
                        return r;
                }
-               r = amdgpu_bo_reserve(ring->ring_obj, false);
-               if (unlikely(r != 0))
-                       return r;
-               r = amdgpu_bo_pin(ring->ring_obj, AMDGPU_GEM_DOMAIN_GTT,
-                                       &ring->gpu_addr);
-               if (r) {
-                       amdgpu_bo_unreserve(ring->ring_obj);
-                       dev_err(adev->dev, "(%d) ring pin failed\n", r);
-                       return r;
-               }
-               r = amdgpu_bo_kmap(ring->ring_obj,
-                                      (void **)&ring->ring);
-
                memset((void *)ring->ring, 0, ring->ring_size);
-
-               amdgpu_bo_unreserve(ring->ring_obj);
-               if (r) {
-                       dev_err(adev->dev, "(%d) ring map failed\n", r);
-                       return r;
-               }
        }
        ring->ptr_mask = (ring->ring_size / 4) - 1;
        ring->max_dw = max_dw;
@@ -269,29 +252,20 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
  */
 void amdgpu_ring_fini(struct amdgpu_ring *ring)
 {
-       int r;
-       struct amdgpu_bo *ring_obj;
-
-       ring_obj = ring->ring_obj;
        ring->ready = false;
-       ring->ring = NULL;
-       ring->ring_obj = NULL;
 
        amdgpu_wb_free(ring->adev, ring->cond_exe_offs);
        amdgpu_wb_free(ring->adev, ring->fence_offs);
        amdgpu_wb_free(ring->adev, ring->rptr_offs);
        amdgpu_wb_free(ring->adev, ring->wptr_offs);
 
-       if (ring_obj) {
-               r = amdgpu_bo_reserve(ring_obj, false);
-               if (likely(r == 0)) {
-                       amdgpu_bo_kunmap(ring_obj);
-                       amdgpu_bo_unpin(ring_obj);
-                       amdgpu_bo_unreserve(ring_obj);
-               }
-               amdgpu_bo_unref(&ring_obj);
-       }
+       amdgpu_bo_free_kernel(&ring->ring_obj,
+                             &ring->gpu_addr,
+                             (void **)&ring->ring);
+
        amdgpu_debugfs_ring_fini(ring);
+
+       ring->adev->rings[ring->idx] = NULL;
 }
 
 /*
index 05a53f4..b827c75 100644 (file)
@@ -111,7 +111,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev)
                amdgpu_bo_kunmap(gtt_obj[i]);
 
                r = amdgpu_copy_buffer(ring, gtt_addr, vram_addr,
-                                      size, NULL, &fence);
+                                      size, NULL, &fence, false);
 
                if (r) {
                        DRM_ERROR("Failed GTT->VRAM copy %d\n", i);
@@ -156,7 +156,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev)
                amdgpu_bo_kunmap(vram_obj);
 
                r = amdgpu_copy_buffer(ring, vram_addr, gtt_addr,
-                                      size, NULL, &fence);
+                                      size, NULL, &fence, false);
 
                if (r) {
                        DRM_ERROR("Failed VRAM->GTT copy %d\n", i);
index 0d8d65e..067e5e6 100644 (file)
@@ -247,7 +247,7 @@ DEFINE_EVENT(amdgpu_vm_mapping, amdgpu_vm_bo_mapping,
            TP_ARGS(mapping)
 );
 
-TRACE_EVENT(amdgpu_vm_set_page,
+TRACE_EVENT(amdgpu_vm_set_ptes,
            TP_PROTO(uint64_t pe, uint64_t addr, unsigned count,
                     uint32_t incr, uint32_t flags),
            TP_ARGS(pe, addr, count, incr, flags),
@@ -271,6 +271,24 @@ TRACE_EVENT(amdgpu_vm_set_page,
                      __entry->flags, __entry->count)
 );
 
+TRACE_EVENT(amdgpu_vm_copy_ptes,
+           TP_PROTO(uint64_t pe, uint64_t src, unsigned count),
+           TP_ARGS(pe, src, count),
+           TP_STRUCT__entry(
+                            __field(u64, pe)
+                            __field(u64, src)
+                            __field(u32, count)
+                            ),
+
+           TP_fast_assign(
+                          __entry->pe = pe;
+                          __entry->src = src;
+                          __entry->count = count;
+                          ),
+           TP_printk("pe=%010Lx, src=%010Lx, count=%u",
+                     __entry->pe, __entry->src, __entry->count)
+);
+
 TRACE_EVENT(amdgpu_vm_flush,
            TP_PROTO(uint64_t pd_addr, unsigned ring, unsigned id),
            TP_ARGS(pd_addr, ring, id),
index 716f2af..887483b 100644 (file)
@@ -34,6 +34,7 @@
 #include <ttm/ttm_placement.h>
 #include <ttm/ttm_module.h>
 #include <ttm/ttm_page_alloc.h>
+#include <ttm/ttm_memory.h>
 #include <drm/drmP.h>
 #include <drm/amdgpu_drm.h>
 #include <linux/seq_file.h>
@@ -74,7 +75,7 @@ static void amdgpu_ttm_mem_global_release(struct drm_global_reference *ref)
        ttm_mem_global_release(ref->object);
 }
 
-static int amdgpu_ttm_global_init(struct amdgpu_device *adev)
+int amdgpu_ttm_global_init(struct amdgpu_device *adev)
 {
        struct drm_global_reference *global_ref;
        struct amdgpu_ring *ring;
@@ -88,10 +89,10 @@ static int amdgpu_ttm_global_init(struct amdgpu_device *adev)
        global_ref->init = &amdgpu_ttm_mem_global_init;
        global_ref->release = &amdgpu_ttm_mem_global_release;
        r = drm_global_item_ref(global_ref);
-       if (r != 0) {
+       if (r) {
                DRM_ERROR("Failed setting up TTM memory accounting "
                          "subsystem.\n");
-               return r;
+               goto error_mem;
        }
 
        adev->mman.bo_global_ref.mem_glob =
@@ -102,26 +103,30 @@ static int amdgpu_ttm_global_init(struct amdgpu_device *adev)
        global_ref->init = &ttm_bo_global_init;
        global_ref->release = &ttm_bo_global_release;
        r = drm_global_item_ref(global_ref);
-       if (r != 0) {
+       if (r) {
                DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(&adev->mman.mem_global_ref);
-               return r;
+               goto error_bo;
        }
 
        ring = adev->mman.buffer_funcs_ring;
        rq = &ring->sched.sched_rq[AMD_SCHED_PRIORITY_KERNEL];
        r = amd_sched_entity_init(&ring->sched, &adev->mman.entity,
                                  rq, amdgpu_sched_jobs);
-       if (r != 0) {
+       if (r) {
                DRM_ERROR("Failed setting up TTM BO move run queue.\n");
-               drm_global_item_unref(&adev->mman.mem_global_ref);
-               drm_global_item_unref(&adev->mman.bo_global_ref.ref);
-               return r;
+               goto error_entity;
        }
 
        adev->mman.mem_global_referenced = true;
 
        return 0;
+
+error_entity:
+       drm_global_item_unref(&adev->mman.bo_global_ref.ref);
+error_bo:
+       drm_global_item_unref(&adev->mman.mem_global_ref);
+error_mem:
+       return r;
 }
 
 static void amdgpu_ttm_global_fini(struct amdgpu_device *adev)
@@ -155,7 +160,7 @@ static int amdgpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->default_caching = TTM_PL_FLAG_CACHED;
                break;
        case TTM_PL_TT:
-               man->func = &ttm_bo_manager_func;
+               man->func = &amdgpu_gtt_mgr_func;
                man->gpu_offset = adev->mc.gtt_start;
                man->available_caching = TTM_PL_MASK_CACHING;
                man->default_caching = TTM_PL_FLAG_CACHED;
@@ -190,12 +195,13 @@ static int amdgpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
 static void amdgpu_evict_flags(struct ttm_buffer_object *bo,
                                struct ttm_placement *placement)
 {
-       struct amdgpu_bo *rbo;
+       struct amdgpu_bo *abo;
        static struct ttm_place placements = {
                .fpfn = 0,
                .lpfn = 0,
                .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM
        };
+       unsigned i;
 
        if (!amdgpu_ttm_bo_is_amdgpu_bo(bo)) {
                placement->placement = &placements;
@@ -204,28 +210,44 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo,
                placement->num_busy_placement = 1;
                return;
        }
-       rbo = container_of(bo, struct amdgpu_bo, tbo);
+       abo = container_of(bo, struct amdgpu_bo, tbo);
        switch (bo->mem.mem_type) {
        case TTM_PL_VRAM:
-               if (rbo->adev->mman.buffer_funcs_ring->ready == false)
-                       amdgpu_ttm_placement_from_domain(rbo, AMDGPU_GEM_DOMAIN_CPU);
-               else
-                       amdgpu_ttm_placement_from_domain(rbo, AMDGPU_GEM_DOMAIN_GTT);
+               if (abo->adev->mman.buffer_funcs_ring->ready == false) {
+                       amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU);
+               } else {
+                       amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_GTT);
+                       for (i = 0; i < abo->placement.num_placement; ++i) {
+                               if (!(abo->placements[i].flags &
+                                     TTM_PL_FLAG_TT))
+                                       continue;
+
+                               if (abo->placements[i].lpfn)
+                                       continue;
+
+                               /* set an upper limit to force directly
+                                * allocating address space for the BO.
+                                */
+                               abo->placements[i].lpfn =
+                                       abo->adev->mc.gtt_size >> PAGE_SHIFT;
+                       }
+               }
                break;
        case TTM_PL_TT:
        default:
-               amdgpu_ttm_placement_from_domain(rbo, AMDGPU_GEM_DOMAIN_CPU);
+               amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU);
        }
-       *placement = rbo->placement;
+       *placement = abo->placement;
 }
 
 static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp)
 {
-       struct amdgpu_bo *rbo = container_of(bo, struct amdgpu_bo, tbo);
+       struct amdgpu_bo *abo = container_of(bo, struct amdgpu_bo, tbo);
 
        if (amdgpu_ttm_tt_get_usermm(bo->ttm))
                return -EPERM;
-       return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp);
+       return drm_vma_node_verify_access(&abo->gem_base.vma_node,
+                                         filp->private_data);
 }
 
 static void amdgpu_move_null(struct ttm_buffer_object *bo,
@@ -251,26 +273,30 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo,
 
        adev = amdgpu_get_adev(bo->bdev);
        ring = adev->mman.buffer_funcs_ring;
-       old_start = (u64)old_mem->start << PAGE_SHIFT;
-       new_start = (u64)new_mem->start << PAGE_SHIFT;
 
        switch (old_mem->mem_type) {
-       case TTM_PL_VRAM:
-               old_start += adev->mc.vram_start;
-               break;
        case TTM_PL_TT:
-               old_start += adev->mc.gtt_start;
+               r = amdgpu_ttm_bind(bo, old_mem);
+               if (r)
+                       return r;
+
+       case TTM_PL_VRAM:
+               old_start = (u64)old_mem->start << PAGE_SHIFT;
+               old_start += bo->bdev->man[old_mem->mem_type].gpu_offset;
                break;
        default:
                DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
                return -EINVAL;
        }
        switch (new_mem->mem_type) {
-       case TTM_PL_VRAM:
-               new_start += adev->mc.vram_start;
-               break;
        case TTM_PL_TT:
-               new_start += adev->mc.gtt_start;
+               r = amdgpu_ttm_bind(bo, new_mem);
+               if (r)
+                       return r;
+
+       case TTM_PL_VRAM:
+               new_start = (u64)new_mem->start << PAGE_SHIFT;
+               new_start += bo->bdev->man[new_mem->mem_type].gpu_offset;
                break;
        default:
                DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
@@ -285,7 +311,7 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo,
 
        r = amdgpu_copy_buffer(ring, old_start, new_start,
                               new_mem->num_pages * PAGE_SIZE, /* bytes */
-                              bo->resv, &fence);
+                              bo->resv, &fence, false);
        if (r)
                return r;
 
@@ -314,7 +340,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo,
        placement.num_busy_placement = 1;
        placement.busy_placement = &placements;
        placements.fpfn = 0;
-       placements.lpfn = 0;
+       placements.lpfn = adev->mc.gtt_size >> PAGE_SHIFT;
        placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem,
                             interruptible, no_wait_gpu);
@@ -335,7 +361,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo,
        if (unlikely(r)) {
                goto out_cleanup;
        }
-       r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, new_mem);
+       r = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, new_mem);
 out_cleanup:
        ttm_bo_mem_put(bo, &tmp_mem);
        return r;
@@ -361,14 +387,14 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo,
        placement.num_busy_placement = 1;
        placement.busy_placement = &placements;
        placements.fpfn = 0;
-       placements.lpfn = 0;
+       placements.lpfn = adev->mc.gtt_size >> PAGE_SHIFT;
        placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem,
                             interruptible, no_wait_gpu);
        if (unlikely(r)) {
                return r;
        }
-       r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, &tmp_mem);
+       r = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, &tmp_mem);
        if (unlikely(r)) {
                goto out_cleanup;
        }
@@ -435,8 +461,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo,
 
        if (r) {
 memcpy:
-               r = ttm_bo_move_memcpy(bo, evict, interruptible,
-                                      no_wait_gpu, new_mem);
+               r = ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, new_mem);
                if (r) {
                        return r;
                }
@@ -524,6 +549,7 @@ struct amdgpu_ttm_tt {
        spinlock_t              guptasklock;
        struct list_head        guptasks;
        atomic_t                mmu_invalidations;
+       struct list_head        list;
 };
 
 int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
@@ -641,7 +667,6 @@ static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm,
                                   struct ttm_mem_reg *bo_mem)
 {
        struct amdgpu_ttm_tt *gtt = (void*)ttm;
-       uint32_t flags = amdgpu_ttm_tt_pte_flags(gtt->adev, ttm, bo_mem);
        int r;
 
        if (gtt->userptr) {
@@ -651,7 +676,6 @@ static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm,
                        return r;
                }
        }
-       gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT);
        if (!ttm->num_pages) {
                WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
                     ttm->num_pages, bo_mem, ttm);
@@ -662,14 +686,71 @@ static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm,
            bo_mem->mem_type == AMDGPU_PL_OA)
                return -EINVAL;
 
+       return 0;
+}
+
+bool amdgpu_ttm_is_bound(struct ttm_tt *ttm)
+{
+       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+
+       return gtt && !list_empty(&gtt->list);
+}
+
+int amdgpu_ttm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *bo_mem)
+{
+       struct ttm_tt *ttm = bo->ttm;
+       struct amdgpu_ttm_tt *gtt = (void *)bo->ttm;
+       uint32_t flags;
+       int r;
+
+       if (!ttm || amdgpu_ttm_is_bound(ttm))
+               return 0;
+
+       r = amdgpu_gtt_mgr_alloc(&bo->bdev->man[TTM_PL_TT], bo,
+                                NULL, bo_mem);
+       if (r) {
+               DRM_ERROR("Failed to allocate GTT address space (%d)\n", r);
+               return r;
+       }
+
+       flags = amdgpu_ttm_tt_pte_flags(gtt->adev, ttm, bo_mem);
+       gtt->offset = (u64)bo_mem->start << PAGE_SHIFT;
        r = amdgpu_gart_bind(gtt->adev, gtt->offset, ttm->num_pages,
                ttm->pages, gtt->ttm.dma_address, flags);
 
        if (r) {
-               DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
-                         ttm->num_pages, (unsigned)gtt->offset);
+               DRM_ERROR("failed to bind %lu pages at 0x%08llX\n",
+                         ttm->num_pages, gtt->offset);
                return r;
        }
+       spin_lock(&gtt->adev->gtt_list_lock);
+       list_add_tail(&gtt->list, &gtt->adev->gtt_list);
+       spin_unlock(&gtt->adev->gtt_list_lock);
+       return 0;
+}
+
+int amdgpu_ttm_recover_gart(struct amdgpu_device *adev)
+{
+       struct amdgpu_ttm_tt *gtt, *tmp;
+       struct ttm_mem_reg bo_mem;
+       uint32_t flags;
+       int r;
+
+       bo_mem.mem_type = TTM_PL_TT;
+       spin_lock(&adev->gtt_list_lock);
+       list_for_each_entry_safe(gtt, tmp, &adev->gtt_list, list) {
+               flags = amdgpu_ttm_tt_pte_flags(gtt->adev, &gtt->ttm.ttm, &bo_mem);
+               r = amdgpu_gart_bind(adev, gtt->offset, gtt->ttm.ttm.num_pages,
+                                    gtt->ttm.ttm.pages, gtt->ttm.dma_address,
+                                    flags);
+               if (r) {
+                       spin_unlock(&adev->gtt_list_lock);
+                       DRM_ERROR("failed to bind %lu pages at 0x%08llX\n",
+                                 gtt->ttm.ttm.num_pages, gtt->offset);
+                       return r;
+               }
+       }
+       spin_unlock(&adev->gtt_list_lock);
        return 0;
 }
 
@@ -677,12 +758,19 @@ static int amdgpu_ttm_backend_unbind(struct ttm_tt *ttm)
 {
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
 
+       if (gtt->userptr)
+               amdgpu_ttm_tt_unpin_userptr(ttm);
+
+       if (!amdgpu_ttm_is_bound(ttm))
+               return 0;
+
        /* unbind shouldn't be done for GDS/GWS/OA in ttm_bo_clean_mm */
        if (gtt->adev->gart.ready)
                amdgpu_gart_unbind(gtt->adev, gtt->offset, ttm->num_pages);
 
-       if (gtt->userptr)
-               amdgpu_ttm_tt_unpin_userptr(ttm);
+       spin_lock(&gtt->adev->gtt_list_lock);
+       list_del_init(&gtt->list);
+       spin_unlock(&gtt->adev->gtt_list_lock);
 
        return 0;
 }
@@ -720,6 +808,7 @@ static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_bo_device *bdev,
                kfree(gtt);
                return NULL;
        }
+       INIT_LIST_HEAD(&gtt->list);
        return &gtt->ttm.ttm;
 }
 
@@ -991,10 +1080,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
        unsigned i, j;
        int r;
 
-       r = amdgpu_ttm_global_init(adev);
-       if (r) {
-               return r;
-       }
        /* No others user of address space so set it to 0 */
        r = ttm_bo_device_init(&adev->mman.bdev,
                               adev->mman.bo_global_ref.ref.object,
@@ -1159,7 +1244,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring,
                       uint64_t dst_offset,
                       uint32_t byte_count,
                       struct reservation_object *resv,
-                      struct fence **fence)
+                      struct fence **fence, bool direct_submit)
 {
        struct amdgpu_device *adev = ring->adev;
        struct amdgpu_job *job;
@@ -1201,10 +1286,81 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring,
                byte_count -= cur_size_in_bytes;
        }
 
+       amdgpu_ring_pad_ib(ring, &job->ibs[0]);
+       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);
+               job->fence = fence_get(*fence);
+               if (r)
+                       DRM_ERROR("Error scheduling IBs (%d)\n", r);
+               amdgpu_job_free(job);
+       } else {
+               r = amdgpu_job_submit(job, ring, &adev->mman.entity,
+                                     AMDGPU_FENCE_OWNER_UNDEFINED, fence);
+               if (r)
+                       goto error_free;
+       }
+
+       return r;
+
+error_free:
+       amdgpu_job_free(job);
+       return r;
+}
+
+int amdgpu_fill_buffer(struct amdgpu_bo *bo,
+               uint32_t src_data,
+               struct reservation_object *resv,
+               struct fence **fence)
+{
+       struct amdgpu_device *adev = bo->adev;
+       struct amdgpu_job *job;
+       struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
+
+       uint32_t max_bytes, byte_count;
+       uint64_t dst_offset;
+       unsigned int num_loops, num_dw;
+       unsigned int i;
+       int r;
+
+       byte_count = bo->tbo.num_pages << PAGE_SHIFT;
+       max_bytes = adev->mman.buffer_funcs->fill_max_bytes;
+       num_loops = DIV_ROUND_UP(byte_count, max_bytes);
+       num_dw = num_loops * adev->mman.buffer_funcs->fill_num_dw;
+
+       /* for IB padding */
+       while (num_dw & 0x7)
+               num_dw++;
+
+       r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, &job);
+       if (r)
+               return r;
+
+       if (resv) {
+               r = amdgpu_sync_resv(adev, &job->sync, resv,
+                               AMDGPU_FENCE_OWNER_UNDEFINED);
+               if (r) {
+                       DRM_ERROR("sync failed (%d).\n", r);
+                       goto error_free;
+               }
+       }
+
+       dst_offset = bo->tbo.mem.start << PAGE_SHIFT;
+       for (i = 0; i < num_loops; i++) {
+               uint32_t cur_size_in_bytes = min(byte_count, max_bytes);
+
+               amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data,
+                               dst_offset, cur_size_in_bytes);
+
+               dst_offset += cur_size_in_bytes;
+               byte_count -= cur_size_in_bytes;
+       }
+
        amdgpu_ring_pad_ib(ring, &job->ibs[0]);
        WARN_ON(job->ibs[0].length_dw > num_dw);
        r = amdgpu_job_submit(job, ring, &adev->mman.entity,
-                             AMDGPU_FENCE_OWNER_UNDEFINED, fence);
+                       AMDGPU_FENCE_OWNER_UNDEFINED, fence);
        if (r)
                goto error_free;
 
@@ -1395,3 +1551,8 @@ static void amdgpu_ttm_debugfs_fini(struct amdgpu_device *adev)
 
 #endif
 }
+
+u64 amdgpu_ttm_get_gtt_mem_size(struct amdgpu_device *adev)
+{
+       return ttm_get_kernel_zone_memory_size(adev->mman.mem_global_ref.object);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
new file mode 100644 (file)
index 0000000..9812c80
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef __AMDGPU_TTM_H__
+#define __AMDGPU_TTM_H__
+
+#include "gpu_scheduler.h"
+
+#define AMDGPU_PL_GDS          (TTM_PL_PRIV + 0)
+#define AMDGPU_PL_GWS          (TTM_PL_PRIV + 1)
+#define AMDGPU_PL_OA           (TTM_PL_PRIV + 2)
+
+#define AMDGPU_PL_FLAG_GDS             (TTM_PL_FLAG_PRIV << 0)
+#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;
+       struct ttm_bo_device            bdev;
+       bool                            mem_global_referenced;
+       bool                            initialized;
+
+#if defined(CONFIG_DEBUG_FS)
+       struct dentry                   *vram;
+       struct dentry                   *gtt;
+#endif
+
+       /* buffer handling */
+       const struct amdgpu_buffer_funcs        *buffer_funcs;
+       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;
+
+int amdgpu_gtt_mgr_alloc(struct ttm_mem_type_manager *man,
+                        struct ttm_buffer_object *tbo,
+                        const struct ttm_place *place,
+                        struct ttm_mem_reg *mem);
+
+int amdgpu_copy_buffer(struct amdgpu_ring *ring,
+                      uint64_t src_offset,
+                      uint64_t dst_offset,
+                      uint32_t byte_count,
+                      struct reservation_object *resv,
+                      struct fence **fence, bool direct_submit);
+int amdgpu_fill_buffer(struct amdgpu_bo *bo,
+                       uint32_t src_data,
+                       struct reservation_object *resv,
+                       struct fence **fence);
+
+int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma);
+bool amdgpu_ttm_is_bound(struct ttm_tt *ttm);
+int amdgpu_ttm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *bo_mem);
+
+#endif
index 5cc95f1..cb3d252 100644 (file)
@@ -247,40 +247,32 @@ int amdgpu_ucode_init_bo(struct amdgpu_device *adev)
        const struct common_firmware_header *header = NULL;
 
        err = amdgpu_bo_create(adev, adev->firmware.fw_size, PAGE_SIZE, true,
-                       AMDGPU_GEM_DOMAIN_GTT, 0, NULL, NULL, bo);
+                              AMDGPU_GEM_DOMAIN_GTT, 0, NULL, NULL, bo);
        if (err) {
                dev_err(adev->dev, "(%d) Firmware buffer allocate failed\n", err);
-               err = -ENOMEM;
                goto failed;
        }
 
        err = amdgpu_bo_reserve(*bo, false);
        if (err) {
-               amdgpu_bo_unref(bo);
                dev_err(adev->dev, "(%d) Firmware buffer reserve failed\n", err);
-               goto failed;
+               goto failed_reserve;
        }
 
        err = amdgpu_bo_pin(*bo, AMDGPU_GEM_DOMAIN_GTT, &fw_mc_addr);
        if (err) {
-               amdgpu_bo_unreserve(*bo);
-               amdgpu_bo_unref(bo);
                dev_err(adev->dev, "(%d) Firmware buffer pin failed\n", err);
-               goto failed;
+               goto failed_pin;
        }
 
        err = amdgpu_bo_kmap(*bo, &fw_buf_ptr);
        if (err) {
                dev_err(adev->dev, "(%d) Firmware buffer kmap failed\n", err);
-               amdgpu_bo_unpin(*bo);
-               amdgpu_bo_unreserve(*bo);
-               amdgpu_bo_unref(bo);
-               goto failed;
+               goto failed_kmap;
        }
 
        amdgpu_bo_unreserve(*bo);
 
-       fw_offset = 0;
        for (i = 0; i < AMDGPU_UCODE_ID_MAXIMUM; i++) {
                ucode = &adev->firmware.ucode[i];
                if (ucode->fw) {
@@ -290,10 +282,16 @@ int amdgpu_ucode_init_bo(struct amdgpu_device *adev)
                        fw_offset += ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE);
                }
        }
+       return 0;
 
+failed_kmap:
+       amdgpu_bo_unpin(*bo);
+failed_pin:
+       amdgpu_bo_unreserve(*bo);
+failed_reserve:
+       amdgpu_bo_unref(bo);
 failed:
-       if (err)
-               adev->firmware.smu_load = false;
+       adev->firmware.smu_load = false;
 
        return err;
 }
index 4aa993d..e3281ca 100644 (file)
@@ -201,39 +201,14 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
        bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8)
                  +  AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE
                  +  AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles;
-       r = amdgpu_bo_create(adev, bo_size, PAGE_SIZE, true,
-                            AMDGPU_GEM_DOMAIN_VRAM,
-                            AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
-                            NULL, NULL, &adev->uvd.vcpu_bo);
+       r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE,
+                                   AMDGPU_GEM_DOMAIN_VRAM, &adev->uvd.vcpu_bo,
+                                   &adev->uvd.gpu_addr, &adev->uvd.cpu_addr);
        if (r) {
                dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r);
                return r;
        }
 
-       r = amdgpu_bo_reserve(adev->uvd.vcpu_bo, false);
-       if (r) {
-               amdgpu_bo_unref(&adev->uvd.vcpu_bo);
-               dev_err(adev->dev, "(%d) failed to reserve UVD bo\n", r);
-               return r;
-       }
-
-       r = amdgpu_bo_pin(adev->uvd.vcpu_bo, AMDGPU_GEM_DOMAIN_VRAM,
-                         &adev->uvd.gpu_addr);
-       if (r) {
-               amdgpu_bo_unreserve(adev->uvd.vcpu_bo);
-               amdgpu_bo_unref(&adev->uvd.vcpu_bo);
-               dev_err(adev->dev, "(%d) UVD bo pin failed\n", r);
-               return r;
-       }
-
-       r = amdgpu_bo_kmap(adev->uvd.vcpu_bo, &adev->uvd.cpu_addr);
-       if (r) {
-               dev_err(adev->dev, "(%d) UVD map failed\n", r);
-               return r;
-       }
-
-       amdgpu_bo_unreserve(adev->uvd.vcpu_bo);
-
        ring = &adev->uvd.ring;
        rq = &ring->sched.sched_rq[AMD_SCHED_PRIORITY_NORMAL];
        r = amd_sched_entity_init(&ring->sched, &adev->uvd.entity,
@@ -274,22 +249,13 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
 
 int amdgpu_uvd_sw_fini(struct amdgpu_device *adev)
 {
-       int r;
-
        kfree(adev->uvd.saved_bo);
 
        amd_sched_entity_fini(&adev->uvd.ring.sched, &adev->uvd.entity);
 
-       if (adev->uvd.vcpu_bo) {
-               r = amdgpu_bo_reserve(adev->uvd.vcpu_bo, false);
-               if (!r) {
-                       amdgpu_bo_kunmap(adev->uvd.vcpu_bo);
-                       amdgpu_bo_unpin(adev->uvd.vcpu_bo);
-                       amdgpu_bo_unreserve(adev->uvd.vcpu_bo);
-               }
-
-               amdgpu_bo_unref(&adev->uvd.vcpu_bo);
-       }
+       amdgpu_bo_free_kernel(&adev->uvd.vcpu_bo,
+                             &adev->uvd.gpu_addr,
+                             (void **)&adev->uvd.cpu_addr);
 
        amdgpu_ring_fini(&adev->uvd.ring);
 
@@ -323,7 +289,7 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev)
        if (!adev->uvd.saved_bo)
                return -ENOMEM;
 
-       memcpy(adev->uvd.saved_bo, ptr, size);
+       memcpy_fromio(adev->uvd.saved_bo, ptr, size);
 
        return 0;
 }
@@ -340,7 +306,7 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev)
        ptr = adev->uvd.cpu_addr;
 
        if (adev->uvd.saved_bo != NULL) {
-               memcpy(ptr, adev->uvd.saved_bo, size);
+               memcpy_toio(ptr, adev->uvd.saved_bo, size);
                kfree(adev->uvd.saved_bo);
                adev->uvd.saved_bo = NULL;
        } else {
@@ -349,11 +315,11 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev)
 
                hdr = (const struct common_firmware_header *)adev->uvd.fw->data;
                offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
-               memcpy(adev->uvd.cpu_addr, (adev->uvd.fw->data) + offset,
-                       (adev->uvd.fw->size) - offset);
+               memcpy_toio(adev->uvd.cpu_addr, adev->uvd.fw->data + offset,
+                           le32_to_cpu(hdr->ucode_size_bytes));
                size -= le32_to_cpu(hdr->ucode_size_bytes);
                ptr += le32_to_cpu(hdr->ucode_size_bytes);
-               memset(ptr, 0, size);
+               memset_io(ptr, 0, size);
        }
 
        return 0;
@@ -385,12 +351,12 @@ void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
        }
 }
 
-static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *rbo)
+static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo)
 {
        int i;
-       for (i = 0; i < rbo->placement.num_placement; ++i) {
-               rbo->placements[i].fpfn = 0 >> PAGE_SHIFT;
-               rbo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
+       for (i = 0; i < abo->placement.num_placement; ++i) {
+               abo->placements[i].fpfn = 0 >> PAGE_SHIFT;
+               abo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
        }
 }
 
@@ -843,6 +809,7 @@ static int amdgpu_uvd_cs_reg(struct amdgpu_uvd_cs_ctx *ctx,
                                return r;
                        break;
                case mmUVD_ENGINE_CNTL:
+               case mmUVD_NO_OP:
                        break;
                default:
                        DRM_ERROR("Invalid reg 0x%X!\n", reg);
@@ -915,6 +882,10 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx)
                return -EINVAL;
        }
 
+       r = amdgpu_cs_sysvm_access_required(parser);
+       if (r)
+               return r;
+
        ctx.parser = parser;
        ctx.buf_sizes = buf_sizes;
        ctx.ib_idx = ib_idx;
@@ -981,8 +952,10 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo,
        ib->ptr[3] = addr >> 32;
        ib->ptr[4] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0);
        ib->ptr[5] = 0;
-       for (i = 6; i < 16; ++i)
-               ib->ptr[i] = PACKET2(0);
+       for (i = 6; i < 16; i += 2) {
+               ib->ptr[i] = PACKET0(mmUVD_NO_OP, 0);
+               ib->ptr[i+1] = 0;
+       }
        ib->length_dw = 16;
 
        if (direct) {
@@ -1114,15 +1087,9 @@ static void amdgpu_uvd_idle_work_handler(struct work_struct *work)
 {
        struct amdgpu_device *adev =
                container_of(work, struct amdgpu_device, uvd.idle_work.work);
-       unsigned i, fences, handles = 0;
-
-       fences = amdgpu_fence_count_emitted(&adev->uvd.ring);
-
-       for (i = 0; i < adev->uvd.max_handles; ++i)
-               if (atomic_read(&adev->uvd.handles[i]))
-                       ++handles;
+       unsigned fences = amdgpu_fence_count_emitted(&adev->uvd.ring);
 
-       if (fences == 0 && handles == 0) {
+       if (fences == 0) {
                if (adev->pm.dpm_enabled) {
                        amdgpu_dpm_enable_uvd(adev, false);
                } else {
index 05865ce..7fe8fd8 100644 (file)
@@ -210,6 +210,8 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
  */
 int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
 {
+       unsigned i;
+
        if (adev->vce.vcpu_bo == NULL)
                return 0;
 
@@ -217,8 +219,8 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
 
        amdgpu_bo_unref(&adev->vce.vcpu_bo);
 
-       amdgpu_ring_fini(&adev->vce.ring[0]);
-       amdgpu_ring_fini(&adev->vce.ring[1]);
+       for (i = 0; i < adev->vce.num_rings; i++)
+               amdgpu_ring_fini(&adev->vce.ring[i]);
 
        release_firmware(adev->vce.fw);
        mutex_destroy(&adev->vce.idle_mutex);
@@ -282,8 +284,8 @@ int amdgpu_vce_resume(struct amdgpu_device *adev)
 
        hdr = (const struct common_firmware_header *)adev->vce.fw->data;
        offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
-       memcpy(cpu_addr, (adev->vce.fw->data) + offset,
-               (adev->vce.fw->size) - offset);
+       memcpy_toio(cpu_addr, adev->vce.fw->data + offset,
+                   adev->vce.fw->size - offset);
 
        amdgpu_bo_kunmap(adev->vce.vcpu_bo);
 
@@ -303,9 +305,12 @@ static void amdgpu_vce_idle_work_handler(struct work_struct *work)
 {
        struct amdgpu_device *adev =
                container_of(work, struct amdgpu_device, vce.idle_work.work);
+       unsigned i, count = 0;
+
+       for (i = 0; i < adev->vce.num_rings; i++)
+               count += amdgpu_fence_count_emitted(&adev->vce.ring[i]);
 
-       if ((amdgpu_fence_count_emitted(&adev->vce.ring[0]) == 0) &&
-           (amdgpu_fence_count_emitted(&adev->vce.ring[1]) == 0)) {
+       if (count == 0) {
                if (adev->pm.dpm_enabled) {
                        amdgpu_dpm_enable_vce(adev, false);
                } else {
@@ -634,7 +639,11 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
        uint32_t allocated = 0;
        uint32_t tmp, handle = 0;
        uint32_t *size = &tmp;
-       int i, r = 0, idx = 0;
+       int i, r, idx = 0;
+
+       r = amdgpu_cs_sysvm_access_required(p);
+       if (r)
+               return r;
 
        while (idx < ib->length_dw) {
                uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
@@ -687,6 +696,21 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
                case 0x04000008: /* rdo */
                case 0x04000009: /* vui */
                case 0x05000002: /* auxiliary buffer */
+               case 0x05000009: /* clock table */
+                       break;
+
+               case 0x0500000c: /* hw config */
+                       switch (p->adev->asic_type) {
+#ifdef CONFIG_DRM_AMDGPU_CIK
+                       case CHIP_KAVERI:
+                       case CHIP_MULLINS:
+#endif
+                       case CHIP_CARRIZO:
+                               break;
+                       default:
+                               r = -EINVAL;
+                               goto out;
+                       }
                        break;
 
                case 0x03000001: /* encode */
@@ -799,6 +823,18 @@ void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
        amdgpu_ring_write(ring, VCE_CMD_END);
 }
 
+unsigned amdgpu_vce_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               4; /* amdgpu_vce_ring_emit_ib */
+}
+
+unsigned amdgpu_vce_ring_get_dma_frame_size(struct amdgpu_ring *ring)
+{
+       return
+               6; /* amdgpu_vce_ring_emit_fence  x1 no user fence */
+}
+
 /**
  * amdgpu_vce_ring_test_ring - test if VCE ring is working
  *
@@ -850,8 +886,8 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        struct fence *fence = NULL;
        long r;
 
-       /* skip vce ring1 ib test for now, since it's not reliable */
-       if (ring == &ring->adev->vce.ring[1])
+       /* skip vce ring1/2 ib test for now, since it's not reliable */
+       if (ring != &ring->adev->vce.ring[0])
                return 0;
 
        r = amdgpu_vce_get_create_msg(ring, 1, NULL);
index 63f83d0..12729d2 100644 (file)
@@ -42,5 +42,7 @@ int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring);
 int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout);
 void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring);
 void amdgpu_vce_ring_end_use(struct amdgpu_ring *ring);
+unsigned amdgpu_vce_ring_get_emit_ib_size(struct amdgpu_ring *ring);
+unsigned amdgpu_vce_ring_get_dma_frame_size(struct amdgpu_ring *ring);
 
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
new file mode 100644 (file)
index 0000000..2c37a37
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ * Author: Monk.liu@amd.com
+ */
+#ifndef AMDGPU_VIRT_H
+#define AMDGPU_VIRT_H
+
+#define AMDGPU_SRIOV_CAPS_SRIOV_VBIOS  (1 << 0) /* vBIOS is sr-iov ready */
+#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 */
+/* GPU virtualization */
+struct amdgpu_virtualization {
+       uint32_t virtual_caps;
+};
+
+#define amdgpu_sriov_enabled(adev) \
+((adev)->virtualization.virtual_caps & AMDGPU_SRIOV_CAPS_ENABLE_IOV)
+
+#define amdgpu_sriov_vf(adev) \
+((adev)->virtualization.virtual_caps & AMDGPU_SRIOV_CAPS_IS_VF)
+
+#define amdgpu_sriov_bios(adev) \
+((adev)->virtualization.virtual_caps & AMDGPU_SRIOV_CAPS_SRIOV_VBIOS)
+
+#define amdgpu_passthrough(adev) \
+((adev)->virtualization.virtual_caps & AMDGPU_PASSTHROUGH_MODE)
+
+static inline bool is_virtual_machine(void)
+{
+#ifdef CONFIG_X86
+       return boot_cpu_has(X86_FEATURE_HYPERVISOR);
+#else
+       return false;
+#endif
+}
+
+#endif
\ No newline at end of file
index 80120fa..06f2432 100644 (file)
  * SI supports 16.
  */
 
-/* Special value that no flush is necessary */
-#define AMDGPU_VM_NO_FLUSH (~0ll)
-
 /* Local structure. Encapsulate some VM table update parameters to reduce
  * the number of function parameters
  */
-struct amdgpu_vm_update_params {
+struct amdgpu_pte_update_params {
+       /* amdgpu device we do this update for */
+       struct amdgpu_device *adev;
        /* address where to copy page table entries from */
        uint64_t src;
-       /* DMA addresses to use for mapping */
-       dma_addr_t *pages_addr;
        /* indirect buffer to fill with commands */
        struct amdgpu_ib *ib;
+       /* Function which actually does the update */
+       void (*func)(struct amdgpu_pte_update_params *params, uint64_t pe,
+                    uint64_t addr, unsigned count, uint32_t incr,
+                    uint32_t flags);
+       /* indicate update pt or its shadow */
+       bool shadow;
 };
 
 /**
@@ -467,10 +470,9 @@ struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
 }
 
 /**
- * amdgpu_vm_update_pages - helper to call the right asic function
+ * amdgpu_vm_do_set_ptes - helper to call the right asic function
  *
- * @adev: amdgpu_device pointer
- * @vm_update_params: see amdgpu_vm_update_params definition
+ * @params: see amdgpu_pte_update_params definition
  * @pe: addr of the page entry
  * @addr: dst addr to write into pe
  * @count: number of page entries to update
@@ -480,32 +482,46 @@ struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
  * Traces the parameters and calls the right asic functions
  * to setup the page table using the DMA.
  */
-static void amdgpu_vm_update_pages(struct amdgpu_device *adev,
-                                  struct amdgpu_vm_update_params
-                                       *vm_update_params,
+static void amdgpu_vm_do_set_ptes(struct amdgpu_pte_update_params *params,
+                                 uint64_t pe, uint64_t addr,
+                                 unsigned count, uint32_t incr,
+                                 uint32_t flags)
+{
+       trace_amdgpu_vm_set_ptes(pe, addr, count, incr, flags);
+
+       if (count < 3) {
+               amdgpu_vm_write_pte(params->adev, params->ib, pe,
+                                   addr | flags, count, incr);
+
+       } else {
+               amdgpu_vm_set_pte_pde(params->adev, params->ib, pe, addr,
+                                     count, incr, flags);
+       }
+}
+
+/**
+ * amdgpu_vm_do_copy_ptes - copy the PTEs from the GART
+ *
+ * @params: see amdgpu_pte_update_params definition
+ * @pe: addr of the page entry
+ * @addr: dst addr to write into pe
+ * @count: number of page entries to update
+ * @incr: increase next addr by incr bytes
+ * @flags: hw access flags
+ *
+ * Traces the parameters and calls the DMA function to copy the PTEs.
+ */
+static void amdgpu_vm_do_copy_ptes(struct amdgpu_pte_update_params *params,
                                   uint64_t pe, uint64_t addr,
                                   unsigned count, uint32_t incr,
                                   uint32_t flags)
 {
-       trace_amdgpu_vm_set_page(pe, addr, count, incr, flags);
-
-       if (vm_update_params->src) {
-               amdgpu_vm_copy_pte(adev, vm_update_params->ib,
-                       pe, (vm_update_params->src + (addr >> 12) * 8), count);
+       uint64_t src = (params->src + (addr >> 12) * 8);
 
-       } else if (vm_update_params->pages_addr) {
-               amdgpu_vm_write_pte(adev, vm_update_params->ib,
-                       vm_update_params->pages_addr,
-                       pe, addr, count, incr, flags);
 
-       } else if (count < 3) {
-               amdgpu_vm_write_pte(adev, vm_update_params->ib, NULL, pe, addr,
-                                   count, incr, flags);
+       trace_amdgpu_vm_copy_ptes(pe, src, count);
 
-       } else {
-               amdgpu_vm_set_pte_pde(adev, vm_update_params->ib, pe, addr,
-                                     count, incr, flags);
-       }
+       amdgpu_vm_copy_pte(params->adev, params->ib, pe, src, count);
 }
 
 /**
@@ -523,12 +539,11 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
        struct amdgpu_ring *ring;
        struct fence *fence = NULL;
        struct amdgpu_job *job;
-       struct amdgpu_vm_update_params vm_update_params;
+       struct amdgpu_pte_update_params params;
        unsigned entries;
        uint64_t addr;
        int r;
 
-       memset(&vm_update_params, 0, sizeof(vm_update_params));
        ring = container_of(vm->entity.sched, struct amdgpu_ring, sched);
 
        r = reservation_object_reserve_shared(bo->tbo.resv);
@@ -539,6 +554,10 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
        if (r)
                goto error;
 
+       r = amdgpu_ttm_bind(&bo->tbo, &bo->tbo.mem);
+       if (r)
+               goto error;
+
        addr = amdgpu_bo_gpu_offset(bo);
        entries = amdgpu_bo_size(bo) / 8;
 
@@ -546,9 +565,10 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
        if (r)
                goto error;
 
-       vm_update_params.ib = &job->ibs[0];
-       amdgpu_vm_update_pages(adev, &vm_update_params, addr, 0, entries,
-                              0, 0);
+       memset(&params, 0, sizeof(params));
+       params.adev = adev;
+       params.ib = &job->ibs[0];
+       amdgpu_vm_do_set_ptes(&params, addr, 0, entries, 0, 0);
        amdgpu_ring_pad_ib(ring, &job->ibs[0]);
 
        WARN_ON(job->ibs[0].length_dw > 64);
@@ -577,55 +597,46 @@ error:
  * Look up the physical address of the page that the pte resolves
  * to and return the pointer for the page table entry.
  */
-uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr)
+static uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr)
 {
        uint64_t result;
 
-       if (pages_addr) {
-               /* page table offset */
-               result = pages_addr[addr >> PAGE_SHIFT];
-
-               /* in case cpu page size != gpu page size*/
-               result |= addr & (~PAGE_MASK);
+       /* page table offset */
+       result = pages_addr[addr >> PAGE_SHIFT];
 
-       } else {
-               /* No mapping required */
-               result = addr;
-       }
+       /* in case cpu page size != gpu page size*/
+       result |= addr & (~PAGE_MASK);
 
        result &= 0xFFFFFFFFFFFFF000ULL;
 
        return result;
 }
 
-/**
- * amdgpu_vm_update_pdes - make sure that page directory is valid
- *
- * @adev: amdgpu_device pointer
- * @vm: requested vm
- * @start: start of GPU address range
- * @end: end of GPU address range
- *
- * Allocates new page tables if necessary
- * and updates the page directory.
- * Returns 0 for success, error for failure.
- */
-int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
-                                   struct amdgpu_vm *vm)
+static int amdgpu_vm_update_pd_or_shadow(struct amdgpu_device *adev,
+                                        struct amdgpu_vm *vm,
+                                        bool shadow)
 {
        struct amdgpu_ring *ring;
-       struct amdgpu_bo *pd = vm->page_directory;
-       uint64_t pd_addr = amdgpu_bo_gpu_offset(pd);
+       struct amdgpu_bo *pd = shadow ? vm->page_directory->shadow :
+               vm->page_directory;
+       uint64_t pd_addr;
        uint32_t incr = AMDGPU_VM_PTE_COUNT * 8;
        uint64_t last_pde = ~0, last_pt = ~0;
        unsigned count = 0, pt_idx, ndw;
        struct amdgpu_job *job;
-       struct amdgpu_vm_update_params vm_update_params;
+       struct amdgpu_pte_update_params params;
        struct fence *fence = NULL;
 
        int r;
 
-       memset(&vm_update_params, 0, sizeof(vm_update_params));
+       if (!pd)
+               return 0;
+
+       r = amdgpu_ttm_bind(&pd->tbo, &pd->tbo.mem);
+       if (r)
+               return r;
+
+       pd_addr = amdgpu_bo_gpu_offset(pd);
        ring = container_of(vm->entity.sched, struct amdgpu_ring, sched);
 
        /* padding, etc. */
@@ -638,7 +649,9 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
        if (r)
                return r;
 
-       vm_update_params.ib = &job->ibs[0];
+       memset(&params, 0, sizeof(params));
+       params.adev = adev;
+       params.ib = &job->ibs[0];
 
        /* walk over the address space and update the page directory */
        for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) {
@@ -648,20 +661,34 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
                if (bo == NULL)
                        continue;
 
+               if (bo->shadow) {
+                       struct amdgpu_bo *shadow = bo->shadow;
+
+                       r = amdgpu_ttm_bind(&shadow->tbo, &shadow->tbo.mem);
+                       if (r)
+                               return r;
+               }
+
                pt = amdgpu_bo_gpu_offset(bo);
-               if (vm->page_tables[pt_idx].addr == pt)
-                       continue;
-               vm->page_tables[pt_idx].addr = pt;
+               if (!shadow) {
+                       if (vm->page_tables[pt_idx].addr == pt)
+                               continue;
+                       vm->page_tables[pt_idx].addr = pt;
+               } else {
+                       if (vm->page_tables[pt_idx].shadow_addr == pt)
+                               continue;
+                       vm->page_tables[pt_idx].shadow_addr = pt;
+               }
 
                pde = pd_addr + pt_idx * 8;
                if (((last_pde + 8 * count) != pde) ||
-                   ((last_pt + incr * count) != pt)) {
+                   ((last_pt + incr * count) != pt) ||
+                   (count == AMDGPU_VM_MAX_UPDATE_SIZE)) {
 
                        if (count) {
-                               amdgpu_vm_update_pages(adev, &vm_update_params,
-                                                      last_pde, last_pt,
-                                                      count, incr,
-                                                      AMDGPU_PTE_VALID);
+                               amdgpu_vm_do_set_ptes(&params, last_pde,
+                                                     last_pt, count, incr,
+                                                     AMDGPU_PTE_VALID);
                        }
 
                        count = 1;
@@ -673,15 +700,14 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
        }
 
        if (count)
-               amdgpu_vm_update_pages(adev, &vm_update_params,
-                                       last_pde, last_pt,
-                                       count, incr, AMDGPU_PTE_VALID);
+               amdgpu_vm_do_set_ptes(&params, last_pde, last_pt,
+                                     count, incr, AMDGPU_PTE_VALID);
 
-       if (vm_update_params.ib->length_dw != 0) {
-               amdgpu_ring_pad_ib(ring, vm_update_params.ib);
+       if (params.ib->length_dw != 0) {
+               amdgpu_ring_pad_ib(ring, params.ib);
                amdgpu_sync_resv(adev, &job->sync, pd->tbo.resv,
                                 AMDGPU_FENCE_OWNER_VM);
-               WARN_ON(vm_update_params.ib->length_dw > ndw);
+               WARN_ON(params.ib->length_dw > ndw);
                r = amdgpu_job_submit(job, ring, &vm->entity,
                                      AMDGPU_FENCE_OWNER_VM, &fence);
                if (r)
@@ -703,92 +729,33 @@ error_free:
        return r;
 }
 
-/**
- * amdgpu_vm_frag_ptes - add fragment information to PTEs
+/*
+ * amdgpu_vm_update_pdes - make sure that page directory is valid
  *
  * @adev: amdgpu_device pointer
- * @vm_update_params: see amdgpu_vm_update_params definition
- * @pe_start: first PTE to handle
- * @pe_end: last PTE to handle
- * @addr: addr those PTEs should point to
- * @flags: hw mapping flags
+ * @vm: requested vm
+ * @start: start of GPU address range
+ * @end: end of GPU address range
+ *
+ * Allocates new page tables if necessary
+ * and updates the page directory.
+ * Returns 0 for success, error for failure.
  */
-static void amdgpu_vm_frag_ptes(struct amdgpu_device *adev,
-                               struct amdgpu_vm_update_params
-                                       *vm_update_params,
-                               uint64_t pe_start, uint64_t pe_end,
-                               uint64_t addr, uint32_t flags)
+int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
+                                   struct amdgpu_vm *vm)
 {
-       /**
-        * The MC L1 TLB supports variable sized pages, based on a fragment
-        * field in the PTE. When this field is set to a non-zero value, page
-        * granularity is increased from 4KB to (1 << (12 + frag)). The PTE
-        * flags are considered valid for all PTEs within the fragment range
-        * and corresponding mappings are assumed to be physically contiguous.
-        *
-        * The L1 TLB can store a single PTE for the whole fragment,
-        * significantly increasing the space available for translation
-        * caching. This leads to large improvements in throughput when the
-        * TLB is under pressure.
-        *
-        * The L2 TLB distributes small and large fragments into two
-        * asymmetric partitions. The large fragment cache is significantly
-        * larger. Thus, we try to use large fragments wherever possible.
-        * Userspace can support this by aligning virtual base address and
-        * allocation size to the fragment size.
-        */
-
-       /* SI and newer are optimized for 64KB */
-       uint64_t frag_flags = AMDGPU_PTE_FRAG_64KB;
-       uint64_t frag_align = 0x80;
-
-       uint64_t frag_start = ALIGN(pe_start, frag_align);
-       uint64_t frag_end = pe_end & ~(frag_align - 1);
-
-       unsigned count;
-
-       /* Abort early if there isn't anything to do */
-       if (pe_start == pe_end)
-               return;
-
-       /* system pages are non continuously */
-       if (vm_update_params->src || vm_update_params->pages_addr ||
-               !(flags & AMDGPU_PTE_VALID) || (frag_start >= frag_end)) {
-
-               count = (pe_end - pe_start) / 8;
-               amdgpu_vm_update_pages(adev, vm_update_params, pe_start,
-                                      addr, count, AMDGPU_GPU_PAGE_SIZE,
-                                      flags);
-               return;
-       }
-
-       /* handle the 4K area at the beginning */
-       if (pe_start != frag_start) {
-               count = (frag_start - pe_start) / 8;
-               amdgpu_vm_update_pages(adev, vm_update_params, pe_start, addr,
-                                      count, AMDGPU_GPU_PAGE_SIZE, flags);
-               addr += AMDGPU_GPU_PAGE_SIZE * count;
-       }
-
-       /* handle the area in the middle */
-       count = (frag_end - frag_start) / 8;
-       amdgpu_vm_update_pages(adev, vm_update_params, frag_start, addr, count,
-                              AMDGPU_GPU_PAGE_SIZE, flags | frag_flags);
+       int r;
 
-       /* handle the 4K area at the end */
-       if (frag_end != pe_end) {
-               addr += AMDGPU_GPU_PAGE_SIZE * count;
-               count = (pe_end - frag_end) / 8;
-               amdgpu_vm_update_pages(adev, vm_update_params, frag_end, addr,
-                                      count, AMDGPU_GPU_PAGE_SIZE, flags);
-       }
+       r = amdgpu_vm_update_pd_or_shadow(adev, vm, true);
+       if (r)
+               return r;
+       return amdgpu_vm_update_pd_or_shadow(adev, vm, false);
 }
 
 /**
  * amdgpu_vm_update_ptes - make sure that page tables are valid
  *
- * @adev: amdgpu_device pointer
- * @vm_update_params: see amdgpu_vm_update_params definition
+ * @params: see amdgpu_pte_update_params definition
  * @vm: requested vm
  * @start: start of GPU address range
  * @end: end of GPU address range
@@ -797,16 +764,14 @@ static void amdgpu_vm_frag_ptes(struct amdgpu_device *adev,
  *
  * Update the page tables in the range @start - @end.
  */
-static void amdgpu_vm_update_ptes(struct amdgpu_device *adev,
-                                 struct amdgpu_vm_update_params
-                                       *vm_update_params,
+static void amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
                                  struct amdgpu_vm *vm,
                                  uint64_t start, uint64_t end,
                                  uint64_t dst, uint32_t flags)
 {
        const uint64_t mask = AMDGPU_VM_PTE_COUNT - 1;
 
-       uint64_t cur_pe_start, cur_pe_end, cur_dst;
+       uint64_t cur_pe_start, cur_nptes, cur_dst;
        uint64_t addr; /* next GPU address to be updated */
        uint64_t pt_idx;
        struct amdgpu_bo *pt;
@@ -817,7 +782,11 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev,
        addr = start;
        pt_idx = addr >> amdgpu_vm_block_size;
        pt = vm->page_tables[pt_idx].entry.robj;
-
+       if (params->shadow) {
+               if (!pt->shadow)
+                       return;
+               pt = vm->page_tables[pt_idx].entry.robj->shadow;
+       }
        if ((addr & ~mask) == (end & ~mask))
                nptes = end - addr;
        else
@@ -825,7 +794,7 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev,
 
        cur_pe_start = amdgpu_bo_gpu_offset(pt);
        cur_pe_start += (addr & mask) * 8;
-       cur_pe_end = cur_pe_start + 8 * nptes;
+       cur_nptes = nptes;
        cur_dst = dst;
 
        /* for next ptb*/
@@ -836,6 +805,11 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev,
        while (addr < end) {
                pt_idx = addr >> amdgpu_vm_block_size;
                pt = vm->page_tables[pt_idx].entry.robj;
+               if (params->shadow) {
+                       if (!pt->shadow)
+                               return;
+                       pt = vm->page_tables[pt_idx].entry.robj->shadow;
+               }
 
                if ((addr & ~mask) == (end & ~mask))
                        nptes = end - addr;
@@ -845,19 +819,19 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev,
                next_pe_start = amdgpu_bo_gpu_offset(pt);
                next_pe_start += (addr & mask) * 8;
 
-               if (cur_pe_end == next_pe_start) {
+               if ((cur_pe_start + 8 * cur_nptes) == next_pe_start &&
+                   ((cur_nptes + nptes) <= AMDGPU_VM_MAX_UPDATE_SIZE)) {
                        /* The next ptb is consecutive to current ptb.
-                        * Don't call amdgpu_vm_frag_ptes now.
+                        * Don't call the update function now.
                         * Will update two ptbs together in future.
                        */
-                       cur_pe_end += 8 * nptes;
+                       cur_nptes += nptes;
                } else {
-                       amdgpu_vm_frag_ptes(adev, vm_update_params,
-                                           cur_pe_start, cur_pe_end,
-                                           cur_dst, flags);
+                       params->func(params, cur_pe_start, cur_dst, cur_nptes,
+                                    AMDGPU_GPU_PAGE_SIZE, flags);
 
                        cur_pe_start = next_pe_start;
-                       cur_pe_end = next_pe_start + 8 * nptes;
+                       cur_nptes = nptes;
                        cur_dst = dst;
                }
 
@@ -866,8 +840,75 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev,
                dst += nptes * AMDGPU_GPU_PAGE_SIZE;
        }
 
-       amdgpu_vm_frag_ptes(adev, vm_update_params, cur_pe_start,
-                           cur_pe_end, cur_dst, flags);
+       params->func(params, cur_pe_start, cur_dst, cur_nptes,
+                    AMDGPU_GPU_PAGE_SIZE, flags);
+}
+
+/*
+ * amdgpu_vm_frag_ptes - add fragment information to PTEs
+ *
+ * @params: see amdgpu_pte_update_params definition
+ * @vm: requested vm
+ * @start: first PTE to handle
+ * @end: last PTE to handle
+ * @dst: addr those PTEs should point to
+ * @flags: hw mapping flags
+ */
+static void amdgpu_vm_frag_ptes(struct amdgpu_pte_update_params        *params,
+                               struct amdgpu_vm *vm,
+                               uint64_t start, uint64_t end,
+                               uint64_t dst, uint32_t flags)
+{
+       /**
+        * The MC L1 TLB supports variable sized pages, based on a fragment
+        * field in the PTE. When this field is set to a non-zero value, page
+        * granularity is increased from 4KB to (1 << (12 + frag)). The PTE
+        * flags are considered valid for all PTEs within the fragment range
+        * and corresponding mappings are assumed to be physically contiguous.
+        *
+        * The L1 TLB can store a single PTE for the whole fragment,
+        * significantly increasing the space available for translation
+        * caching. This leads to large improvements in throughput when the
+        * TLB is under pressure.
+        *
+        * The L2 TLB distributes small and large fragments into two
+        * asymmetric partitions. The large fragment cache is significantly
+        * larger. Thus, we try to use large fragments wherever possible.
+        * Userspace can support this by aligning virtual base address and
+        * allocation size to the fragment size.
+        */
+
+       /* SI and newer are optimized for 64KB */
+       uint64_t frag_flags = AMDGPU_PTE_FRAG(AMDGPU_LOG2_PAGES_PER_FRAG);
+       uint64_t frag_align = 1 << AMDGPU_LOG2_PAGES_PER_FRAG;
+
+       uint64_t frag_start = ALIGN(start, frag_align);
+       uint64_t frag_end = end & ~(frag_align - 1);
+
+       /* system pages are non continuously */
+       if (params->src || !(flags & AMDGPU_PTE_VALID) ||
+           (frag_start >= frag_end)) {
+
+               amdgpu_vm_update_ptes(params, vm, start, end, dst, flags);
+               return;
+       }
+
+       /* handle the 4K area at the beginning */
+       if (start != frag_start) {
+               amdgpu_vm_update_ptes(params, vm, start, frag_start,
+                                     dst, flags);
+               dst += (frag_start - start) * AMDGPU_GPU_PAGE_SIZE;
+       }
+
+       /* handle the area in the middle */
+       amdgpu_vm_update_ptes(params, vm, frag_start, frag_end, dst,
+                             flags | frag_flags);
+
+       /* handle the 4K area at the end */
+       if (frag_end != end) {
+               dst += (frag_end - frag_start) * AMDGPU_GPU_PAGE_SIZE;
+               amdgpu_vm_update_ptes(params, vm, frag_end, end, dst, flags);
+       }
 }
 
 /**
@@ -900,14 +941,19 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
        void *owner = AMDGPU_FENCE_OWNER_VM;
        unsigned nptes, ncmds, ndw;
        struct amdgpu_job *job;
-       struct amdgpu_vm_update_params vm_update_params;
+       struct amdgpu_pte_update_params params;
        struct fence *f = NULL;
        int r;
 
+       memset(&params, 0, sizeof(params));
+       params.adev = adev;
+       params.src = src;
+
        ring = container_of(vm->entity.sched, struct amdgpu_ring, sched);
-       memset(&vm_update_params, 0, sizeof(vm_update_params));
-       vm_update_params.src = src;
-       vm_update_params.pages_addr = pages_addr;
+
+       memset(&params, 0, sizeof(params));
+       params.adev = adev;
+       params.src = src;
 
        /* sync to everything on unmapping */
        if (!(flags & AMDGPU_PTE_VALID))
@@ -924,30 +970,53 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
        /* padding, etc. */
        ndw = 64;
 
-       if (vm_update_params.src) {
+       if (src) {
                /* only copy commands needed */
                ndw += ncmds * 7;
 
-       } else if (vm_update_params.pages_addr) {
-               /* header for write data commands */
-               ndw += ncmds * 4;
+               params.func = amdgpu_vm_do_copy_ptes;
+
+       } else if (pages_addr) {
+               /* copy commands needed */
+               ndw += ncmds * 7;
 
-               /* body of write data command */
+               /* and also PTEs */
                ndw += nptes * 2;
 
+               params.func = amdgpu_vm_do_copy_ptes;
+
        } else {
                /* set page commands needed */
                ndw += ncmds * 10;
 
                /* two extra commands for begin/end of fragment */
                ndw += 2 * 10;
+
+               params.func = amdgpu_vm_do_set_ptes;
        }
 
        r = amdgpu_job_alloc_with_ib(adev, ndw * 4, &job);
        if (r)
                return r;
 
-       vm_update_params.ib = &job->ibs[0];
+       params.ib = &job->ibs[0];
+
+       if (!src && pages_addr) {
+               uint64_t *pte;
+               unsigned i;
+
+               /* Put the PTEs at the end of the IB. */
+               i = ndw - nptes * 2;
+               pte= (uint64_t *)&(job->ibs->ptr[i]);
+               params.src = job->ibs->gpu_addr + i * 4;
+
+               for (i = 0; i < nptes; ++i) {
+                       pte[i] = amdgpu_vm_map_gart(pages_addr, addr + i *
+                                                   AMDGPU_GPU_PAGE_SIZE);
+                       pte[i] |= flags;
+               }
+               addr = 0;
+       }
 
        r = amdgpu_sync_fence(adev, &job->sync, exclusive);
        if (r)
@@ -962,11 +1031,13 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
        if (r)
                goto error_free;
 
-       amdgpu_vm_update_ptes(adev, &vm_update_params, vm, start,
-                             last + 1, addr, flags);
+       params.shadow = true;
+       amdgpu_vm_frag_ptes(&params, vm, start, last + 1, addr, flags);
+       params.shadow = false;
+       amdgpu_vm_frag_ptes(&params, vm, start, last + 1, addr, flags);
 
-       amdgpu_ring_pad_ib(ring, vm_update_params.ib);
-       WARN_ON(vm_update_params.ib->length_dw > ndw);
+       amdgpu_ring_pad_ib(ring, params.ib);
+       WARN_ON(params.ib->length_dw > ndw);
        r = amdgpu_job_submit(job, ring, &vm->entity,
                              AMDGPU_FENCE_OWNER_VM, &f);
        if (r)
@@ -1062,28 +1133,32 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev,
  *
  * @adev: amdgpu_device pointer
  * @bo_va: requested BO and VM object
- * @mem: ttm mem
+ * @clear: if true clear the entries
  *
  * Fill in the page table entries for @bo_va.
  * Returns 0 for success, -EINVAL for failure.
- *
- * Object have to be reserved and mutex must be locked!
  */
 int amdgpu_vm_bo_update(struct amdgpu_device *adev,
                        struct amdgpu_bo_va *bo_va,
-                       struct ttm_mem_reg *mem)
+                       bool clear)
 {
        struct amdgpu_vm *vm = bo_va->vm;
        struct amdgpu_bo_va_mapping *mapping;
        dma_addr_t *pages_addr = NULL;
        uint32_t gtt_flags, flags;
+       struct ttm_mem_reg *mem;
        struct fence *exclusive;
        uint64_t addr;
        int r;
 
-       if (mem) {
+       if (clear) {
+               mem = NULL;
+               addr = 0;
+               exclusive = NULL;
+       } else {
                struct ttm_dma_tt *ttm;
 
+               mem = &bo_va->bo->tbo.mem;
                addr = (u64)mem->start << PAGE_SHIFT;
                switch (mem->mem_type) {
                case TTM_PL_TT:
@@ -1101,13 +1176,11 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev,
                }
 
                exclusive = reservation_object_get_excl(bo_va->bo->tbo.resv);
-       } else {
-               addr = 0;
-               exclusive = NULL;
        }
 
        flags = amdgpu_ttm_tt_pte_flags(adev, bo_va->bo->tbo.ttm, mem);
-       gtt_flags = (adev == bo_va->bo->adev) ? flags : 0;
+       gtt_flags = (amdgpu_ttm_is_bound(bo_va->bo->tbo.ttm) &&
+               adev == bo_va->bo->adev) ? flags : 0;
 
        spin_lock(&vm->status_lock);
        if (!list_empty(&bo_va->vm_status))
@@ -1134,7 +1207,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev,
        spin_lock(&vm->status_lock);
        list_splice_init(&bo_va->invalids, &bo_va->valids);
        list_del_init(&bo_va->vm_status);
-       if (!mem)
+       if (clear)
                list_add(&bo_va->vm_status, &vm->cleared);
        spin_unlock(&vm->status_lock);
 
@@ -1197,7 +1270,7 @@ int amdgpu_vm_clear_invalids(struct amdgpu_device *adev,
                        struct amdgpu_bo_va, vm_status);
                spin_unlock(&vm->status_lock);
 
-               r = amdgpu_vm_bo_update(adev, bo_va, NULL);
+               r = amdgpu_vm_bo_update(adev, bo_va, true);
                if (r)
                        return r;
 
@@ -1342,7 +1415,8 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
                r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8,
                                     AMDGPU_GPU_PAGE_SIZE, true,
                                     AMDGPU_GEM_DOMAIN_VRAM,
-                                    AMDGPU_GEM_CREATE_NO_CPU_ACCESS,
+                                    AMDGPU_GEM_CREATE_NO_CPU_ACCESS |
+                                    AMDGPU_GEM_CREATE_SHADOW,
                                     NULL, resv, &pt);
                if (r)
                        goto error_free;
@@ -1354,10 +1428,20 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
 
                r = amdgpu_vm_clear_bo(adev, vm, pt);
                if (r) {
+                       amdgpu_bo_unref(&pt->shadow);
                        amdgpu_bo_unref(&pt);
                        goto error_free;
                }
 
+               if (pt->shadow) {
+                       r = amdgpu_vm_clear_bo(adev, vm, pt->shadow);
+                       if (r) {
+                               amdgpu_bo_unref(&pt->shadow);
+                               amdgpu_bo_unref(&pt);
+                               goto error_free;
+                       }
+               }
+
                entry->robj = pt;
                entry->priority = 0;
                entry->tv.bo = &entry->robj->tbo;
@@ -1541,7 +1625,8 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
 
        r = amdgpu_bo_create(adev, pd_size, align, true,
                             AMDGPU_GEM_DOMAIN_VRAM,
-                            AMDGPU_GEM_CREATE_NO_CPU_ACCESS,
+                            AMDGPU_GEM_CREATE_NO_CPU_ACCESS |
+                            AMDGPU_GEM_CREATE_SHADOW,
                             NULL, NULL, &vm->page_directory);
        if (r)
                goto error_free_sched_entity;
@@ -1551,14 +1636,25 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
                goto error_free_page_directory;
 
        r = amdgpu_vm_clear_bo(adev, vm, vm->page_directory);
-       amdgpu_bo_unreserve(vm->page_directory);
        if (r)
-               goto error_free_page_directory;
+               goto error_unreserve;
+
+       if (vm->page_directory->shadow) {
+               r = amdgpu_vm_clear_bo(adev, vm, vm->page_directory->shadow);
+               if (r)
+                       goto error_unreserve;
+       }
+
        vm->last_eviction_counter = atomic64_read(&adev->num_evictions);
+       amdgpu_bo_unreserve(vm->page_directory);
 
        return 0;
 
+error_unreserve:
+       amdgpu_bo_unreserve(vm->page_directory);
+
 error_free_page_directory:
+       amdgpu_bo_unref(&vm->page_directory->shadow);
        amdgpu_bo_unref(&vm->page_directory);
        vm->page_directory = NULL;
 
@@ -1600,10 +1696,18 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
                kfree(mapping);
        }
 
-       for (i = 0; i < amdgpu_vm_num_pdes(adev); i++)
-               amdgpu_bo_unref(&vm->page_tables[i].entry.robj);
+       for (i = 0; i < amdgpu_vm_num_pdes(adev); i++) {
+               struct amdgpu_bo *pt = vm->page_tables[i].entry.robj;
+
+               if (!pt)
+                       continue;
+
+               amdgpu_bo_unref(&pt->shadow);
+               amdgpu_bo_unref(&pt);
+       }
        drm_free_large(vm->page_tables);
 
+       amdgpu_bo_unref(&vm->page_directory->shadow);
        amdgpu_bo_unref(&vm->page_directory);
        fence_put(vm->page_directory_fence);
 }
index 49a39b1..f7d236f 100644 (file)
@@ -497,7 +497,13 @@ void amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev,
                         * SetPixelClock provides the dividers
                         */
                        args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
-                       args.v6.ucPpll = ATOM_EXT_PLL1;
+                       if (adev->asic_type == CHIP_TAHITI ||
+                           adev->asic_type == CHIP_PITCAIRN ||
+                           adev->asic_type == CHIP_VERDE ||
+                           adev->asic_type == CHIP_OLAND)
+                               args.v6.ucPpll = ATOM_PPLL0;
+                       else
+                               args.v6.ucPpll = ATOM_EXT_PLL1;
                        break;
                default:
                        DRM_ERROR("Unknown table version %d %d\n", frev, crev);
index 7f85c2c..f81068b 100644 (file)
@@ -88,7 +88,6 @@ static int amdgpu_atombios_dp_process_aux_ch(struct amdgpu_i2c_chan *chan,
 
        /* timeout */
        if (args.v2.ucReplyStatus == 1) {
-               DRM_DEBUG_KMS("dp_aux_ch timeout\n");
                r = -ETIMEDOUT;
                goto done;
        }
@@ -339,22 +338,21 @@ int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector)
 {
        struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
        u8 msg[DP_DPCD_SIZE];
-       int ret, i;
+       int ret;
 
-       for (i = 0; i < 7; i++) {
-               ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_DPCD_REV, msg,
-                                      DP_DPCD_SIZE);
-               if (ret == DP_DPCD_SIZE) {
-                       memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
+       ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_DPCD_REV,
+                              msg, DP_DPCD_SIZE);
+       if (ret == DP_DPCD_SIZE) {
+               memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
 
-                       DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd),
-                                     dig_connector->dpcd);
+               DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd),
+                             dig_connector->dpcd);
 
-                       amdgpu_atombios_dp_probe_oui(amdgpu_connector);
+               amdgpu_atombios_dp_probe_oui(amdgpu_connector);
 
-                       return 0;
-               }
+               return 0;
        }
+
        dig_connector->dpcd[0] = 0;
        return -EINVAL;
 }
index bc56c8a..b374653 100644 (file)
@@ -27,6 +27,7 @@
 #include "amdgpu.h"
 #include "atom.h"
 #include "amdgpu_atombios.h"
+#include "atombios_i2c.h"
 
 #define TARGET_HW_I2C_CLOCK 50
 
index a5c94b4..1d8c375 100644 (file)
@@ -5396,7 +5396,7 @@ static void ci_dpm_disable(struct amdgpu_device *adev)
        amdgpu_irq_put(adev, &adev->pm.dpm.thermal.irq,
                       AMDGPU_THERMAL_IRQ_HIGH_TO_LOW);
 
-       ci_dpm_powergate_uvd(adev, false);
+       ci_dpm_powergate_uvd(adev, true);
 
        if (!amdgpu_ci_is_smc_running(adev))
                return;
@@ -5874,7 +5874,10 @@ static int ci_dpm_init(struct amdgpu_device *adev)
        pi->pcie_dpm_key_disabled = 0;
        pi->thermal_sclk_dpm_enabled = 0;
 
-       pi->caps_sclk_ds = true;
+       if (amdgpu_sclk_deep_sleep_en)
+               pi->caps_sclk_ds = true;
+       else
+               pi->caps_sclk_ds = false;
 
        pi->mclk_strobe_mode_threshold = 40000;
        pi->mclk_stutter_mode_threshold = 40000;
@@ -6033,7 +6036,7 @@ static int ci_dpm_init(struct amdgpu_device *adev)
 
        pi->caps_dynamic_ac_timing = true;
 
-       pi->uvd_power_gated = false;
+       pi->uvd_power_gated = true;
 
        /* make sure dc limits are valid */
        if ((adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) ||
@@ -6176,8 +6179,6 @@ static int ci_dpm_late_init(void *handle)
        if (ret)
                return ret;
 
-       ci_dpm_powergate_uvd(adev, true);
-
        return 0;
 }
 
index 4efc901..a845b6a 100644 (file)
@@ -67,6 +67,7 @@
 
 #include "amdgpu_amdkfd.h"
 #include "amdgpu_powerplay.h"
+#include "dce_virtual.h"
 
 /*
  * Indirect registers accessor
@@ -962,12 +963,6 @@ static bool cik_read_bios_from_rom(struct amdgpu_device *adev,
        return true;
 }
 
-static u32 cik_get_virtual_caps(struct amdgpu_device *adev)
-{
-       /* CIK does not support SR-IOV */
-       return 0;
-}
-
 static const struct amdgpu_allowed_register_entry cik_allowed_read_registers[] = {
        {mmGRBM_STATUS, false},
        {mmGB_ADDR_CONFIG, false},
@@ -1640,6 +1635,12 @@ static uint32_t cik_get_rev_id(struct amdgpu_device *adev)
                >> CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT;
 }
 
+static void cik_detect_hw_virtualization(struct amdgpu_device *adev)
+{
+       if (is_virtual_machine()) /* passthrough mode */
+               adev->virtualization.virtual_caps |= AMDGPU_PASSTHROUGH_MODE;
+}
+
 static const struct amdgpu_ip_block_version bonaire_ip_blocks[] =
 {
        /* ORDER MATTERS! */
@@ -1708,6 +1709,74 @@ static const struct amdgpu_ip_block_version bonaire_ip_blocks[] =
        },
 };
 
+static const struct amdgpu_ip_block_version bonaire_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gmc_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 8,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 7,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &gfx_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_sdma_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 4,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &uvd_v4_2_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vce_v2_0_ip_funcs,
+       },
+};
+
 static const struct amdgpu_ip_block_version hawaii_ip_blocks[] =
 {
        /* ORDER MATTERS! */
@@ -1776,6 +1845,74 @@ static const struct amdgpu_ip_block_version hawaii_ip_blocks[] =
        },
 };
 
+static const struct amdgpu_ip_block_version hawaii_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gmc_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 8,
+               .minor = 5,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 7,
+               .minor = 3,
+               .rev = 0,
+               .funcs = &gfx_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_sdma_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 4,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &uvd_v4_2_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vce_v2_0_ip_funcs,
+       },
+};
+
 static const struct amdgpu_ip_block_version kabini_ip_blocks[] =
 {
        /* ORDER MATTERS! */
@@ -1844,6 +1981,74 @@ static const struct amdgpu_ip_block_version kabini_ip_blocks[] =
        },
 };
 
+static const struct amdgpu_ip_block_version kabini_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gmc_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 8,
+               .minor = 3,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 7,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &gfx_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_sdma_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 4,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &uvd_v4_2_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vce_v2_0_ip_funcs,
+       },
+};
+
 static const struct amdgpu_ip_block_version mullins_ip_blocks[] =
 {
        /* ORDER MATTERS! */
@@ -1912,6 +2117,74 @@ static const struct amdgpu_ip_block_version mullins_ip_blocks[] =
        },
 };
 
+static const struct amdgpu_ip_block_version mullins_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gmc_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 8,
+               .minor = 3,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 7,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &gfx_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_sdma_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 4,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &uvd_v4_2_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vce_v2_0_ip_funcs,
+       },
+};
+
 static const struct amdgpu_ip_block_version kaveri_ip_blocks[] =
 {
        /* ORDER MATTERS! */
@@ -1980,32 +2253,128 @@ static const struct amdgpu_ip_block_version kaveri_ip_blocks[] =
        },
 };
 
+static const struct amdgpu_ip_block_version kaveri_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gmc_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 7,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 8,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 7,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &gfx_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cik_sdma_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 4,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &uvd_v4_2_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vce_v2_0_ip_funcs,
+       },
+};
+
 int cik_set_ip_blocks(struct amdgpu_device *adev)
 {
-       switch (adev->asic_type) {
-       case CHIP_BONAIRE:
-               adev->ip_blocks = bonaire_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(bonaire_ip_blocks);
-               break;
-       case CHIP_HAWAII:
-               adev->ip_blocks = hawaii_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(hawaii_ip_blocks);
-               break;
-       case CHIP_KAVERI:
-               adev->ip_blocks = kaveri_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(kaveri_ip_blocks);
-               break;
-       case CHIP_KABINI:
-               adev->ip_blocks = kabini_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(kabini_ip_blocks);
-               break;
-       case CHIP_MULLINS:
-               adev->ip_blocks = mullins_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(mullins_ip_blocks);
-               break;
-       default:
-               /* FIXME: not supported yet */
-               return -EINVAL;
+       if (adev->enable_virtual_display) {
+               switch (adev->asic_type) {
+               case CHIP_BONAIRE:
+                       adev->ip_blocks = bonaire_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(bonaire_ip_blocks_vd);
+                       break;
+               case CHIP_HAWAII:
+                       adev->ip_blocks = hawaii_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(hawaii_ip_blocks_vd);
+                       break;
+               case CHIP_KAVERI:
+                       adev->ip_blocks = kaveri_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(kaveri_ip_blocks_vd);
+                       break;
+               case CHIP_KABINI:
+                       adev->ip_blocks = kabini_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(kabini_ip_blocks_vd);
+                       break;
+               case CHIP_MULLINS:
+                       adev->ip_blocks = mullins_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(mullins_ip_blocks_vd);
+                       break;
+               default:
+                       /* FIXME: not supported yet */
+                       return -EINVAL;
+               }
+       } else {
+               switch (adev->asic_type) {
+               case CHIP_BONAIRE:
+                       adev->ip_blocks = bonaire_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(bonaire_ip_blocks);
+                       break;
+               case CHIP_HAWAII:
+                       adev->ip_blocks = hawaii_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(hawaii_ip_blocks);
+                       break;
+               case CHIP_KAVERI:
+                       adev->ip_blocks = kaveri_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(kaveri_ip_blocks);
+                       break;
+               case CHIP_KABINI:
+                       adev->ip_blocks = kabini_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(kabini_ip_blocks);
+                       break;
+               case CHIP_MULLINS:
+                       adev->ip_blocks = mullins_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(mullins_ip_blocks);
+                       break;
+               default:
+                       /* FIXME: not supported yet */
+                       return -EINVAL;
+               }
        }
 
        return 0;
@@ -2015,13 +2384,13 @@ 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,
        .get_xclk = &cik_get_xclk,
        .set_uvd_clocks = &cik_set_uvd_clocks,
        .set_vce_clocks = &cik_set_vce_clocks,
-       .get_virtual_caps = &cik_get_virtual_caps,
 };
 
 static int cik_common_early_init(void *handle)
index 77fdd99..cb952ac 100644 (file)
@@ -695,24 +695,16 @@ static void cik_sdma_vm_copy_pte(struct amdgpu_ib *ib,
                                 uint64_t pe, uint64_t src,
                                 unsigned count)
 {
-       while (count) {
-               unsigned bytes = count * 8;
-               if (bytes > 0x1FFFF8)
-                       bytes = 0x1FFFF8;
-
-               ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY,
-                       SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
-               ib->ptr[ib->length_dw++] = bytes;
-               ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */
-               ib->ptr[ib->length_dw++] = lower_32_bits(src);
-               ib->ptr[ib->length_dw++] = upper_32_bits(src);
-               ib->ptr[ib->length_dw++] = lower_32_bits(pe);
-               ib->ptr[ib->length_dw++] = upper_32_bits(pe);
-
-               pe += bytes;
-               src += bytes;
-               count -= bytes / 8;
-       }
+       unsigned bytes = count * 8;
+
+       ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY,
+               SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+       ib->ptr[ib->length_dw++] = bytes;
+       ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */
+       ib->ptr[ib->length_dw++] = lower_32_bits(src);
+       ib->ptr[ib->length_dw++] = upper_32_bits(src);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe);
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
 }
 
 /**
@@ -720,39 +712,27 @@ static void cik_sdma_vm_copy_pte(struct amdgpu_ib *ib,
  *
  * @ib: indirect buffer to fill with commands
  * @pe: addr of the page entry
- * @addr: dst addr to write into pe
+ * @value: dst addr to write into pe
  * @count: number of page entries to update
  * @incr: increase next addr by incr bytes
- * @flags: access flags
  *
  * Update PTEs by writing them manually using sDMA (CIK).
  */
-static void cik_sdma_vm_write_pte(struct amdgpu_ib *ib,
-                                 const dma_addr_t *pages_addr, uint64_t pe,
-                                 uint64_t addr, unsigned count,
-                                 uint32_t incr, uint32_t flags)
+static void cik_sdma_vm_write_pte(struct amdgpu_ib *ib, uint64_t pe,
+                                 uint64_t value, unsigned count,
+                                 uint32_t incr)
 {
-       uint64_t value;
-       unsigned ndw;
-
-       while (count) {
-               ndw = count * 2;
-               if (ndw > 0xFFFFE)
-                       ndw = 0xFFFFE;
-
-               /* for non-physically contiguous pages (system) */
-               ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE,
-                       SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
-               ib->ptr[ib->length_dw++] = pe;
-               ib->ptr[ib->length_dw++] = upper_32_bits(pe);
-               ib->ptr[ib->length_dw++] = ndw;
-               for (; ndw > 0; ndw -= 2, --count, pe += 8) {
-                       value = amdgpu_vm_map_gart(pages_addr, addr);
-                       addr += incr;
-                       value |= flags;
-                       ib->ptr[ib->length_dw++] = value;
-                       ib->ptr[ib->length_dw++] = upper_32_bits(value);
-               }
+       unsigned ndw = count * 2;
+
+       ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE,
+               SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe);
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+       ib->ptr[ib->length_dw++] = ndw;
+       for (; ndw > 0; ndw -= 2) {
+               ib->ptr[ib->length_dw++] = lower_32_bits(value);
+               ib->ptr[ib->length_dw++] = upper_32_bits(value);
+               value += incr;
        }
 }
 
@@ -768,40 +748,21 @@ static void cik_sdma_vm_write_pte(struct amdgpu_ib *ib,
  *
  * Update the page tables using sDMA (CIK).
  */
-static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib,
-                                   uint64_t pe,
+static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
                                    uint64_t addr, unsigned count,
                                    uint32_t incr, uint32_t flags)
 {
-       uint64_t value;
-       unsigned ndw;
-
-       while (count) {
-               ndw = count;
-               if (ndw > 0x7FFFF)
-                       ndw = 0x7FFFF;
-
-               if (flags & AMDGPU_PTE_VALID)
-                       value = addr;
-               else
-                       value = 0;
-
-               /* for physically contiguous pages (vram) */
-               ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0);
-               ib->ptr[ib->length_dw++] = pe; /* dst addr */
-               ib->ptr[ib->length_dw++] = upper_32_bits(pe);
-               ib->ptr[ib->length_dw++] = flags; /* mask */
-               ib->ptr[ib->length_dw++] = 0;
-               ib->ptr[ib->length_dw++] = value; /* value */
-               ib->ptr[ib->length_dw++] = upper_32_bits(value);
-               ib->ptr[ib->length_dw++] = incr; /* increment size */
-               ib->ptr[ib->length_dw++] = 0;
-               ib->ptr[ib->length_dw++] = ndw; /* number of entries */
-
-               pe += ndw * 8;
-               addr += ndw * incr;
-               count -= ndw;
-       }
+       /* for physically contiguous pages (vram) */
+       ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe); /* dst addr */
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+       ib->ptr[ib->length_dw++] = flags; /* mask */
+       ib->ptr[ib->length_dw++] = 0;
+       ib->ptr[ib->length_dw++] = lower_32_bits(addr); /* value */
+       ib->ptr[ib->length_dw++] = upper_32_bits(addr);
+       ib->ptr[ib->length_dw++] = incr; /* increment size */
+       ib->ptr[ib->length_dw++] = 0;
+       ib->ptr[ib->length_dw++] = count; /* number of entries */
 }
 
 /**
@@ -887,6 +848,22 @@ static void cik_sdma_ring_emit_vm_flush(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */
 }
 
+static unsigned cik_sdma_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               7 + 4; /* cik_sdma_ring_emit_ib */
+}
+
+static unsigned cik_sdma_ring_get_dma_frame_size(struct amdgpu_ring *ring)
+{
+       return
+               6 + /* cik_sdma_ring_emit_hdp_flush */
+               3 + /* cik_sdma_ring_emit_hdp_invalidate */
+               6 + /* cik_sdma_ring_emit_pipeline_sync */
+               12 + /* cik_sdma_ring_emit_vm_flush */
+               9 + 9 + 9; /* cik_sdma_ring_emit_fence x3 for user fence, vm fence */
+}
+
 static void cik_enable_sdma_mgcg(struct amdgpu_device *adev,
                                 bool enable)
 {
@@ -1262,6 +1239,8 @@ static const struct amdgpu_ring_funcs cik_sdma_ring_funcs = {
        .test_ib = cik_sdma_ring_test_ib,
        .insert_nop = cik_sdma_ring_insert_nop,
        .pad_ib = cik_sdma_ring_pad_ib,
+       .get_emit_ib_size = cik_sdma_ring_get_emit_ib_size,
+       .get_dma_frame_size = cik_sdma_ring_get_dma_frame_size,
 };
 
 static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev)
index c4f6f00..8659852 100644 (file)
@@ -562,4 +562,40 @@ enum {
        MTYPE_NONCACHED = 3
 };
 
+/* mmPA_SC_RASTER_CONFIG mask */
+#define RB_MAP_PKR0(x)                         ((x) << 0)
+#define RB_MAP_PKR0_MASK                       (0x3 << 0)
+#define RB_MAP_PKR1(x)                         ((x) << 2)
+#define RB_MAP_PKR1_MASK                       (0x3 << 2)
+#define RB_XSEL2(x)                            ((x) << 4)
+#define RB_XSEL2_MASK                          (0x3 << 4)
+#define RB_XSEL                                        (1 << 6)
+#define RB_YSEL                                        (1 << 7)
+#define PKR_MAP(x)                             ((x) << 8)
+#define PKR_MAP_MASK                           (0x3 << 8)
+#define PKR_XSEL(x)                            ((x) << 10)
+#define PKR_XSEL_MASK                          (0x3 << 10)
+#define PKR_YSEL(x)                            ((x) << 12)
+#define PKR_YSEL_MASK                          (0x3 << 12)
+#define SC_MAP(x)                              ((x) << 16)
+#define SC_MAP_MASK                            (0x3 << 16)
+#define SC_XSEL(x)                             ((x) << 18)
+#define SC_XSEL_MASK                           (0x3 << 18)
+#define SC_YSEL(x)                             ((x) << 20)
+#define SC_YSEL_MASK                           (0x3 << 20)
+#define SE_MAP(x)                              ((x) << 24)
+#define SE_MAP_MASK                            (0x3 << 24)
+#define SE_XSEL(x)                             ((x) << 26)
+#define SE_XSEL_MASK                           (0x3 << 26)
+#define SE_YSEL(x)                             ((x) << 28)
+#define SE_YSEL_MASK                           (0x3 << 28)
+
+/* mmPA_SC_RASTER_CONFIG_1 mask */
+#define SE_PAIR_MAP(x)                         ((x) << 0)
+#define SE_PAIR_MAP_MASK                       (0x3 << 0)
+#define SE_PAIR_XSEL(x)                                ((x) << 2)
+#define SE_PAIR_XSEL_MASK                      (0x3 << 2)
+#define SE_PAIR_YSEL(x)                                ((x) << 4)
+#define SE_PAIR_YSEL_MASK                      (0x3 << 4)
+
 #endif
index 2a11413..f80a083 100644 (file)
@@ -44,6 +44,7 @@
 
 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)
 {
@@ -350,6 +351,8 @@ static int cz_parse_power_table(struct amdgpu_device *adev)
 
                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;
                }
@@ -409,11 +412,11 @@ static int cz_dpm_init(struct amdgpu_device *adev)
 
        ret = amdgpu_get_platform_caps(adev);
        if (ret)
-               return ret;
+               goto err;
 
        ret = amdgpu_parse_extended_power_table(adev);
        if (ret)
-               return ret;
+               goto err;
 
        pi->sram_end = SMC_RAM_END;
 
@@ -435,7 +438,11 @@ static int cz_dpm_init(struct amdgpu_device *adev)
                pi->caps_td_ramping = true;
                pi->caps_tcp_ramping = true;
        }
-       pi->caps_sclk_ds = true;
+       if (amdgpu_sclk_deep_sleep_en)
+               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;
@@ -463,23 +470,26 @@ static int cz_dpm_init(struct amdgpu_device *adev)
 
        ret = cz_parse_sys_info_table(adev);
        if (ret)
-               return ret;
+               goto err;
 
        cz_patch_voltage_values(adev);
        cz_construct_boot_state(adev);
 
        ret = cz_parse_power_table(adev);
        if (ret)
-               return ret;
+               goto err;
 
        ret = cz_process_firmware_header(adev);
        if (ret)
-               return 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)
@@ -668,17 +678,12 @@ 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)
 {
-       int ret = 0;
-
-       ret = cz_smu_download_pptable(adev, table);
-
-       return ret;
+       return cz_smu_download_pptable(adev, table);
 }
 
 static int cz_dpm_upload_pptable_to_smu(struct amdgpu_device *adev)
@@ -818,9 +823,9 @@ static void cz_init_sclk_limit(struct amdgpu_device *adev)
        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)
+       if (level < table->count) {
                clock = table->entries[level].clk;
-       else {
+       else {
                DRM_ERROR("Invalid SLCK Voltage Dependency table entry.\n");
                clock = table->entries[table->count - 1].clk;
        }
@@ -846,9 +851,9 @@ static void cz_init_uvd_limit(struct amdgpu_device *adev)
        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)
+       if (level < table->count) {
                clock = table->entries[level].vclk;
-       else {
+       else {
                DRM_ERROR("Invalid UVD Voltage Dependency table entry.\n");
                clock = table->entries[table->count - 1].vclk;
        }
@@ -874,9 +879,9 @@ static void cz_init_vce_limit(struct amdgpu_device *adev)
        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)
+       if (level < table->count) {
                clock = table->entries[level].ecclk;
-       else {
+       else {
                /* future BIOS would fix this error */
                DRM_ERROR("Invalid VCE Voltage Dependency table entry.\n");
                clock = table->entries[table->count - 1].ecclk;
@@ -903,9 +908,9 @@ static void cz_init_acp_limit(struct amdgpu_device *adev)
        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)
+       if (level < table->count) {
                clock = table->entries[level].clk;
-       else {
+       else {
                DRM_ERROR("Invalid ACP Voltage Dependency table entry.\n");
                clock = table->entries[table->count - 1].clk;
        }
@@ -930,7 +935,6 @@ 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)
@@ -1203,7 +1207,7 @@ static int cz_enable_didt(struct amdgpu_device *adev, bool enable)
        int ret;
 
        if (pi->caps_sq_ramping || pi->caps_db_ramping ||
-                       pi->caps_td_ramping || pi->caps_tcp_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) {
@@ -1277,7 +1281,7 @@ static void cz_apply_state_adjust_rules(struct amdgpu_device *adev,
        ps->force_high = false;
        ps->need_dfs_bypass = true;
        pi->video_start = new_rps->dclk || new_rps->vclk ||
-                               new_rps->evclk || new_rps->ecclk;
+                         new_rps->evclk || new_rps->ecclk;
 
        if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
                        ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
@@ -1335,7 +1339,6 @@ static int cz_dpm_enable(struct amdgpu_device *adev)
        }
 
        cz_reset_acp_boot_level(adev);
-
        cz_update_current_ps(adev, adev->pm.dpm.boot_ps);
 
        return 0;
@@ -1665,7 +1668,6 @@ static void cz_dpm_post_set_power_state(struct amdgpu_device *adev)
        struct amdgpu_ps *ps = &pi->requested_rps;
 
        cz_update_current_ps(adev, ps);
-
 }
 
 static int cz_dpm_force_highest(struct amdgpu_device *adev)
@@ -2108,29 +2110,58 @@ static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate)
                        /* disable clockgating so we can properly shut down the block */
                        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;
+                       }
+
                        /* shutdown the UVD block */
                        ret = amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
                                                            AMD_PG_STATE_GATE);
-                       /* XXX: check for errors */
+
+                       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)
+               if (pi->caps_uvd_pg) {
                        /* power off the UVD block */
-                       cz_send_msg_to_smc(adev, PPSMC_MSG_UVDPowerOFF);
+                       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)
-                               cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 1);
+                               ret = cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 1);
                        else
-                               cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 0);
+                               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;
+                       }
+
                        /* enable clockgating. hw will dynamically gate/ungate clocks on the fly */
                        ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
                                                            AMD_CG_STATE_GATE);
-                       /* XXX: check for errors */
+                       if (ret) {
+                               DRM_ERROR("UVD DPM Power Gating Failed to set clockgating state\n");
+                               return;
+                       }
                }
                cz_update_uvd_dpm(adev, gate);
        }
@@ -2168,7 +2199,6 @@ static int cz_update_vce_dpm(struct amdgpu_device *adev)
        /* 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;*/
index ac7fee7..aed7033 100644 (file)
@@ -29,6 +29,8 @@
 #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"
@@ -48,7 +50,7 @@ static struct cz_smu_private_data *cz_smu_get_priv(struct amdgpu_device *adev)
        return priv;
 }
 
-int cz_send_msg_to_smc_async(struct amdgpu_device *adev, u16 msg)
+static int cz_send_msg_to_smc_async(struct amdgpu_device *adev, u16 msg)
 {
        int i;
        u32 content = 0, tmp;
@@ -99,13 +101,6 @@ int cz_send_msg_to_smc(struct amdgpu_device *adev, u16 msg)
        return 0;
 }
 
-int cz_send_msg_to_smc_with_parameter_async(struct amdgpu_device *adev,
-                                               u16 msg, u32 parameter)
-{
-       WREG32(mmSMU_MP1_SRBM2P_ARG_0, parameter);
-       return cz_send_msg_to_smc_async(adev, msg);
-}
-
 int cz_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
                                                u16 msg, u32 parameter)
 {
@@ -140,7 +135,7 @@ int cz_read_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
        return 0;
 }
 
-int cz_write_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
+static int cz_write_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
                                                u32 value, u32 limit)
 {
        int ret;
index c1b04e9..613ebb7 100644 (file)
@@ -221,7 +221,7 @@ static bool dce_v10_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
  */
 static void dce_v10_0_vblank_wait(struct amdgpu_device *adev, int crtc)
 {
-       unsigned i = 0;
+       unsigned i = 100;
 
        if (crtc >= adev->mode_info.num_crtc)
                return;
@@ -233,14 +233,16 @@ static void dce_v10_0_vblank_wait(struct amdgpu_device *adev, int crtc)
         * wait for another frame.
         */
        while (dce_v10_0_is_in_vblank(adev, crtc)) {
-               if (i++ % 100 == 0) {
+               if (i++ == 100) {
+                       i = 0;
                        if (!dce_v10_0_is_counter_moving(adev, crtc))
                                break;
                }
        }
 
        while (!dce_v10_0_is_in_vblank(adev, crtc)) {
-               if (i++ % 100 == 0) {
+               if (i++ == 100) {
+                       i = 0;
                        if (!dce_v10_0_is_counter_moving(adev, crtc))
                                break;
                }
@@ -425,16 +427,6 @@ static void dce_v10_0_hpd_init(struct amdgpu_device *adev)
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
-                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
-                        * aux dp channel on imac and help (but not completely fix)
-                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
-                        * also avoid interrupt storms during dpms.
-                        */
-                       continue;
-               }
-
                switch (amdgpu_connector->hpd.hpd) {
                case AMDGPU_HPD_1:
                        idx = 0;
@@ -458,6 +450,19 @@ static void dce_v10_0_hpd_init(struct amdgpu_device *adev)
                        continue;
                }
 
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
+                        * aux dp channel on imac and help (but not completely fix)
+                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+                        * also avoid interrupt storms during dpms.
+                        */
+                       tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx]);
+                       tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_EN, 0);
+                       WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx], tmp);
+                       continue;
+               }
+
                tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
                tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 1);
                WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
@@ -646,8 +651,8 @@ static void dce_v10_0_resume_mc_access(struct amdgpu_device *adev,
 
                if (save->crtc_enabled[i]) {
                        tmp = RREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i]);
-                       if (REG_GET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE) != 3) {
-                               tmp = REG_SET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE, 3);
+                       if (REG_GET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE) != 0) {
+                               tmp = REG_SET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE, 0);
                                WREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i], tmp);
                        }
                        tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
@@ -712,6 +717,45 @@ static void dce_v10_0_set_vga_render_state(struct amdgpu_device *adev,
        WREG32(mmVGA_RENDER_CONTROL, tmp);
 }
 
+static int dce_v10_0_get_num_crtc(struct amdgpu_device *adev)
+{
+       int num_crtc = 0;
+
+       switch (adev->asic_type) {
+       case CHIP_FIJI:
+       case CHIP_TONGA:
+               num_crtc = 6;
+               break;
+       default:
+               num_crtc = 0;
+       }
+       return num_crtc;
+}
+
+void dce_v10_0_disable_dce(struct amdgpu_device *adev)
+{
+       /*Disable VGA render and enabled crtc, if has DCE engine*/
+       if (amdgpu_atombios_has_dce_engine_info(adev)) {
+               u32 tmp;
+               int crtc_enabled, i;
+
+               dce_v10_0_set_vga_render_state(adev, false);
+
+               /*Disable crtc*/
+               for (i = 0; i < dce_v10_0_get_num_crtc(adev); i++) {
+                       crtc_enabled = REG_GET_FIELD(RREG32(mmCRTC_CONTROL + crtc_offsets[i]),
+                                                                        CRTC_CONTROL, CRTC_MASTER_EN);
+                       if (crtc_enabled) {
+                               WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+                               tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]);
+                               tmp = REG_SET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN, 0);
+                               WREG32(mmCRTC_CONTROL + crtc_offsets[i], tmp);
+                               WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+                       }
+               }
+       }
+}
+
 static void dce_v10_0_program_fmt(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
@@ -2063,7 +2107,7 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
        struct amdgpu_framebuffer *amdgpu_fb;
        struct drm_framebuffer *target_fb;
        struct drm_gem_object *obj;
-       struct amdgpu_bo *rbo;
+       struct amdgpu_bo *abo;
        uint64_t fb_location, tiling_flags;
        uint32_t fb_format, fb_pitch_pixels;
        u32 fb_swap = REG_SET_FIELD(0, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP, ENDIAN_NONE);
@@ -2071,6 +2115,7 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
        u32 tmp, viewport_w, viewport_h;
        int r;
        bool bypass_lut = false;
+       char *format_name;
 
        /* no fb bound */
        if (!atomic && !crtc->primary->fb) {
@@ -2090,23 +2135,23 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
         * just update base pointers
         */
        obj = amdgpu_fb->obj;
-       rbo = gem_to_amdgpu_bo(obj);
-       r = amdgpu_bo_reserve(rbo, false);
+       abo = gem_to_amdgpu_bo(obj);
+       r = amdgpu_bo_reserve(abo, false);
        if (unlikely(r != 0))
                return r;
 
        if (atomic) {
-               fb_location = amdgpu_bo_gpu_offset(rbo);
+               fb_location = amdgpu_bo_gpu_offset(abo);
        } else {
-               r = amdgpu_bo_pin(rbo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location);
+               r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location);
                if (unlikely(r != 0)) {
-                       amdgpu_bo_unreserve(rbo);
+                       amdgpu_bo_unreserve(abo);
                        return -EINVAL;
                }
        }
 
-       amdgpu_bo_get_tiling_flags(rbo, &tiling_flags);
-       amdgpu_bo_unreserve(rbo);
+       amdgpu_bo_get_tiling_flags(abo, &tiling_flags);
+       amdgpu_bo_unreserve(abo);
 
        pipe_config = AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
 
@@ -2182,8 +2227,9 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
                bypass_lut = true;
                break;
        default:
-               DRM_ERROR("Unsupported screen format %s\n",
-                       drm_get_format_name(target_fb->pixel_format));
+               format_name = drm_get_format_name(target_fb->pixel_format);
+               DRM_ERROR("Unsupported screen format %s\n", format_name);
+               kfree(format_name);
                return -EINVAL;
        }
 
@@ -2275,17 +2321,17 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset,
               (viewport_w << 16) | viewport_h);
 
-       /* set pageflip to happen only at start of vblank interval (front porch) */
-       WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3);
+       /* set pageflip to happen anywhere in vblank interval */
+       WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0);
 
        if (!atomic && fb && fb != crtc->primary->fb) {
                amdgpu_fb = to_amdgpu_framebuffer(fb);
-               rbo = gem_to_amdgpu_bo(amdgpu_fb->obj);
-               r = amdgpu_bo_reserve(rbo, false);
+               abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+               r = amdgpu_bo_reserve(abo, false);
                if (unlikely(r != 0))
                        return r;
-               amdgpu_bo_unpin(rbo);
-               amdgpu_bo_unreserve(rbo);
+               amdgpu_bo_unpin(abo);
+               amdgpu_bo_unreserve(abo);
        }
 
        /* Bytes per pixel may have changed */
@@ -2698,7 +2744,7 @@ static const struct drm_crtc_funcs dce_v10_0_crtc_funcs = {
        .gamma_set = dce_v10_0_crtc_gamma_set,
        .set_config = amdgpu_crtc_set_config,
        .destroy = dce_v10_0_crtc_destroy,
-       .page_flip = amdgpu_crtc_page_flip,
+       .page_flip_target = amdgpu_crtc_page_flip_target,
 };
 
 static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -2765,16 +2811,16 @@ static void dce_v10_0_crtc_disable(struct drm_crtc *crtc)
        if (crtc->primary->fb) {
                int r;
                struct amdgpu_framebuffer *amdgpu_fb;
-               struct amdgpu_bo *rbo;
+               struct amdgpu_bo *abo;
 
                amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
-               rbo = gem_to_amdgpu_bo(amdgpu_fb->obj);
-               r = amdgpu_bo_reserve(rbo, false);
+               abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+               r = amdgpu_bo_reserve(abo, false);
                if (unlikely(r))
-                       DRM_ERROR("failed to reserve rbo before unpin\n");
+                       DRM_ERROR("failed to reserve abo before unpin\n");
                else {
-                       amdgpu_bo_unpin(rbo);
-                       amdgpu_bo_unreserve(rbo);
+                       amdgpu_bo_unpin(abo);
+                       amdgpu_bo_unreserve(abo);
                }
        }
        /* disable the GRPH */
@@ -2962,10 +3008,11 @@ static int dce_v10_0_early_init(void *handle)
        dce_v10_0_set_display_funcs(adev);
        dce_v10_0_set_irq_funcs(adev);
 
+       adev->mode_info.num_crtc = dce_v10_0_get_num_crtc(adev);
+
        switch (adev->asic_type) {
        case CHIP_FIJI:
        case CHIP_TONGA:
-               adev->mode_info.num_crtc = 6; /* XXX 7??? */
                adev->mode_info.num_hpd = 6;
                adev->mode_info.num_dig = 7;
                break;
@@ -3141,11 +3188,26 @@ static int dce_v10_0_wait_for_idle(void *handle)
        return 0;
 }
 
+static int dce_v10_0_check_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (dce_v10_0_is_display_hung(adev))
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang = true;
+       else
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang = false;
+
+       return 0;
+}
+
 static int dce_v10_0_soft_reset(void *handle)
 {
        u32 srbm_soft_reset = 0, tmp;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang)
+               return 0;
+
        if (dce_v10_0_is_display_hung(adev))
                srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK;
 
@@ -3512,6 +3574,7 @@ const struct amd_ip_funcs dce_v10_0_ip_funcs = {
        .resume = dce_v10_0_resume,
        .is_idle = dce_v10_0_is_idle,
        .wait_for_idle = dce_v10_0_wait_for_idle,
+       .check_soft_reset = dce_v10_0_check_soft_reset,
        .soft_reset = dce_v10_0_soft_reset,
        .set_clockgating_state = dce_v10_0_set_clockgating_state,
        .set_powergating_state = dce_v10_0_set_powergating_state,
index 1bfa48d..e3dc04d 100644 (file)
@@ -26,4 +26,6 @@
 
 extern const struct amd_ip_funcs dce_v10_0_ip_funcs;
 
+void dce_v10_0_disable_dce(struct amdgpu_device *adev);
+
 #endif
index d4bf133..f264b8f 100644 (file)
@@ -443,16 +443,6 @@ static void dce_v11_0_hpd_init(struct amdgpu_device *adev)
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
-                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
-                        * aux dp channel on imac and help (but not completely fix)
-                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
-                        * also avoid interrupt storms during dpms.
-                        */
-                       continue;
-               }
-
                switch (amdgpu_connector->hpd.hpd) {
                case AMDGPU_HPD_1:
                        idx = 0;
@@ -476,6 +466,19 @@ static void dce_v11_0_hpd_init(struct amdgpu_device *adev)
                        continue;
                }
 
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
+                        * aux dp channel on imac and help (but not completely fix)
+                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+                        * also avoid interrupt storms during dpms.
+                        */
+                       tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx]);
+                       tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_EN, 0);
+                       WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx], tmp);
+                       continue;
+               }
+
                tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
                tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 1);
                WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
@@ -673,6 +676,53 @@ static void dce_v11_0_set_vga_render_state(struct amdgpu_device *adev,
        WREG32(mmVGA_RENDER_CONTROL, tmp);
 }
 
+static int dce_v11_0_get_num_crtc (struct amdgpu_device *adev)
+{
+       int num_crtc = 0;
+
+       switch (adev->asic_type) {
+       case CHIP_CARRIZO:
+               num_crtc = 3;
+               break;
+       case CHIP_STONEY:
+               num_crtc = 2;
+               break;
+       case CHIP_POLARIS10:
+               num_crtc = 6;
+               break;
+       case CHIP_POLARIS11:
+               num_crtc = 5;
+               break;
+       default:
+               num_crtc = 0;
+       }
+       return num_crtc;
+}
+
+void dce_v11_0_disable_dce(struct amdgpu_device *adev)
+{
+       /*Disable VGA render and enabled crtc, if has DCE engine*/
+       if (amdgpu_atombios_has_dce_engine_info(adev)) {
+               u32 tmp;
+               int crtc_enabled, i;
+
+               dce_v11_0_set_vga_render_state(adev, false);
+
+               /*Disable crtc*/
+               for (i = 0; i < dce_v11_0_get_num_crtc(adev); i++) {
+                       crtc_enabled = REG_GET_FIELD(RREG32(mmCRTC_CONTROL + crtc_offsets[i]),
+                                                                        CRTC_CONTROL, CRTC_MASTER_EN);
+                       if (crtc_enabled) {
+                               WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+                               tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]);
+                               tmp = REG_SET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN, 0);
+                               WREG32(mmCRTC_CONTROL + crtc_offsets[i], tmp);
+                               WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+                       }
+               }
+       }
+}
+
 static void dce_v11_0_program_fmt(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
@@ -2038,7 +2088,7 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc,
        struct amdgpu_framebuffer *amdgpu_fb;
        struct drm_framebuffer *target_fb;
        struct drm_gem_object *obj;
-       struct amdgpu_bo *rbo;
+       struct amdgpu_bo *abo;
        uint64_t fb_location, tiling_flags;
        uint32_t fb_format, fb_pitch_pixels;
        u32 fb_swap = REG_SET_FIELD(0, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP, ENDIAN_NONE);
@@ -2046,6 +2096,7 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc,
        u32 tmp, viewport_w, viewport_h;
        int r;
        bool bypass_lut = false;
+       char *format_name;
 
        /* no fb bound */
        if (!atomic && !crtc->primary->fb) {
@@ -2065,23 +2116,23 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc,
         * just update base pointers
         */
        obj = amdgpu_fb->obj;
-       rbo = gem_to_amdgpu_bo(obj);
-       r = amdgpu_bo_reserve(rbo, false);
+       abo = gem_to_amdgpu_bo(obj);
+       r = amdgpu_bo_reserve(abo, false);
        if (unlikely(r != 0))
                return r;
 
        if (atomic) {
-               fb_location = amdgpu_bo_gpu_offset(rbo);
+               fb_location = amdgpu_bo_gpu_offset(abo);
        } else {
-               r = amdgpu_bo_pin(rbo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location);
+               r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location);
                if (unlikely(r != 0)) {
-                       amdgpu_bo_unreserve(rbo);
+                       amdgpu_bo_unreserve(abo);
                        return -EINVAL;
                }
        }
 
-       amdgpu_bo_get_tiling_flags(rbo, &tiling_flags);
-       amdgpu_bo_unreserve(rbo);
+       amdgpu_bo_get_tiling_flags(abo, &tiling_flags);
+       amdgpu_bo_unreserve(abo);
 
        pipe_config = AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
 
@@ -2157,8 +2208,9 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc,
                bypass_lut = true;
                break;
        default:
-               DRM_ERROR("Unsupported screen format %s\n",
-                       drm_get_format_name(target_fb->pixel_format));
+               format_name = drm_get_format_name(target_fb->pixel_format);
+               DRM_ERROR("Unsupported screen format %s\n", format_name);
+               kfree(format_name);
                return -EINVAL;
        }
 
@@ -2250,17 +2302,17 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset,
               (viewport_w << 16) | viewport_h);
 
-       /* set pageflip to happen only at start of vblank interval (front porch) */
-       WREG32(mmCRTC_MASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3);
+       /* set pageflip to happen anywhere in vblank interval */
+       WREG32(mmCRTC_MASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0);
 
        if (!atomic && fb && fb != crtc->primary->fb) {
                amdgpu_fb = to_amdgpu_framebuffer(fb);
-               rbo = gem_to_amdgpu_bo(amdgpu_fb->obj);
-               r = amdgpu_bo_reserve(rbo, false);
+               abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+               r = amdgpu_bo_reserve(abo, false);
                if (unlikely(r != 0))
                        return r;
-               amdgpu_bo_unpin(rbo);
-               amdgpu_bo_unreserve(rbo);
+               amdgpu_bo_unpin(abo);
+               amdgpu_bo_unreserve(abo);
        }
 
        /* Bytes per pixel may have changed */
@@ -2708,7 +2760,7 @@ static const struct drm_crtc_funcs dce_v11_0_crtc_funcs = {
        .gamma_set = dce_v11_0_crtc_gamma_set,
        .set_config = amdgpu_crtc_set_config,
        .destroy = dce_v11_0_crtc_destroy,
-       .page_flip = amdgpu_crtc_page_flip,
+       .page_flip_target = amdgpu_crtc_page_flip_target,
 };
 
 static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -2775,16 +2827,16 @@ static void dce_v11_0_crtc_disable(struct drm_crtc *crtc)
        if (crtc->primary->fb) {
                int r;
                struct amdgpu_framebuffer *amdgpu_fb;
-               struct amdgpu_bo *rbo;
+               struct amdgpu_bo *abo;
 
                amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
-               rbo = gem_to_amdgpu_bo(amdgpu_fb->obj);
-               r = amdgpu_bo_reserve(rbo, false);
+               abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+               r = amdgpu_bo_reserve(abo, false);
                if (unlikely(r))
-                       DRM_ERROR("failed to reserve rbo before unpin\n");
+                       DRM_ERROR("failed to reserve abo before unpin\n");
                else {
-                       amdgpu_bo_unpin(rbo);
-                       amdgpu_bo_unreserve(rbo);
+                       amdgpu_bo_unpin(abo);
+                       amdgpu_bo_unreserve(abo);
                }
        }
        /* disable the GRPH */
@@ -2999,24 +3051,22 @@ static int dce_v11_0_early_init(void *handle)
        dce_v11_0_set_display_funcs(adev);
        dce_v11_0_set_irq_funcs(adev);
 
+       adev->mode_info.num_crtc = dce_v11_0_get_num_crtc(adev);
+
        switch (adev->asic_type) {
        case CHIP_CARRIZO:
-               adev->mode_info.num_crtc = 3;
                adev->mode_info.num_hpd = 6;
                adev->mode_info.num_dig = 9;
                break;
        case CHIP_STONEY:
-               adev->mode_info.num_crtc = 2;
                adev->mode_info.num_hpd = 6;
                adev->mode_info.num_dig = 9;
                break;
        case CHIP_POLARIS10:
-               adev->mode_info.num_crtc = 6;
                adev->mode_info.num_hpd = 6;
                adev->mode_info.num_dig = 6;
                break;
        case CHIP_POLARIS11:
-               adev->mode_info.num_crtc = 5;
                adev->mode_info.num_hpd = 5;
                adev->mode_info.num_dig = 5;
                break;
@@ -3109,6 +3159,7 @@ static int dce_v11_0_sw_fini(void *handle)
 
        dce_v11_0_afmt_fini(adev);
 
+       drm_mode_config_cleanup(adev->ddev);
        adev->mode_info.mode_config_initialized = false;
 
        return 0;
index 84e4618..1f58a65 100644 (file)
@@ -26,4 +26,6 @@
 
 extern const struct amd_ip_funcs dce_v11_0_ip_funcs;
 
+void dce_v11_0_disable_dce(struct amdgpu_device *adev);
+
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
new file mode 100644 (file)
index 0000000..b948d6c
--- /dev/null
@@ -0,0 +1,3176 @@
+/*
+ * Copyright 2015 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 "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_i2c.h"
+#include "atom.h"
+#include "amdgpu_atombios.h"
+#include "atombios_crtc.h"
+#include "atombios_encoders.h"
+#include "amdgpu_pll.h"
+#include "amdgpu_connectors.h"
+#include "si/si_reg.h"
+#include "si/sid.h"
+
+static void dce_v6_0_set_display_funcs(struct amdgpu_device *adev);
+static void dce_v6_0_set_irq_funcs(struct amdgpu_device *adev);
+
+static const u32 crtc_offsets[6] =
+{
+       SI_CRTC0_REGISTER_OFFSET,
+       SI_CRTC1_REGISTER_OFFSET,
+       SI_CRTC2_REGISTER_OFFSET,
+       SI_CRTC3_REGISTER_OFFSET,
+       SI_CRTC4_REGISTER_OFFSET,
+       SI_CRTC5_REGISTER_OFFSET
+};
+
+static const uint32_t dig_offsets[] = {
+       SI_CRTC0_REGISTER_OFFSET,
+       SI_CRTC1_REGISTER_OFFSET,
+       SI_CRTC2_REGISTER_OFFSET,
+       SI_CRTC3_REGISTER_OFFSET,
+       SI_CRTC4_REGISTER_OFFSET,
+       SI_CRTC5_REGISTER_OFFSET,
+       (0x13830 - 0x7030) >> 2,
+};
+
+static const struct {
+       uint32_t        reg;
+       uint32_t        vblank;
+       uint32_t        vline;
+       uint32_t        hpd;
+
+} interrupt_status_offsets[6] = { {
+       .reg = DISP_INTERRUPT_STATUS,
+       .vblank = DISP_INTERRUPT_STATUS__LB_D1_VBLANK_INTERRUPT_MASK,
+       .vline = DISP_INTERRUPT_STATUS__LB_D1_VLINE_INTERRUPT_MASK,
+       .hpd = DISP_INTERRUPT_STATUS__DC_HPD1_INTERRUPT_MASK
+}, {
+       .reg = DISP_INTERRUPT_STATUS_CONTINUE,
+       .vblank = DISP_INTERRUPT_STATUS_CONTINUE__LB_D2_VBLANK_INTERRUPT_MASK,
+       .vline = DISP_INTERRUPT_STATUS_CONTINUE__LB_D2_VLINE_INTERRUPT_MASK,
+       .hpd = DISP_INTERRUPT_STATUS_CONTINUE__DC_HPD2_INTERRUPT_MASK
+}, {
+       .reg = DISP_INTERRUPT_STATUS_CONTINUE2,
+       .vblank = DISP_INTERRUPT_STATUS_CONTINUE2__LB_D3_VBLANK_INTERRUPT_MASK,
+       .vline = DISP_INTERRUPT_STATUS_CONTINUE2__LB_D3_VLINE_INTERRUPT_MASK,
+       .hpd = DISP_INTERRUPT_STATUS_CONTINUE2__DC_HPD3_INTERRUPT_MASK
+}, {
+       .reg = DISP_INTERRUPT_STATUS_CONTINUE3,
+       .vblank = DISP_INTERRUPT_STATUS_CONTINUE3__LB_D4_VBLANK_INTERRUPT_MASK,
+       .vline = DISP_INTERRUPT_STATUS_CONTINUE3__LB_D4_VLINE_INTERRUPT_MASK,
+       .hpd = DISP_INTERRUPT_STATUS_CONTINUE3__DC_HPD4_INTERRUPT_MASK
+}, {
+       .reg = DISP_INTERRUPT_STATUS_CONTINUE4,
+       .vblank = DISP_INTERRUPT_STATUS_CONTINUE4__LB_D5_VBLANK_INTERRUPT_MASK,
+       .vline = DISP_INTERRUPT_STATUS_CONTINUE4__LB_D5_VLINE_INTERRUPT_MASK,
+       .hpd = DISP_INTERRUPT_STATUS_CONTINUE4__DC_HPD5_INTERRUPT_MASK
+}, {
+       .reg = DISP_INTERRUPT_STATUS_CONTINUE5,
+       .vblank = DISP_INTERRUPT_STATUS_CONTINUE5__LB_D6_VBLANK_INTERRUPT_MASK,
+       .vline = DISP_INTERRUPT_STATUS_CONTINUE5__LB_D6_VLINE_INTERRUPT_MASK,
+       .hpd = DISP_INTERRUPT_STATUS_CONTINUE5__DC_HPD6_INTERRUPT_MASK
+} };
+
+static const uint32_t hpd_int_control_offsets[6] = {
+       DC_HPD1_INT_CONTROL,
+       DC_HPD2_INT_CONTROL,
+       DC_HPD3_INT_CONTROL,
+       DC_HPD4_INT_CONTROL,
+       DC_HPD5_INT_CONTROL,
+       DC_HPD6_INT_CONTROL,
+};
+
+static u32 dce_v6_0_audio_endpt_rreg(struct amdgpu_device *adev,
+                                    u32 block_offset, u32 reg)
+{
+       DRM_INFO("xxxx: dce_v6_0_audio_endpt_rreg ----no impl!!!!\n");
+       return 0;
+}
+
+static void dce_v6_0_audio_endpt_wreg(struct amdgpu_device *adev,
+                                     u32 block_offset, u32 reg, u32 v)
+{
+       DRM_INFO("xxxx: dce_v6_0_audio_endpt_wreg ----no impl!!!!\n");
+}
+
+static bool dce_v6_0_is_in_vblank(struct amdgpu_device *adev, int crtc)
+{
+       if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK)
+               return true;
+       else
+               return false;
+}
+
+static bool dce_v6_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
+{
+       u32 pos1, pos2;
+
+       pos1 = RREG32(EVERGREEN_CRTC_STATUS_POSITION + crtc_offsets[crtc]);
+       pos2 = RREG32(EVERGREEN_CRTC_STATUS_POSITION + crtc_offsets[crtc]);
+
+       if (pos1 != pos2)
+               return true;
+       else
+               return false;
+}
+
+/**
+ * dce_v6_0_wait_for_vblank - vblank wait asic callback.
+ *
+ * @crtc: crtc to wait for vblank on
+ *
+ * Wait for vblank on the requested crtc (evergreen+).
+ */
+static void dce_v6_0_vblank_wait(struct amdgpu_device *adev, int crtc)
+{
+       unsigned i = 100;
+
+       if (crtc >= adev->mode_info.num_crtc)
+               return;
+
+       if (!(RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN))
+               return;
+
+       /* depending on when we hit vblank, we may be close to active; if so,
+        * wait for another frame.
+        */
+       while (dce_v6_0_is_in_vblank(adev, crtc)) {
+               if (i++ == 100) {
+                       i = 0;
+                       if (!dce_v6_0_is_counter_moving(adev, crtc))
+                               break;
+               }
+       }
+
+       while (!dce_v6_0_is_in_vblank(adev, crtc)) {
+               if (i++ == 100) {
+                       i = 0;
+                       if (!dce_v6_0_is_counter_moving(adev, crtc))
+                               break;
+               }
+       }
+}
+
+static u32 dce_v6_0_vblank_get_counter(struct amdgpu_device *adev, int crtc)
+{
+       if (crtc >= adev->mode_info.num_crtc)
+               return 0;
+       else
+               return RREG32(CRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]);
+}
+
+static void dce_v6_0_pageflip_interrupt_init(struct amdgpu_device *adev)
+{
+       unsigned i;
+
+       /* Enable pflip interrupts */
+       for (i = 0; i < adev->mode_info.num_crtc; i++)
+               amdgpu_irq_get(adev, &adev->pageflip_irq, i);
+}
+
+static void dce_v6_0_pageflip_interrupt_fini(struct amdgpu_device *adev)
+{
+       unsigned i;
+
+       /* Disable pflip interrupts */
+       for (i = 0; i < adev->mode_info.num_crtc; i++)
+               amdgpu_irq_put(adev, &adev->pageflip_irq, i);
+}
+
+/**
+ * dce_v6_0_page_flip - pageflip callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @crtc_id: crtc to cleanup pageflip on
+ * @crtc_base: new address of the crtc (GPU MC address)
+ *
+ * Does the actual pageflip (evergreen+).
+ * During vblank we take the crtc lock and wait for the update_pending
+ * bit to go high, when it does, we release the lock, and allow the
+ * double buffered update to take place.
+ * Returns the current update pending status.
+ */
+static void dce_v6_0_page_flip(struct amdgpu_device *adev,
+                              int crtc_id, u64 crtc_base, bool async)
+{
+       struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
+
+       /* flip at hsync for async, default is vsync */
+       WREG32(EVERGREEN_GRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, async ?
+              EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0);
+       /* update the scanout addresses */
+       WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+              upper_32_bits(crtc_base));
+       WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+              (u32)crtc_base);
+
+       /* post the write */
+       RREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset);
+}
+
+static int dce_v6_0_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
+                                       u32 *vbl, u32 *position)
+{
+       if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc))
+               return -EINVAL;
+       *vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + crtc_offsets[crtc]);
+       *position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + crtc_offsets[crtc]);
+
+       return 0;
+
+}
+
+/**
+ * dce_v6_0_hpd_sense - hpd sense callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @hpd: hpd (hotplug detect) pin
+ *
+ * Checks if a digital monitor is connected (evergreen+).
+ * Returns true if connected, false if not connected.
+ */
+static bool dce_v6_0_hpd_sense(struct amdgpu_device *adev,
+                              enum amdgpu_hpd_id hpd)
+{
+       bool connected = false;
+
+       switch (hpd) {
+       case AMDGPU_HPD_1:
+               if (RREG32(DC_HPD1_INT_STATUS) & DC_HPDx_SENSE)
+                       connected = true;
+               break;
+       case AMDGPU_HPD_2:
+               if (RREG32(DC_HPD2_INT_STATUS) & DC_HPDx_SENSE)
+                       connected = true;
+               break;
+       case AMDGPU_HPD_3:
+               if (RREG32(DC_HPD3_INT_STATUS) & DC_HPDx_SENSE)
+                       connected = true;
+               break;
+       case AMDGPU_HPD_4:
+               if (RREG32(DC_HPD4_INT_STATUS) & DC_HPDx_SENSE)
+                       connected = true;
+               break;
+       case AMDGPU_HPD_5:
+               if (RREG32(DC_HPD5_INT_STATUS) & DC_HPDx_SENSE)
+                       connected = true;
+               break;
+       case AMDGPU_HPD_6:
+               if (RREG32(DC_HPD6_INT_STATUS) & DC_HPDx_SENSE)
+                       connected = true;
+               break;
+       default:
+               break;
+       }
+
+       return connected;
+}
+
+/**
+ * dce_v6_0_hpd_set_polarity - hpd set polarity callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @hpd: hpd (hotplug detect) pin
+ *
+ * Set the polarity of the hpd pin (evergreen+).
+ */
+static void dce_v6_0_hpd_set_polarity(struct amdgpu_device *adev,
+                                     enum amdgpu_hpd_id hpd)
+{
+       u32 tmp;
+       bool connected = dce_v6_0_hpd_sense(adev, hpd);
+
+       switch (hpd) {
+       case AMDGPU_HPD_1:
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               if (connected)
+                       tmp &= ~DC_HPDx_INT_POLARITY;
+               else
+                       tmp |= DC_HPDx_INT_POLARITY;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+               break;
+       case AMDGPU_HPD_2:
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               if (connected)
+                       tmp &= ~DC_HPDx_INT_POLARITY;
+               else
+                       tmp |= DC_HPDx_INT_POLARITY;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+               break;
+       case AMDGPU_HPD_3:
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               if (connected)
+                       tmp &= ~DC_HPDx_INT_POLARITY;
+               else
+                       tmp |= DC_HPDx_INT_POLARITY;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+               break;
+       case AMDGPU_HPD_4:
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               if (connected)
+                       tmp &= ~DC_HPDx_INT_POLARITY;
+               else
+                       tmp |= DC_HPDx_INT_POLARITY;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+               break;
+       case AMDGPU_HPD_5:
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               if (connected)
+                       tmp &= ~DC_HPDx_INT_POLARITY;
+               else
+                       tmp |= DC_HPDx_INT_POLARITY;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+                       break;
+       case AMDGPU_HPD_6:
+               tmp = RREG32(DC_HPD6_INT_CONTROL);
+               if (connected)
+                       tmp &= ~DC_HPDx_INT_POLARITY;
+               else
+                       tmp |= DC_HPDx_INT_POLARITY;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+               break;
+       default:
+               break;
+       }
+}
+
+/**
+ * dce_v6_0_hpd_init - hpd setup callback.
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Setup the hpd pins used by the card (evergreen+).
+ * Enable the pin, set the polarity, and enable the hpd interrupts.
+ */
+static void dce_v6_0_hpd_init(struct amdgpu_device *adev)
+{
+       struct drm_device *dev = adev->ddev;
+       struct drm_connector *connector;
+       u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) |
+               DC_HPDx_RX_INT_TIMER(0xfa) | DC_HPDx_EN;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+               switch (amdgpu_connector->hpd.hpd) {
+               case AMDGPU_HPD_1:
+                       WREG32(DC_HPD1_CONTROL, tmp);
+                       break;
+               case AMDGPU_HPD_2:
+                       WREG32(DC_HPD2_CONTROL, tmp);
+                       break;
+               case AMDGPU_HPD_3:
+                       WREG32(DC_HPD3_CONTROL, tmp);
+                       break;
+               case AMDGPU_HPD_4:
+                       WREG32(DC_HPD4_CONTROL, tmp);
+                       break;
+               case AMDGPU_HPD_5:
+                       WREG32(DC_HPD5_CONTROL, tmp);
+                       break;
+               case AMDGPU_HPD_6:
+                       WREG32(DC_HPD6_CONTROL, tmp);
+                       break;
+               default:
+                       break;
+               }
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
+                        * aux dp channel on imac and help (but not completely fix)
+                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+                        * also avoid interrupt storms during dpms.
+                        */
+                       u32 dc_hpd_int_cntl_reg, dc_hpd_int_cntl;
+
+                       switch (amdgpu_connector->hpd.hpd) {
+                       case AMDGPU_HPD_1:
+                               dc_hpd_int_cntl_reg = DC_HPD1_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_2:
+                               dc_hpd_int_cntl_reg = DC_HPD2_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_3:
+                               dc_hpd_int_cntl_reg = DC_HPD3_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_4:
+                               dc_hpd_int_cntl_reg = DC_HPD4_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_5:
+                               dc_hpd_int_cntl_reg = DC_HPD5_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_6:
+                               dc_hpd_int_cntl_reg = DC_HPD6_INT_CONTROL;
+                               break;
+                       default:
+                               continue;
+                       }
+
+                       dc_hpd_int_cntl = RREG32(dc_hpd_int_cntl_reg);
+                       dc_hpd_int_cntl &= ~DC_HPDx_INT_EN;
+                       WREG32(dc_hpd_int_cntl_reg, dc_hpd_int_cntl);
+                       continue;
+               }
+
+               dce_v6_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd);
+               amdgpu_irq_get(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd);
+       }
+
+}
+
+/**
+ * dce_v6_0_hpd_fini - hpd tear down callback.
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Tear down the hpd pins used by the card (evergreen+).
+ * Disable the hpd interrupts.
+ */
+static void dce_v6_0_hpd_fini(struct amdgpu_device *adev)
+{
+       struct drm_device *dev = adev->ddev;
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+               switch (amdgpu_connector->hpd.hpd) {
+               case AMDGPU_HPD_1:
+                       WREG32(DC_HPD1_CONTROL, 0);
+                       break;
+               case AMDGPU_HPD_2:
+                       WREG32(DC_HPD2_CONTROL, 0);
+                       break;
+               case AMDGPU_HPD_3:
+                       WREG32(DC_HPD3_CONTROL, 0);
+                       break;
+               case AMDGPU_HPD_4:
+                       WREG32(DC_HPD4_CONTROL, 0);
+                       break;
+               case AMDGPU_HPD_5:
+                       WREG32(DC_HPD5_CONTROL, 0);
+                       break;
+               case AMDGPU_HPD_6:
+                       WREG32(DC_HPD6_CONTROL, 0);
+                       break;
+               default:
+                       break;
+               }
+               amdgpu_irq_put(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd);
+       }
+}
+
+static u32 dce_v6_0_hpd_get_gpio_reg(struct amdgpu_device *adev)
+{
+       return SI_DC_GPIO_HPD_A;
+}
+
+static bool dce_v6_0_is_display_hung(struct amdgpu_device *adev)
+{
+       DRM_INFO("xxxx: dce_v6_0_is_display_hung ----no imp!!!!!\n");
+
+       return true;
+}
+
+static u32 evergreen_get_vblank_counter(struct amdgpu_device* adev, int crtc)
+{
+       if (crtc >= adev->mode_info.num_crtc)
+               return 0;
+       else
+               return RREG32(CRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]);
+}
+
+static void dce_v6_0_stop_mc_access(struct amdgpu_device *adev,
+                                   struct amdgpu_mode_mc_save *save)
+{
+       u32 crtc_enabled, tmp, frame_count;
+       int i, j;
+
+       save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
+       save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
+
+       /* disable VGA render */
+       WREG32(VGA_RENDER_CONTROL, 0);
+
+       /* blank the display controllers */
+       for (i = 0; i < adev->mode_info.num_crtc; i++) {
+               crtc_enabled = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN;
+               if (crtc_enabled) {
+                       save->crtc_enabled[i] = true;
+                       tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]);
+
+                       if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) {
+                               dce_v6_0_vblank_wait(adev, i);
+                               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+                               tmp |= EVERGREEN_CRTC_BLANK_DATA_EN;
+                               WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+                               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+                       }
+                       /* wait for the next frame */
+                       frame_count = evergreen_get_vblank_counter(adev, i);
+                       for (j = 0; j < adev->usec_timeout; j++) {
+                               if (evergreen_get_vblank_counter(adev, i) != frame_count)
+                                       break;
+                               udelay(1);
+                       }
+
+                       /* XXX this is a hack to avoid strange behavior with EFI on certain systems */
+                       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+                       tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
+                       tmp &= ~EVERGREEN_CRTC_MASTER_EN;
+                       WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
+                       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+                       save->crtc_enabled[i] = false;
+                       /* ***** */
+               } else {
+                       save->crtc_enabled[i] = false;
+               }
+       }
+}
+
+static void dce_v6_0_resume_mc_access(struct amdgpu_device *adev,
+                                     struct amdgpu_mode_mc_save *save)
+{
+       u32 tmp;
+       int i, j;
+
+       /* update crtc base addresses */
+       for (i = 0; i < adev->mode_info.num_crtc; i++) {
+               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
+                      upper_32_bits(adev->mc.vram_start));
+               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
+                      upper_32_bits(adev->mc.vram_start));
+               WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
+                      (u32)adev->mc.vram_start);
+               WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
+                      (u32)adev->mc.vram_start);
+       }
+
+       WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(adev->mc.vram_start));
+       WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)adev->mc.vram_start);
+
+       /* unlock regs and wait for update */
+       for (i = 0; i < adev->mode_info.num_crtc; i++) {
+               if (save->crtc_enabled[i]) {
+                       tmp = RREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i]);
+                       if ((tmp & 0x7) != 3) {
+                               tmp &= ~0x7;
+                               tmp |= 0x3;
+                               WREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i], tmp);
+                       }
+                       tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]);
+                       if (tmp & EVERGREEN_GRPH_UPDATE_LOCK) {
+                               tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK;
+                               WREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i], tmp);
+                       }
+                       tmp = RREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i]);
+                       if (tmp & 1) {
+                               tmp &= ~1;
+                               WREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
+                       }
+                       for (j = 0; j < adev->usec_timeout; j++) {
+                               tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]);
+                               if ((tmp & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING) == 0)
+                                       break;
+                               udelay(1);
+                       }
+               }
+       }
+
+       /* Unlock vga access */
+       WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
+       mdelay(1);
+       WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
+
+}
+
+static void dce_v6_0_set_vga_render_state(struct amdgpu_device *adev,
+                                         bool render)
+{
+       if (!render) 
+               WREG32(R_000300_VGA_RENDER_CONTROL,
+                       RREG32(R_000300_VGA_RENDER_CONTROL) & C_000300_VGA_VSTATUS_CNTL);
+
+}
+
+static void dce_v6_0_program_fmt(struct drm_encoder *encoder)
+{
+
+       struct drm_device *dev = encoder->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+       struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+       int bpc = 0;
+       u32 tmp = 0;
+       enum amdgpu_connector_dither dither = AMDGPU_FMT_DITHER_DISABLE;
+
+       if (connector) {
+               struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+               bpc = amdgpu_connector_get_monitor_bpc(connector);
+               dither = amdgpu_connector->dither;
+       }
+
+       /* LVDS FMT is set up by atom */
+       if (amdgpu_encoder->devices & ATOM_DEVICE_LCD_SUPPORT)
+               return;
+
+       if (bpc == 0)
+               return;
+
+
+       switch (bpc) {
+       case 6:
+               if (dither == AMDGPU_FMT_DITHER_ENABLE)
+                       /* XXX sort out optimal dither settings */
+                       tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE |
+                               FMT_SPATIAL_DITHER_EN);
+               else
+                       tmp |= FMT_TRUNCATE_EN;
+               break;
+       case 8:
+               if (dither == AMDGPU_FMT_DITHER_ENABLE)
+                       /* XXX sort out optimal dither settings */
+                       tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE |
+                               FMT_RGB_RANDOM_ENABLE |
+                               FMT_SPATIAL_DITHER_EN | FMT_SPATIAL_DITHER_DEPTH);
+               else
+                       tmp |= (FMT_TRUNCATE_EN | FMT_TRUNCATE_DEPTH);
+               break;
+       case 10:
+       default:
+               /* not needed */
+               break;
+       }
+
+       WREG32(FMT_BIT_DEPTH_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+}
+
+/**
+ * cik_get_number_of_dram_channels - get the number of dram channels
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Look up the number of video ram channels (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the number of dram channels
+ */
+static u32 si_get_number_of_dram_channels(struct amdgpu_device *adev)
+{
+       u32 tmp = RREG32(MC_SHARED_CHMAP);
+
+       switch ((tmp & MC_SHARED_CHMAP__NOOFCHAN_MASK) >> MC_SHARED_CHMAP__NOOFCHAN__SHIFT) {
+       case 0:
+       default:
+               return 1;
+       case 1:
+               return 2;
+       case 2:
+               return 4;
+       case 3:
+               return 8;
+       case 4:
+               return 3;
+       case 5:
+               return 6;
+       case 6:
+               return 10;
+       case 7:
+               return 12;
+       case 8:
+               return 16;
+       }
+}
+
+struct dce6_wm_params {
+       u32 dram_channels; /* number of dram channels */
+       u32 yclk;          /* bandwidth per dram data pin in kHz */
+       u32 sclk;          /* engine clock in kHz */
+       u32 disp_clk;      /* display clock in kHz */
+       u32 src_width;     /* viewport width */
+       u32 active_time;   /* active display time in ns */
+       u32 blank_time;    /* blank time in ns */
+       bool interlaced;    /* mode is interlaced */
+       fixed20_12 vsc;    /* vertical scale ratio */
+       u32 num_heads;     /* number of active crtcs */
+       u32 bytes_per_pixel; /* bytes per pixel display + overlay */
+       u32 lb_size;       /* line buffer allocated to pipe */
+       u32 vtaps;         /* vertical scaler taps */
+};
+
+/**
+ * dce_v6_0_dram_bandwidth - get the dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the raw dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth in MBytes/s
+ */
+static u32 dce_v6_0_dram_bandwidth(struct dce6_wm_params *wm)
+{
+       /* Calculate raw DRAM Bandwidth */
+       fixed20_12 dram_efficiency; /* 0.7 */
+       fixed20_12 yclk, dram_channels, bandwidth;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1000);
+       yclk.full = dfixed_const(wm->yclk);
+       yclk.full = dfixed_div(yclk, a);
+       dram_channels.full = dfixed_const(wm->dram_channels * 4);
+       a.full = dfixed_const(10);
+       dram_efficiency.full = dfixed_const(7);
+       dram_efficiency.full = dfixed_div(dram_efficiency, a);
+       bandwidth.full = dfixed_mul(dram_channels, yclk);
+       bandwidth.full = dfixed_mul(bandwidth, dram_efficiency);
+
+       return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v6_0_dram_bandwidth_for_display - get the dram bandwidth for display
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dram bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth for display in MBytes/s
+ */
+static u32 dce_v6_0_dram_bandwidth_for_display(struct dce6_wm_params *wm)
+{
+       /* Calculate DRAM Bandwidth and the part allocated to display. */
+       fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
+       fixed20_12 yclk, dram_channels, bandwidth;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1000);
+       yclk.full = dfixed_const(wm->yclk);
+       yclk.full = dfixed_div(yclk, a);
+       dram_channels.full = dfixed_const(wm->dram_channels * 4);
+       a.full = dfixed_const(10);
+       disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */
+       disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a);
+       bandwidth.full = dfixed_mul(dram_channels, yclk);
+       bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation);
+
+       return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v6_0_data_return_bandwidth - get the data return bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the data return bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the data return bandwidth in MBytes/s
+ */
+static u32 dce_v6_0_data_return_bandwidth(struct dce6_wm_params *wm)
+{
+       /* Calculate the display Data return Bandwidth */
+       fixed20_12 return_efficiency; /* 0.8 */
+       fixed20_12 sclk, bandwidth;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1000);
+       sclk.full = dfixed_const(wm->sclk);
+       sclk.full = dfixed_div(sclk, a);
+       a.full = dfixed_const(10);
+       return_efficiency.full = dfixed_const(8);
+       return_efficiency.full = dfixed_div(return_efficiency, a);
+       a.full = dfixed_const(32);
+       bandwidth.full = dfixed_mul(a, sclk);
+       bandwidth.full = dfixed_mul(bandwidth, return_efficiency);
+
+       return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v6_0_dmif_request_bandwidth - get the dmif bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dmif bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dmif bandwidth in MBytes/s
+ */
+static u32 dce_v6_0_dmif_request_bandwidth(struct dce6_wm_params *wm)
+{
+       /* Calculate the DMIF Request Bandwidth */
+       fixed20_12 disp_clk_request_efficiency; /* 0.8 */
+       fixed20_12 disp_clk, bandwidth;
+       fixed20_12 a, b;
+
+       a.full = dfixed_const(1000);
+       disp_clk.full = dfixed_const(wm->disp_clk);
+       disp_clk.full = dfixed_div(disp_clk, a);
+       a.full = dfixed_const(32);
+       b.full = dfixed_mul(a, disp_clk);
+
+       a.full = dfixed_const(10);
+       disp_clk_request_efficiency.full = dfixed_const(8);
+       disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a);
+
+       bandwidth.full = dfixed_mul(b, disp_clk_request_efficiency);
+
+       return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v6_0_available_bandwidth - get the min available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the min available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the min available bandwidth in MBytes/s
+ */
+static u32 dce_v6_0_available_bandwidth(struct dce6_wm_params *wm)
+{
+       /* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+       u32 dram_bandwidth = dce_v6_0_dram_bandwidth(wm);
+       u32 data_return_bandwidth = dce_v6_0_data_return_bandwidth(wm);
+       u32 dmif_req_bandwidth = dce_v6_0_dmif_request_bandwidth(wm);
+
+       return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+/**
+ * dce_v6_0_average_bandwidth - get the average available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the average available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the average available bandwidth in MBytes/s
+ */
+static u32 dce_v6_0_average_bandwidth(struct dce6_wm_params *wm)
+{
+       /* Calculate the display mode Average Bandwidth
+        * DisplayMode should contain the source and destination dimensions,
+        * timing, etc.
+        */
+       fixed20_12 bpp;
+       fixed20_12 line_time;
+       fixed20_12 src_width;
+       fixed20_12 bandwidth;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1000);
+       line_time.full = dfixed_const(wm->active_time + wm->blank_time);
+       line_time.full = dfixed_div(line_time, a);
+       bpp.full = dfixed_const(wm->bytes_per_pixel);
+       src_width.full = dfixed_const(wm->src_width);
+       bandwidth.full = dfixed_mul(src_width, bpp);
+       bandwidth.full = dfixed_mul(bandwidth, wm->vsc);
+       bandwidth.full = dfixed_div(bandwidth, line_time);
+
+       return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v6_0_latency_watermark - get the latency watermark
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the latency watermark (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the latency watermark in ns
+ */
+static u32 dce_v6_0_latency_watermark(struct dce6_wm_params *wm)
+{
+       /* First calculate the latency in ns */
+       u32 mc_latency = 2000; /* 2000 ns. */
+       u32 available_bandwidth = dce_v6_0_available_bandwidth(wm);
+       u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+       u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+       u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+       u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+               (wm->num_heads * cursor_line_pair_return_time);
+       u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+       u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
+       u32 tmp, dmif_size = 12288;
+       fixed20_12 a, b, c;
+
+       if (wm->num_heads == 0)
+               return 0;
+
+       a.full = dfixed_const(2);
+       b.full = dfixed_const(1);
+       if ((wm->vsc.full > a.full) ||
+           ((wm->vsc.full > b.full) && (wm->vtaps >= 3)) ||
+           (wm->vtaps >= 5) ||
+           ((wm->vsc.full >= a.full) && wm->interlaced))
+               max_src_lines_per_dst_line = 4;
+       else
+               max_src_lines_per_dst_line = 2;
+
+       a.full = dfixed_const(available_bandwidth);
+       b.full = dfixed_const(wm->num_heads);
+       a.full = dfixed_div(a, b);
+
+       b.full = dfixed_const(mc_latency + 512);
+       c.full = dfixed_const(wm->disp_clk);
+       b.full = dfixed_div(b, c);
+
+       c.full = dfixed_const(dmif_size);
+       b.full = dfixed_div(c, b);
+
+       tmp = min(dfixed_trunc(a), dfixed_trunc(b));
+
+       b.full = dfixed_const(1000);
+       c.full = dfixed_const(wm->disp_clk);
+       b.full = dfixed_div(c, b);
+       c.full = dfixed_const(wm->bytes_per_pixel);
+       b.full = dfixed_mul(b, c);
+
+       lb_fill_bw = min(tmp, dfixed_trunc(b));
+
+       a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
+       b.full = dfixed_const(1000);
+       c.full = dfixed_const(lb_fill_bw);
+       b.full = dfixed_div(c, b);
+       a.full = dfixed_div(a, b);
+       line_fill_time = dfixed_trunc(a);
+
+       if (line_fill_time < wm->active_time)
+               return latency;
+       else
+               return latency + (line_fill_time - wm->active_time);
+
+}
+
+/**
+ * dce_v6_0_average_bandwidth_vs_dram_bandwidth_for_display - check
+ * average and available dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce_v6_0_average_bandwidth_vs_dram_bandwidth_for_display(struct dce6_wm_params *wm)
+{
+       if (dce_v6_0_average_bandwidth(wm) <=
+           (dce_v6_0_dram_bandwidth_for_display(wm) / wm->num_heads))
+               return true;
+       else
+               return false;
+}
+
+/**
+ * dce_v6_0_average_bandwidth_vs_available_bandwidth - check
+ * average and available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * available bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce_v6_0_average_bandwidth_vs_available_bandwidth(struct dce6_wm_params *wm)
+{
+       if (dce_v6_0_average_bandwidth(wm) <=
+           (dce_v6_0_available_bandwidth(wm) / wm->num_heads))
+               return true;
+       else
+               return false;
+}
+
+/**
+ * dce_v6_0_check_latency_hiding - check latency hiding
+ *
+ * @wm: watermark calculation data
+ *
+ * Check latency hiding (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce_v6_0_check_latency_hiding(struct dce6_wm_params *wm)
+{
+       u32 lb_partitions = wm->lb_size / wm->src_width;
+       u32 line_time = wm->active_time + wm->blank_time;
+       u32 latency_tolerant_lines;
+       u32 latency_hiding;
+       fixed20_12 a;
+
+       a.full = dfixed_const(1);
+       if (wm->vsc.full > a.full)
+               latency_tolerant_lines = 1;
+       else {
+               if (lb_partitions <= (wm->vtaps + 1))
+                       latency_tolerant_lines = 1;
+               else
+                       latency_tolerant_lines = 2;
+       }
+
+       latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time);
+
+       if (dce_v6_0_latency_watermark(wm) <= latency_hiding)
+               return true;
+       else
+               return false;
+}
+
+/**
+ * dce_v6_0_program_watermarks - program display watermarks
+ *
+ * @adev: amdgpu_device pointer
+ * @amdgpu_crtc: the selected display controller
+ * @lb_size: line buffer size
+ * @num_heads: number of display controllers in use
+ *
+ * Calculate and program the display watermarks for the
+ * selected display controller (CIK).
+ */
+static void dce_v6_0_program_watermarks(struct amdgpu_device *adev,
+                                       struct amdgpu_crtc *amdgpu_crtc,
+                                       u32 lb_size, u32 num_heads)
+{
+       struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
+       struct dce6_wm_params wm_low, wm_high;
+       u32 dram_channels;
+       u32 pixel_period;
+       u32 line_time = 0;
+       u32 latency_watermark_a = 0, latency_watermark_b = 0;
+       u32 priority_a_mark = 0, priority_b_mark = 0;
+       u32 priority_a_cnt = PRIORITY_OFF;
+       u32 priority_b_cnt = PRIORITY_OFF;
+       u32 tmp, arb_control3;
+       fixed20_12 a, b, c;
+
+       if (amdgpu_crtc->base.enabled && num_heads && mode) {
+               pixel_period = 1000000 / (u32)mode->clock;
+               line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+               priority_a_cnt = 0;
+               priority_b_cnt = 0;
+
+               dram_channels = si_get_number_of_dram_channels(adev);
+
+               /* watermark for high clocks */
+               if (adev->pm.dpm_enabled) {
+                       wm_high.yclk =
+                               amdgpu_dpm_get_mclk(adev, false) * 10;
+                       wm_high.sclk =
+                               amdgpu_dpm_get_sclk(adev, false) * 10;
+               } else {
+                       wm_high.yclk = adev->pm.current_mclk * 10;
+                       wm_high.sclk = adev->pm.current_sclk * 10;
+               }
+
+               wm_high.disp_clk = mode->clock;
+               wm_high.src_width = mode->crtc_hdisplay;
+               wm_high.active_time = mode->crtc_hdisplay * pixel_period;
+               wm_high.blank_time = line_time - wm_high.active_time;
+               wm_high.interlaced = false;
+               if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                       wm_high.interlaced = true;
+               wm_high.vsc = amdgpu_crtc->vsc;
+               wm_high.vtaps = 1;
+               if (amdgpu_crtc->rmx_type != RMX_OFF)
+                       wm_high.vtaps = 2;
+               wm_high.bytes_per_pixel = 4; /* XXX: get this from fb config */
+               wm_high.lb_size = lb_size;
+               wm_high.dram_channels = dram_channels;
+               wm_high.num_heads = num_heads;
+
+               if (adev->pm.dpm_enabled) {
+               /* watermark for low clocks */
+                       wm_low.yclk =
+                               amdgpu_dpm_get_mclk(adev, true) * 10;
+                       wm_low.sclk =
+                               amdgpu_dpm_get_sclk(adev, true) * 10;
+               } else {
+                       wm_low.yclk = adev->pm.current_mclk * 10;
+                       wm_low.sclk = adev->pm.current_sclk * 10;
+               }
+
+               wm_low.disp_clk = mode->clock;
+               wm_low.src_width = mode->crtc_hdisplay;
+               wm_low.active_time = mode->crtc_hdisplay * pixel_period;
+               wm_low.blank_time = line_time - wm_low.active_time;
+               wm_low.interlaced = false;
+               if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                       wm_low.interlaced = true;
+               wm_low.vsc = amdgpu_crtc->vsc;
+               wm_low.vtaps = 1;
+               if (amdgpu_crtc->rmx_type != RMX_OFF)
+                       wm_low.vtaps = 2;
+               wm_low.bytes_per_pixel = 4; /* XXX: get this from fb config */
+               wm_low.lb_size = lb_size;
+               wm_low.dram_channels = dram_channels;
+               wm_low.num_heads = num_heads;
+
+               /* set for high clocks */
+               latency_watermark_a = min(dce_v6_0_latency_watermark(&wm_high), (u32)65535);
+               /* set for low clocks */
+               latency_watermark_b = min(dce_v6_0_latency_watermark(&wm_low), (u32)65535);
+
+               /* possibly force display priority to high */
+               /* should really do this at mode validation time... */
+               if (!dce_v6_0_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) ||
+                   !dce_v6_0_average_bandwidth_vs_available_bandwidth(&wm_high) ||
+                   !dce_v6_0_check_latency_hiding(&wm_high) ||
+                   (adev->mode_info.disp_priority == 2)) {
+                       DRM_DEBUG_KMS("force priority to high\n");
+                       priority_a_cnt |= PRIORITY_ALWAYS_ON;
+                       priority_b_cnt |= PRIORITY_ALWAYS_ON;
+               }
+               if (!dce_v6_0_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) ||
+                   !dce_v6_0_average_bandwidth_vs_available_bandwidth(&wm_low) ||
+                   !dce_v6_0_check_latency_hiding(&wm_low) ||
+                   (adev->mode_info.disp_priority == 2)) {
+                       DRM_DEBUG_KMS("force priority to high\n");
+                       priority_a_cnt |= PRIORITY_ALWAYS_ON;
+                       priority_b_cnt |= PRIORITY_ALWAYS_ON;
+               }
+
+               a.full = dfixed_const(1000);
+               b.full = dfixed_const(mode->clock);
+               b.full = dfixed_div(b, a);
+               c.full = dfixed_const(latency_watermark_a);
+               c.full = dfixed_mul(c, b);
+               c.full = dfixed_mul(c, amdgpu_crtc->hsc);
+               c.full = dfixed_div(c, a);
+               a.full = dfixed_const(16);
+               c.full = dfixed_div(c, a);
+               priority_a_mark = dfixed_trunc(c);
+               priority_a_cnt |= priority_a_mark & PRIORITY_MARK_MASK;
+
+               a.full = dfixed_const(1000);
+               b.full = dfixed_const(mode->clock);
+               b.full = dfixed_div(b, a);
+               c.full = dfixed_const(latency_watermark_b);
+               c.full = dfixed_mul(c, b);
+               c.full = dfixed_mul(c, amdgpu_crtc->hsc);
+               c.full = dfixed_div(c, a);
+               a.full = dfixed_const(16);
+               c.full = dfixed_div(c, a);
+               priority_b_mark = dfixed_trunc(c);
+               priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
+       }
+
+       /* select wm A */
+       arb_control3 = RREG32(DPG_PIPE_ARBITRATION_CONTROL3 + amdgpu_crtc->crtc_offset);
+       tmp = arb_control3;
+       tmp &= ~LATENCY_WATERMARK_MASK(3);
+       tmp |= LATENCY_WATERMARK_MASK(1);
+       WREG32(DPG_PIPE_ARBITRATION_CONTROL3 + amdgpu_crtc->crtc_offset, tmp);
+       WREG32(DPG_PIPE_LATENCY_CONTROL + amdgpu_crtc->crtc_offset,
+              (LATENCY_LOW_WATERMARK(latency_watermark_a) |
+               LATENCY_HIGH_WATERMARK(line_time)));
+       /* select wm B */
+       tmp = RREG32(DPG_PIPE_ARBITRATION_CONTROL3 + amdgpu_crtc->crtc_offset);
+       tmp &= ~LATENCY_WATERMARK_MASK(3);
+       tmp |= LATENCY_WATERMARK_MASK(2);
+       WREG32(DPG_PIPE_ARBITRATION_CONTROL3 + amdgpu_crtc->crtc_offset, tmp);
+       WREG32(DPG_PIPE_LATENCY_CONTROL + amdgpu_crtc->crtc_offset,
+              (LATENCY_LOW_WATERMARK(latency_watermark_b) |
+               LATENCY_HIGH_WATERMARK(line_time)));
+       /* restore original selection */
+       WREG32(DPG_PIPE_ARBITRATION_CONTROL3 + amdgpu_crtc->crtc_offset, arb_control3);
+
+       /* write the priority marks */
+       WREG32(PRIORITY_A_CNT + amdgpu_crtc->crtc_offset, priority_a_cnt);
+       WREG32(PRIORITY_B_CNT + amdgpu_crtc->crtc_offset, priority_b_cnt);
+
+       /* save values for DPM */
+       amdgpu_crtc->line_time = line_time;
+       amdgpu_crtc->wm_high = latency_watermark_a;
+}
+
+/* watermark setup */
+static u32 dce_v6_0_line_buffer_adjust(struct amdgpu_device *adev,
+                                  struct amdgpu_crtc *amdgpu_crtc,
+                                  struct drm_display_mode *mode,
+                                  struct drm_display_mode *other_mode)
+{
+       u32 tmp, buffer_alloc, i;
+       u32 pipe_offset = amdgpu_crtc->crtc_id * 0x8;
+       /*
+        * Line Buffer Setup
+        * There are 3 line buffers, each one shared by 2 display controllers.
+        * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between
+        * the display controllers.  The paritioning is done via one of four
+        * preset allocations specified in bits 21:20:
+        *  0 - half lb
+        *  2 - whole lb, other crtc must be disabled
+        */
+       /* this can get tricky if we have two large displays on a paired group
+        * of crtcs.  Ideally for multiple large displays we'd assign them to
+        * non-linked crtcs for maximum line buffer allocation.
+        */
+       if (amdgpu_crtc->base.enabled && mode) {
+               if (other_mode) {
+                       tmp = 0; /* 1/2 */
+                       buffer_alloc = 1;
+               } else {
+                       tmp = 2; /* whole */
+                       buffer_alloc = 2;
+               }
+       } else {
+               tmp = 0;
+               buffer_alloc = 0;
+       }
+
+       WREG32(DC_LB_MEMORY_SPLIT + amdgpu_crtc->crtc_offset,
+              DC_LB_MEMORY_CONFIG(tmp));
+
+       WREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset,
+              DMIF_BUFFERS_ALLOCATED(buffer_alloc));
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (RREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset) &
+                   DMIF_BUFFERS_ALLOCATED_COMPLETED)
+                       break;
+               udelay(1);
+       }
+
+       if (amdgpu_crtc->base.enabled && mode) {
+               switch (tmp) {
+               case 0:
+               default:
+                       return 4096 * 2;
+               case 2:
+                       return 8192 * 2;
+               }
+       }
+
+       /* controller not enabled, so no lb used */
+       return 0;
+}
+
+
+/**
+ *
+ * dce_v6_0_bandwidth_update - program display watermarks
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Calculate and program the display watermarks and line
+ * buffer allocation (CIK).
+ */
+static void dce_v6_0_bandwidth_update(struct amdgpu_device *adev)
+{
+       struct drm_display_mode *mode0 = NULL;
+       struct drm_display_mode *mode1 = NULL;
+       u32 num_heads = 0, lb_size;
+       int i;
+
+       if (!adev->mode_info.mode_config_initialized)
+               return;
+
+       amdgpu_update_display_priority(adev);
+
+       for (i = 0; i < adev->mode_info.num_crtc; i++) {
+               if (adev->mode_info.crtcs[i]->base.enabled)
+                       num_heads++;
+       }
+       for (i = 0; i < adev->mode_info.num_crtc; i += 2) {
+               mode0 = &adev->mode_info.crtcs[i]->base.mode;
+               mode1 = &adev->mode_info.crtcs[i+1]->base.mode;
+               lb_size = dce_v6_0_line_buffer_adjust(adev, adev->mode_info.crtcs[i], mode0, mode1);
+               dce_v6_0_program_watermarks(adev, adev->mode_info.crtcs[i], lb_size, num_heads);
+               lb_size = dce_v6_0_line_buffer_adjust(adev, adev->mode_info.crtcs[i+1], mode1, mode0);
+               dce_v6_0_program_watermarks(adev, adev->mode_info.crtcs[i+1], lb_size, num_heads);
+       }
+}
+/*
+static void dce_v6_0_audio_get_connected_pins(struct amdgpu_device *adev)
+{
+       int i;
+       u32 offset, tmp;
+
+       for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+               offset = adev->mode_info.audio.pin[i].offset;
+               tmp = RREG32_AUDIO_ENDPT(offset,
+                                     AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
+               if (((tmp & PORT_CONNECTIVITY_MASK) >> PORT_CONNECTIVITY_SHIFT) == 1)
+                       adev->mode_info.audio.pin[i].connected = false;
+               else
+                       adev->mode_info.audio.pin[i].connected = true;
+       }
+
+}
+
+static struct amdgpu_audio_pin *dce_v6_0_audio_get_pin(struct amdgpu_device *adev)
+{
+       int i;
+
+       dce_v6_0_audio_get_connected_pins(adev);
+
+       for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+               if (adev->mode_info.audio.pin[i].connected)
+                       return &adev->mode_info.audio.pin[i];
+       }
+       DRM_ERROR("No connected audio pins found!\n");
+       return NULL;
+}
+
+static void dce_v6_0_afmt_audio_select_pin(struct drm_encoder *encoder)
+{
+       struct amdgpu_device *adev = encoder->dev->dev_private;
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+       struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+       u32 offset;
+
+       if (!dig || !dig->afmt || !dig->afmt->pin)
+               return;
+
+       offset = dig->afmt->offset;
+
+       WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
+              AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
+
+}
+
+static void dce_v6_0_audio_write_latency_fields(struct drm_encoder *encoder,
+                                               struct drm_display_mode *mode)
+{
+       DRM_INFO("xxxx: dce_v6_0_audio_write_latency_fields---no imp!!!!!\n");
+}
+
+static void dce_v6_0_audio_write_speaker_allocation(struct drm_encoder *encoder)
+{
+       DRM_INFO("xxxx: dce_v6_0_audio_write_speaker_allocation---no imp!!!!!\n");
+}
+
+static void dce_v6_0_audio_write_sad_regs(struct drm_encoder *encoder)
+{
+       DRM_INFO("xxxx: dce_v6_0_audio_write_sad_regs---no imp!!!!!\n");
+
+}
+*/
+static void dce_v6_0_audio_enable(struct amdgpu_device *adev,
+                                 struct amdgpu_audio_pin *pin,
+                                 bool enable)
+{
+       DRM_INFO("xxxx: dce_v6_0_audio_enable---no imp!!!!!\n");
+}
+
+static const u32 pin_offsets[7] =
+{
+       (0x1780 - 0x1780),
+       (0x1786 - 0x1780),
+       (0x178c - 0x1780),
+       (0x1792 - 0x1780),
+       (0x1798 - 0x1780),
+       (0x179d - 0x1780),
+       (0x17a4 - 0x1780),
+};
+
+static int dce_v6_0_audio_init(struct amdgpu_device *adev)
+{
+       return 0;
+}
+
+static void dce_v6_0_audio_fini(struct amdgpu_device *adev)
+{
+
+}
+
+/*
+static void dce_v6_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock)
+{
+       DRM_INFO("xxxx: dce_v6_0_afmt_update_ACR---no imp!!!!!\n");
+}
+*/
+/*
+ * build a HDMI Video Info Frame
+ */
+/*
+static void dce_v6_0_afmt_update_avi_infoframe(struct drm_encoder *encoder,
+                                              void *buffer, size_t size)
+{
+       DRM_INFO("xxxx: dce_v6_0_afmt_update_avi_infoframe---no imp!!!!!\n");
+}
+
+static void dce_v6_0_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+{
+       DRM_INFO("xxxx: dce_v6_0_audio_set_dto---no imp!!!!!\n");
+}
+*/
+/*
+ * update the info frames with the data from the current display mode
+ */
+static void dce_v6_0_afmt_setmode(struct drm_encoder *encoder,
+                                 struct drm_display_mode *mode)
+{
+       DRM_INFO("xxxx: dce_v6_0_afmt_setmode ----no impl !!!!!!!!\n");
+}
+
+static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable)
+{
+       struct drm_device *dev = encoder->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+       struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+
+       if (!dig || !dig->afmt)
+               return;
+
+       /* Silent, r600_hdmi_enable will raise WARN for us */
+       if (enable && dig->afmt->enabled)
+               return;
+       if (!enable && !dig->afmt->enabled)
+               return;
+
+       if (!enable && dig->afmt->pin) {
+               dce_v6_0_audio_enable(adev, dig->afmt->pin, false);
+               dig->afmt->pin = NULL;
+       }
+
+       dig->afmt->enabled = enable;
+
+       DRM_DEBUG("%sabling AFMT interface @ 0x%04X for encoder 0x%x\n",
+                 enable ? "En" : "Dis", dig->afmt->offset, amdgpu_encoder->encoder_id);
+}
+
+static int dce_v6_0_afmt_init(struct amdgpu_device *adev)
+{
+       int i, j;
+
+       for (i = 0; i < adev->mode_info.num_dig; i++)
+               adev->mode_info.afmt[i] = NULL;
+
+       /* DCE6 has audio blocks tied to DIG encoders */
+       for (i = 0; i < adev->mode_info.num_dig; i++) {
+               adev->mode_info.afmt[i] = kzalloc(sizeof(struct amdgpu_afmt), GFP_KERNEL);
+               if (adev->mode_info.afmt[i]) {
+                       adev->mode_info.afmt[i]->offset = dig_offsets[i];
+                       adev->mode_info.afmt[i]->id = i;
+               } else {
+                       for (j = 0; j < i; j++) {
+                               kfree(adev->mode_info.afmt[j]);
+                               adev->mode_info.afmt[j] = NULL;
+                       }
+                       DRM_ERROR("Out of memory allocating afmt table\n");
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
+static void dce_v6_0_afmt_fini(struct amdgpu_device *adev)
+{
+       int i;
+
+       for (i = 0; i < adev->mode_info.num_dig; i++) {
+               kfree(adev->mode_info.afmt[i]);
+               adev->mode_info.afmt[i] = NULL;
+       }
+}
+
+static const u32 vga_control_regs[6] =
+{
+       AVIVO_D1VGA_CONTROL,
+       AVIVO_D2VGA_CONTROL,
+       EVERGREEN_D3VGA_CONTROL,
+       EVERGREEN_D4VGA_CONTROL,
+       EVERGREEN_D5VGA_CONTROL,
+       EVERGREEN_D6VGA_CONTROL,
+};
+
+static void dce_v6_0_vga_enable(struct drm_crtc *crtc, bool enable)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       u32 vga_control;
+
+       vga_control = RREG32(vga_control_regs[amdgpu_crtc->crtc_id]) & ~1;
+       WREG32(vga_control_regs[amdgpu_crtc->crtc_id], vga_control | (enable ? 1 : 0));
+}
+
+static void dce_v6_0_grph_enable(struct drm_crtc *crtc, bool enable)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+
+       WREG32(EVERGREEN_GRPH_ENABLE + amdgpu_crtc->crtc_offset, enable ? 1 : 0);
+}
+
+static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc,
+                                    struct drm_framebuffer *fb,
+                                    int x, int y, int atomic)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_framebuffer *amdgpu_fb;
+       struct drm_framebuffer *target_fb;
+       struct drm_gem_object *obj;
+       struct amdgpu_bo *abo;
+       uint64_t fb_location, tiling_flags;
+       uint32_t fb_format, fb_pitch_pixels, pipe_config;
+       u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
+       u32 viewport_w, viewport_h;
+       int r;
+       bool bypass_lut = false;
+
+       /* no fb bound */
+       if (!atomic && !crtc->primary->fb) {
+               DRM_DEBUG_KMS("No FB bound\n");
+               return 0;
+       }
+
+       if (atomic) {
+               amdgpu_fb = to_amdgpu_framebuffer(fb);
+               target_fb = fb;
+       } else {
+               amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
+               target_fb = crtc->primary->fb;
+       }
+
+       /* If atomic, assume fb object is pinned & idle & fenced and
+        * just update base pointers
+        */
+       obj = amdgpu_fb->obj;
+       abo = gem_to_amdgpu_bo(obj);
+       r = amdgpu_bo_reserve(abo, false);
+       if (unlikely(r != 0))
+               return r;
+
+       if (atomic) {
+               fb_location = amdgpu_bo_gpu_offset(abo);
+       } else {
+               r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location);
+               if (unlikely(r != 0)) {
+                       amdgpu_bo_unreserve(abo);
+                       return -EINVAL;
+               }
+       }
+
+       amdgpu_bo_get_tiling_flags(abo, &tiling_flags);
+       amdgpu_bo_unreserve(abo);
+
+       switch (target_fb->pixel_format) {
+       case DRM_FORMAT_C8:
+               fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
+                            EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
+               break;
+       case DRM_FORMAT_XRGB4444:
+       case DRM_FORMAT_ARGB4444:
+               fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
+                            EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB4444));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
+#endif
+               break;
+       case DRM_FORMAT_XRGB1555:
+       case DRM_FORMAT_ARGB1555:
+               fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
+                            EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
+#endif
+               break;
+       case DRM_FORMAT_BGRX5551:
+       case DRM_FORMAT_BGRA5551:
+               fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
+                            EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA5551));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
+#endif
+               break;
+       case DRM_FORMAT_RGB565:
+               fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
+                            EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
+#endif
+               break;
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_ARGB8888:
+               fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
+                            EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
+#endif
+               break;
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_ARGB2101010:
+               fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
+                            EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB2101010));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
+#endif
+               /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
+               bypass_lut = true;
+               break;
+       case DRM_FORMAT_BGRX1010102:
+       case DRM_FORMAT_BGRA1010102:
+               fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
+                            EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA1010102));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
+#endif
+               /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
+               bypass_lut = true;
+               break;
+       default:
+               DRM_ERROR("Unsupported screen format %s\n",
+                         drm_get_format_name(target_fb->pixel_format));
+               return -EINVAL;
+       }
+
+       if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == ARRAY_2D_TILED_THIN1) {
+               unsigned bankw, bankh, mtaspect, tile_split, num_banks;
+
+               bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
+               bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
+               mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
+               tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
+               num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
+
+               fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks);
+               fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
+               fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split);
+               fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
+               fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
+               fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect);
+       } else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == ARRAY_1D_TILED_THIN1) {
+               fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
+       }
+
+       pipe_config = AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
+       fb_format |= SI_GRPH_PIPE_CONFIG(pipe_config);
+
+       dce_v6_0_vga_enable(crtc, false);
+
+       /* Make sure surface address is updated at vertical blank rather than
+        * horizontal blank
+        */
+       WREG32(EVERGREEN_GRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, 0);
+
+       WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+              upper_32_bits(fb_location));
+       WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+              upper_32_bits(fb_location));
+       WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+              (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
+       WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+              (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
+       WREG32(EVERGREEN_GRPH_CONTROL + amdgpu_crtc->crtc_offset, fb_format);
+       WREG32(EVERGREEN_GRPH_SWAP_CONTROL + amdgpu_crtc->crtc_offset, fb_swap);
+
+       /*
+        * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT
+        * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to
+        * retain the full precision throughout the pipeline.
+        */
+       WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + amdgpu_crtc->crtc_offset,
+                (bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0),
+                ~EVERGREEN_LUT_10BIT_BYPASS_EN);
+
+       if (bypass_lut)
+               DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n");
+
+       WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + amdgpu_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + amdgpu_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_GRPH_X_START + amdgpu_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_GRPH_Y_START + amdgpu_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_GRPH_X_END + amdgpu_crtc->crtc_offset, target_fb->width);
+       WREG32(EVERGREEN_GRPH_Y_END + amdgpu_crtc->crtc_offset, target_fb->height);
+
+       fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8);
+       WREG32(EVERGREEN_GRPH_PITCH + amdgpu_crtc->crtc_offset, fb_pitch_pixels);
+
+       dce_v6_0_grph_enable(crtc, true);
+
+       WREG32(EVERGREEN_DESKTOP_HEIGHT + amdgpu_crtc->crtc_offset,
+                      target_fb->height);
+       x &= ~3;
+       y &= ~1;
+       WREG32(EVERGREEN_VIEWPORT_START + amdgpu_crtc->crtc_offset,
+              (x << 16) | y);
+       viewport_w = crtc->mode.hdisplay;
+       viewport_h = (crtc->mode.vdisplay + 1) & ~1;
+
+       WREG32(EVERGREEN_VIEWPORT_SIZE + amdgpu_crtc->crtc_offset,
+              (viewport_w << 16) | viewport_h);
+
+       /* set pageflip to happen anywhere in vblank interval */
+       WREG32(EVERGREEN_MASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0);
+
+       if (!atomic && fb && fb != crtc->primary->fb) {
+               amdgpu_fb = to_amdgpu_framebuffer(fb);
+               abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+               r = amdgpu_bo_reserve(abo, false);
+               if (unlikely(r != 0))
+                       return r;
+               amdgpu_bo_unpin(abo);
+               amdgpu_bo_unreserve(abo);
+       }
+
+       /* Bytes per pixel may have changed */
+       dce_v6_0_bandwidth_update(adev);
+
+       return 0;
+
+}
+
+static void dce_v6_0_set_interleave(struct drm_crtc *crtc,
+                                   struct drm_display_mode *mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               WREG32(EVERGREEN_DATA_FORMAT + amdgpu_crtc->crtc_offset,
+                      EVERGREEN_INTERLEAVE_EN);
+       else
+               WREG32(EVERGREEN_DATA_FORMAT + amdgpu_crtc->crtc_offset, 0);
+}
+
+static void dce_v6_0_crtc_load_lut(struct drm_crtc *crtc)
+{
+
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       int i;
+
+       DRM_DEBUG_KMS("%d\n", amdgpu_crtc->crtc_id);
+
+       WREG32(NI_INPUT_CSC_CONTROL + amdgpu_crtc->crtc_offset,
+              (NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS) |
+               NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS)));
+       WREG32(NI_PRESCALE_GRPH_CONTROL + amdgpu_crtc->crtc_offset,
+              NI_GRPH_PRESCALE_BYPASS);
+       WREG32(NI_PRESCALE_OVL_CONTROL + amdgpu_crtc->crtc_offset,
+              NI_OVL_PRESCALE_BYPASS);
+       WREG32(NI_INPUT_GAMMA_CONTROL + amdgpu_crtc->crtc_offset,
+              (NI_GRPH_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT) |
+               NI_OVL_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT)));
+
+
+
+       WREG32(EVERGREEN_DC_LUT_CONTROL + amdgpu_crtc->crtc_offset, 0);
+
+       WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + amdgpu_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + amdgpu_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_RED + amdgpu_crtc->crtc_offset, 0);
+
+       WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + amdgpu_crtc->crtc_offset, 0xffff);
+       WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + amdgpu_crtc->crtc_offset, 0xffff);
+       WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_RED + amdgpu_crtc->crtc_offset, 0xffff);
+
+       WREG32(EVERGREEN_DC_LUT_RW_MODE + amdgpu_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_DC_LUT_WRITE_EN_MASK + amdgpu_crtc->crtc_offset, 0x00000007);
+
+       WREG32(EVERGREEN_DC_LUT_RW_INDEX + amdgpu_crtc->crtc_offset, 0);
+       for (i = 0; i < 256; i++) {
+               WREG32(EVERGREEN_DC_LUT_30_COLOR + amdgpu_crtc->crtc_offset,
+                      (amdgpu_crtc->lut_r[i] << 20) |
+                      (amdgpu_crtc->lut_g[i] << 10) |
+                      (amdgpu_crtc->lut_b[i] << 0));
+       }
+
+       WREG32(NI_DEGAMMA_CONTROL + amdgpu_crtc->crtc_offset,
+              (NI_GRPH_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) |
+               NI_OVL_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) |
+               NI_ICON_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) |
+               NI_CURSOR_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)));
+       WREG32(NI_GAMUT_REMAP_CONTROL + amdgpu_crtc->crtc_offset,
+              (NI_GRPH_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS) |
+               NI_OVL_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS)));
+       WREG32(NI_REGAMMA_CONTROL + amdgpu_crtc->crtc_offset,
+              (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) |
+               NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS)));
+       WREG32(NI_OUTPUT_CSC_CONTROL + amdgpu_crtc->crtc_offset,
+              (NI_OUTPUT_CSC_GRPH_MODE(0) |
+               NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
+       /* XXX match this to the depth of the crtc fmt block, move to modeset? */
+       WREG32(0x1a50 + amdgpu_crtc->crtc_offset, 0);
+
+
+}
+
+static int dce_v6_0_pick_dig_encoder(struct drm_encoder *encoder)
+{
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+       struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+
+       switch (amdgpu_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+               return dig->linkb ? 1 : 0;
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+               return dig->linkb ? 3 : 2;
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+               return dig->linkb ? 5 : 4;
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+               return 6;
+       default:
+               DRM_ERROR("invalid encoder_id: 0x%x\n", amdgpu_encoder->encoder_id);
+               return 0;
+       }
+}
+
+/**
+ * dce_v6_0_pick_pll - Allocate a PPLL for use by the crtc.
+ *
+ * @crtc: drm crtc
+ *
+ * Returns the PPLL (Pixel PLL) to be used by the crtc.  For DP monitors
+ * a single PPLL can be used for all DP crtcs/encoders.  For non-DP
+ * monitors a dedicated PPLL must be used.  If a particular board has
+ * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming
+ * as there is no need to program the PLL itself.  If we are not able to
+ * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to
+ * avoid messing up an existing monitor.
+ *
+ *
+ */
+static u32 dce_v6_0_pick_pll(struct drm_crtc *crtc)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       u32 pll_in_use;
+       int pll;
+
+       if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder))) {
+               if (adev->clock.dp_extclk)
+                       /* skip PPLL programming if using ext clock */
+                       return ATOM_PPLL_INVALID;
+               else
+                       return ATOM_PPLL0;
+       } else {
+               /* use the same PPLL for all monitors with the same clock */
+               pll = amdgpu_pll_get_shared_nondp_ppll(crtc);
+               if (pll != ATOM_PPLL_INVALID)
+                       return pll;
+       }
+
+       /*  PPLL1, and PPLL2 */
+       pll_in_use = amdgpu_pll_get_use_mask(crtc);
+       if (!(pll_in_use & (1 << ATOM_PPLL2)))
+               return ATOM_PPLL2;
+       if (!(pll_in_use & (1 << ATOM_PPLL1)))
+               return ATOM_PPLL1;
+       DRM_ERROR("unable to allocate a PPLL\n");
+       return ATOM_PPLL_INVALID;
+}
+
+static void dce_v6_0_lock_cursor(struct drm_crtc *crtc, bool lock)
+{
+       struct amdgpu_device *adev = crtc->dev->dev_private;
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       uint32_t cur_lock;
+
+       cur_lock = RREG32(EVERGREEN_CUR_UPDATE + amdgpu_crtc->crtc_offset);
+       if (lock)
+               cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
+       else
+               cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
+       WREG32(EVERGREEN_CUR_UPDATE + amdgpu_crtc->crtc_offset, cur_lock);
+}
+
+static void dce_v6_0_hide_cursor(struct drm_crtc *crtc)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct amdgpu_device *adev = crtc->dev->dev_private;
+
+       WREG32_IDX(EVERGREEN_CUR_CONTROL + amdgpu_crtc->crtc_offset,
+                  EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
+                  EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
+
+
+}
+
+static void dce_v6_0_show_cursor(struct drm_crtc *crtc)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct amdgpu_device *adev = crtc->dev->dev_private;
+
+       WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+              upper_32_bits(amdgpu_crtc->cursor_addr));
+       WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+              lower_32_bits(amdgpu_crtc->cursor_addr));
+
+       WREG32_IDX(EVERGREEN_CUR_CONTROL + amdgpu_crtc->crtc_offset,
+                  EVERGREEN_CURSOR_EN |
+                  EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
+                  EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
+
+}
+
+static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc,
+                                      int x, int y)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct amdgpu_device *adev = crtc->dev->dev_private;
+       int xorigin = 0, yorigin = 0;
+
+       int w = amdgpu_crtc->cursor_width;
+
+       /* avivo cursor are offset into the total surface */
+       x += crtc->x;
+       y += crtc->y;
+       DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+
+       if (x < 0) {
+               xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
+               x = 0;
+       }
+       if (y < 0) {
+               yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
+               y = 0;
+       }
+
+       WREG32(EVERGREEN_CUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
+       WREG32(EVERGREEN_CUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+       WREG32(EVERGREEN_CUR_SIZE + amdgpu_crtc->crtc_offset,
+              ((w - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
+
+       amdgpu_crtc->cursor_x = x;
+       amdgpu_crtc->cursor_y = y;
+       return 0;
+}
+
+static int dce_v6_0_crtc_cursor_move(struct drm_crtc *crtc,
+                                    int x, int y)
+{
+       int ret;
+
+       dce_v6_0_lock_cursor(crtc, true);
+       ret = dce_v6_0_cursor_move_locked(crtc, x, y);
+       dce_v6_0_lock_cursor(crtc, false);
+
+       return ret;
+}
+
+static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
+                                    struct drm_file *file_priv,
+                                    uint32_t handle,
+                                    uint32_t width,
+                                    uint32_t height,
+                                    int32_t hot_x,
+                                    int32_t hot_y)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct drm_gem_object *obj;
+       struct amdgpu_bo *aobj;
+       int ret;
+
+       if (!handle) {
+               /* turn off cursor */
+               dce_v6_0_hide_cursor(crtc);
+               obj = NULL;
+               goto unpin;
+       }
+
+       if ((width > amdgpu_crtc->max_cursor_width) ||
+           (height > amdgpu_crtc->max_cursor_height)) {
+               DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
+               return -EINVAL;
+       }
+
+       obj = drm_gem_object_lookup(file_priv, handle);
+       if (!obj) {
+               DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, amdgpu_crtc->crtc_id);
+               return -ENOENT;
+       }
+
+       aobj = gem_to_amdgpu_bo(obj);
+       ret = amdgpu_bo_reserve(aobj, false);
+       if (ret != 0) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
+
+       ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM, &amdgpu_crtc->cursor_addr);
+       amdgpu_bo_unreserve(aobj);
+       if (ret) {
+               DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
+
+       amdgpu_crtc->cursor_width = width;
+       amdgpu_crtc->cursor_height = height;
+
+       dce_v6_0_lock_cursor(crtc, true);
+
+       if (hot_x != amdgpu_crtc->cursor_hot_x ||
+           hot_y != amdgpu_crtc->cursor_hot_y) {
+               int x, y;
+
+               x = amdgpu_crtc->cursor_x + amdgpu_crtc->cursor_hot_x - hot_x;
+               y = amdgpu_crtc->cursor_y + amdgpu_crtc->cursor_hot_y - hot_y;
+
+               dce_v6_0_cursor_move_locked(crtc, x, y);
+
+               amdgpu_crtc->cursor_hot_x = hot_x;
+               amdgpu_crtc->cursor_hot_y = hot_y;
+       }
+
+       dce_v6_0_show_cursor(crtc);
+       dce_v6_0_lock_cursor(crtc, false);
+
+unpin:
+       if (amdgpu_crtc->cursor_bo) {
+               struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo);
+               ret = amdgpu_bo_reserve(aobj, false);
+               if (likely(ret == 0)) {
+                       amdgpu_bo_unpin(aobj);
+                       amdgpu_bo_unreserve(aobj);
+               }
+               drm_gem_object_unreference_unlocked(amdgpu_crtc->cursor_bo);
+       }
+
+       amdgpu_crtc->cursor_bo = obj;
+       return 0;
+}
+
+static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+       if (amdgpu_crtc->cursor_bo) {
+               dce_v6_0_lock_cursor(crtc, true);
+
+               dce_v6_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
+                                           amdgpu_crtc->cursor_y);
+
+               dce_v6_0_show_cursor(crtc);
+               dce_v6_0_lock_cursor(crtc, false);
+       }
+}
+
+static int dce_v6_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+                                  u16 *blue, uint32_t size)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       int i;
+
+       /* userspace palettes are always correct as is */
+       for (i = 0; i < size; i++) {
+               amdgpu_crtc->lut_r[i] = red[i] >> 6;
+               amdgpu_crtc->lut_g[i] = green[i] >> 6;
+               amdgpu_crtc->lut_b[i] = blue[i] >> 6;
+       }
+       dce_v6_0_crtc_load_lut(crtc);
+
+       return 0;
+}
+
+static void dce_v6_0_crtc_destroy(struct drm_crtc *crtc)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+       drm_crtc_cleanup(crtc);
+       kfree(amdgpu_crtc);
+}
+
+static const struct drm_crtc_funcs dce_v6_0_crtc_funcs = {
+       .cursor_set2 = dce_v6_0_crtc_cursor_set2,
+       .cursor_move = dce_v6_0_crtc_cursor_move,
+       .gamma_set = dce_v6_0_crtc_gamma_set,
+       .set_config = amdgpu_crtc_set_config,
+       .destroy = dce_v6_0_crtc_destroy,
+       .page_flip_target = amdgpu_crtc_page_flip_target,
+};
+
+static void dce_v6_0_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       unsigned type;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               amdgpu_crtc->enabled = true;
+               amdgpu_atombios_crtc_enable(crtc, ATOM_ENABLE);
+               amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE);
+               /* Make sure VBLANK and PFLIP interrupts are still enabled */
+               type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id);
+               amdgpu_irq_update(adev, &adev->crtc_irq, type);
+               amdgpu_irq_update(adev, &adev->pageflip_irq, type);
+               drm_vblank_post_modeset(dev, amdgpu_crtc->crtc_id);
+               dce_v6_0_crtc_load_lut(crtc);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               drm_vblank_pre_modeset(dev, amdgpu_crtc->crtc_id);
+               if (amdgpu_crtc->enabled)
+                       amdgpu_atombios_crtc_blank(crtc, ATOM_ENABLE);
+               amdgpu_atombios_crtc_enable(crtc, ATOM_DISABLE);
+               amdgpu_crtc->enabled = false;
+               break;
+       }
+       /* adjust pm to dpms */
+       amdgpu_pm_compute_clocks(adev);
+}
+
+static void dce_v6_0_crtc_prepare(struct drm_crtc *crtc)
+{
+       /* disable crtc pair power gating before programming */
+       amdgpu_atombios_crtc_powergate(crtc, ATOM_DISABLE);
+       amdgpu_atombios_crtc_lock(crtc, ATOM_ENABLE);
+       dce_v6_0_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void dce_v6_0_crtc_commit(struct drm_crtc *crtc)
+{
+       dce_v6_0_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+       amdgpu_atombios_crtc_lock(crtc, ATOM_DISABLE);
+}
+
+static void dce_v6_0_crtc_disable(struct drm_crtc *crtc)
+{
+
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_atom_ss ss;
+       int i;
+
+       dce_v6_0_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       if (crtc->primary->fb) {
+               int r;
+               struct amdgpu_framebuffer *amdgpu_fb;
+               struct amdgpu_bo *abo;
+
+               amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
+               abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+               r = amdgpu_bo_reserve(abo, false);
+               if (unlikely(r))
+                       DRM_ERROR("failed to reserve abo before unpin\n");
+               else {
+                       amdgpu_bo_unpin(abo);
+                       amdgpu_bo_unreserve(abo);
+               }
+       }
+       /* disable the GRPH */
+       dce_v6_0_grph_enable(crtc, false);
+
+       amdgpu_atombios_crtc_powergate(crtc, ATOM_ENABLE);
+
+       for (i = 0; i < adev->mode_info.num_crtc; i++) {
+               if (adev->mode_info.crtcs[i] &&
+                   adev->mode_info.crtcs[i]->enabled &&
+                   i != amdgpu_crtc->crtc_id &&
+                   amdgpu_crtc->pll_id == adev->mode_info.crtcs[i]->pll_id) {
+                       /* one other crtc is using this pll don't turn
+                        * off the pll
+                        */
+                       goto done;
+               }
+       }
+
+       switch (amdgpu_crtc->pll_id) {
+       case ATOM_PPLL1:
+       case ATOM_PPLL2:
+               /* disable the ppll */
+               amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id,
+                                                0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
+               break;
+       default:
+               break;
+       }
+done:
+       amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
+       amdgpu_crtc->adjusted_clock = 0;
+       amdgpu_crtc->encoder = NULL;
+       amdgpu_crtc->connector = NULL;
+}
+
+static int dce_v6_0_crtc_mode_set(struct drm_crtc *crtc,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode,
+                                 int x, int y, struct drm_framebuffer *old_fb)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+       if (!amdgpu_crtc->adjusted_clock)
+               return -EINVAL;
+
+       amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode);
+       amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode);
+       dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
+       amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode);
+       amdgpu_atombios_crtc_scaler_setup(crtc);
+       dce_v6_0_cursor_reset(crtc);
+       /* update the hw version fpr dpm */
+       amdgpu_crtc->hw_mode = *adjusted_mode;
+
+       return 0;
+}
+
+static bool dce_v6_0_crtc_mode_fixup(struct drm_crtc *crtc,
+                                    const struct drm_display_mode *mode,
+                                    struct drm_display_mode *adjusted_mode)
+{
+
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct drm_encoder *encoder;
+
+       /* assign the encoder to the amdgpu crtc to avoid repeated lookups later */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               if (encoder->crtc == crtc) {
+                       amdgpu_crtc->encoder = encoder;
+                       amdgpu_crtc->connector = amdgpu_get_connector_for_encoder(encoder);
+                       break;
+               }
+       }
+       if ((amdgpu_crtc->encoder == NULL) || (amdgpu_crtc->connector == NULL)) {
+               amdgpu_crtc->encoder = NULL;
+               amdgpu_crtc->connector = NULL;
+               return false;
+       }
+       if (!amdgpu_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
+               return false;
+       if (amdgpu_atombios_crtc_prepare_pll(crtc, adjusted_mode))
+               return false;
+       /* pick pll */
+       amdgpu_crtc->pll_id = dce_v6_0_pick_pll(crtc);
+       /* if we can't get a PPLL for a non-DP encoder, fail */
+       if ((amdgpu_crtc->pll_id == ATOM_PPLL_INVALID) &&
+           !ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder)))
+               return false;
+
+       return true;
+}
+
+static int dce_v6_0_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+                                 struct drm_framebuffer *old_fb)
+{
+       return dce_v6_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+static int dce_v6_0_crtc_set_base_atomic(struct drm_crtc *crtc,
+                                        struct drm_framebuffer *fb,
+                                        int x, int y, enum mode_set_atomic state)
+{
+       return dce_v6_0_crtc_do_set_base(crtc, fb, x, y, 1);
+}
+
+static const struct drm_crtc_helper_funcs dce_v6_0_crtc_helper_funcs = {
+       .dpms = dce_v6_0_crtc_dpms,
+       .mode_fixup = dce_v6_0_crtc_mode_fixup,
+       .mode_set = dce_v6_0_crtc_mode_set,
+       .mode_set_base = dce_v6_0_crtc_set_base,
+       .mode_set_base_atomic = dce_v6_0_crtc_set_base_atomic,
+       .prepare = dce_v6_0_crtc_prepare,
+       .commit = dce_v6_0_crtc_commit,
+       .load_lut = dce_v6_0_crtc_load_lut,
+       .disable = dce_v6_0_crtc_disable,
+};
+
+static int dce_v6_0_crtc_init(struct amdgpu_device *adev, int index)
+{
+       struct amdgpu_crtc *amdgpu_crtc;
+       int i;
+
+       amdgpu_crtc = kzalloc(sizeof(struct amdgpu_crtc) +
+                             (AMDGPUFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
+       if (amdgpu_crtc == NULL)
+               return -ENOMEM;
+
+       drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_v6_0_crtc_funcs);
+
+       drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256);
+       amdgpu_crtc->crtc_id = index;
+       adev->mode_info.crtcs[index] = amdgpu_crtc;
+
+       amdgpu_crtc->max_cursor_width = CURSOR_WIDTH;
+       amdgpu_crtc->max_cursor_height = CURSOR_HEIGHT;
+       adev->ddev->mode_config.cursor_width = amdgpu_crtc->max_cursor_width;
+       adev->ddev->mode_config.cursor_height = amdgpu_crtc->max_cursor_height;
+
+       for (i = 0; i < 256; i++) {
+               amdgpu_crtc->lut_r[i] = i << 2;
+               amdgpu_crtc->lut_g[i] = i << 2;
+               amdgpu_crtc->lut_b[i] = i << 2;
+       }
+
+       amdgpu_crtc->crtc_offset = crtc_offsets[amdgpu_crtc->crtc_id];
+
+       amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
+       amdgpu_crtc->adjusted_clock = 0;
+       amdgpu_crtc->encoder = NULL;
+       amdgpu_crtc->connector = NULL;
+       drm_crtc_helper_add(&amdgpu_crtc->base, &dce_v6_0_crtc_helper_funcs);
+
+       return 0;
+}
+
+static int dce_v6_0_early_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       adev->audio_endpt_rreg = &dce_v6_0_audio_endpt_rreg;
+       adev->audio_endpt_wreg = &dce_v6_0_audio_endpt_wreg;
+
+       dce_v6_0_set_display_funcs(adev);
+       dce_v6_0_set_irq_funcs(adev);
+
+       switch (adev->asic_type) {
+       case CHIP_TAHITI:
+       case CHIP_PITCAIRN:
+       case CHIP_VERDE:
+               adev->mode_info.num_crtc = 6;
+               adev->mode_info.num_hpd = 6;
+               adev->mode_info.num_dig = 6;
+               break;
+       case CHIP_OLAND:
+               adev->mode_info.num_crtc = 2;
+               adev->mode_info.num_hpd = 2;
+               adev->mode_info.num_dig = 2;
+               break;
+       default:
+               /* FIXME: not supported yet */
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int dce_v6_0_sw_init(void *handle)
+{
+       int r, i;
+       bool ret;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       for (i = 0; i < adev->mode_info.num_crtc; i++) {
+               r = amdgpu_irq_add_id(adev, i + 1, &adev->crtc_irq);
+               if (r)
+                       return r;
+       }
+
+       for (i = 8; i < 20; i += 2) {
+               r = amdgpu_irq_add_id(adev, i, &adev->pageflip_irq);
+               if (r)
+                       return r;
+       }
+
+       /* HPD hotplug */
+       r = amdgpu_irq_add_id(adev, 42, &adev->hpd_irq);
+       if (r)
+               return r;
+
+       adev->mode_info.mode_config_initialized = true;
+
+       adev->ddev->mode_config.funcs = &amdgpu_mode_funcs;
+       adev->ddev->mode_config.async_page_flip = true;
+       adev->ddev->mode_config.max_width = 16384;
+       adev->ddev->mode_config.max_height = 16384;
+       adev->ddev->mode_config.preferred_depth = 24;
+       adev->ddev->mode_config.prefer_shadow = 1;
+       adev->ddev->mode_config.fb_base = adev->mc.aper_base;
+
+       r = amdgpu_modeset_create_props(adev);
+       if (r)
+               return r;
+
+       adev->ddev->mode_config.max_width = 16384;
+       adev->ddev->mode_config.max_height = 16384;
+
+       /* allocate crtcs */
+       for (i = 0; i < adev->mode_info.num_crtc; i++) {
+               r = dce_v6_0_crtc_init(adev, i);
+               if (r)
+                       return r;
+       }
+
+       ret = amdgpu_atombios_get_connector_info_from_object_table(adev);
+       if (ret)
+               amdgpu_print_display_setup(adev->ddev);
+       else
+               return -EINVAL;
+
+       /* setup afmt */
+       r = dce_v6_0_afmt_init(adev);
+       if (r)
+               return r;
+
+       r = dce_v6_0_audio_init(adev);
+       if (r)
+               return r;
+
+       drm_kms_helper_poll_init(adev->ddev);
+
+       return r;
+}
+
+static int dce_v6_0_sw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       kfree(adev->mode_info.bios_hardcoded_edid);
+
+       drm_kms_helper_poll_fini(adev->ddev);
+
+       dce_v6_0_audio_fini(adev);
+       dce_v6_0_afmt_fini(adev);
+
+       drm_mode_config_cleanup(adev->ddev);
+       adev->mode_info.mode_config_initialized = false;
+
+       return 0;
+}
+
+static int dce_v6_0_hw_init(void *handle)
+{
+       int i;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       /* init dig PHYs, disp eng pll */
+       amdgpu_atombios_encoder_init_dig(adev);
+       amdgpu_atombios_crtc_set_disp_eng_pll(adev, adev->clock.default_dispclk);
+
+       /* initialize hpd */
+       dce_v6_0_hpd_init(adev);
+
+       for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+               dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+       }
+
+       dce_v6_0_pageflip_interrupt_init(adev);
+
+       return 0;
+}
+
+static int dce_v6_0_hw_fini(void *handle)
+{
+       int i;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       dce_v6_0_hpd_fini(adev);
+
+       for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+               dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+       }
+
+       dce_v6_0_pageflip_interrupt_fini(adev);
+
+       return 0;
+}
+
+static int dce_v6_0_suspend(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       amdgpu_atombios_scratch_regs_save(adev);
+
+       return dce_v6_0_hw_fini(handle);
+}
+
+static int dce_v6_0_resume(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       int ret;
+
+       ret = dce_v6_0_hw_init(handle);
+
+       amdgpu_atombios_scratch_regs_restore(adev);
+
+       /* turn on the BL */
+       if (adev->mode_info.bl_encoder) {
+               u8 bl_level = amdgpu_display_backlight_get_level(adev,
+                                                                 adev->mode_info.bl_encoder);
+               amdgpu_display_backlight_set_level(adev, adev->mode_info.bl_encoder,
+                                                   bl_level);
+       }
+
+       return ret;
+}
+
+static bool dce_v6_0_is_idle(void *handle)
+{
+       return true;
+}
+
+static int dce_v6_0_wait_for_idle(void *handle)
+{
+       return 0;
+}
+
+static int dce_v6_0_soft_reset(void *handle)
+{
+       DRM_INFO("xxxx: dce_v6_0_soft_reset --- no impl!!\n");
+       return 0;
+}
+
+static void dce_v6_0_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
+                                                    int crtc,
+                                                    enum amdgpu_interrupt_state state)
+{
+       u32 reg_block, interrupt_mask;
+
+       if (crtc >= adev->mode_info.num_crtc) {
+               DRM_DEBUG("invalid crtc %d\n", crtc);
+               return;
+       }
+
+       switch (crtc) {
+       case 0:
+               reg_block = SI_CRTC0_REGISTER_OFFSET;
+               break;
+       case 1:
+               reg_block = SI_CRTC1_REGISTER_OFFSET;
+               break;
+       case 2:
+               reg_block = SI_CRTC2_REGISTER_OFFSET;
+               break;
+       case 3:
+               reg_block = SI_CRTC3_REGISTER_OFFSET;
+               break;
+       case 4:
+               reg_block = SI_CRTC4_REGISTER_OFFSET;
+               break;
+       case 5:
+               reg_block = SI_CRTC5_REGISTER_OFFSET;
+               break;
+       default:
+               DRM_DEBUG("invalid crtc %d\n", crtc);
+               return;
+       }
+
+       switch (state) {
+       case AMDGPU_IRQ_STATE_DISABLE:
+               interrupt_mask = RREG32(INT_MASK + reg_block);
+               interrupt_mask &= ~VBLANK_INT_MASK;
+               WREG32(INT_MASK + reg_block, interrupt_mask);
+               break;
+       case AMDGPU_IRQ_STATE_ENABLE:
+               interrupt_mask = RREG32(INT_MASK + reg_block);
+               interrupt_mask |= VBLANK_INT_MASK;
+               WREG32(INT_MASK + reg_block, interrupt_mask);
+               break;
+       default:
+               break;
+       }
+}
+
+static void dce_v6_0_set_crtc_vline_interrupt_state(struct amdgpu_device *adev,
+                                                   int crtc,
+                                                   enum amdgpu_interrupt_state state)
+{
+
+}
+
+static int dce_v6_0_set_hpd_interrupt_state(struct amdgpu_device *adev,
+                                           struct amdgpu_irq_src *src,
+                                           unsigned type,
+                                           enum amdgpu_interrupt_state state)
+{
+       u32 dc_hpd_int_cntl_reg, dc_hpd_int_cntl;
+
+       switch (type) {
+       case AMDGPU_HPD_1:
+               dc_hpd_int_cntl_reg = DC_HPD1_INT_CONTROL;
+               break;
+       case AMDGPU_HPD_2:
+               dc_hpd_int_cntl_reg = DC_HPD2_INT_CONTROL;
+               break;
+       case AMDGPU_HPD_3:
+               dc_hpd_int_cntl_reg = DC_HPD3_INT_CONTROL;
+               break;
+       case AMDGPU_HPD_4:
+               dc_hpd_int_cntl_reg = DC_HPD4_INT_CONTROL;
+               break;
+       case AMDGPU_HPD_5:
+               dc_hpd_int_cntl_reg = DC_HPD5_INT_CONTROL;
+               break;
+       case AMDGPU_HPD_6:
+               dc_hpd_int_cntl_reg = DC_HPD6_INT_CONTROL;
+               break;
+       default:
+               DRM_DEBUG("invalid hdp %d\n", type);
+               return 0;
+       }
+
+       switch (state) {
+       case AMDGPU_IRQ_STATE_DISABLE:
+               dc_hpd_int_cntl = RREG32(dc_hpd_int_cntl_reg);
+               dc_hpd_int_cntl &= ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               WREG32(dc_hpd_int_cntl_reg, dc_hpd_int_cntl);
+               break;
+       case AMDGPU_IRQ_STATE_ENABLE:
+               dc_hpd_int_cntl = RREG32(dc_hpd_int_cntl_reg);
+               dc_hpd_int_cntl |= (DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               WREG32(dc_hpd_int_cntl_reg, dc_hpd_int_cntl);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int dce_v6_0_set_crtc_interrupt_state(struct amdgpu_device *adev,
+                                            struct amdgpu_irq_src *src,
+                                            unsigned type,
+                                            enum amdgpu_interrupt_state state)
+{
+       switch (type) {
+       case AMDGPU_CRTC_IRQ_VBLANK1:
+               dce_v6_0_set_crtc_vblank_interrupt_state(adev, 0, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VBLANK2:
+               dce_v6_0_set_crtc_vblank_interrupt_state(adev, 1, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VBLANK3:
+               dce_v6_0_set_crtc_vblank_interrupt_state(adev, 2, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VBLANK4:
+               dce_v6_0_set_crtc_vblank_interrupt_state(adev, 3, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VBLANK5:
+               dce_v6_0_set_crtc_vblank_interrupt_state(adev, 4, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VBLANK6:
+               dce_v6_0_set_crtc_vblank_interrupt_state(adev, 5, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VLINE1:
+               dce_v6_0_set_crtc_vline_interrupt_state(adev, 0, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VLINE2:
+               dce_v6_0_set_crtc_vline_interrupt_state(adev, 1, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VLINE3:
+               dce_v6_0_set_crtc_vline_interrupt_state(adev, 2, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VLINE4:
+               dce_v6_0_set_crtc_vline_interrupt_state(adev, 3, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VLINE5:
+               dce_v6_0_set_crtc_vline_interrupt_state(adev, 4, state);
+               break;
+       case AMDGPU_CRTC_IRQ_VLINE6:
+               dce_v6_0_set_crtc_vline_interrupt_state(adev, 5, state);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int dce_v6_0_crtc_irq(struct amdgpu_device *adev,
+                            struct amdgpu_irq_src *source,
+                            struct amdgpu_iv_entry *entry)
+{
+       unsigned crtc = entry->src_id - 1;
+       uint32_t disp_int = RREG32(interrupt_status_offsets[crtc].reg);
+       unsigned irq_type = amdgpu_crtc_idx_to_irq_type(adev, crtc);
+
+       switch (entry->src_data) {
+       case 0: /* vblank */
+               if (disp_int & interrupt_status_offsets[crtc].vblank)
+                       WREG32(VBLANK_STATUS + crtc_offsets[crtc], VBLANK_ACK);
+               else
+                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+               if (amdgpu_irq_enabled(adev, source, irq_type)) {
+                       drm_handle_vblank(adev->ddev, crtc);
+               }
+               DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
+               break;
+       case 1: /* vline */
+               if (disp_int & interrupt_status_offsets[crtc].vline)
+                       WREG32(VLINE_STATUS + crtc_offsets[crtc], VLINE_ACK);
+               else
+                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+               DRM_DEBUG("IH: D%d vline\n", crtc + 1);
+               break;
+       default:
+               DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data);
+               break;
+       }
+
+       return 0;
+}
+
+static int dce_v6_0_set_pageflip_interrupt_state(struct amdgpu_device *adev,
+                                                struct amdgpu_irq_src *src,
+                                                unsigned type,
+                                                enum amdgpu_interrupt_state state)
+{
+       u32 reg;
+
+       if (type >= adev->mode_info.num_crtc) {
+               DRM_ERROR("invalid pageflip crtc %d\n", type);
+               return -EINVAL;
+       }
+
+       reg = RREG32(GRPH_INT_CONTROL + crtc_offsets[type]);
+       if (state == AMDGPU_IRQ_STATE_DISABLE)
+               WREG32(GRPH_INT_CONTROL + crtc_offsets[type],
+                      reg & ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK);
+       else
+               WREG32(GRPH_INT_CONTROL + crtc_offsets[type],
+                      reg | GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK);
+
+       return 0;
+}
+
+static int dce_v6_0_pageflip_irq(struct amdgpu_device *adev,
+                                struct amdgpu_irq_src *source,
+                                struct amdgpu_iv_entry *entry)
+{
+               unsigned long flags;
+       unsigned crtc_id;
+       struct amdgpu_crtc *amdgpu_crtc;
+       struct amdgpu_flip_work *works;
+
+       crtc_id = (entry->src_id - 8) >> 1;
+       amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
+
+       if (crtc_id >= adev->mode_info.num_crtc) {
+               DRM_ERROR("invalid pageflip crtc %d\n", crtc_id);
+               return -EINVAL;
+       }
+
+       if (RREG32(GRPH_INT_STATUS + crtc_offsets[crtc_id]) &
+           GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_OCCURRED_MASK)
+               WREG32(GRPH_INT_STATUS + crtc_offsets[crtc_id],
+                      GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK);
+
+       /* IRQ could occur when in initial stage */
+       if (amdgpu_crtc == NULL)
+               return 0;
+
+       spin_lock_irqsave(&adev->ddev->event_lock, flags);
+       works = amdgpu_crtc->pflip_works;
+       if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){
+               DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != "
+                                               "AMDGPU_FLIP_SUBMITTED(%d)\n",
+                                               amdgpu_crtc->pflip_status,
+                                               AMDGPU_FLIP_SUBMITTED);
+               spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+               return 0;
+       }
+
+       /* page flip completed. clean up */
+       amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
+       amdgpu_crtc->pflip_works = NULL;
+
+       /* wakeup usersapce */
+       if (works->event)
+               drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event);
+
+       spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+
+       drm_crtc_vblank_put(&amdgpu_crtc->base);
+       schedule_work(&works->unpin_work);
+
+       return 0;
+}
+
+static int dce_v6_0_hpd_irq(struct amdgpu_device *adev,
+                           struct amdgpu_irq_src *source,
+                           struct amdgpu_iv_entry *entry)
+{
+       uint32_t disp_int, mask, int_control, tmp;
+       unsigned hpd;
+
+       if (entry->src_data >= adev->mode_info.num_hpd) {
+               DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data);
+               return 0;
+       }
+
+       hpd = entry->src_data;
+       disp_int = RREG32(interrupt_status_offsets[hpd].reg);
+       mask = interrupt_status_offsets[hpd].hpd;
+       int_control = hpd_int_control_offsets[hpd];
+
+       if (disp_int & mask) {
+               tmp = RREG32(int_control);
+               tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK;
+               WREG32(int_control, tmp);
+               schedule_work(&adev->hotplug_work);
+               DRM_INFO("IH: HPD%d\n", hpd + 1);
+       }
+
+       return 0;
+
+}
+
+static int dce_v6_0_set_clockgating_state(void *handle,
+                                         enum amd_clockgating_state state)
+{
+       return 0;
+}
+
+static int dce_v6_0_set_powergating_state(void *handle,
+                                         enum amd_powergating_state state)
+{
+       return 0;
+}
+
+const struct amd_ip_funcs dce_v6_0_ip_funcs = {
+       .name = "dce_v6_0",
+       .early_init = dce_v6_0_early_init,
+       .late_init = NULL,
+       .sw_init = dce_v6_0_sw_init,
+       .sw_fini = dce_v6_0_sw_fini,
+       .hw_init = dce_v6_0_hw_init,
+       .hw_fini = dce_v6_0_hw_fini,
+       .suspend = dce_v6_0_suspend,
+       .resume = dce_v6_0_resume,
+       .is_idle = dce_v6_0_is_idle,
+       .wait_for_idle = dce_v6_0_wait_for_idle,
+       .soft_reset = dce_v6_0_soft_reset,
+       .set_clockgating_state = dce_v6_0_set_clockgating_state,
+       .set_powergating_state = dce_v6_0_set_powergating_state,
+};
+
+static void
+dce_v6_0_encoder_mode_set(struct drm_encoder *encoder,
+                         struct drm_display_mode *mode,
+                         struct drm_display_mode *adjusted_mode)
+{
+
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+       amdgpu_encoder->pixel_clock = adjusted_mode->clock;
+
+       /* need to call this here rather than in prepare() since we need some crtc info */
+       amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+       /* set scaler clears this on some chips */
+       dce_v6_0_set_interleave(encoder->crtc, mode);
+
+       if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
+               dce_v6_0_afmt_enable(encoder, true);
+               dce_v6_0_afmt_setmode(encoder, adjusted_mode);
+       }
+}
+
+static void dce_v6_0_encoder_prepare(struct drm_encoder *encoder)
+{
+
+       struct amdgpu_device *adev = encoder->dev->dev_private;
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+       struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+
+       if ((amdgpu_encoder->active_device &
+            (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
+           (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) !=
+            ENCODER_OBJECT_ID_NONE)) {
+               struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+               if (dig) {
+                       dig->dig_encoder = dce_v6_0_pick_dig_encoder(encoder);
+                       if (amdgpu_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT)
+                               dig->afmt = adev->mode_info.afmt[dig->dig_encoder];
+               }
+       }
+
+       amdgpu_atombios_scratch_regs_lock(adev, true);
+
+       if (connector) {
+               struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+               /* select the clock/data port if it uses a router */
+               if (amdgpu_connector->router.cd_valid)
+                       amdgpu_i2c_router_select_cd_port(amdgpu_connector);
+
+               /* turn eDP panel on for mode set */
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+                       amdgpu_atombios_encoder_set_edp_panel_power(connector,
+                                                            ATOM_TRANSMITTER_ACTION_POWER_ON);
+       }
+
+       /* this is needed for the pll/ss setup to work correctly in some cases */
+       amdgpu_atombios_encoder_set_crtc_source(encoder);
+       /* set up the FMT blocks */
+       dce_v6_0_program_fmt(encoder);
+}
+
+static void dce_v6_0_encoder_commit(struct drm_encoder *encoder)
+{
+
+       struct drm_device *dev = encoder->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+
+       /* need to call this here as we need the crtc set up */
+       amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+       amdgpu_atombios_scratch_regs_lock(adev, false);
+}
+
+static void dce_v6_0_encoder_disable(struct drm_encoder *encoder)
+{
+
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+       struct amdgpu_encoder_atom_dig *dig;
+
+       amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+       if (amdgpu_atombios_encoder_is_digital(encoder)) {
+               if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
+                       dce_v6_0_afmt_enable(encoder, false);
+               dig = amdgpu_encoder->enc_priv;
+               dig->dig_encoder = -1;
+       }
+       amdgpu_encoder->active_device = 0;
+}
+
+/* these are handled by the primary encoders */
+static void dce_v6_0_ext_prepare(struct drm_encoder *encoder)
+{
+
+}
+
+static void dce_v6_0_ext_commit(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+dce_v6_0_ext_mode_set(struct drm_encoder *encoder,
+                     struct drm_display_mode *mode,
+                     struct drm_display_mode *adjusted_mode)
+{
+
+}
+
+static void dce_v6_0_ext_disable(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+dce_v6_0_ext_dpms(struct drm_encoder *encoder, int mode)
+{
+
+}
+
+static bool dce_v6_0_ext_mode_fixup(struct drm_encoder *encoder,
+                                   const struct drm_display_mode *mode,
+                                   struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static const struct drm_encoder_helper_funcs dce_v6_0_ext_helper_funcs = {
+       .dpms = dce_v6_0_ext_dpms,
+       .mode_fixup = dce_v6_0_ext_mode_fixup,
+       .prepare = dce_v6_0_ext_prepare,
+       .mode_set = dce_v6_0_ext_mode_set,
+       .commit = dce_v6_0_ext_commit,
+       .disable = dce_v6_0_ext_disable,
+       /* no detect for TMDS/LVDS yet */
+};
+
+static const struct drm_encoder_helper_funcs dce_v6_0_dig_helper_funcs = {
+       .dpms = amdgpu_atombios_encoder_dpms,
+       .mode_fixup = amdgpu_atombios_encoder_mode_fixup,
+       .prepare = dce_v6_0_encoder_prepare,
+       .mode_set = dce_v6_0_encoder_mode_set,
+       .commit = dce_v6_0_encoder_commit,
+       .disable = dce_v6_0_encoder_disable,
+       .detect = amdgpu_atombios_encoder_dig_detect,
+};
+
+static const struct drm_encoder_helper_funcs dce_v6_0_dac_helper_funcs = {
+       .dpms = amdgpu_atombios_encoder_dpms,
+       .mode_fixup = amdgpu_atombios_encoder_mode_fixup,
+       .prepare = dce_v6_0_encoder_prepare,
+       .mode_set = dce_v6_0_encoder_mode_set,
+       .commit = dce_v6_0_encoder_commit,
+       .detect = amdgpu_atombios_encoder_dac_detect,
+};
+
+static void dce_v6_0_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+       if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+               amdgpu_atombios_encoder_fini_backlight(amdgpu_encoder);
+       kfree(amdgpu_encoder->enc_priv);
+       drm_encoder_cleanup(encoder);
+       kfree(amdgpu_encoder);
+}
+
+static const struct drm_encoder_funcs dce_v6_0_encoder_funcs = {
+       .destroy = dce_v6_0_encoder_destroy,
+};
+
+static void dce_v6_0_encoder_add(struct amdgpu_device *adev,
+                                uint32_t encoder_enum,
+                                uint32_t supported_device,
+                                u16 caps)
+{
+       struct drm_device *dev = adev->ddev;
+       struct drm_encoder *encoder;
+       struct amdgpu_encoder *amdgpu_encoder;
+
+       /* see if we already added it */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               amdgpu_encoder = to_amdgpu_encoder(encoder);
+               if (amdgpu_encoder->encoder_enum == encoder_enum) {
+                       amdgpu_encoder->devices |= supported_device;
+                       return;
+               }
+
+       }
+
+       /* add a new one */
+       amdgpu_encoder = kzalloc(sizeof(struct amdgpu_encoder), GFP_KERNEL);
+       if (!amdgpu_encoder)
+               return;
+
+       encoder = &amdgpu_encoder->base;
+       switch (adev->mode_info.num_crtc) {
+       case 1:
+               encoder->possible_crtcs = 0x1;
+               break;
+       case 2:
+       default:
+               encoder->possible_crtcs = 0x3;
+               break;
+       case 4:
+               encoder->possible_crtcs = 0xf;
+               break;
+       case 6:
+               encoder->possible_crtcs = 0x3f;
+               break;
+       }
+
+       amdgpu_encoder->enc_priv = NULL;
+       amdgpu_encoder->encoder_enum = encoder_enum;
+       amdgpu_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+       amdgpu_encoder->devices = supported_device;
+       amdgpu_encoder->rmx_type = RMX_OFF;
+       amdgpu_encoder->underscan_type = UNDERSCAN_OFF;
+       amdgpu_encoder->is_ext_encoder = false;
+       amdgpu_encoder->caps = caps;
+
+       switch (amdgpu_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+               drm_encoder_init(dev, encoder, &dce_v6_0_encoder_funcs,
+                                DRM_MODE_ENCODER_DAC, NULL);
+               drm_encoder_helper_add(encoder, &dce_v6_0_dac_helper_funcs);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+               if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                       amdgpu_encoder->rmx_type = RMX_FULL;
+                       drm_encoder_init(dev, encoder, &dce_v6_0_encoder_funcs,
+                                        DRM_MODE_ENCODER_LVDS, NULL);
+                       amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_lcd_info(amdgpu_encoder);
+               } else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
+                       drm_encoder_init(dev, encoder, &dce_v6_0_encoder_funcs,
+                                        DRM_MODE_ENCODER_DAC, NULL);
+                       amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
+               } else {
+                       drm_encoder_init(dev, encoder, &dce_v6_0_encoder_funcs,
+                                        DRM_MODE_ENCODER_TMDS, NULL);
+                       amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
+               }
+               drm_encoder_helper_add(encoder, &dce_v6_0_dig_helper_funcs);
+               break;
+       case ENCODER_OBJECT_ID_SI170B:
+       case ENCODER_OBJECT_ID_CH7303:
+       case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
+       case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
+       case ENCODER_OBJECT_ID_TITFP513:
+       case ENCODER_OBJECT_ID_VT1623:
+       case ENCODER_OBJECT_ID_HDMI_SI1930:
+       case ENCODER_OBJECT_ID_TRAVIS:
+       case ENCODER_OBJECT_ID_NUTMEG:
+               /* these are handled by the primary encoders */
+               amdgpu_encoder->is_ext_encoder = true;
+               if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+                       drm_encoder_init(dev, encoder, &dce_v6_0_encoder_funcs,
+                                        DRM_MODE_ENCODER_LVDS, NULL);
+               else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
+                       drm_encoder_init(dev, encoder, &dce_v6_0_encoder_funcs,
+                                        DRM_MODE_ENCODER_DAC, NULL);
+               else
+                       drm_encoder_init(dev, encoder, &dce_v6_0_encoder_funcs,
+                                        DRM_MODE_ENCODER_TMDS, NULL);
+               drm_encoder_helper_add(encoder, &dce_v6_0_ext_helper_funcs);
+               break;
+       }
+}
+
+static const struct amdgpu_display_funcs dce_v6_0_display_funcs = {
+       .set_vga_render_state = &dce_v6_0_set_vga_render_state,
+       .bandwidth_update = &dce_v6_0_bandwidth_update,
+       .vblank_get_counter = &dce_v6_0_vblank_get_counter,
+       .vblank_wait = &dce_v6_0_vblank_wait,
+       .is_display_hung = &dce_v6_0_is_display_hung,
+       .backlight_set_level = &amdgpu_atombios_encoder_set_backlight_level,
+       .backlight_get_level = &amdgpu_atombios_encoder_get_backlight_level,
+       .hpd_sense = &dce_v6_0_hpd_sense,
+       .hpd_set_polarity = &dce_v6_0_hpd_set_polarity,
+       .hpd_get_gpio_reg = &dce_v6_0_hpd_get_gpio_reg,
+       .page_flip = &dce_v6_0_page_flip,
+       .page_flip_get_scanoutpos = &dce_v6_0_crtc_get_scanoutpos,
+       .add_encoder = &dce_v6_0_encoder_add,
+       .add_connector = &amdgpu_connector_add,
+       .stop_mc_access = &dce_v6_0_stop_mc_access,
+       .resume_mc_access = &dce_v6_0_resume_mc_access,
+};
+
+static void dce_v6_0_set_display_funcs(struct amdgpu_device *adev)
+{
+       if (adev->mode_info.funcs == NULL)
+               adev->mode_info.funcs = &dce_v6_0_display_funcs;
+}
+
+static const struct amdgpu_irq_src_funcs dce_v6_0_crtc_irq_funcs = {
+       .set = dce_v6_0_set_crtc_interrupt_state,
+       .process = dce_v6_0_crtc_irq,
+};
+
+static const struct amdgpu_irq_src_funcs dce_v6_0_pageflip_irq_funcs = {
+       .set = dce_v6_0_set_pageflip_interrupt_state,
+       .process = dce_v6_0_pageflip_irq,
+};
+
+static const struct amdgpu_irq_src_funcs dce_v6_0_hpd_irq_funcs = {
+       .set = dce_v6_0_set_hpd_interrupt_state,
+       .process = dce_v6_0_hpd_irq,
+};
+
+static void dce_v6_0_set_irq_funcs(struct amdgpu_device *adev)
+{
+       adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_LAST;
+       adev->crtc_irq.funcs = &dce_v6_0_crtc_irq_funcs;
+
+       adev->pageflip_irq.num_types = AMDGPU_PAGEFLIP_IRQ_LAST;
+       adev->pageflip_irq.funcs = &dce_v6_0_pageflip_irq_funcs;
+
+       adev->hpd_irq.num_types = AMDGPU_HPD_LAST;
+       adev->hpd_irq.funcs = &dce_v6_0_hpd_irq_funcs;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.h b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.h
new file mode 100644 (file)
index 0000000..6a55281
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 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 __DCE_V6_0_H__
+#define __DCE_V6_0_H__
+
+extern const struct amd_ip_funcs dce_v6_0_ip_funcs;
+
+#endif
index 4fdfab1..5966166 100644 (file)
@@ -170,7 +170,7 @@ static bool dce_v8_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
  */
 static void dce_v8_0_vblank_wait(struct amdgpu_device *adev, int crtc)
 {
-       unsigned i = 0;
+       unsigned i = 100;
 
        if (crtc >= adev->mode_info.num_crtc)
                return;
@@ -182,14 +182,16 @@ static void dce_v8_0_vblank_wait(struct amdgpu_device *adev, int crtc)
         * wait for another frame.
         */
        while (dce_v8_0_is_in_vblank(adev, crtc)) {
-               if (i++ % 100 == 0) {
+               if (i++ == 100) {
+                       i = 0;
                        if (!dce_v8_0_is_counter_moving(adev, crtc))
                                break;
                }
        }
 
        while (!dce_v8_0_is_in_vblank(adev, crtc)) {
-               if (i++ % 100 == 0) {
+               if (i++ == 100) {
+                       i = 0;
                        if (!dce_v8_0_is_counter_moving(adev, crtc))
                                break;
                }
@@ -395,15 +397,6 @@ static void dce_v8_0_hpd_init(struct amdgpu_device *adev)
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
-                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
-                        * aux dp channel on imac and help (but not completely fix)
-                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
-                        * also avoid interrupt storms during dpms.
-                        */
-                       continue;
-               }
                switch (amdgpu_connector->hpd.hpd) {
                case AMDGPU_HPD_1:
                        WREG32(mmDC_HPD1_CONTROL, tmp);
@@ -426,6 +419,45 @@ static void dce_v8_0_hpd_init(struct amdgpu_device *adev)
                default:
                        break;
                }
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
+                        * aux dp channel on imac and help (but not completely fix)
+                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+                        * also avoid interrupt storms during dpms.
+                        */
+                       u32 dc_hpd_int_cntl_reg, dc_hpd_int_cntl;
+
+                       switch (amdgpu_connector->hpd.hpd) {
+                       case AMDGPU_HPD_1:
+                               dc_hpd_int_cntl_reg = mmDC_HPD1_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_2:
+                               dc_hpd_int_cntl_reg = mmDC_HPD2_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_3:
+                               dc_hpd_int_cntl_reg = mmDC_HPD3_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_4:
+                               dc_hpd_int_cntl_reg = mmDC_HPD4_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_5:
+                               dc_hpd_int_cntl_reg = mmDC_HPD5_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_6:
+                               dc_hpd_int_cntl_reg = mmDC_HPD6_INT_CONTROL;
+                               break;
+                       default:
+                               continue;
+                       }
+
+                       dc_hpd_int_cntl = RREG32(dc_hpd_int_cntl_reg);
+                       dc_hpd_int_cntl &= ~DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK;
+                       WREG32(dc_hpd_int_cntl_reg, dc_hpd_int_cntl);
+                       continue;
+               }
+
                dce_v8_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd);
                amdgpu_irq_get(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd);
        }
@@ -604,6 +636,52 @@ static void dce_v8_0_set_vga_render_state(struct amdgpu_device *adev,
        WREG32(mmVGA_RENDER_CONTROL, tmp);
 }
 
+static int dce_v8_0_get_num_crtc(struct amdgpu_device *adev)
+{
+       int num_crtc = 0;
+
+       switch (adev->asic_type) {
+       case CHIP_BONAIRE:
+       case CHIP_HAWAII:
+               num_crtc = 6;
+               break;
+       case CHIP_KAVERI:
+               num_crtc = 4;
+               break;
+       case CHIP_KABINI:
+       case CHIP_MULLINS:
+               num_crtc = 2;
+               break;
+       default:
+               num_crtc = 0;
+       }
+       return num_crtc;
+}
+
+void dce_v8_0_disable_dce(struct amdgpu_device *adev)
+{
+       /*Disable VGA render and enabled crtc, if has DCE engine*/
+       if (amdgpu_atombios_has_dce_engine_info(adev)) {
+               u32 tmp;
+               int crtc_enabled, i;
+
+               dce_v8_0_set_vga_render_state(adev, false);
+
+               /*Disable crtc*/
+               for (i = 0; i < dce_v8_0_get_num_crtc(adev); i++) {
+                       crtc_enabled = REG_GET_FIELD(RREG32(mmCRTC_CONTROL + crtc_offsets[i]),
+                                                                        CRTC_CONTROL, CRTC_MASTER_EN);
+                       if (crtc_enabled) {
+                               WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+                               tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]);
+                               tmp = REG_SET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN, 0);
+                               WREG32(mmCRTC_CONTROL + crtc_offsets[i], tmp);
+                               WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+                       }
+               }
+       }
+}
+
 static void dce_v8_0_program_fmt(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
@@ -1501,13 +1579,13 @@ static void dce_v8_0_audio_write_sad_regs(struct drm_encoder *encoder)
 
                        if (sad->format == eld_reg_to_type[i][1]) {
                                if (sad->channels > max_channels) {
-                               value = (sad->channels <<
-                                AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__MAX_CHANNELS__SHIFT) |
-                               (sad->byte2 <<
-                                AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__DESCRIPTOR_BYTE_2__SHIFT) |
-                               (sad->freq <<
-                                AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__SUPPORTED_FREQUENCIES__SHIFT);
-                               max_channels = sad->channels;
+                                       value = (sad->channels <<
+                                                AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__MAX_CHANNELS__SHIFT) |
+                                               (sad->byte2 <<
+                                                AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__DESCRIPTOR_BYTE_2__SHIFT) |
+                                               (sad->freq <<
+                                                AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__SUPPORTED_FREQUENCIES__SHIFT);
+                                       max_channels = sad->channels;
                                }
 
                                if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
@@ -1613,7 +1691,7 @@ static void dce_v8_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock
        struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
        uint32_t offset = dig->afmt->offset;
 
-       WREG32(mmHDMI_ACR_32_0 + offset, (acr.cts_32khz << HDMI_ACR_44_0__HDMI_ACR_CTS_44__SHIFT));
+       WREG32(mmHDMI_ACR_32_0 + offset, (acr.cts_32khz << HDMI_ACR_32_0__HDMI_ACR_CTS_32__SHIFT));
        WREG32(mmHDMI_ACR_32_1 + offset, acr.n_32khz);
 
        WREG32(mmHDMI_ACR_44_0 + offset, (acr.cts_44_1khz << HDMI_ACR_44_0__HDMI_ACR_CTS_44__SHIFT));
@@ -1693,6 +1771,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder,
        /* Silent, r600_hdmi_enable will raise WARN for us */
        if (!dig->afmt->enabled)
                return;
+
        offset = dig->afmt->offset;
 
        /* hdmi deep color mode general control packets setup, if bpc > 8 */
@@ -1817,7 +1896,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder,
 
        WREG32_OR(mmHDMI_INFOFRAME_CONTROL0 + offset,
                  HDMI_INFOFRAME_CONTROL0__HDMI_AVI_INFO_SEND_MASK | /* enable AVI info frames */
-                 HDMI_INFOFRAME_CONTROL0__HDMI_AVI_INFO_SEND_MASK); /* required for audio info values to be updated */
+                 HDMI_INFOFRAME_CONTROL0__HDMI_AVI_INFO_CONT_MASK); /* required for audio info values to be updated */
 
        WREG32_P(mmHDMI_INFOFRAME_CONTROL1 + offset,
                 (2 << HDMI_INFOFRAME_CONTROL1__HDMI_AVI_INFO_LINE__SHIFT), /* anything other than 0 */
@@ -1826,13 +1905,12 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder,
        WREG32_OR(mmAFMT_AUDIO_PACKET_CONTROL + offset,
                  AFMT_AUDIO_PACKET_CONTROL__AFMT_AUDIO_SAMPLE_SEND_MASK); /* send audio packets */
 
-       /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
        WREG32(mmAFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF);
        WREG32(mmAFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
        WREG32(mmAFMT_RAMP_CONTROL2 + offset, 0x00000001);
        WREG32(mmAFMT_RAMP_CONTROL3 + offset, 0x00000001);
 
-       /* enable audio after to setting up hw */
+       /* enable audio after setting up hw */
        dce_v8_0_audio_enable(adev, dig->afmt->pin, true);
 }
 
@@ -1944,7 +2022,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
        struct amdgpu_framebuffer *amdgpu_fb;
        struct drm_framebuffer *target_fb;
        struct drm_gem_object *obj;
-       struct amdgpu_bo *rbo;
+       struct amdgpu_bo *abo;
        uint64_t fb_location, tiling_flags;
        uint32_t fb_format, fb_pitch_pixels;
        u32 fb_swap = (GRPH_ENDIAN_NONE << GRPH_SWAP_CNTL__GRPH_ENDIAN_SWAP__SHIFT);
@@ -1952,6 +2030,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
        u32 viewport_w, viewport_h;
        int r;
        bool bypass_lut = false;
+       char *format_name;
 
        /* no fb bound */
        if (!atomic && !crtc->primary->fb) {
@@ -1971,23 +2050,23 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
         * just update base pointers
         */
        obj = amdgpu_fb->obj;
-       rbo = gem_to_amdgpu_bo(obj);
-       r = amdgpu_bo_reserve(rbo, false);
+       abo = gem_to_amdgpu_bo(obj);
+       r = amdgpu_bo_reserve(abo, false);
        if (unlikely(r != 0))
                return r;
 
        if (atomic) {
-               fb_location = amdgpu_bo_gpu_offset(rbo);
+               fb_location = amdgpu_bo_gpu_offset(abo);
        } else {
-               r = amdgpu_bo_pin(rbo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location);
+               r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location);
                if (unlikely(r != 0)) {
-                       amdgpu_bo_unreserve(rbo);
+                       amdgpu_bo_unreserve(abo);
                        return -EINVAL;
                }
        }
 
-       amdgpu_bo_get_tiling_flags(rbo, &tiling_flags);
-       amdgpu_bo_unreserve(rbo);
+       amdgpu_bo_get_tiling_flags(abo, &tiling_flags);
+       amdgpu_bo_unreserve(abo);
 
        pipe_config = AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
 
@@ -1999,7 +2078,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
        case DRM_FORMAT_XRGB4444:
        case DRM_FORMAT_ARGB4444:
                fb_format = ((GRPH_DEPTH_16BPP << GRPH_CONTROL__GRPH_DEPTH__SHIFT) |
-                            (GRPH_FORMAT_ARGB1555 << GRPH_CONTROL__GRPH_FORMAT__SHIFT));
+                            (GRPH_FORMAT_ARGB4444 << GRPH_CONTROL__GRPH_FORMAT__SHIFT));
 #ifdef __BIG_ENDIAN
                fb_swap = (GRPH_ENDIAN_8IN16 << GRPH_SWAP_CNTL__GRPH_ENDIAN_SWAP__SHIFT);
 #endif
@@ -2056,8 +2135,9 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
                bypass_lut = true;
                break;
        default:
-               DRM_ERROR("Unsupported screen format %s\n",
-                         drm_get_format_name(target_fb->pixel_format));
+               format_name = drm_get_format_name(target_fb->pixel_format);
+               DRM_ERROR("Unsupported screen format %s\n", format_name);
+               kfree(format_name);
                return -EINVAL;
        }
 
@@ -2137,17 +2217,17 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset,
               (viewport_w << 16) | viewport_h);
 
-       /* set pageflip to happen only at start of vblank interval (front porch) */
-       WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3);
+       /* set pageflip to happen anywhere in vblank interval */
+       WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0);
 
        if (!atomic && fb && fb != crtc->primary->fb) {
                amdgpu_fb = to_amdgpu_framebuffer(fb);
-               rbo = gem_to_amdgpu_bo(amdgpu_fb->obj);
-               r = amdgpu_bo_reserve(rbo, false);
+               abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+               r = amdgpu_bo_reserve(abo, false);
                if (unlikely(r != 0))
                        return r;
-               amdgpu_bo_unpin(rbo);
-               amdgpu_bo_unreserve(rbo);
+               amdgpu_bo_unpin(abo);
+               amdgpu_bo_unreserve(abo);
        }
 
        /* Bytes per pixel may have changed */
@@ -2552,7 +2632,7 @@ static const struct drm_crtc_funcs dce_v8_0_crtc_funcs = {
        .gamma_set = dce_v8_0_crtc_gamma_set,
        .set_config = amdgpu_crtc_set_config,
        .destroy = dce_v8_0_crtc_destroy,
-       .page_flip = amdgpu_crtc_page_flip,
+       .page_flip_target = amdgpu_crtc_page_flip_target,
 };
 
 static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -2619,16 +2699,16 @@ static void dce_v8_0_crtc_disable(struct drm_crtc *crtc)
        if (crtc->primary->fb) {
                int r;
                struct amdgpu_framebuffer *amdgpu_fb;
-               struct amdgpu_bo *rbo;
+               struct amdgpu_bo *abo;
 
                amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
-               rbo = gem_to_amdgpu_bo(amdgpu_fb->obj);
-               r = amdgpu_bo_reserve(rbo, false);
+               abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+               r = amdgpu_bo_reserve(abo, false);
                if (unlikely(r))
-                       DRM_ERROR("failed to reserve rbo before unpin\n");
+                       DRM_ERROR("failed to reserve abo before unpin\n");
                else {
-                       amdgpu_bo_unpin(rbo);
-                       amdgpu_bo_unreserve(rbo);
+                       amdgpu_bo_unpin(abo);
+                       amdgpu_bo_unreserve(abo);
                }
        }
        /* disable the GRPH */
@@ -2653,7 +2733,7 @@ static void dce_v8_0_crtc_disable(struct drm_crtc *crtc)
        case ATOM_PPLL2:
                /* disable the ppll */
                amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id,
-                                         0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
+                                                 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
                break;
        case ATOM_PPLL0:
                /* disable the ppll */
@@ -2803,21 +2883,20 @@ static int dce_v8_0_early_init(void *handle)
        dce_v8_0_set_display_funcs(adev);
        dce_v8_0_set_irq_funcs(adev);
 
+       adev->mode_info.num_crtc = dce_v8_0_get_num_crtc(adev);
+
        switch (adev->asic_type) {
        case CHIP_BONAIRE:
        case CHIP_HAWAII:
-               adev->mode_info.num_crtc = 6;
                adev->mode_info.num_hpd = 6;
                adev->mode_info.num_dig = 6;
                break;
        case CHIP_KAVERI:
-               adev->mode_info.num_crtc = 4;
                adev->mode_info.num_hpd = 6;
                adev->mode_info.num_dig = 7;
                break;
        case CHIP_KABINI:
        case CHIP_MULLINS:
-               adev->mode_info.num_crtc = 2;
                adev->mode_info.num_hpd = 6;
                adev->mode_info.num_dig = 6; /* ? */
                break;
@@ -3236,7 +3315,6 @@ static int dce_v8_0_crtc_irq(struct amdgpu_device *adev,
                        drm_handle_vblank(adev->ddev, crtc);
                }
                DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
-
                break;
        case 1: /* vline */
                if (disp_int & interrupt_status_offsets[crtc].vline)
@@ -3245,7 +3323,6 @@ static int dce_v8_0_crtc_irq(struct amdgpu_device *adev,
                        DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
 
                DRM_DEBUG("IH: D%d vline\n", crtc + 1);
-
                break;
        default:
                DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data);
index 7701685..7d0770c 100644 (file)
@@ -26,4 +26,6 @@
 
 extern const struct amd_ip_funcs dce_v8_0_ip_funcs;
 
+void dce_v8_0_disable_dce(struct amdgpu_device *adev);
+
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
new file mode 100644 (file)
index 0000000..c2bd9f0
--- /dev/null
@@ -0,0 +1,802 @@
+/*
+ * 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 "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_i2c.h"
+#include "atom.h"
+#include "amdgpu_pll.h"
+#include "amdgpu_connectors.h"
+#ifdef CONFIG_DRM_AMDGPU_CIK
+#include "dce_v8_0.h"
+#endif
+#include "dce_v10_0.h"
+#include "dce_v11_0.h"
+#include "dce_virtual.h"
+
+static void dce_virtual_set_display_funcs(struct amdgpu_device *adev);
+static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev);
+static int dce_virtual_pageflip_irq(struct amdgpu_device *adev,
+                                 struct amdgpu_irq_src *source,
+                                 struct amdgpu_iv_entry *entry);
+
+/**
+ * dce_virtual_vblank_wait - vblank wait asic callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @crtc: crtc to wait for vblank on
+ *
+ * Wait for vblank on the requested crtc (evergreen+).
+ */
+static void dce_virtual_vblank_wait(struct amdgpu_device *adev, int crtc)
+{
+       return;
+}
+
+static u32 dce_virtual_vblank_get_counter(struct amdgpu_device *adev, int crtc)
+{
+       return 0;
+}
+
+static void dce_virtual_page_flip(struct amdgpu_device *adev,
+                             int crtc_id, u64 crtc_base, bool async)
+{
+       return;
+}
+
+static int dce_virtual_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
+                                       u32 *vbl, u32 *position)
+{
+       *vbl = 0;
+       *position = 0;
+
+       return -EINVAL;
+}
+
+static bool dce_virtual_hpd_sense(struct amdgpu_device *adev,
+                              enum amdgpu_hpd_id hpd)
+{
+       return true;
+}
+
+static void dce_virtual_hpd_set_polarity(struct amdgpu_device *adev,
+                                     enum amdgpu_hpd_id hpd)
+{
+       return;
+}
+
+static u32 dce_virtual_hpd_get_gpio_reg(struct amdgpu_device *adev)
+{
+       return 0;
+}
+
+static bool dce_virtual_is_display_hung(struct amdgpu_device *adev)
+{
+       return false;
+}
+
+static void dce_virtual_stop_mc_access(struct amdgpu_device *adev,
+                             struct amdgpu_mode_mc_save *save)
+{
+       switch (adev->asic_type) {
+#ifdef CONFIG_DRM_AMDGPU_CIK
+       case CHIP_BONAIRE:
+       case CHIP_HAWAII:
+       case CHIP_KAVERI:
+       case CHIP_KABINI:
+       case CHIP_MULLINS:
+               dce_v8_0_disable_dce(adev);
+               break;
+#endif
+       case CHIP_FIJI:
+       case CHIP_TONGA:
+               dce_v10_0_disable_dce(adev);
+               break;
+       case CHIP_CARRIZO:
+       case CHIP_STONEY:
+       case CHIP_POLARIS11:
+       case CHIP_POLARIS10:
+               dce_v11_0_disable_dce(adev);
+               break;
+       case CHIP_TOPAZ:
+               /* no DCE */
+               return;
+       default:
+               DRM_ERROR("Virtual display unsupported ASIC type: 0x%X\n", adev->asic_type);
+       }
+
+       return;
+}
+static void dce_virtual_resume_mc_access(struct amdgpu_device *adev,
+                               struct amdgpu_mode_mc_save *save)
+{
+       return;
+}
+
+static void dce_virtual_set_vga_render_state(struct amdgpu_device *adev,
+                                   bool render)
+{
+       return;
+}
+
+/**
+ * dce_virtual_bandwidth_update - program display watermarks
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Calculate and program the display watermarks and line
+ * buffer allocation (CIK).
+ */
+static void dce_virtual_bandwidth_update(struct amdgpu_device *adev)
+{
+       return;
+}
+
+static int dce_virtual_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
+                                     u16 *green, u16 *blue, uint32_t size)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       int i;
+
+       /* userspace palettes are always correct as is */
+       for (i = 0; i < size; i++) {
+               amdgpu_crtc->lut_r[i] = red[i] >> 6;
+               amdgpu_crtc->lut_g[i] = green[i] >> 6;
+               amdgpu_crtc->lut_b[i] = blue[i] >> 6;
+       }
+
+       return 0;
+}
+
+static void dce_virtual_crtc_destroy(struct drm_crtc *crtc)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+       drm_crtc_cleanup(crtc);
+       kfree(amdgpu_crtc);
+}
+
+static const struct drm_crtc_funcs dce_virtual_crtc_funcs = {
+       .cursor_set2 = NULL,
+       .cursor_move = NULL,
+       .gamma_set = dce_virtual_crtc_gamma_set,
+       .set_config = amdgpu_crtc_set_config,
+       .destroy = dce_virtual_crtc_destroy,
+       .page_flip_target = amdgpu_crtc_page_flip_target,
+};
+
+static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       unsigned type;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               amdgpu_crtc->enabled = true;
+               /* Make sure VBLANK and PFLIP interrupts are still enabled */
+               type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id);
+               amdgpu_irq_update(adev, &adev->crtc_irq, type);
+               amdgpu_irq_update(adev, &adev->pageflip_irq, type);
+               drm_vblank_on(dev, amdgpu_crtc->crtc_id);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               drm_vblank_off(dev, amdgpu_crtc->crtc_id);
+               amdgpu_crtc->enabled = false;
+               break;
+       }
+}
+
+
+static void dce_virtual_crtc_prepare(struct drm_crtc *crtc)
+{
+       dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void dce_virtual_crtc_commit(struct drm_crtc *crtc)
+{
+       dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static void dce_virtual_crtc_disable(struct drm_crtc *crtc)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+       dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       if (crtc->primary->fb) {
+               int r;
+               struct amdgpu_framebuffer *amdgpu_fb;
+               struct amdgpu_bo *abo;
+
+               amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
+               abo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+               r = amdgpu_bo_reserve(abo, false);
+               if (unlikely(r))
+                       DRM_ERROR("failed to reserve abo before unpin\n");
+               else {
+                       amdgpu_bo_unpin(abo);
+                       amdgpu_bo_unreserve(abo);
+               }
+       }
+
+       amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
+       amdgpu_crtc->encoder = NULL;
+       amdgpu_crtc->connector = NULL;
+}
+
+static int dce_virtual_crtc_mode_set(struct drm_crtc *crtc,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode,
+                                 int x, int y, struct drm_framebuffer *old_fb)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+       /* update the hw version fpr dpm */
+       amdgpu_crtc->hw_mode = *adjusted_mode;
+
+       return 0;
+}
+
+static bool dce_virtual_crtc_mode_fixup(struct drm_crtc *crtc,
+                                    const struct drm_display_mode *mode,
+                                    struct drm_display_mode *adjusted_mode)
+{
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct drm_encoder *encoder;
+
+       /* assign the encoder to the amdgpu crtc to avoid repeated lookups later */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               if (encoder->crtc == crtc) {
+                       amdgpu_crtc->encoder = encoder;
+                       amdgpu_crtc->connector = amdgpu_get_connector_for_encoder(encoder);
+                       break;
+               }
+       }
+       if ((amdgpu_crtc->encoder == NULL) || (amdgpu_crtc->connector == NULL)) {
+               amdgpu_crtc->encoder = NULL;
+               amdgpu_crtc->connector = NULL;
+               return false;
+       }
+
+       return true;
+}
+
+
+static int dce_virtual_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+                                 struct drm_framebuffer *old_fb)
+{
+       return 0;
+}
+
+static void dce_virtual_crtc_load_lut(struct drm_crtc *crtc)
+{
+       return;
+}
+
+static int dce_virtual_crtc_set_base_atomic(struct drm_crtc *crtc,
+                                        struct drm_framebuffer *fb,
+                                        int x, int y, enum mode_set_atomic state)
+{
+       return 0;
+}
+
+static const struct drm_crtc_helper_funcs dce_virtual_crtc_helper_funcs = {
+       .dpms = dce_virtual_crtc_dpms,
+       .mode_fixup = dce_virtual_crtc_mode_fixup,
+       .mode_set = dce_virtual_crtc_mode_set,
+       .mode_set_base = dce_virtual_crtc_set_base,
+       .mode_set_base_atomic = dce_virtual_crtc_set_base_atomic,
+       .prepare = dce_virtual_crtc_prepare,
+       .commit = dce_virtual_crtc_commit,
+       .load_lut = dce_virtual_crtc_load_lut,
+       .disable = dce_virtual_crtc_disable,
+};
+
+static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index)
+{
+       struct amdgpu_crtc *amdgpu_crtc;
+       int i;
+
+       amdgpu_crtc = kzalloc(sizeof(struct amdgpu_crtc) +
+                             (AMDGPUFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
+       if (amdgpu_crtc == NULL)
+               return -ENOMEM;
+
+       drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_virtual_crtc_funcs);
+
+       drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256);
+       amdgpu_crtc->crtc_id = index;
+       adev->mode_info.crtcs[index] = amdgpu_crtc;
+
+       for (i = 0; i < 256; i++) {
+               amdgpu_crtc->lut_r[i] = i << 2;
+               amdgpu_crtc->lut_g[i] = i << 2;
+               amdgpu_crtc->lut_b[i] = i << 2;
+       }
+
+       amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
+       amdgpu_crtc->encoder = NULL;
+       amdgpu_crtc->connector = NULL;
+       drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs);
+
+       return 0;
+}
+
+static int dce_virtual_early_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       adev->mode_info.vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;
+       dce_virtual_set_display_funcs(adev);
+       dce_virtual_set_irq_funcs(adev);
+
+       adev->mode_info.num_crtc = 1;
+       adev->mode_info.num_hpd = 1;
+       adev->mode_info.num_dig = 1;
+       return 0;
+}
+
+static bool dce_virtual_get_connector_info(struct amdgpu_device *adev)
+{
+       struct amdgpu_i2c_bus_rec ddc_bus;
+       struct amdgpu_router router;
+       struct amdgpu_hpd hpd;
+
+       /* look up gpio for ddc, hpd */
+       ddc_bus.valid = false;
+       hpd.hpd = AMDGPU_HPD_NONE;
+       /* needed for aux chan transactions */
+       ddc_bus.hpd = hpd.hpd;
+
+       memset(&router, 0, sizeof(router));
+       router.ddc_valid = false;
+       router.cd_valid = false;
+       amdgpu_display_add_connector(adev,
+                                     0,
+                                     ATOM_DEVICE_CRT1_SUPPORT,
+                                     DRM_MODE_CONNECTOR_VIRTUAL, &ddc_bus,
+                                     CONNECTOR_OBJECT_ID_VIRTUAL,
+                                     &hpd,
+                                     &router);
+
+       amdgpu_display_add_encoder(adev, ENCODER_VIRTUAL_ENUM_VIRTUAL,
+                                                       ATOM_DEVICE_CRT1_SUPPORT,
+                                                       0);
+
+       amdgpu_link_encoder_connector(adev->ddev);
+
+       return true;
+}
+
+static int dce_virtual_sw_init(void *handle)
+{
+       int r, i;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       r = amdgpu_irq_add_id(adev, 229, &adev->crtc_irq);
+       if (r)
+               return r;
+
+       adev->ddev->max_vblank_count = 0;
+
+       adev->ddev->mode_config.funcs = &amdgpu_mode_funcs;
+
+       adev->ddev->mode_config.max_width = 16384;
+       adev->ddev->mode_config.max_height = 16384;
+
+       adev->ddev->mode_config.preferred_depth = 24;
+       adev->ddev->mode_config.prefer_shadow = 1;
+
+       adev->ddev->mode_config.fb_base = adev->mc.aper_base;
+
+       r = amdgpu_modeset_create_props(adev);
+       if (r)
+               return r;
+
+       adev->ddev->mode_config.max_width = 16384;
+       adev->ddev->mode_config.max_height = 16384;
+
+       /* allocate crtcs */
+       for (i = 0; i < adev->mode_info.num_crtc; i++) {
+               r = dce_virtual_crtc_init(adev, i);
+               if (r)
+                       return r;
+       }
+
+       dce_virtual_get_connector_info(adev);
+       amdgpu_print_display_setup(adev->ddev);
+
+       drm_kms_helper_poll_init(adev->ddev);
+
+       adev->mode_info.mode_config_initialized = true;
+       return 0;
+}
+
+static int dce_virtual_sw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       kfree(adev->mode_info.bios_hardcoded_edid);
+
+       drm_kms_helper_poll_fini(adev->ddev);
+
+       drm_mode_config_cleanup(adev->ddev);
+       adev->mode_info.mode_config_initialized = false;
+       return 0;
+}
+
+static int dce_virtual_hw_init(void *handle)
+{
+       return 0;
+}
+
+static int dce_virtual_hw_fini(void *handle)
+{
+       return 0;
+}
+
+static int dce_virtual_suspend(void *handle)
+{
+       return dce_virtual_hw_fini(handle);
+}
+
+static int dce_virtual_resume(void *handle)
+{
+       return dce_virtual_hw_init(handle);
+}
+
+static bool dce_virtual_is_idle(void *handle)
+{
+       return true;
+}
+
+static int dce_virtual_wait_for_idle(void *handle)
+{
+       return 0;
+}
+
+static int dce_virtual_soft_reset(void *handle)
+{
+       return 0;
+}
+
+static int dce_virtual_set_clockgating_state(void *handle,
+                                         enum amd_clockgating_state state)
+{
+       return 0;
+}
+
+static int dce_virtual_set_powergating_state(void *handle,
+                                         enum amd_powergating_state state)
+{
+       return 0;
+}
+
+const struct amd_ip_funcs dce_virtual_ip_funcs = {
+       .name = "dce_virtual",
+       .early_init = dce_virtual_early_init,
+       .late_init = NULL,
+       .sw_init = dce_virtual_sw_init,
+       .sw_fini = dce_virtual_sw_fini,
+       .hw_init = dce_virtual_hw_init,
+       .hw_fini = dce_virtual_hw_fini,
+       .suspend = dce_virtual_suspend,
+       .resume = dce_virtual_resume,
+       .is_idle = dce_virtual_is_idle,
+       .wait_for_idle = dce_virtual_wait_for_idle,
+       .soft_reset = dce_virtual_soft_reset,
+       .set_clockgating_state = dce_virtual_set_clockgating_state,
+       .set_powergating_state = dce_virtual_set_powergating_state,
+};
+
+/* these are handled by the primary encoders */
+static void dce_virtual_encoder_prepare(struct drm_encoder *encoder)
+{
+       return;
+}
+
+static void dce_virtual_encoder_commit(struct drm_encoder *encoder)
+{
+       return;
+}
+
+static void
+dce_virtual_encoder_mode_set(struct drm_encoder *encoder,
+                     struct drm_display_mode *mode,
+                     struct drm_display_mode *adjusted_mode)
+{
+       return;
+}
+
+static void dce_virtual_encoder_disable(struct drm_encoder *encoder)
+{
+       return;
+}
+
+static void
+dce_virtual_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       return;
+}
+
+static bool dce_virtual_encoder_mode_fixup(struct drm_encoder *encoder,
+                                   const struct drm_display_mode *mode,
+                                   struct drm_display_mode *adjusted_mode)
+{
+
+       /* set the active encoder to connector routing */
+       amdgpu_encoder_set_active_device(encoder);
+
+       return true;
+}
+
+static const struct drm_encoder_helper_funcs dce_virtual_encoder_helper_funcs = {
+       .dpms = dce_virtual_encoder_dpms,
+       .mode_fixup = dce_virtual_encoder_mode_fixup,
+       .prepare = dce_virtual_encoder_prepare,
+       .mode_set = dce_virtual_encoder_mode_set,
+       .commit = dce_virtual_encoder_commit,
+       .disable = dce_virtual_encoder_disable,
+};
+
+static void dce_virtual_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+       kfree(amdgpu_encoder->enc_priv);
+       drm_encoder_cleanup(encoder);
+       kfree(amdgpu_encoder);
+}
+
+static const struct drm_encoder_funcs dce_virtual_encoder_funcs = {
+       .destroy = dce_virtual_encoder_destroy,
+};
+
+static void dce_virtual_encoder_add(struct amdgpu_device *adev,
+                                uint32_t encoder_enum,
+                                uint32_t supported_device,
+                                u16 caps)
+{
+       struct drm_device *dev = adev->ddev;
+       struct drm_encoder *encoder;
+       struct amdgpu_encoder *amdgpu_encoder;
+
+       /* see if we already added it */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               amdgpu_encoder = to_amdgpu_encoder(encoder);
+               if (amdgpu_encoder->encoder_enum == encoder_enum) {
+                       amdgpu_encoder->devices |= supported_device;
+                       return;
+               }
+
+       }
+
+       /* add a new one */
+       amdgpu_encoder = kzalloc(sizeof(struct amdgpu_encoder), GFP_KERNEL);
+       if (!amdgpu_encoder)
+               return;
+
+       encoder = &amdgpu_encoder->base;
+       encoder->possible_crtcs = 0x1;
+       amdgpu_encoder->enc_priv = NULL;
+       amdgpu_encoder->encoder_enum = encoder_enum;
+       amdgpu_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+       amdgpu_encoder->devices = supported_device;
+       amdgpu_encoder->rmx_type = RMX_OFF;
+       amdgpu_encoder->underscan_type = UNDERSCAN_OFF;
+       amdgpu_encoder->is_ext_encoder = false;
+       amdgpu_encoder->caps = caps;
+
+       drm_encoder_init(dev, encoder, &dce_virtual_encoder_funcs,
+                                        DRM_MODE_ENCODER_VIRTUAL, NULL);
+       drm_encoder_helper_add(encoder, &dce_virtual_encoder_helper_funcs);
+       DRM_INFO("[FM]encoder: %d is VIRTUAL\n", amdgpu_encoder->encoder_id);
+}
+
+static const struct amdgpu_display_funcs dce_virtual_display_funcs = {
+       .set_vga_render_state = &dce_virtual_set_vga_render_state,
+       .bandwidth_update = &dce_virtual_bandwidth_update,
+       .vblank_get_counter = &dce_virtual_vblank_get_counter,
+       .vblank_wait = &dce_virtual_vblank_wait,
+       .is_display_hung = &dce_virtual_is_display_hung,
+       .backlight_set_level = NULL,
+       .backlight_get_level = NULL,
+       .hpd_sense = &dce_virtual_hpd_sense,
+       .hpd_set_polarity = &dce_virtual_hpd_set_polarity,
+       .hpd_get_gpio_reg = &dce_virtual_hpd_get_gpio_reg,
+       .page_flip = &dce_virtual_page_flip,
+       .page_flip_get_scanoutpos = &dce_virtual_crtc_get_scanoutpos,
+       .add_encoder = &dce_virtual_encoder_add,
+       .add_connector = &amdgpu_connector_add,
+       .stop_mc_access = &dce_virtual_stop_mc_access,
+       .resume_mc_access = &dce_virtual_resume_mc_access,
+};
+
+static void dce_virtual_set_display_funcs(struct amdgpu_device *adev)
+{
+       if (adev->mode_info.funcs == NULL)
+               adev->mode_info.funcs = &dce_virtual_display_funcs;
+}
+
+static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer)
+{
+       struct amdgpu_mode_info *mode_info = container_of(vblank_timer, struct amdgpu_mode_info ,vblank_timer);
+       struct amdgpu_device *adev = container_of(mode_info, struct amdgpu_device ,mode_info);
+       unsigned crtc = 0;
+       drm_handle_vblank(adev->ddev, crtc);
+       dce_virtual_pageflip_irq(adev, NULL, NULL);
+       hrtimer_start(vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL);
+       return HRTIMER_NORESTART;
+}
+
+static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
+                                                    int crtc,
+                                                    enum amdgpu_interrupt_state state)
+{
+       if (crtc >= adev->mode_info.num_crtc) {
+               DRM_DEBUG("invalid crtc %d\n", crtc);
+               return;
+       }
+
+       if (state && !adev->mode_info.vsync_timer_enabled) {
+               DRM_DEBUG("Enable software vsync timer\n");
+               hrtimer_init(&adev->mode_info.vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+               hrtimer_set_expires(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD));
+               adev->mode_info.vblank_timer.function = dce_virtual_vblank_timer_handle;
+               hrtimer_start(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL);
+       } else if (!state && adev->mode_info.vsync_timer_enabled) {
+               DRM_DEBUG("Disable software vsync timer\n");
+               hrtimer_cancel(&adev->mode_info.vblank_timer);
+       }
+
+       adev->mode_info.vsync_timer_enabled = state;
+       DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state);
+}
+
+
+static int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev,
+                                       struct amdgpu_irq_src *source,
+                                       unsigned type,
+                                       enum amdgpu_interrupt_state state)
+{
+       switch (type) {
+       case AMDGPU_CRTC_IRQ_VBLANK1:
+               dce_virtual_set_crtc_vblank_interrupt_state(adev, 0, state);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static void dce_virtual_crtc_vblank_int_ack(struct amdgpu_device *adev,
+                                         int crtc)
+{
+       if (crtc >= adev->mode_info.num_crtc) {
+               DRM_DEBUG("invalid crtc %d\n", crtc);
+               return;
+       }
+}
+
+static int dce_virtual_crtc_irq(struct amdgpu_device *adev,
+                             struct amdgpu_irq_src *source,
+                             struct amdgpu_iv_entry *entry)
+{
+       unsigned crtc = 0;
+       unsigned irq_type = AMDGPU_CRTC_IRQ_VBLANK1;
+
+       dce_virtual_crtc_vblank_int_ack(adev, crtc);
+
+       if (amdgpu_irq_enabled(adev, source, irq_type)) {
+               drm_handle_vblank(adev->ddev, crtc);
+       }
+       dce_virtual_pageflip_irq(adev, NULL, NULL);
+       DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
+       return 0;
+}
+
+static int dce_virtual_set_pageflip_irq_state(struct amdgpu_device *adev,
+                                           struct amdgpu_irq_src *src,
+                                           unsigned type,
+                                           enum amdgpu_interrupt_state state)
+{
+       if (type >= adev->mode_info.num_crtc) {
+               DRM_ERROR("invalid pageflip crtc %d\n", type);
+               return -EINVAL;
+       }
+       DRM_DEBUG("[FM]set pageflip irq type %d state %d\n", type, state);
+
+       return 0;
+}
+
+static int dce_virtual_pageflip_irq(struct amdgpu_device *adev,
+                                 struct amdgpu_irq_src *source,
+                                 struct amdgpu_iv_entry *entry)
+{
+       unsigned long flags;
+       unsigned crtc_id = 0;
+       struct amdgpu_crtc *amdgpu_crtc;
+       struct amdgpu_flip_work *works;
+
+       crtc_id = 0;
+       amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
+
+       if (crtc_id >= adev->mode_info.num_crtc) {
+               DRM_ERROR("invalid pageflip crtc %d\n", crtc_id);
+               return -EINVAL;
+       }
+
+       /* IRQ could occur when in initial stage */
+       if (amdgpu_crtc == NULL)
+               return 0;
+
+       spin_lock_irqsave(&adev->ddev->event_lock, flags);
+       works = amdgpu_crtc->pflip_works;
+       if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
+               DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != "
+                       "AMDGPU_FLIP_SUBMITTED(%d)\n",
+                       amdgpu_crtc->pflip_status,
+                       AMDGPU_FLIP_SUBMITTED);
+               spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+               return 0;
+       }
+
+       /* page flip completed. clean up */
+       amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
+       amdgpu_crtc->pflip_works = NULL;
+
+       /* wakeup usersapce */
+       if (works->event)
+               drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event);
+
+       spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+
+       drm_crtc_vblank_put(&amdgpu_crtc->base);
+       schedule_work(&works->unpin_work);
+
+       return 0;
+}
+
+static const struct amdgpu_irq_src_funcs dce_virtual_crtc_irq_funcs = {
+       .set = dce_virtual_set_crtc_irq_state,
+       .process = dce_virtual_crtc_irq,
+};
+
+static const struct amdgpu_irq_src_funcs dce_virtual_pageflip_irq_funcs = {
+       .set = dce_virtual_set_pageflip_irq_state,
+       .process = dce_virtual_pageflip_irq,
+};
+
+static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev)
+{
+       adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_LAST;
+       adev->crtc_irq.funcs = &dce_virtual_crtc_irq_funcs;
+
+       adev->pageflip_irq.num_types = AMDGPU_PAGEFLIP_IRQ_LAST;
+       adev->pageflip_irq.funcs = &dce_virtual_pageflip_irq_funcs;
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.h b/drivers/gpu/drm/amd/amdgpu/dce_virtual.h
new file mode 100644 (file)
index 0000000..e239243
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 __DCE_VIRTUAL_H__
+#define __DCE_VIRTUAL_H__
+
+extern const struct amd_ip_funcs dce_virtual_ip_funcs;
+#define DCE_VIRTUAL_VBLANK_PERIOD 16666666
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c b/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c
deleted file mode 100644 (file)
index ed03b75..0000000
+++ /dev/null
@@ -1,186 +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 "fiji_smum.h"
-
-MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
-
-static void fiji_dpm_set_funcs(struct amdgpu_device *adev);
-
-static int fiji_dpm_early_init(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       fiji_dpm_set_funcs(adev);
-
-       return 0;
-}
-
-static int fiji_dpm_init_microcode(struct amdgpu_device *adev)
-{
-       char fw_name[30] = "amdgpu/fiji_smc.bin";
-       int err;
-
-       err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
-       if (err)
-               goto out;
-       err = amdgpu_ucode_validate(adev->pm.fw);
-
-out:
-       if (err) {
-               DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
-               release_firmware(adev->pm.fw);
-               adev->pm.fw = NULL;
-       }
-       return err;
-}
-
-static int fiji_dpm_sw_init(void *handle)
-{
-       int ret;
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       ret = fiji_dpm_init_microcode(adev);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int fiji_dpm_sw_fini(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       release_firmware(adev->pm.fw);
-       adev->pm.fw = NULL;
-
-       return 0;
-}
-
-static int fiji_dpm_hw_init(void *handle)
-{
-       int ret;
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       mutex_lock(&adev->pm.mutex);
-
-       ret = fiji_smu_init(adev);
-       if (ret) {
-               DRM_ERROR("SMU initialization failed\n");
-               goto fail;
-       }
-
-       ret = fiji_smu_start(adev);
-       if (ret) {
-               DRM_ERROR("SMU start failed\n");
-               goto fail;
-       }
-
-       mutex_unlock(&adev->pm.mutex);
-       return 0;
-
-fail:
-       adev->firmware.smu_load = false;
-       mutex_unlock(&adev->pm.mutex);
-       return -EINVAL;
-}
-
-static int fiji_dpm_hw_fini(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-       mutex_lock(&adev->pm.mutex);
-       fiji_smu_fini(adev);
-       mutex_unlock(&adev->pm.mutex);
-       return 0;
-}
-
-static int fiji_dpm_suspend(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       fiji_dpm_hw_fini(adev);
-
-       return 0;
-}
-
-static int fiji_dpm_resume(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       fiji_dpm_hw_init(adev);
-
-       return 0;
-}
-
-static int fiji_dpm_set_clockgating_state(void *handle,
-                       enum amd_clockgating_state state)
-{
-       return 0;
-}
-
-static int fiji_dpm_set_powergating_state(void *handle,
-                       enum amd_powergating_state state)
-{
-       return 0;
-}
-
-const struct amd_ip_funcs fiji_dpm_ip_funcs = {
-       .name = "fiji_dpm",
-       .early_init = fiji_dpm_early_init,
-       .late_init = NULL,
-       .sw_init = fiji_dpm_sw_init,
-       .sw_fini = fiji_dpm_sw_fini,
-       .hw_init = fiji_dpm_hw_init,
-       .hw_fini = fiji_dpm_hw_fini,
-       .suspend = fiji_dpm_suspend,
-       .resume = fiji_dpm_resume,
-       .is_idle = NULL,
-       .wait_for_idle = NULL,
-       .soft_reset = NULL,
-       .set_clockgating_state = fiji_dpm_set_clockgating_state,
-       .set_powergating_state = fiji_dpm_set_powergating_state,
-};
-
-static const struct amdgpu_dpm_funcs fiji_dpm_funcs = {
-       .get_temperature = NULL,
-       .pre_set_power_state = NULL,
-       .set_power_state = NULL,
-       .post_set_power_state = NULL,
-       .display_configuration_changed = NULL,
-       .get_sclk = NULL,
-       .get_mclk = NULL,
-       .print_power_state = NULL,
-       .debugfs_print_current_performance_level = NULL,
-       .force_performance_level = NULL,
-       .vblank_too_short = NULL,
-       .powergate_uvd = NULL,
-};
-
-static void fiji_dpm_set_funcs(struct amdgpu_device *adev)
-{
-       if (NULL == adev->pm.funcs)
-               adev->pm.funcs = &fiji_dpm_funcs;
-}
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_smc.c b/drivers/gpu/drm/amd/amdgpu/fiji_smc.c
deleted file mode 100644 (file)
index b3e19ba..0000000
+++ /dev/null
@@ -1,863 +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 "fiji_ppsmc.h"
-#include "fiji_smum.h"
-#include "smu_ucode_xfer_vi.h"
-#include "amdgpu_ucode.h"
-
-#include "smu/smu_7_1_3_d.h"
-#include "smu/smu_7_1_3_sh_mask.h"
-
-#define FIJI_SMC_SIZE 0x20000
-
-static int fiji_set_smc_sram_address(struct amdgpu_device *adev, uint32_t smc_address, uint32_t limit)
-{
-       uint32_t val;
-
-       if (smc_address & 3)
-               return -EINVAL;
-
-       if ((smc_address + 3) > limit)
-               return -EINVAL;
-
-       WREG32(mmSMC_IND_INDEX_0, smc_address);
-
-       val = RREG32(mmSMC_IND_ACCESS_CNTL);
-       val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
-       WREG32(mmSMC_IND_ACCESS_CNTL, val);
-
-       return 0;
-}
-
-static int fiji_copy_bytes_to_smc(struct amdgpu_device *adev, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit)
-{
-       uint32_t addr;
-       uint32_t data, orig_data;
-       int result = 0;
-       uint32_t extra_shift;
-       unsigned long flags;
-
-       if (smc_start_address & 3)
-               return -EINVAL;
-
-       if ((smc_start_address + byte_count) > limit)
-               return -EINVAL;
-
-       addr = smc_start_address;
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       while (byte_count >= 4) {
-               /* Bytes are written into the SMC addres space with the MSB first */
-               data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
-
-               result = fiji_set_smc_sram_address(adev, addr, limit);
-
-               if (result)
-                       goto out;
-
-               WREG32(mmSMC_IND_DATA_0, data);
-
-               src += 4;
-               byte_count -= 4;
-               addr += 4;
-       }
-
-       if (0 != byte_count) {
-               /* Now write odd bytes left, do a read modify write cycle */
-               data = 0;
-
-               result = fiji_set_smc_sram_address(adev, addr, limit);
-               if (result)
-                       goto out;
-
-               orig_data = RREG32(mmSMC_IND_DATA_0);
-               extra_shift = 8 * (4 - byte_count);
-
-               while (byte_count > 0) {
-                       data = (data << 8) + *src++;
-                       byte_count--;
-               }
-
-               data <<= extra_shift;
-               data |= (orig_data & ~((~0UL) << extra_shift));
-
-               result = fiji_set_smc_sram_address(adev, addr, limit);
-               if (result)
-                       goto out;
-
-               WREG32(mmSMC_IND_DATA_0, data);
-       }
-
-out:
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-       return result;
-}
-
-static int fiji_program_jump_on_start(struct amdgpu_device *adev)
-{
-       static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40};
-       fiji_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
-
-       return 0;
-}
-
-static bool fiji_is_smc_ram_running(struct amdgpu_device *adev)
-{
-       uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-       val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable);
-
-       return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C)));
-}
-
-static int wait_smu_response(struct amdgpu_device *adev)
-{
-       int i;
-       uint32_t val;
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32(mmSMC_RESP_0);
-               if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int fiji_send_msg_to_smc_offset(struct amdgpu_device *adev)
-{
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MSG_ARG_0, 0x20000);
-       WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_Test);
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send message\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int fiji_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg)
-{
-       if (!fiji_is_smc_ram_running(adev))
-       {
-               return -EINVAL;
-       }
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MESSAGE_0, msg);
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send message\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int fiji_send_msg_to_smc_without_waiting(struct amdgpu_device *adev,
-                                               PPSMC_Msg msg)
-{
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MESSAGE_0, msg);
-
-       return 0;
-}
-
-static int fiji_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
-                                               PPSMC_Msg msg,
-                                               uint32_t parameter)
-{
-       if (!fiji_is_smc_ram_running(adev))
-               return -EINVAL;
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MSG_ARG_0, parameter);
-
-       return fiji_send_msg_to_smc(adev, msg);
-}
-
-static int fiji_send_msg_to_smc_with_parameter_without_waiting(
-                                       struct amdgpu_device *adev,
-                                       PPSMC_Msg msg, uint32_t parameter)
-{
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MSG_ARG_0, parameter);
-
-       return fiji_send_msg_to_smc_without_waiting(adev, msg);
-}
-
-#if 0 /* not used yet */
-static int fiji_wait_for_smc_inactive(struct amdgpu_device *adev)
-{
-       int i;
-       uint32_t val;
-
-       if (!fiji_is_smc_ram_running(adev))
-               return -EINVAL;
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-               if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0)
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout)
-               return -EINVAL;
-
-       return 0;
-}
-#endif
-
-static int fiji_smu_upload_firmware_image(struct amdgpu_device *adev)
-{
-       const struct smc_firmware_header_v1_0 *hdr;
-       uint32_t ucode_size;
-       uint32_t ucode_start_address;
-       const uint8_t *src;
-       uint32_t val;
-       uint32_t byte_count;
-       uint32_t *data;
-       unsigned long flags;
-
-       if (!adev->pm.fw)
-               return -EINVAL;
-
-       /* Skip SMC ucode loading on SR-IOV capable boards.
-        * vbios does this for us in asic_init in that case.
-        */
-       if (adev->virtualization.supports_sr_iov)
-               return 0;
-
-       hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
-       amdgpu_ucode_print_smc_hdr(&hdr->header);
-
-       adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
-       ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
-       ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
-       src = (const uint8_t *)
-               (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-
-       if (ucode_size & 3) {
-               DRM_ERROR("SMC ucode is not 4 bytes aligned\n");
-               return -EINVAL;
-       }
-
-       if (ucode_size > FIJI_SMC_SIZE) {
-               DRM_ERROR("SMC address is beyond the SMC RAM area\n");
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
-
-       val = RREG32(mmSMC_IND_ACCESS_CNTL);
-       val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
-       WREG32(mmSMC_IND_ACCESS_CNTL, val);
-
-       byte_count = ucode_size;
-       data = (uint32_t *)src;
-       for (; byte_count >= 4; data++, byte_count -= 4)
-               WREG32(mmSMC_IND_DATA_0, data[0]);
-
-       val = RREG32(mmSMC_IND_ACCESS_CNTL);
-       val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
-       WREG32(mmSMC_IND_ACCESS_CNTL, val);
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-
-       return 0;
-}
-
-#if 0 /* not used yet */
-static int fiji_read_smc_sram_dword(struct amdgpu_device *adev,
-                               uint32_t smc_address,
-                               uint32_t *value,
-                               uint32_t limit)
-{
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       result = fiji_set_smc_sram_address(adev, smc_address, limit);
-       if (result == 0)
-               *value = RREG32(mmSMC_IND_DATA_0);
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-       return result;
-}
-
-static int fiji_write_smc_sram_dword(struct amdgpu_device *adev,
-                               uint32_t smc_address,
-                               uint32_t value,
-                               uint32_t limit)
-{
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       result = fiji_set_smc_sram_address(adev, smc_address, limit);
-       if (result == 0)
-               WREG32(mmSMC_IND_DATA_0, value);
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-       return result;
-}
-
-static int fiji_smu_stop_smc(struct amdgpu_device *adev)
-{
-       uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-       val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1);
-       WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
-
-       return 0;
-}
-#endif
-
-static enum AMDGPU_UCODE_ID fiji_convert_fw_type(uint32_t fw_type)
-{
-       switch (fw_type) {
-               case UCODE_ID_SDMA0:
-                       return AMDGPU_UCODE_ID_SDMA0;
-               case UCODE_ID_SDMA1:
-                       return AMDGPU_UCODE_ID_SDMA1;
-               case UCODE_ID_CP_CE:
-                       return AMDGPU_UCODE_ID_CP_CE;
-               case UCODE_ID_CP_PFP:
-                       return AMDGPU_UCODE_ID_CP_PFP;
-               case UCODE_ID_CP_ME:
-                       return AMDGPU_UCODE_ID_CP_ME;
-               case UCODE_ID_CP_MEC:
-               case UCODE_ID_CP_MEC_JT1:
-               case UCODE_ID_CP_MEC_JT2:
-                       return AMDGPU_UCODE_ID_CP_MEC1;
-               case UCODE_ID_RLC_G:
-                       return AMDGPU_UCODE_ID_RLC_G;
-               default:
-                       DRM_ERROR("ucode type is out of range!\n");
-                       return AMDGPU_UCODE_ID_MAXIMUM;
-       }
-}
-
-static int fiji_smu_populate_single_firmware_entry(struct amdgpu_device *adev,
-                                               uint32_t fw_type,
-                                               struct SMU_Entry *entry)
-{
-       enum AMDGPU_UCODE_ID id = fiji_convert_fw_type(fw_type);
-       struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id];
-       const struct gfx_firmware_header_v1_0 *header = NULL;
-       uint64_t gpu_addr;
-       uint32_t data_size;
-
-       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 ((fw_type == UCODE_ID_CP_MEC_JT1) ||
-               (fw_type == UCODE_ID_CP_MEC_JT2)) {
-               gpu_addr += le32_to_cpu(header->jt_offset) << 2;
-               data_size = le32_to_cpu(header->jt_size) << 2;
-       }
-
-       entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
-       entry->id = (uint16_t)fw_type;
-       entry->image_addr_high = upper_32_bits(gpu_addr);
-       entry->image_addr_low = lower_32_bits(gpu_addr);
-       entry->meta_data_addr_high = 0;
-       entry->meta_data_addr_low = 0;
-       entry->data_size_byte = data_size;
-       entry->num_register_entries = 0;
-
-       if (fw_type == UCODE_ID_RLC_G)
-               entry->flags = 1;
-       else
-               entry->flags = 0;
-
-       return 0;
-}
-
-static int fiji_smu_request_load_fw(struct amdgpu_device *adev)
-{
-       struct fiji_smu_private_data *private = (struct fiji_smu_private_data *)adev->smu.priv;
-       struct SMU_DRAMData_TOC *toc;
-       uint32_t fw_to_load;
-
-       WREG32_SMC(ixSOFT_REGISTERS_TABLE_28, 0);
-
-       fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_HI, private->smu_buffer_addr_high);
-       fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_LO, private->smu_buffer_addr_low);
-
-       toc = (struct SMU_DRAMData_TOC *)private->header;
-       toc->num_entries = 0;
-       toc->structure_version = 1;
-
-       if (!adev->firmware.smu_load)
-               return 0;
-
-       if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for RLC\n");
-               return -EINVAL;
-       }
-
-       if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for CE\n");
-               return -EINVAL;
-       }
-
-       if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for PFP\n");
-               return -EINVAL;
-       }
-
-       if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for ME\n");
-               return -EINVAL;
-       }
-
-       if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for MEC\n");
-               return -EINVAL;
-       }
-
-       if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for MEC_JT1\n");
-               return -EINVAL;
-       }
-
-       if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for MEC_JT2\n");
-               return -EINVAL;
-       }
-
-       if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for SDMA0\n");
-               return -EINVAL;
-       }
-
-       if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for SDMA1\n");
-               return -EINVAL;
-       }
-
-       fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high);
-       fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low);
-
-       fw_to_load = 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_MASK;
-
-       if (fiji_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) {
-               DRM_ERROR("Fail to request SMU load ucode\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static uint32_t fiji_smu_get_mask_for_fw_type(uint32_t fw_type)
-{
-       switch (fw_type) {
-               case AMDGPU_UCODE_ID_SDMA0:
-                       return UCODE_ID_SDMA0_MASK;
-               case AMDGPU_UCODE_ID_SDMA1:
-                       return UCODE_ID_SDMA1_MASK;
-               case AMDGPU_UCODE_ID_CP_CE:
-                       return UCODE_ID_CP_CE_MASK;
-               case AMDGPU_UCODE_ID_CP_PFP:
-                       return UCODE_ID_CP_PFP_MASK;
-               case AMDGPU_UCODE_ID_CP_ME:
-                       return UCODE_ID_CP_ME_MASK;
-               case AMDGPU_UCODE_ID_CP_MEC1:
-                       return UCODE_ID_CP_MEC_MASK;
-               case AMDGPU_UCODE_ID_CP_MEC2:
-                       return UCODE_ID_CP_MEC_MASK;
-               case AMDGPU_UCODE_ID_RLC_G:
-                       return UCODE_ID_RLC_G_MASK;
-               default:
-                       DRM_ERROR("ucode type is out of range!\n");
-                       return 0;
-       }
-}
-
-static int fiji_smu_check_fw_load_finish(struct amdgpu_device *adev,
-                                       uint32_t fw_type)
-{
-       uint32_t fw_mask = fiji_smu_get_mask_for_fw_type(fw_type);
-       int i;
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_28) & fw_mask))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("check firmware loading failed\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int fiji_smu_start_in_protection_mode(struct amdgpu_device *adev)
-{
-       int result;
-       uint32_t val;
-       int i;
-
-       /* Assert reset */
-       val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       result = fiji_smu_upload_firmware_image(adev);
-       if (result)
-               return result;
-
-       /* Clear status */
-       WREG32_SMC(ixSMU_STATUS, 0);
-
-       /* Enable clock */
-       val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-       val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
-       WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
-
-       /* De-assert reset */
-       val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       /* Set SMU Auto Start */
-       val = RREG32_SMC(ixSMU_INPUT_DATA);
-       val = REG_SET_FIELD(val, SMU_INPUT_DATA, AUTO_START, 1);
-       WREG32_SMC(ixSMU_INPUT_DATA, val);
-
-       /* Clear firmware interrupt enable flag */
-       WREG32_SMC(ixFIRMWARE_FLAGS, 0);
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixRCU_UC_EVENTS);
-               if (REG_GET_FIELD(val, RCU_UC_EVENTS, INTERRUPTS_ENABLED))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("Interrupt is not enabled by firmware\n");
-               return -EINVAL;
-       }
-
-       /* Call Test SMU message with 0x20000 offset
-        * to trigger SMU start
-        */
-       fiji_send_msg_to_smc_offset(adev);
-       DRM_INFO("[FM]try triger smu start\n");
-       /* Wait for done bit to be set */
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixSMU_STATUS);
-               if (REG_GET_FIELD(val, SMU_STATUS, SMU_DONE))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("Timeout for SMU start\n");
-               return -EINVAL;
-       }
-
-       /* Check pass/failed indicator */
-       val = RREG32_SMC(ixSMU_STATUS);
-       if (!REG_GET_FIELD(val, SMU_STATUS, SMU_PASS)) {
-               DRM_ERROR("SMU Firmware start failed\n");
-               return -EINVAL;
-       }
-       DRM_INFO("[FM]smu started\n");
-       /* Wait for firmware to initialize */
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixFIRMWARE_FLAGS);
-               if(REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("SMU firmware initialization failed\n");
-               return -EINVAL;
-       }
-       DRM_INFO("[FM]smu initialized\n");
-
-       return 0;
-}
-
-static int fiji_smu_start_in_non_protection_mode(struct amdgpu_device *adev)
-{
-       int i, result;
-       uint32_t val;
-
-       /* wait for smc boot up */
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixRCU_UC_EVENTS);
-               val = REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done);
-               if (val)
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("SMC boot sequence is not completed\n");
-               return -EINVAL;
-       }
-
-       /* Clear firmware interrupt enable flag */
-       WREG32_SMC(ixFIRMWARE_FLAGS, 0);
-
-       /* Assert reset */
-       val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       result = fiji_smu_upload_firmware_image(adev);
-       if (result)
-               return result;
-
-       /* Set smc instruct start point at 0x0 */
-       fiji_program_jump_on_start(adev);
-
-       /* Enable clock */
-       val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-       val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
-       WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
-
-       /* De-assert reset */
-       val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       /* Wait for firmware to initialize */
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixFIRMWARE_FLAGS);
-               if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("Timeout for SMC firmware initialization\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int fiji_smu_start(struct amdgpu_device *adev)
-{
-       int result;
-       uint32_t val;
-
-       if (!fiji_is_smc_ram_running(adev)) {
-               val = RREG32_SMC(ixSMU_FIRMWARE);
-               if (!REG_GET_FIELD(val, SMU_FIRMWARE, SMU_MODE)) {
-                       DRM_INFO("[FM]start smu in nonprotection mode\n");
-                       result = fiji_smu_start_in_non_protection_mode(adev);
-                       if (result)
-                               return result;
-               } else {
-                       DRM_INFO("[FM]start smu in protection mode\n");
-                       result = fiji_smu_start_in_protection_mode(adev);
-                       if (result)
-                               return result;
-               }
-       }
-
-       return fiji_smu_request_load_fw(adev);
-}
-
-static const struct amdgpu_smumgr_funcs fiji_smumgr_funcs = {
-       .check_fw_load_finish = fiji_smu_check_fw_load_finish,
-       .request_smu_load_fw = NULL,
-       .request_smu_specific_fw = NULL,
-};
-
-int fiji_smu_init(struct amdgpu_device *adev)
-{
-       struct fiji_smu_private_data *private;
-       uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
-       uint32_t smu_internal_buffer_size = 200*4096;
-       struct amdgpu_bo **toc_buf = &adev->smu.toc_buf;
-       struct amdgpu_bo **smu_buf = &adev->smu.smu_buf;
-       uint64_t mc_addr;
-       void *toc_buf_ptr;
-       void *smu_buf_ptr;
-       int ret;
-
-       private = kzalloc(sizeof(struct fiji_smu_private_data), GFP_KERNEL);
-       if (NULL == private)
-               return -ENOMEM;
-
-       /* allocate firmware buffers */
-       if (adev->firmware.smu_load)
-               amdgpu_ucode_init_bo(adev);
-
-       adev->smu.priv = private;
-       adev->smu.fw_flags = 0;
-
-       /* Allocate FW image data structure and header buffer */
-       ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE,
-                              true, AMDGPU_GEM_DOMAIN_VRAM,
-                              AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
-                              NULL, NULL, toc_buf);
-       if (ret) {
-               DRM_ERROR("Failed to allocate memory for TOC buffer\n");
-               return -ENOMEM;
-       }
-
-       /* Allocate buffer for SMU internal buffer */
-       ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE,
-                              true, AMDGPU_GEM_DOMAIN_VRAM,
-                              AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
-                              NULL, NULL, smu_buf);
-       if (ret) {
-               DRM_ERROR("Failed to allocate memory for SMU internal buffer\n");
-               return -ENOMEM;
-       }
-
-       /* Retrieve GPU address for header buffer and internal buffer */
-       ret = amdgpu_bo_reserve(adev->smu.toc_buf, false);
-       if (ret) {
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to reserve the TOC buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.toc_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to pin the TOC buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.toc_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to map the TOC buffer\n");
-               return -EINVAL;
-       }
-
-       amdgpu_bo_unreserve(adev->smu.toc_buf);
-       private->header_addr_low = lower_32_bits(mc_addr);
-       private->header_addr_high = upper_32_bits(mc_addr);
-       private->header = toc_buf_ptr;
-
-       ret = amdgpu_bo_reserve(adev->smu.smu_buf, false);
-       if (ret) {
-               amdgpu_bo_unref(&adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to reserve the SMU internal buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to pin the SMU internal buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to map the SMU internal buffer\n");
-               return -EINVAL;
-       }
-
-       amdgpu_bo_unreserve(adev->smu.smu_buf);
-       private->smu_buffer_addr_low = lower_32_bits(mc_addr);
-       private->smu_buffer_addr_high = upper_32_bits(mc_addr);
-
-       adev->smu.smumgr_funcs = &fiji_smumgr_funcs;
-
-       return 0;
-}
-
-int fiji_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.fw_buf)
-               amdgpu_ucode_fini_bo(adev);
-
-       return 0;
-}
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_smum.h b/drivers/gpu/drm/amd/amdgpu/fiji_smum.h
deleted file mode 100644 (file)
index 1cef03d..0000000
+++ /dev/null
@@ -1,42 +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 FIJI_SMUMGR_H
-#define FIJI_SMUMGR_H
-
-#include "fiji_ppsmc.h"
-
-int fiji_smu_init(struct amdgpu_device *adev);
-int fiji_smu_fini(struct amdgpu_device *adev);
-int fiji_smu_start(struct amdgpu_device *adev);
-
-struct fiji_smu_private_data
-{
-       uint8_t *header;
-       uint32_t smu_buffer_addr_high;
-       uint32_t smu_buffer_addr_low;
-       uint32_t header_addr_high;
-       uint32_t header_addr_low;
-};
-
-#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
new file mode 100644 (file)
index 0000000..40abb6b
--- /dev/null
@@ -0,0 +1,3362 @@
+/*
+ * Copyright 2015 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 "amdgpu.h"
+#include "amdgpu_ih.h"
+#include "amdgpu_gfx.h"
+#include "amdgpu_ucode.h"
+#include "si/clearstate_si.h"
+#include "si/sid.h"
+
+#define GFX6_NUM_GFX_RINGS     1
+#define GFX6_NUM_COMPUTE_RINGS 2
+#define STATIC_PER_CU_PG_ENABLE                    (1 << 3)
+#define DYN_PER_CU_PG_ENABLE                       (1 << 2)
+#define RLC_SAVE_AND_RESTORE_STARTING_OFFSET 0x90
+#define RLC_CLEAR_STATE_DESCRIPTOR_OFFSET    0x3D
+
+
+static void gfx_v6_0_set_ring_funcs(struct amdgpu_device *adev);
+static void gfx_v6_0_set_irq_funcs(struct amdgpu_device *adev);
+static void gfx_v6_0_get_cu_info(struct amdgpu_device *adev);
+
+MODULE_FIRMWARE("radeon/tahiti_pfp.bin");
+MODULE_FIRMWARE("radeon/tahiti_me.bin");
+MODULE_FIRMWARE("radeon/tahiti_ce.bin");
+MODULE_FIRMWARE("radeon/tahiti_rlc.bin");
+
+MODULE_FIRMWARE("radeon/pitcairn_pfp.bin");
+MODULE_FIRMWARE("radeon/pitcairn_me.bin");
+MODULE_FIRMWARE("radeon/pitcairn_ce.bin");
+MODULE_FIRMWARE("radeon/pitcairn_rlc.bin");
+
+MODULE_FIRMWARE("radeon/verde_pfp.bin");
+MODULE_FIRMWARE("radeon/verde_me.bin");
+MODULE_FIRMWARE("radeon/verde_ce.bin");
+MODULE_FIRMWARE("radeon/verde_rlc.bin");
+
+MODULE_FIRMWARE("radeon/oland_pfp.bin");
+MODULE_FIRMWARE("radeon/oland_me.bin");
+MODULE_FIRMWARE("radeon/oland_ce.bin");
+MODULE_FIRMWARE("radeon/oland_rlc.bin");
+
+MODULE_FIRMWARE("radeon/hainan_pfp.bin");
+MODULE_FIRMWARE("radeon/hainan_me.bin");
+MODULE_FIRMWARE("radeon/hainan_ce.bin");
+MODULE_FIRMWARE("radeon/hainan_rlc.bin");
+
+static u32 gfx_v6_0_get_csb_size(struct amdgpu_device *adev);
+static void gfx_v6_0_get_csb_buffer(struct amdgpu_device *adev, volatile u32 *buffer);
+//static void gfx_v6_0_init_cp_pg_table(struct amdgpu_device *adev);
+static void gfx_v6_0_init_pg(struct amdgpu_device *adev);
+
+
+static const u32 verde_rlc_save_restore_register_list[] =
+{
+       (0x8000 << 16) | (0x98f4 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x98f4 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0xe80 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0xe80 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x89bc >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x89bc >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x8c1c >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x8c1c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x98f0 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0xe7c >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x9148 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x9148 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9150 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x897c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8d8c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0xac54 >> 2),
+       0X00000000,
+       0x3,
+       (0x9c00 << 16) | (0x98f8 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9910 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9914 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9918 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x991c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9920 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9924 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9928 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x992c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9930 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9934 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9938 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x993c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9940 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9944 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9948 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x994c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9950 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9954 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9958 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x995c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9960 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9964 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9968 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x996c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9970 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9974 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9978 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x997c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9980 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9984 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9988 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x998c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8c00 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8c14 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8c04 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8c08 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x9b7c >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x9b7c >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0xe84 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0xe84 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x89c0 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x89c0 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x914c >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x914c >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x8c20 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x8c20 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x9354 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x9354 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9060 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9364 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9100 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x913c >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x90e0 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x90e4 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x90e8 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x90e0 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x90e4 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x90e8 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8bcc >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8b24 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x88c4 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8e50 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8c0c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8e58 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8e5c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9508 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x950c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9494 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0xac0c >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0xac10 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0xac14 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0xae00 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0xac08 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x88d4 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x88c8 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x88cc >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x89b0 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8b10 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x8a14 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9830 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9834 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9838 >> 2),
+       0x00000000,
+       (0x9c00 << 16) | (0x9a10 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x9870 >> 2),
+       0x00000000,
+       (0x8000 << 16) | (0x9874 >> 2),
+       0x00000000,
+       (0x8001 << 16) | (0x9870 >> 2),
+       0x00000000,
+       (0x8001 << 16) | (0x9874 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x9870 >> 2),
+       0x00000000,
+       (0x8040 << 16) | (0x9874 >> 2),
+       0x00000000,
+       (0x8041 << 16) | (0x9870 >> 2),
+       0x00000000,
+       (0x8041 << 16) | (0x9874 >> 2),
+       0x00000000,
+       0x00000000
+};
+
+static int gfx_v6_0_init_microcode(struct amdgpu_device *adev)
+{
+       const char *chip_name;
+       char fw_name[30];
+       int err;
+       const struct gfx_firmware_header_v1_0 *cp_hdr;
+       const struct rlc_firmware_header_v1_0 *rlc_hdr;
+
+       DRM_DEBUG("\n");
+
+       switch (adev->asic_type) {
+       case CHIP_TAHITI:
+               chip_name = "tahiti";
+               break;
+       case CHIP_PITCAIRN:
+               chip_name = "pitcairn";
+               break;
+       case CHIP_VERDE:
+               chip_name = "verde";
+               break;
+       case CHIP_OLAND:
+               chip_name = "oland";
+               break;
+       case CHIP_HAINAN:
+               chip_name = "hainan";
+               break;
+       default: BUG();
+       }
+
+       snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
+       err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev);
+       if (err)
+               goto out;
+       err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
+       if (err)
+               goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
+       adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
+
+       snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
+       err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
+       if (err)
+               goto out;
+       err = amdgpu_ucode_validate(adev->gfx.me_fw);
+       if (err)
+               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);
+       adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
+
+       snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name);
+       err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
+       if (err)
+               goto out;
+       err = amdgpu_ucode_validate(adev->gfx.ce_fw);
+       if (err)
+               goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
+       adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
+
+       snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name);
+       err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
+       if (err)
+               goto out;
+       err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
+       rlc_hdr = (const struct rlc_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
+       adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version);
+       adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version);
+
+out:
+       if (err) {
+               printk(KERN_ERR
+                      "gfx6: Failed to load firmware \"%s\"\n",
+                      fw_name);
+               release_firmware(adev->gfx.pfp_fw);
+               adev->gfx.pfp_fw = NULL;
+               release_firmware(adev->gfx.me_fw);
+               adev->gfx.me_fw = NULL;
+               release_firmware(adev->gfx.ce_fw);
+               adev->gfx.ce_fw = NULL;
+               release_firmware(adev->gfx.rlc_fw);
+               adev->gfx.rlc_fw = NULL;
+       }
+       return err;
+}
+
+static void gfx_v6_0_tiling_mode_table_init(struct amdgpu_device *adev)
+{
+       const u32 num_tile_mode_states = 32;
+       u32 reg_offset, gb_tile_moden, split_equal_to_row_size;
+
+       switch (adev->gfx.config.mem_row_size_in_kb) {
+       case 1:
+               split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_1KB;
+               break;
+       case 2:
+       default:
+               split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_2KB;
+               break;
+       case 4:
+               split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_4KB;
+               break;
+       }
+
+       if (adev->asic_type == CHIP_VERDE ||
+               adev->asic_type == CHIP_OLAND ||
+               adev->asic_type == CHIP_HAINAN) {
+               for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+                       switch (reg_offset) {
+                       case 0:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+                               break;
+                       case 1: 
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+                               break;
+                       case 2:
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+                               break;
+                       case 3:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+                               break;
+                       case 4:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 5:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(split_equal_to_row_size) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 6:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(split_equal_to_row_size) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 7:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(split_equal_to_row_size) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+                               break;
+                       case 8: 
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 9:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 10:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+                               break;
+                       case 11:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 12:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 13:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 14:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 15:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 16:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 17:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+                                                TILE_SPLIT(split_equal_to_row_size) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 21:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 22:  
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+                               break;
+                       case 23: 
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 24: 
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 25: 
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) |
+                                                NUM_BANKS(ADDR_SURF_8_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+                               break;
+                       default:
+                               gb_tile_moden = 0;
+                               break;
+                       }
+                       adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden;
+                       WREG32(GB_TILE_MODE0 + reg_offset, gb_tile_moden);
+               }
+       } else if ((adev->asic_type == CHIP_TAHITI) || (adev->asic_type == CHIP_PITCAIRN)) {
+               for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+                       switch (reg_offset) {
+                       case 0:  /* non-AA compressed depth or any compressed stencil */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 1:  /* 2xAA/4xAA compressed depth only */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 2:  /* 8xAA compressed depth only */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 3:  /* 2xAA/4xAA compressed depth with stencil (for depth buffer) */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 4:  /* Maps w/ a dimension less than the 2D macro-tile dimensions (for mipmapped depth textures) */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 5:  /* Uncompressed 16bpp depth - and stencil buffer allocated with it */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(split_equal_to_row_size) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 6:  /* Uncompressed 32bpp depth - and stencil buffer allocated with it */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(split_equal_to_row_size) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+                               break;
+                       case 7:  /* Uncompressed 8bpp stencil without depth (drivers typically do not use) */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(split_equal_to_row_size) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 8:  /* 1D and 1D Array Surfaces */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 9:  /* Displayable maps. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 10:  /* Display 8bpp. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 11:  /* Display 16bpp. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 12:  /* Display 32bpp. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+                               break;
+                       case 13:  /* Thin. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 14:  /* Thin 8 bpp. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+                               break;
+                       case 15:  /* Thin 16 bpp. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+                               break;
+                       case 16:  /* Thin 32 bpp. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+                               break;
+                       case 17:  /* Thin 64 bpp. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(split_equal_to_row_size) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+                               break;
+                       case 21:  /* 8 bpp PRT. */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 22:  /* 16 bpp PRT */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+                               break;
+                       case 23:  /* 32 bpp PRT */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 24:  /* 64 bpp PRT */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+                                                NUM_BANKS(ADDR_SURF_16_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+                               break;
+                       case 25:  /* 128 bpp PRT */
+                               gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+                                                MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+                                                TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) |
+                                                NUM_BANKS(ADDR_SURF_8_BANK) |
+                                                BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+                                                BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+                                                MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+                               break;
+                       default:
+                               gb_tile_moden = 0;
+                               break;
+                       }
+                       adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden;
+                       WREG32(GB_TILE_MODE0 + reg_offset, gb_tile_moden);
+               }
+       } else{
+
+               DRM_ERROR("unknown asic: 0x%x\n", adev->asic_type);
+       }
+
+}
+
+static void gfx_v6_0_select_se_sh(struct amdgpu_device *adev, u32 se_num,
+                                 u32 sh_num, u32 instance)
+{
+       u32 data;
+
+       if (instance == 0xffffffff)
+               data = INSTANCE_BROADCAST_WRITES;
+       else
+               data = INSTANCE_INDEX(instance);
+
+       if ((se_num == 0xffffffff) && (sh_num == 0xffffffff))
+               data |= SH_BROADCAST_WRITES | SE_BROADCAST_WRITES;
+       else if (se_num == 0xffffffff)
+               data |= SE_BROADCAST_WRITES | SH_INDEX(sh_num);
+       else if (sh_num == 0xffffffff)
+               data |= SH_BROADCAST_WRITES | SE_INDEX(se_num);
+       else
+               data |= SH_INDEX(sh_num) | SE_INDEX(se_num);
+       WREG32(GRBM_GFX_INDEX, data);
+}
+
+static u32 gfx_v6_0_create_bitmask(u32 bit_width)
+{
+       return (u32)(((u64)1 << bit_width) - 1);
+}
+
+static u32 gfx_v6_0_get_rb_disabled(struct amdgpu_device *adev,
+                                   u32 max_rb_num_per_se,
+                                   u32 sh_per_se)
+{
+       u32 data, mask;
+
+       data = RREG32(CC_RB_BACKEND_DISABLE);
+       data &= BACKEND_DISABLE_MASK;
+       data |= RREG32(GC_USER_RB_BACKEND_DISABLE);
+
+       data >>= BACKEND_DISABLE_SHIFT;
+
+       mask = gfx_v6_0_create_bitmask(max_rb_num_per_se / sh_per_se);
+
+       return data & mask;
+}
+
+static void gfx_v6_0_raster_config(struct amdgpu_device *adev, u32 *rconf)
+{
+       switch (adev->asic_type) {
+       case CHIP_TAHITI:
+       case CHIP_PITCAIRN:
+               *rconf |= RB_XSEL2(2) | RB_XSEL | PKR_MAP(2) | PKR_YSEL(1) |
+                         SE_MAP(2) | SE_XSEL(2) | SE_YSEL(2);
+               break;
+       case CHIP_VERDE:
+               *rconf |= RB_XSEL | PKR_MAP(2) | PKR_YSEL(1);
+               break;
+       case CHIP_OLAND:
+               *rconf |= RB_YSEL;
+               break;
+       case CHIP_HAINAN:
+               *rconf |= 0x0;
+               break;
+       default:
+               DRM_ERROR("unknown asic: 0x%x\n", adev->asic_type);
+               break;
+       }
+}
+
+static void gfx_v6_0_write_harvested_raster_configs(struct amdgpu_device *adev,
+                                                   u32 raster_config, unsigned rb_mask,
+                                                   unsigned num_rb)
+{
+       unsigned sh_per_se = max_t(unsigned, adev->gfx.config.max_sh_per_se, 1);
+       unsigned num_se = max_t(unsigned, adev->gfx.config.max_shader_engines, 1);
+       unsigned rb_per_pkr = min_t(unsigned, num_rb / num_se / sh_per_se, 2);
+       unsigned rb_per_se = num_rb / num_se;
+       unsigned se_mask[4];
+       unsigned se;
+
+       se_mask[0] = ((1 << rb_per_se) - 1) & rb_mask;
+       se_mask[1] = (se_mask[0] << rb_per_se) & rb_mask;
+       se_mask[2] = (se_mask[1] << rb_per_se) & rb_mask;
+       se_mask[3] = (se_mask[2] << rb_per_se) & rb_mask;
+
+       WARN_ON(!(num_se == 1 || num_se == 2 || num_se == 4));
+       WARN_ON(!(sh_per_se == 1 || sh_per_se == 2));
+       WARN_ON(!(rb_per_pkr == 1 || rb_per_pkr == 2));
+
+       for (se = 0; se < num_se; se++) {
+               unsigned raster_config_se = raster_config;
+               unsigned pkr0_mask = ((1 << rb_per_pkr) - 1) << (se * rb_per_se);
+               unsigned pkr1_mask = pkr0_mask << rb_per_pkr;
+               int idx = (se / 2) * 2;
+
+               if ((num_se > 1) && (!se_mask[idx] || !se_mask[idx + 1])) {
+                       raster_config_se &= ~SE_MAP_MASK;
+
+                       if (!se_mask[idx]) {
+                               raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_3);
+                       } else {
+                               raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_0);
+                       }
+               }
+
+               pkr0_mask &= rb_mask;
+               pkr1_mask &= rb_mask;
+               if (rb_per_se > 2 && (!pkr0_mask || !pkr1_mask)) {
+                       raster_config_se &= ~PKR_MAP_MASK;
+
+                       if (!pkr0_mask) {
+                               raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_3);
+                       } else {
+                               raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_0);
+                       }
+               }
+
+               if (rb_per_se >= 2) {
+                       unsigned rb0_mask = 1 << (se * rb_per_se);
+                       unsigned rb1_mask = rb0_mask << 1;
+
+                       rb0_mask &= rb_mask;
+                       rb1_mask &= rb_mask;
+                       if (!rb0_mask || !rb1_mask) {
+                               raster_config_se &= ~RB_MAP_PKR0_MASK;
+
+                               if (!rb0_mask) {
+                                       raster_config_se |=
+                                               RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_3);
+                               } else {
+                                       raster_config_se |=
+                                               RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_0);
+                               }
+                       }
+
+                       if (rb_per_se > 2) {
+                               rb0_mask = 1 << (se * rb_per_se + rb_per_pkr);
+                               rb1_mask = rb0_mask << 1;
+                               rb0_mask &= rb_mask;
+                               rb1_mask &= rb_mask;
+                               if (!rb0_mask || !rb1_mask) {
+                                       raster_config_se &= ~RB_MAP_PKR1_MASK;
+
+                                       if (!rb0_mask) {
+                                               raster_config_se |=
+                                                       RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_3);
+                                       } else {
+                                               raster_config_se |=
+                                                       RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_0);
+                                       }
+                               }
+                       }
+               }
+
+               /* GRBM_GFX_INDEX has a different offset on SI */
+               gfx_v6_0_select_se_sh(adev, se, 0xffffffff, 0xffffffff);
+               WREG32(PA_SC_RASTER_CONFIG, raster_config_se);
+       }
+
+       /* GRBM_GFX_INDEX has a different offset on SI */
+       gfx_v6_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+}
+
+static void gfx_v6_0_setup_rb(struct amdgpu_device *adev,
+                             u32 se_num, u32 sh_per_se,
+                             u32 max_rb_num_per_se)
+{
+       int i, j;
+       u32 data, mask;
+       u32 disabled_rbs = 0;
+       u32 enabled_rbs = 0;
+       unsigned num_rb_pipes;
+
+       mutex_lock(&adev->grbm_idx_mutex);
+       for (i = 0; i < se_num; i++) {
+               for (j = 0; j < sh_per_se; j++) {
+                       gfx_v6_0_select_se_sh(adev, i, j, 0xffffffff);
+                       data = gfx_v6_0_get_rb_disabled(adev, max_rb_num_per_se, sh_per_se);
+                       disabled_rbs |= data << ((i * sh_per_se + j) * TAHITI_RB_BITMAP_WIDTH_PER_SH);
+               }
+       }
+       gfx_v6_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+       mutex_unlock(&adev->grbm_idx_mutex);
+
+       mask = 1;
+       for (i = 0; i < max_rb_num_per_se * se_num; i++) {
+               if (!(disabled_rbs & mask))
+                       enabled_rbs |= mask;
+               mask <<= 1;
+       }
+
+       adev->gfx.config.backend_enable_mask = enabled_rbs;
+       adev->gfx.config.num_rbs = hweight32(enabled_rbs);
+
+       num_rb_pipes = min_t(unsigned, adev->gfx.config.max_backends_per_se *
+                            adev->gfx.config.max_shader_engines, 16);
+
+       mutex_lock(&adev->grbm_idx_mutex);
+       for (i = 0; i < se_num; i++) {
+               gfx_v6_0_select_se_sh(adev, i, 0xffffffff, 0xffffffff);
+               data = 0;
+               for (j = 0; j < sh_per_se; j++) {
+                       switch (enabled_rbs & 3) {
+                       case 1:
+                               data |= (RASTER_CONFIG_RB_MAP_0 << (i * sh_per_se + j) * 2);
+                               break;
+                       case 2:
+                               data |= (RASTER_CONFIG_RB_MAP_3 << (i * sh_per_se + j) * 2);
+                               break;
+                       case 3:
+                       default:
+                               data |= (RASTER_CONFIG_RB_MAP_2 << (i * sh_per_se + j) * 2);
+                               break;
+                       }
+                       enabled_rbs >>= 2;
+               }
+               gfx_v6_0_raster_config(adev, &data);
+
+               if (!adev->gfx.config.backend_enable_mask ||
+                               adev->gfx.config.num_rbs >= num_rb_pipes)
+                       WREG32(PA_SC_RASTER_CONFIG, data);
+               else
+                       gfx_v6_0_write_harvested_raster_configs(adev, data,
+                                                               adev->gfx.config.backend_enable_mask,
+                                                               num_rb_pipes);
+       }
+       gfx_v6_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+       mutex_unlock(&adev->grbm_idx_mutex);
+}
+/*
+static void gmc_v6_0_init_compute_vmid(struct amdgpu_device *adev)
+{
+}
+*/
+
+static u32 gfx_v6_0_get_cu_enabled(struct amdgpu_device *adev, u32 cu_per_sh)
+{
+       u32 data, mask;
+
+       data = RREG32(CC_GC_SHADER_ARRAY_CONFIG);
+       data &= INACTIVE_CUS_MASK;
+       data |= RREG32(GC_USER_SHADER_ARRAY_CONFIG);
+
+       data >>= INACTIVE_CUS_SHIFT;
+
+       mask = gfx_v6_0_create_bitmask(cu_per_sh);
+
+       return ~data & mask;
+}
+
+
+static void gfx_v6_0_setup_spi(struct amdgpu_device *adev,
+                        u32 se_num, u32 sh_per_se,
+                        u32 cu_per_sh)
+{
+       int i, j, k;
+       u32 data, mask;
+       u32 active_cu = 0;
+
+       mutex_lock(&adev->grbm_idx_mutex);
+       for (i = 0; i < se_num; i++) {
+               for (j = 0; j < sh_per_se; j++) {
+                       gfx_v6_0_select_se_sh(adev, i, j, 0xffffffff);
+                       data = RREG32(SPI_STATIC_THREAD_MGMT_3);
+                       active_cu = gfx_v6_0_get_cu_enabled(adev, cu_per_sh);
+
+                       mask = 1;
+                       for (k = 0; k < 16; k++) {
+                               mask <<= k;
+                               if (active_cu & mask) {
+                                       data &= ~mask;
+                                       WREG32(SPI_STATIC_THREAD_MGMT_3, data);
+                                       break;
+                               }
+                       }
+               }
+       }
+       gfx_v6_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+       mutex_unlock(&adev->grbm_idx_mutex);
+}
+
+static void gfx_v6_0_gpu_init(struct amdgpu_device *adev)
+{
+       u32 gb_addr_config = 0;
+       u32 mc_shared_chmap, mc_arb_ramcfg;
+       u32 sx_debug_1;
+       u32 hdp_host_path_cntl;
+       u32 tmp;
+
+       switch (adev->asic_type) {
+       case CHIP_TAHITI:
+               adev->gfx.config.max_shader_engines = 2;
+               adev->gfx.config.max_tile_pipes = 12;
+               adev->gfx.config.max_cu_per_sh = 8;
+               adev->gfx.config.max_sh_per_se = 2;
+               adev->gfx.config.max_backends_per_se = 4;
+               adev->gfx.config.max_texture_channel_caches = 12;
+               adev->gfx.config.max_gprs = 256;
+               adev->gfx.config.max_gs_threads = 32;
+               adev->gfx.config.max_hw_contexts = 8;
+
+               adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
+               adev->gfx.config.sc_prim_fifo_size_backend = 0x100;
+               adev->gfx.config.sc_hiz_tile_fifo_size = 0x30;
+               adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130;
+               gb_addr_config = TAHITI_GB_ADDR_CONFIG_GOLDEN;
+               break;
+       case CHIP_PITCAIRN:
+               adev->gfx.config.max_shader_engines = 2;
+               adev->gfx.config.max_tile_pipes = 8;
+               adev->gfx.config.max_cu_per_sh = 5;
+               adev->gfx.config.max_sh_per_se = 2;
+               adev->gfx.config.max_backends_per_se = 4;
+               adev->gfx.config.max_texture_channel_caches = 8;
+               adev->gfx.config.max_gprs = 256;
+               adev->gfx.config.max_gs_threads = 32;
+               adev->gfx.config.max_hw_contexts = 8;
+
+               adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
+               adev->gfx.config.sc_prim_fifo_size_backend = 0x100;
+               adev->gfx.config.sc_hiz_tile_fifo_size = 0x30;
+               adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130;
+               gb_addr_config = TAHITI_GB_ADDR_CONFIG_GOLDEN;
+               break;
+
+       case CHIP_VERDE:
+               adev->gfx.config.max_shader_engines = 1;
+               adev->gfx.config.max_tile_pipes = 4;
+               adev->gfx.config.max_cu_per_sh = 5;
+               adev->gfx.config.max_sh_per_se = 2;
+               adev->gfx.config.max_backends_per_se = 4;
+               adev->gfx.config.max_texture_channel_caches = 4;
+               adev->gfx.config.max_gprs = 256;
+               adev->gfx.config.max_gs_threads = 32;
+               adev->gfx.config.max_hw_contexts = 8;
+
+               adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
+               adev->gfx.config.sc_prim_fifo_size_backend = 0x40;
+               adev->gfx.config.sc_hiz_tile_fifo_size = 0x30;
+               adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130;
+               gb_addr_config = VERDE_GB_ADDR_CONFIG_GOLDEN;
+               break;
+       case CHIP_OLAND:
+               adev->gfx.config.max_shader_engines = 1;
+               adev->gfx.config.max_tile_pipes = 4;
+               adev->gfx.config.max_cu_per_sh = 6;
+               adev->gfx.config.max_sh_per_se = 1;
+               adev->gfx.config.max_backends_per_se = 2;
+               adev->gfx.config.max_texture_channel_caches = 4;
+               adev->gfx.config.max_gprs = 256;
+               adev->gfx.config.max_gs_threads = 16;
+               adev->gfx.config.max_hw_contexts = 8;
+
+               adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
+               adev->gfx.config.sc_prim_fifo_size_backend = 0x40;
+               adev->gfx.config.sc_hiz_tile_fifo_size = 0x30;
+               adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130;
+               gb_addr_config = VERDE_GB_ADDR_CONFIG_GOLDEN;
+               break;
+       case CHIP_HAINAN:
+               adev->gfx.config.max_shader_engines = 1;
+               adev->gfx.config.max_tile_pipes = 4;
+               adev->gfx.config.max_cu_per_sh = 5;
+               adev->gfx.config.max_sh_per_se = 1;
+               adev->gfx.config.max_backends_per_se = 1;
+               adev->gfx.config.max_texture_channel_caches = 2;
+               adev->gfx.config.max_gprs = 256;
+               adev->gfx.config.max_gs_threads = 16;
+               adev->gfx.config.max_hw_contexts = 8;
+
+               adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
+               adev->gfx.config.sc_prim_fifo_size_backend = 0x40;
+               adev->gfx.config.sc_hiz_tile_fifo_size = 0x30;
+               adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130;
+               gb_addr_config = HAINAN_GB_ADDR_CONFIG_GOLDEN;
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+       WREG32(SRBM_INT_CNTL, 1);
+       WREG32(SRBM_INT_ACK, 1);
+
+       WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
+
+       mc_shared_chmap = RREG32(MC_SHARED_CHMAP);
+       mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
+
+       adev->gfx.config.num_tile_pipes = adev->gfx.config.max_tile_pipes;
+       adev->gfx.config.mem_max_burst_length_bytes = 256;
+       tmp = (mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT;
+       adev->gfx.config.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024;
+       if (adev->gfx.config.mem_row_size_in_kb > 4)
+               adev->gfx.config.mem_row_size_in_kb = 4;
+       adev->gfx.config.shader_engine_tile_size = 32;
+       adev->gfx.config.num_gpus = 1;
+       adev->gfx.config.multi_gpu_tile_size = 64;
+
+       gb_addr_config &= ~ROW_SIZE_MASK;
+       switch (adev->gfx.config.mem_row_size_in_kb) {
+       case 1:
+       default:
+               gb_addr_config |= ROW_SIZE(0);
+               break;
+       case 2:
+               gb_addr_config |= ROW_SIZE(1);
+               break;
+       case 4:
+               gb_addr_config |= ROW_SIZE(2);
+               break;
+       }
+       adev->gfx.config.gb_addr_config = gb_addr_config;
+
+       WREG32(GB_ADDR_CONFIG, gb_addr_config);
+       WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
+       WREG32(DMIF_ADDR_CALC, gb_addr_config);
+       WREG32(HDP_ADDR_CONFIG, gb_addr_config);
+       WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config);
+       WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config);
+#if 0
+       if (adev->has_uvd) {
+               WREG32(UVD_UDEC_ADDR_CONFIG, gb_addr_config);
+               WREG32(UVD_UDEC_DB_ADDR_CONFIG, gb_addr_config);
+               WREG32(UVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config);
+       }
+#endif
+       gfx_v6_0_tiling_mode_table_init(adev);
+
+       gfx_v6_0_setup_rb(adev, adev->gfx.config.max_shader_engines,
+                   adev->gfx.config.max_sh_per_se,
+                   adev->gfx.config.max_backends_per_se);
+
+       gfx_v6_0_setup_spi(adev, adev->gfx.config.max_shader_engines,
+                    adev->gfx.config.max_sh_per_se,
+                    adev->gfx.config.max_cu_per_sh);
+
+       gfx_v6_0_get_cu_info(adev);
+
+       WREG32(CP_QUEUE_THRESHOLDS, (ROQ_IB1_START(0x16) |
+                                    ROQ_IB2_START(0x2b)));
+       WREG32(CP_MEQ_THRESHOLDS, MEQ1_START(0x30) | MEQ2_START(0x60));
+
+       sx_debug_1 = RREG32(SX_DEBUG_1);
+       WREG32(SX_DEBUG_1, sx_debug_1);
+
+       WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4));
+
+       WREG32(PA_SC_FIFO_SIZE, (SC_FRONTEND_PRIM_FIFO_SIZE(adev->gfx.config.sc_prim_fifo_size_frontend) |
+                                SC_BACKEND_PRIM_FIFO_SIZE(adev->gfx.config.sc_prim_fifo_size_backend) |
+                                SC_HIZ_TILE_FIFO_SIZE(adev->gfx.config.sc_hiz_tile_fifo_size) |
+                                SC_EARLYZ_TILE_FIFO_SIZE(adev->gfx.config.sc_earlyz_tile_fifo_size)));
+
+       WREG32(VGT_NUM_INSTANCES, 1);
+       WREG32(CP_PERFMON_CNTL, 0);
+       WREG32(SQ_CONFIG, 0);
+       WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) |
+                                         FORCE_EOV_MAX_REZ_CNT(255)));
+
+       WREG32(VGT_CACHE_INVALIDATION, CACHE_INVALIDATION(VC_AND_TC) |
+              AUTO_INVLD_EN(ES_AND_GS_AUTO));
+
+       WREG32(VGT_GS_VERTEX_REUSE, 16);
+       WREG32(PA_SC_LINE_STIPPLE_STATE, 0);
+
+       WREG32(CB_PERFCOUNTER0_SELECT0, 0);
+       WREG32(CB_PERFCOUNTER0_SELECT1, 0);
+       WREG32(CB_PERFCOUNTER1_SELECT0, 0);
+       WREG32(CB_PERFCOUNTER1_SELECT1, 0);
+       WREG32(CB_PERFCOUNTER2_SELECT0, 0);
+       WREG32(CB_PERFCOUNTER2_SELECT1, 0);
+       WREG32(CB_PERFCOUNTER3_SELECT0, 0);
+       WREG32(CB_PERFCOUNTER3_SELECT1, 0);
+
+       hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
+       WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
+
+       WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3));
+
+       udelay(50);
+}
+
+
+static void gfx_v6_0_scratch_init(struct amdgpu_device *adev)
+{
+       int i;
+
+       adev->gfx.scratch.num_reg = 7;
+       adev->gfx.scratch.reg_base = SCRATCH_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;
+       }
+}
+
+static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+       uint32_t scratch;
+       uint32_t tmp = 0;
+       unsigned i;
+       int r;
+
+       r = amdgpu_gfx_scratch_get(adev, &scratch);
+       if (r) {
+               DRM_ERROR("amdgpu: cp failed to get scratch reg (%d).\n", r);
+               return r;
+       }
+       WREG32(scratch, 0xCAFEDEAD);
+
+       r = amdgpu_ring_alloc(ring, 3);
+       if (r) {
+               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n", ring->idx, r);
+               amdgpu_gfx_scratch_free(adev, scratch);
+               return r;
+       }
+       amdgpu_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+       amdgpu_ring_write(ring, (scratch - PACKET3_SET_CONFIG_REG_START));
+       amdgpu_ring_write(ring, 0xDEADBEEF);
+       amdgpu_ring_commit(ring);
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               tmp = RREG32(scratch);
+               if (tmp == 0xDEADBEEF)
+                       break;
+               DRM_UDELAY(1);
+       }
+       if (i < adev->usec_timeout) {
+               DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
+       } else {
+               DRM_ERROR("amdgpu: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
+                         ring->idx, scratch, tmp);
+               r = -EINVAL;
+       }
+       amdgpu_gfx_scratch_free(adev, scratch);
+       return r;
+}
+
+static void gfx_v6_0_ring_emit_hdp_flush(struct amdgpu_ring *ring)
+{
+       /* flush hdp cache */
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) |
+                                WRITE_DATA_DST_SEL(0)));
+       amdgpu_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL);
+       amdgpu_ring_write(ring, 0);
+       amdgpu_ring_write(ring, 0x1);
+}
+
+/**
+ * gfx_v6_0_ring_emit_hdp_invalidate - emit an hdp invalidate on the cp
+ *
+ * @adev: amdgpu_device pointer
+ * @ridx: amdgpu ring index
+ *
+ * Emits an hdp invalidate on the cp.
+ */
+static void gfx_v6_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring)
+{
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) |
+                                WRITE_DATA_DST_SEL(0)));
+       amdgpu_ring_write(ring, HDP_DEBUG0);
+       amdgpu_ring_write(ring, 0);
+       amdgpu_ring_write(ring, 0x1);
+}
+
+static void gfx_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
+                                    u64 seq, unsigned flags)
+{
+       bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT;
+       bool int_sel = flags & AMDGPU_FENCE_FLAG_INT;
+       /* flush read cache over gart */
+       amdgpu_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+       amdgpu_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START));
+       amdgpu_ring_write(ring, 0);
+       amdgpu_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
+       amdgpu_ring_write(ring, PACKET3_TCL1_ACTION_ENA |
+                         PACKET3_TC_ACTION_ENA |
+                         PACKET3_SH_KCACHE_ACTION_ENA |
+                         PACKET3_SH_ICACHE_ACTION_ENA);
+       amdgpu_ring_write(ring, 0xFFFFFFFF);
+       amdgpu_ring_write(ring, 0);
+       amdgpu_ring_write(ring, 10); /* poll interval */
+       /* EVENT_WRITE_EOP - flush caches, send int */
+       amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+       amdgpu_ring_write(ring, EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) | EVENT_INDEX(5));
+       amdgpu_ring_write(ring, addr & 0xfffffffc);
+       amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xffff) |
+                               DATA_SEL(write64bit ? 2 : 1) | INT_SEL(int_sel ? 2 : 0));
+       amdgpu_ring_write(ring, lower_32_bits(seq));
+       amdgpu_ring_write(ring, upper_32_bits(seq));
+}
+
+static void gfx_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
+                                 struct amdgpu_ib *ib,
+                                 unsigned vm_id, bool ctx_switch)
+{
+       u32 header, control = 0;
+
+       /* insert SWITCH_BUFFER packet before first IB in the ring frame */
+       if (ctx_switch) {
+               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+               amdgpu_ring_write(ring, 0);
+       }
+
+       if (ib->flags & AMDGPU_IB_FLAG_CE)
+               header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2);
+       else
+               header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
+
+       control |= ib->length_dw | (vm_id << 24);
+
+       amdgpu_ring_write(ring, header);
+       amdgpu_ring_write(ring,
+#ifdef __BIG_ENDIAN
+                         (2 << 0) |
+#endif
+                         (ib->gpu_addr & 0xFFFFFFFC));
+       amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
+       amdgpu_ring_write(ring, control);
+}
+
+/**
+ * gfx_v6_0_ring_test_ib - basic ring IB test
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Allocate an IB and execute it on the gfx ring (SI).
+ * Provides a basic gfx ring test to verify that IBs are working.
+ * Returns 0 on success, error on failure.
+ */
+static int gfx_v6_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
+{
+       struct amdgpu_device *adev = ring->adev;
+       struct amdgpu_ib ib;
+       struct fence *f = NULL;
+       uint32_t scratch;
+       uint32_t tmp = 0;
+       long r;
+
+       r = amdgpu_gfx_scratch_get(adev, &scratch);
+       if (r) {
+               DRM_ERROR("amdgpu: failed to get scratch reg (%ld).\n", r);
+               return r;
+       }
+       WREG32(scratch, 0xCAFEDEAD);
+       memset(&ib, 0, sizeof(ib));
+       r = amdgpu_ib_get(adev, NULL, 256, &ib);
+       if (r) {
+               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+               goto err1;
+       }
+       ib.ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1);
+       ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_START));
+       ib.ptr[2] = 0xDEADBEEF;
+       ib.length_dw = 3;
+
+       r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f);
+       if (r)
+               goto err2;
+
+       r = fence_wait_timeout(f, false, timeout);
+       if (r == 0) {
+               DRM_ERROR("amdgpu: IB test timed out\n");
+               r = -ETIMEDOUT;
+               goto err2;
+       } else if (r < 0) {
+               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
+               goto err2;
+       }
+       tmp = RREG32(scratch);
+       if (tmp == 0xDEADBEEF) {
+               DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
+               r = 0;
+       } else {
+               DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n",
+                         scratch, tmp);
+               r = -EINVAL;
+       }
+
+err2:
+       amdgpu_ib_free(adev, &ib, NULL);
+       fence_put(f);
+err1:
+       amdgpu_gfx_scratch_free(adev, scratch);
+       return r;
+}
+
+static void gfx_v6_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
+{
+       int i;
+       if (enable)
+               WREG32(CP_ME_CNTL, 0);
+       else {
+               WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT));
+               WREG32(SCRATCH_UMSK, 0);
+               for (i = 0; i < adev->gfx.num_gfx_rings; i++)
+                       adev->gfx.gfx_ring[i].ready = false;
+               for (i = 0; i < adev->gfx.num_compute_rings; i++)
+                       adev->gfx.compute_ring[i].ready = false;
+       }
+       udelay(50);
+}
+
+static int gfx_v6_0_cp_gfx_load_microcode(struct amdgpu_device *adev)
+{
+       unsigned i;
+       const struct gfx_firmware_header_v1_0 *pfp_hdr;
+       const struct gfx_firmware_header_v1_0 *ce_hdr;
+       const struct gfx_firmware_header_v1_0 *me_hdr;
+       const __le32 *fw_data;
+       u32 fw_size;
+
+       if (!adev->gfx.me_fw || !adev->gfx.pfp_fw || !adev->gfx.ce_fw)
+               return -EINVAL;
+
+       gfx_v6_0_cp_gfx_enable(adev, false);
+       pfp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
+       ce_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
+       me_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
+
+       amdgpu_ucode_print_gfx_hdr(&pfp_hdr->header);
+       amdgpu_ucode_print_gfx_hdr(&ce_hdr->header);
+       amdgpu_ucode_print_gfx_hdr(&me_hdr->header);
+
+       /* PFP */
+       fw_data = (const __le32 *)
+               (adev->gfx.pfp_fw->data + le32_to_cpu(pfp_hdr->header.ucode_array_offset_bytes));
+       fw_size = le32_to_cpu(pfp_hdr->header.ucode_size_bytes) / 4;
+       WREG32(CP_PFP_UCODE_ADDR, 0);
+       for (i = 0; i < fw_size; i++)
+               WREG32(CP_PFP_UCODE_DATA, le32_to_cpup(fw_data++));
+       WREG32(CP_PFP_UCODE_ADDR, 0);
+
+       /* CE */
+       fw_data = (const __le32 *)
+               (adev->gfx.ce_fw->data + le32_to_cpu(ce_hdr->header.ucode_array_offset_bytes));
+       fw_size = le32_to_cpu(ce_hdr->header.ucode_size_bytes) / 4;
+       WREG32(CP_CE_UCODE_ADDR, 0);
+       for (i = 0; i < fw_size; i++)
+               WREG32(CP_CE_UCODE_DATA, le32_to_cpup(fw_data++));
+       WREG32(CP_CE_UCODE_ADDR, 0);
+
+       /* ME */
+       fw_data = (const __be32 *)
+               (adev->gfx.me_fw->data + le32_to_cpu(me_hdr->header.ucode_array_offset_bytes));
+       fw_size = le32_to_cpu(me_hdr->header.ucode_size_bytes) / 4;
+       WREG32(CP_ME_RAM_WADDR, 0);
+       for (i = 0; i < fw_size; i++)
+               WREG32(CP_ME_RAM_DATA, le32_to_cpup(fw_data++));
+       WREG32(CP_ME_RAM_WADDR, 0);
+
+
+       WREG32(CP_PFP_UCODE_ADDR, 0);
+       WREG32(CP_CE_UCODE_ADDR, 0);
+       WREG32(CP_ME_RAM_WADDR, 0);
+       WREG32(CP_ME_RAM_RADDR, 0);
+       return 0;
+}
+
+static int gfx_v6_0_cp_gfx_start(struct amdgpu_device *adev)
+{
+       const struct cs_section_def *sect = NULL;
+       const struct cs_extent_def *ext = NULL;
+       struct amdgpu_ring *ring = &adev->gfx.gfx_ring[0];
+       int r, i;
+
+       r = amdgpu_ring_alloc(ring, 7 + 4);
+       if (r) {
+               DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r);
+               return r;
+       }
+       amdgpu_ring_write(ring, PACKET3(PACKET3_ME_INITIALIZE, 5));
+       amdgpu_ring_write(ring, 0x1);
+       amdgpu_ring_write(ring, 0x0);
+       amdgpu_ring_write(ring, adev->gfx.config.max_hw_contexts - 1);
+       amdgpu_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1));
+       amdgpu_ring_write(ring, 0);
+       amdgpu_ring_write(ring, 0);
+
+       amdgpu_ring_write(ring, PACKET3(PACKET3_SET_BASE, 2));
+       amdgpu_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE));
+       amdgpu_ring_write(ring, 0xc000);
+       amdgpu_ring_write(ring, 0xe000);
+       amdgpu_ring_commit(ring);
+
+       gfx_v6_0_cp_gfx_enable(adev, true);
+
+       r = amdgpu_ring_alloc(ring, gfx_v6_0_get_csb_size(adev) + 10);
+       if (r) {
+               DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r);
+               return r;
+       }
+
+       amdgpu_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+       amdgpu_ring_write(ring, PACKET3_PREAMBLE_BEGIN_CLEAR_STATE);
+
+       for (sect = adev->gfx.rlc.cs_data; sect->section != NULL; ++sect) {
+               for (ext = sect->section; ext->extent != NULL; ++ext) {
+                       if (sect->id == SECT_CONTEXT) {
+                               amdgpu_ring_write(ring,
+                                                 PACKET3(PACKET3_SET_CONTEXT_REG, ext->reg_count));
+                               amdgpu_ring_write(ring, ext->reg_index - PACKET3_SET_CONTEXT_REG_START);
+                               for (i = 0; i < ext->reg_count; i++)
+                                       amdgpu_ring_write(ring, ext->extent[i]);
+                       }
+               }
+       }
+
+       amdgpu_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+       amdgpu_ring_write(ring, PACKET3_PREAMBLE_END_CLEAR_STATE);
+
+       amdgpu_ring_write(ring, PACKET3(PACKET3_CLEAR_STATE, 0));
+       amdgpu_ring_write(ring, 0);
+
+       amdgpu_ring_write(ring, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+       amdgpu_ring_write(ring, 0x00000316);
+       amdgpu_ring_write(ring, 0x0000000e);
+       amdgpu_ring_write(ring, 0x00000010);
+
+       amdgpu_ring_commit(ring);
+
+       return 0;
+}
+
+static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
+{
+       struct amdgpu_ring *ring;
+       u32 tmp;
+       u32 rb_bufsz;
+       int r;
+       u64 rptr_addr;
+
+       WREG32(CP_SEM_WAIT_TIMER, 0x0);
+       WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0);
+
+       /* Set the write pointer delay */
+       WREG32(CP_RB_WPTR_DELAY, 0);
+
+       WREG32(CP_DEBUG, 0);
+       WREG32(SCRATCH_ADDR, 0);
+
+       /* ring 0 - compute and gfx */
+       /* Set ring buffer size */
+       ring = &adev->gfx.gfx_ring[0];
+       rb_bufsz = order_base_2(ring->ring_size / 8);
+       tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+
+#ifdef __BIG_ENDIAN
+       tmp |= BUF_SWAP_32BIT;
+#endif
+       WREG32(CP_RB0_CNTL, tmp);
+
+       /* Initialize the ring buffer's read and write pointers */
+       WREG32(CP_RB0_CNTL, tmp | RB_RPTR_WR_ENA);
+       ring->wptr = 0;
+       WREG32(CP_RB0_WPTR, ring->wptr);
+
+       /* set the wb address whether it's enabled or not */
+       rptr_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4);
+       WREG32(CP_RB0_RPTR_ADDR, lower_32_bits(rptr_addr));
+       WREG32(CP_RB0_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
+
+       WREG32(SCRATCH_UMSK, 0);
+
+       mdelay(1);
+       WREG32(CP_RB0_CNTL, tmp);
+
+       WREG32(CP_RB0_BASE, ring->gpu_addr >> 8);
+
+       /* start the rings */
+       gfx_v6_0_cp_gfx_start(adev);
+       ring->ready = true;
+       r = amdgpu_ring_test_ring(ring);
+       if (r) {
+               ring->ready = false;
+               return r;
+       }
+
+       return 0;
+}
+
+static u32 gfx_v6_0_ring_get_rptr(struct amdgpu_ring *ring)
+{
+       return ring->adev->wb.wb[ring->rptr_offs];
+}
+
+static u32 gfx_v6_0_ring_get_wptr(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+
+       if (ring == &adev->gfx.gfx_ring[0])
+               return RREG32(CP_RB0_WPTR);
+       else if (ring == &adev->gfx.compute_ring[0])
+               return RREG32(CP_RB1_WPTR);
+       else if (ring == &adev->gfx.compute_ring[1])
+               return RREG32(CP_RB2_WPTR);
+       else
+               BUG();
+}
+
+static void gfx_v6_0_ring_set_wptr_gfx(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+
+       WREG32(CP_RB0_WPTR, ring->wptr);
+       (void)RREG32(CP_RB0_WPTR);
+}
+
+static void gfx_v6_0_ring_set_wptr_compute(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+
+       if (ring == &adev->gfx.compute_ring[0]) {
+               WREG32(CP_RB1_WPTR, ring->wptr);
+               (void)RREG32(CP_RB1_WPTR);
+       } else if (ring == &adev->gfx.compute_ring[1]) {
+               WREG32(CP_RB2_WPTR, ring->wptr);
+               (void)RREG32(CP_RB2_WPTR);
+       } else {
+               BUG();
+       }
+
+}
+
+static int gfx_v6_0_cp_compute_resume(struct amdgpu_device *adev)
+{
+       struct amdgpu_ring *ring;
+       u32 tmp;
+       u32 rb_bufsz;
+       int r;
+       u64 rptr_addr;
+
+       /* ring1  - compute only */
+       /* Set ring buffer size */
+
+       ring = &adev->gfx.compute_ring[0];
+       rb_bufsz = order_base_2(ring->ring_size / 8);
+       tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+#ifdef __BIG_ENDIAN
+       tmp |= BUF_SWAP_32BIT;
+#endif
+       WREG32(CP_RB1_CNTL, tmp);
+
+       WREG32(CP_RB1_CNTL, tmp | RB_RPTR_WR_ENA);
+       ring->wptr = 0;
+       WREG32(CP_RB1_WPTR, ring->wptr);
+
+       rptr_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4);
+       WREG32(CP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
+       WREG32(CP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
+
+       mdelay(1);
+       WREG32(CP_RB1_CNTL, tmp);
+       WREG32(CP_RB1_BASE, ring->gpu_addr >> 8);
+
+       ring = &adev->gfx.compute_ring[1];
+       rb_bufsz = order_base_2(ring->ring_size / 8);
+       tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+#ifdef __BIG_ENDIAN
+       tmp |= BUF_SWAP_32BIT;
+#endif
+       WREG32(CP_RB2_CNTL, tmp);
+
+       WREG32(CP_RB2_CNTL, tmp | RB_RPTR_WR_ENA);
+       ring->wptr = 0;
+       WREG32(CP_RB2_WPTR, ring->wptr);
+       rptr_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4);
+       WREG32(CP_RB2_RPTR_ADDR, lower_32_bits(rptr_addr));
+       WREG32(CP_RB2_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
+
+       mdelay(1);
+       WREG32(CP_RB2_CNTL, tmp);
+       WREG32(CP_RB2_BASE, ring->gpu_addr >> 8);
+
+       adev->gfx.compute_ring[0].ready = true;
+       adev->gfx.compute_ring[1].ready = true;
+
+       r = amdgpu_ring_test_ring(&adev->gfx.compute_ring[0]);
+       if (r) {
+               adev->gfx.compute_ring[0].ready = false;
+               return r;
+       }
+
+       r = amdgpu_ring_test_ring(&adev->gfx.compute_ring[1]);
+       if (r) {
+               adev->gfx.compute_ring[1].ready = false;
+               return r;
+       }
+
+       return 0;
+}
+
+static void gfx_v6_0_cp_enable(struct amdgpu_device *adev, bool enable)
+{
+       gfx_v6_0_cp_gfx_enable(adev, enable);
+}
+
+static int gfx_v6_0_cp_load_microcode(struct amdgpu_device *adev)
+{
+       return gfx_v6_0_cp_gfx_load_microcode(adev);
+}
+
+static void gfx_v6_0_enable_gui_idle_interrupt(struct amdgpu_device *adev,
+                                              bool enable)
+{      
+       u32 tmp = RREG32(CP_INT_CNTL_RING0);
+       u32 mask;
+       int i;
+
+       if (enable)
+               tmp |= (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+       else
+               tmp &= ~(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+       WREG32(CP_INT_CNTL_RING0, tmp);
+
+       if (!enable) {
+               /* read a gfx register */
+               tmp = RREG32(DB_DEPTH_INFO);
+
+               mask = RLC_BUSY_STATUS | GFX_POWER_STATUS | GFX_CLOCK_STATUS | GFX_LS_STATUS;
+               for (i = 0; i < adev->usec_timeout; i++) {
+                       if ((RREG32(RLC_STAT) & mask) == (GFX_CLOCK_STATUS | GFX_POWER_STATUS))
+                               break;
+                       udelay(1);
+               }
+       }
+}
+
+static int gfx_v6_0_cp_resume(struct amdgpu_device *adev)
+{
+       int r;
+
+       gfx_v6_0_enable_gui_idle_interrupt(adev, false);
+
+       r = gfx_v6_0_cp_load_microcode(adev);
+       if (r)
+               return r;
+
+       r = gfx_v6_0_cp_gfx_resume(adev);
+       if (r)
+               return r;
+       r = gfx_v6_0_cp_compute_resume(adev);
+       if (r)
+               return r;
+
+       gfx_v6_0_enable_gui_idle_interrupt(adev, true);
+
+       return 0;
+}
+
+static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
+{
+       int usepfp = (ring->type == AMDGPU_RING_TYPE_GFX);
+       uint32_t seq = ring->fence_drv.sync_seq;
+       uint64_t addr = ring->fence_drv.gpu_addr;
+
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+       amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */
+                                WAIT_REG_MEM_FUNCTION(3) | /* equal */
+                                WAIT_REG_MEM_ENGINE(usepfp)));   /* pfp or me */
+       amdgpu_ring_write(ring, addr & 0xfffffffc);
+       amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+       amdgpu_ring_write(ring, seq);
+       amdgpu_ring_write(ring, 0xffffffff);
+       amdgpu_ring_write(ring, 4); /* poll interval */
+
+       if (usepfp) {
+               /* synce CE with ME to prevent CE fetch CEIB before context switch done */
+               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+               amdgpu_ring_write(ring, 0);
+               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+               amdgpu_ring_write(ring, 0);
+       }
+}
+
+static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
+                                       unsigned vm_id, uint64_t pd_addr)
+{
+       int usepfp = (ring->type == AMDGPU_RING_TYPE_GFX);
+
+       /* write new base address */
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) |
+                                WRITE_DATA_DST_SEL(0)));
+       if (vm_id < 8) {
+               amdgpu_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vm_id ));
+       } else {
+               amdgpu_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + (vm_id - 8)));
+       }
+       amdgpu_ring_write(ring, 0);
+       amdgpu_ring_write(ring, pd_addr >> 12);
+
+       /* bits 0-15 are the VM contexts0-15 */
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) |
+                                WRITE_DATA_DST_SEL(0)));
+       amdgpu_ring_write(ring, VM_INVALIDATE_REQUEST);
+       amdgpu_ring_write(ring, 0);
+       amdgpu_ring_write(ring, 1 << vm_id);
+
+       /* wait for the invalidate to complete */
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+       amdgpu_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) |  /* always */
+                                WAIT_REG_MEM_ENGINE(0))); /* me */
+       amdgpu_ring_write(ring, VM_INVALIDATE_REQUEST);
+       amdgpu_ring_write(ring, 0);
+       amdgpu_ring_write(ring, 0); /* ref */
+       amdgpu_ring_write(ring, 0); /* mask */
+       amdgpu_ring_write(ring, 0x20); /* poll interval */
+
+       if (usepfp) {
+               /* sync PFP to ME, otherwise we might get invalid PFP reads */
+               amdgpu_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
+               amdgpu_ring_write(ring, 0x0);
+
+               /* synce CE with ME to prevent CE fetch CEIB before context switch done */
+               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+               amdgpu_ring_write(ring, 0);
+               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+               amdgpu_ring_write(ring, 0);
+       }
+}
+
+
+static void gfx_v6_0_rlc_fini(struct amdgpu_device *adev)
+{
+       int r;
+
+       if (adev->gfx.rlc.save_restore_obj) {
+               r = amdgpu_bo_reserve(adev->gfx.rlc.save_restore_obj, false);
+               if (unlikely(r != 0))
+                       dev_warn(adev->dev, "(%d) reserve RLC sr bo failed\n", r);
+               amdgpu_bo_unpin(adev->gfx.rlc.save_restore_obj);
+               amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
+
+               amdgpu_bo_unref(&adev->gfx.rlc.save_restore_obj);
+               adev->gfx.rlc.save_restore_obj = NULL;
+       }
+
+       if (adev->gfx.rlc.clear_state_obj) {
+               r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false);
+               if (unlikely(r != 0))
+                       dev_warn(adev->dev, "(%d) reserve RLC c bo failed\n", r);
+               amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
+               amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
+
+               amdgpu_bo_unref(&adev->gfx.rlc.clear_state_obj);
+               adev->gfx.rlc.clear_state_obj = NULL;
+       }
+
+       if (adev->gfx.rlc.cp_table_obj) {
+               r = amdgpu_bo_reserve(adev->gfx.rlc.cp_table_obj, false);
+               if (unlikely(r != 0))
+                       dev_warn(adev->dev, "(%d) reserve RLC cp table bo failed\n", r);
+               amdgpu_bo_unpin(adev->gfx.rlc.cp_table_obj);
+               amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
+
+               amdgpu_bo_unref(&adev->gfx.rlc.cp_table_obj);
+               adev->gfx.rlc.cp_table_obj = NULL;
+       }
+}
+
+static int gfx_v6_0_rlc_init(struct amdgpu_device *adev)
+{
+       const u32 *src_ptr;
+       volatile u32 *dst_ptr;
+       u32 dws, i;
+       u64 reg_list_mc_addr;
+       const struct cs_section_def *cs_data;
+       int r;
+
+       adev->gfx.rlc.reg_list = verde_rlc_save_restore_register_list;
+       adev->gfx.rlc.reg_list_size =
+                       (u32)ARRAY_SIZE(verde_rlc_save_restore_register_list);
+
+       adev->gfx.rlc.cs_data = si_cs_data;
+       src_ptr = adev->gfx.rlc.reg_list;
+       dws = adev->gfx.rlc.reg_list_size;
+       cs_data = adev->gfx.rlc.cs_data;
+
+       if (src_ptr) {
+               /* save restore block */
+               if (adev->gfx.rlc.save_restore_obj == NULL) {
+
+                       r = amdgpu_bo_create(adev, dws * 4, PAGE_SIZE, true,
+                                            AMDGPU_GEM_DOMAIN_VRAM,
+                                            AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
+                                            NULL, NULL,
+                                            &adev->gfx.rlc.save_restore_obj);
+
+                       if (r) {
+                               dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r);
+                               return r;
+                       }
+               }
+
+               r = amdgpu_bo_reserve(adev->gfx.rlc.save_restore_obj, false);
+               if (unlikely(r != 0)) {
+                       gfx_v6_0_rlc_fini(adev);
+                       return r;
+               }
+               r = amdgpu_bo_pin(adev->gfx.rlc.save_restore_obj, AMDGPU_GEM_DOMAIN_VRAM,
+                                 &adev->gfx.rlc.save_restore_gpu_addr);
+               if (r) {
+                       amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
+                       dev_warn(adev->dev, "(%d) pin RLC sr bo failed\n", r);
+                       gfx_v6_0_rlc_fini(adev);
+                       return r;
+               }
+
+               r = amdgpu_bo_kmap(adev->gfx.rlc.save_restore_obj, (void **)&adev->gfx.rlc.sr_ptr);
+               if (r) {
+                       dev_warn(adev->dev, "(%d) map RLC sr bo failed\n", r);
+                       gfx_v6_0_rlc_fini(adev);
+                       return r;
+               }
+               /* write the sr buffer */
+               dst_ptr = adev->gfx.rlc.sr_ptr;
+               for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
+                       dst_ptr[i] = cpu_to_le32(src_ptr[i]);
+               amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
+               amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
+       }
+
+       if (cs_data) {
+               /* clear state block */
+               adev->gfx.rlc.clear_state_size = gfx_v6_0_get_csb_size(adev);
+               dws = adev->gfx.rlc.clear_state_size + (256 / 4);
+
+               if (adev->gfx.rlc.clear_state_obj == NULL) {
+                       r = amdgpu_bo_create(adev, dws * 4, PAGE_SIZE, true,
+                                            AMDGPU_GEM_DOMAIN_VRAM,
+                                            AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
+                                            NULL, NULL,
+                                            &adev->gfx.rlc.clear_state_obj);
+
+                       if (r) {
+                               dev_warn(adev->dev, "(%d) create RLC c bo failed\n", r);
+                               gfx_v6_0_rlc_fini(adev);
+                               return r;
+                       }
+               }
+               r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false);
+               if (unlikely(r != 0)) {
+                       gfx_v6_0_rlc_fini(adev);
+                       return r;
+               }
+               r = amdgpu_bo_pin(adev->gfx.rlc.clear_state_obj, AMDGPU_GEM_DOMAIN_VRAM,
+                                 &adev->gfx.rlc.clear_state_gpu_addr);
+               if (r) {
+                       amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
+                       dev_warn(adev->dev, "(%d) pin RLC c bo failed\n", r);
+                       gfx_v6_0_rlc_fini(adev);
+                       return r;
+               }
+
+               r = amdgpu_bo_kmap(adev->gfx.rlc.clear_state_obj, (void **)&adev->gfx.rlc.cs_ptr);
+               if (r) {
+                       dev_warn(adev->dev, "(%d) map RLC c bo failed\n", r);
+                       gfx_v6_0_rlc_fini(adev);
+                       return r;
+               }
+               /* set up the cs buffer */
+               dst_ptr = adev->gfx.rlc.cs_ptr;
+               reg_list_mc_addr = adev->gfx.rlc.clear_state_gpu_addr + 256;
+               dst_ptr[0] = cpu_to_le32(upper_32_bits(reg_list_mc_addr));
+               dst_ptr[1] = cpu_to_le32(lower_32_bits(reg_list_mc_addr));
+               dst_ptr[2] = cpu_to_le32(adev->gfx.rlc.clear_state_size);
+               gfx_v6_0_get_csb_buffer(adev, &dst_ptr[(256/4)]);
+               amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
+               amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
+       }
+
+       return 0;
+}
+
+static void gfx_v6_0_enable_lbpw(struct amdgpu_device *adev, bool enable)
+{
+       u32 tmp;
+
+       tmp = RREG32(RLC_LB_CNTL);
+       if (enable)
+               tmp |= LOAD_BALANCE_ENABLE;
+       else
+               tmp &= ~LOAD_BALANCE_ENABLE;
+       WREG32(RLC_LB_CNTL, tmp);
+
+       if (!enable) {
+               gfx_v6_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+               WREG32(SPI_LB_CU_MASK, 0x00ff);
+       }
+
+}
+
+static void gfx_v6_0_wait_for_rlc_serdes(struct amdgpu_device *adev)
+{
+       int i;
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (RREG32(RLC_SERDES_MASTER_BUSY_0) == 0)
+                       break;
+               udelay(1);
+       }
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (RREG32(RLC_SERDES_MASTER_BUSY_1) == 0)
+                       break;
+               udelay(1);
+       }
+}
+
+static void gfx_v6_0_update_rlc(struct amdgpu_device *adev, u32 rlc)
+{
+       u32 tmp;
+
+       tmp = RREG32(RLC_CNTL);
+       if (tmp != rlc)
+               WREG32(RLC_CNTL, rlc);
+}
+
+static u32 gfx_v6_0_halt_rlc(struct amdgpu_device *adev)
+{
+       u32 data, orig;
+
+       orig = data = RREG32(RLC_CNTL);
+
+       if (data & RLC_ENABLE) {
+               data &= ~RLC_ENABLE;
+               WREG32(RLC_CNTL, data);
+
+               gfx_v6_0_wait_for_rlc_serdes(adev);
+       }
+
+       return orig;
+}
+
+static void gfx_v6_0_rlc_stop(struct amdgpu_device *adev)
+{
+       WREG32(RLC_CNTL, 0);
+
+       gfx_v6_0_enable_gui_idle_interrupt(adev, false);
+       gfx_v6_0_wait_for_rlc_serdes(adev);
+}
+
+static void gfx_v6_0_rlc_start(struct amdgpu_device *adev)
+{
+       WREG32(RLC_CNTL, RLC_ENABLE);
+
+       gfx_v6_0_enable_gui_idle_interrupt(adev, true);
+
+       udelay(50);
+}
+
+static void gfx_v6_0_rlc_reset(struct amdgpu_device *adev)
+{
+       u32 tmp = RREG32(GRBM_SOFT_RESET);
+
+       tmp |= SOFT_RESET_RLC;
+       WREG32(GRBM_SOFT_RESET, tmp);
+       udelay(50);
+       tmp &= ~SOFT_RESET_RLC;
+       WREG32(GRBM_SOFT_RESET, tmp);
+       udelay(50);
+}
+
+static bool gfx_v6_0_lbpw_supported(struct amdgpu_device *adev)
+{
+       u32 tmp;
+
+       /* Enable LBPW only for DDR3 */
+       tmp = RREG32(MC_SEQ_MISC0);
+       if ((tmp & 0xF0000000) == 0xB0000000)
+               return true;
+       return false;
+}
+static void gfx_v6_0_init_cg(struct amdgpu_device *adev)
+{
+}
+
+static int gfx_v6_0_rlc_resume(struct amdgpu_device *adev)
+{
+       u32 i;
+       const struct rlc_firmware_header_v1_0 *hdr;
+       const __le32 *fw_data;
+       u32 fw_size;
+
+
+       if (!adev->gfx.rlc_fw)
+               return -EINVAL;
+
+       gfx_v6_0_rlc_stop(adev);
+       gfx_v6_0_rlc_reset(adev);
+       gfx_v6_0_init_pg(adev);
+       gfx_v6_0_init_cg(adev);
+
+       WREG32(RLC_RL_BASE, 0);
+       WREG32(RLC_RL_SIZE, 0);
+       WREG32(RLC_LB_CNTL, 0);
+       WREG32(RLC_LB_CNTR_MAX, 0xffffffff);
+       WREG32(RLC_LB_CNTR_INIT, 0);
+       WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff);
+
+       WREG32(RLC_MC_CNTL, 0);
+       WREG32(RLC_UCODE_CNTL, 0);
+
+       hdr = (const struct rlc_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
+       fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
+       fw_data = (const __le32 *)
+               (adev->gfx.rlc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+
+       amdgpu_ucode_print_rlc_hdr(&hdr->header);
+
+       for (i = 0; i < fw_size; i++) {
+               WREG32(RLC_UCODE_ADDR, i);
+               WREG32(RLC_UCODE_DATA, le32_to_cpup(fw_data++));
+       }
+       WREG32(RLC_UCODE_ADDR, 0);
+
+       gfx_v6_0_enable_lbpw(adev, gfx_v6_0_lbpw_supported(adev));
+       gfx_v6_0_rlc_start(adev);
+
+       return 0;
+}
+
+static void gfx_v6_0_enable_cgcg(struct amdgpu_device *adev, bool enable)
+{
+       u32 data, orig, tmp;
+
+       orig = data = RREG32(RLC_CGCG_CGLS_CTRL);
+
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
+               gfx_v6_0_enable_gui_idle_interrupt(adev, true);
+
+               WREG32(RLC_GCPM_GENERAL_3, 0x00000080);
+
+               tmp = gfx_v6_0_halt_rlc(adev);
+
+               WREG32(RLC_SERDES_WR_MASTER_MASK_0, 0xffffffff);
+               WREG32(RLC_SERDES_WR_MASTER_MASK_1, 0xffffffff);
+               WREG32(RLC_SERDES_WR_CTRL, 0x00b000ff);
+
+               gfx_v6_0_wait_for_rlc_serdes(adev);
+               gfx_v6_0_update_rlc(adev, tmp);
+
+               WREG32(RLC_SERDES_WR_CTRL, 0x007000ff);
+
+               data |= CGCG_EN | CGLS_EN;
+       } else {
+               gfx_v6_0_enable_gui_idle_interrupt(adev, false);
+
+               RREG32(CB_CGTT_SCLK_CTRL);
+               RREG32(CB_CGTT_SCLK_CTRL);
+               RREG32(CB_CGTT_SCLK_CTRL);
+               RREG32(CB_CGTT_SCLK_CTRL);
+
+               data &= ~(CGCG_EN | CGLS_EN);
+       }
+
+       if (orig != data)
+               WREG32(RLC_CGCG_CGLS_CTRL, data);
+
+}
+
+static void gfx_v6_0_enable_mgcg(struct amdgpu_device *adev, bool enable)
+{
+
+       u32 data, orig, tmp = 0;
+
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
+               orig = data = RREG32(CGTS_SM_CTRL_REG);
+               data = 0x96940200;
+               if (orig != data)
+                       WREG32(CGTS_SM_CTRL_REG, data);
+
+               if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CP_LS) {
+                       orig = data = RREG32(CP_MEM_SLP_CNTL);
+                       data |= CP_MEM_LS_EN;
+                       if (orig != data)
+                               WREG32(CP_MEM_SLP_CNTL, data);
+               }
+
+               orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE);
+               data &= 0xffffffc0;
+               if (orig != data)
+                       WREG32(RLC_CGTT_MGCG_OVERRIDE, data);
+
+               tmp = gfx_v6_0_halt_rlc(adev);
+
+               WREG32(RLC_SERDES_WR_MASTER_MASK_0, 0xffffffff);
+               WREG32(RLC_SERDES_WR_MASTER_MASK_1, 0xffffffff);
+               WREG32(RLC_SERDES_WR_CTRL, 0x00d000ff);
+
+               gfx_v6_0_update_rlc(adev, tmp);
+       } else {
+               orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE);
+               data |= 0x00000003;
+               if (orig != data)
+                       WREG32(RLC_CGTT_MGCG_OVERRIDE, data);
+
+               data = RREG32(CP_MEM_SLP_CNTL);
+               if (data & CP_MEM_LS_EN) {
+                       data &= ~CP_MEM_LS_EN;
+                       WREG32(CP_MEM_SLP_CNTL, data);
+               }
+               orig = data = RREG32(CGTS_SM_CTRL_REG);
+               data |= LS_OVERRIDE | OVERRIDE;
+               if (orig != data)
+                       WREG32(CGTS_SM_CTRL_REG, data);
+
+               tmp = gfx_v6_0_halt_rlc(adev);
+
+               WREG32(RLC_SERDES_WR_MASTER_MASK_0, 0xffffffff);
+               WREG32(RLC_SERDES_WR_MASTER_MASK_1, 0xffffffff);
+               WREG32(RLC_SERDES_WR_CTRL, 0x00e000ff);
+
+               gfx_v6_0_update_rlc(adev, tmp);
+       }
+}
+/*
+static void gfx_v6_0_update_cg(struct amdgpu_device *adev,
+                              bool enable)
+{
+       gfx_v6_0_enable_gui_idle_interrupt(adev, false);
+       if (enable) {
+               gfx_v6_0_enable_mgcg(adev, true);
+               gfx_v6_0_enable_cgcg(adev, true);
+       } else {
+               gfx_v6_0_enable_cgcg(adev, false);
+               gfx_v6_0_enable_mgcg(adev, false);
+       }
+       gfx_v6_0_enable_gui_idle_interrupt(adev, true);
+}
+*/
+static void gfx_v6_0_enable_sclk_slowdown_on_pu(struct amdgpu_device *adev,
+                                               bool enable)
+{
+}
+
+static void gfx_v6_0_enable_sclk_slowdown_on_pd(struct amdgpu_device *adev,
+                                               bool enable)
+{
+}
+
+static void gfx_v6_0_enable_cp_pg(struct amdgpu_device *adev, bool enable)
+{
+       u32 data, orig;
+
+       orig = data = RREG32(RLC_PG_CNTL);
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_CP))
+               data &= ~0x8000;
+       else
+               data |= 0x8000;
+       if (orig != data)
+               WREG32(RLC_PG_CNTL, data);
+}
+
+static void gfx_v6_0_enable_gds_pg(struct amdgpu_device *adev, bool enable)
+{
+}
+/*
+static void gfx_v6_0_init_cp_pg_table(struct amdgpu_device *adev)
+{
+       const __le32 *fw_data;
+       volatile u32 *dst_ptr;
+       int me, i, max_me = 4;
+       u32 bo_offset = 0;
+       u32 table_offset, table_size;
+
+       if (adev->asic_type == CHIP_KAVERI)
+               max_me = 5;
+
+       if (adev->gfx.rlc.cp_table_ptr == NULL)
+               return;
+
+       dst_ptr = adev->gfx.rlc.cp_table_ptr;
+       for (me = 0; me < max_me; me++) {
+               if (me == 0) {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.ce_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               } else if (me == 1) {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.pfp_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               } else if (me == 2) {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.me_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               } else if (me == 3) {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.mec_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               } else {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.mec2_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               }
+
+               for (i = 0; i < table_size; i ++) {
+                       dst_ptr[bo_offset + i] =
+                               cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
+               }
+
+               bo_offset += table_size;
+       }
+}
+*/
+static void gfx_v6_0_enable_gfx_cgpg(struct amdgpu_device *adev,
+                                    bool enable)
+{
+
+       u32 tmp;
+
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) {
+               tmp = RLC_PUD(0x10) | RLC_PDD(0x10) | RLC_TTPD(0x10) | RLC_MSD(0x10);
+               WREG32(RLC_TTOP_D, tmp);
+
+               tmp = RREG32(RLC_PG_CNTL);
+               tmp |= GFX_PG_ENABLE;
+               WREG32(RLC_PG_CNTL, tmp);
+
+               tmp = RREG32(RLC_AUTO_PG_CTRL);
+               tmp |= AUTO_PG_EN;
+               WREG32(RLC_AUTO_PG_CTRL, tmp);
+       } else {
+               tmp = RREG32(RLC_AUTO_PG_CTRL);
+               tmp &= ~AUTO_PG_EN;
+               WREG32(RLC_AUTO_PG_CTRL, tmp);
+
+               tmp = RREG32(DB_RENDER_CONTROL);
+       }
+}
+
+static u32 gfx_v6_0_get_cu_active_bitmap(struct amdgpu_device *adev,
+                                        u32 se, u32 sh)
+{
+
+       u32 mask = 0, tmp, tmp1;
+       int i;
+
+       mutex_lock(&adev->grbm_idx_mutex);
+       gfx_v6_0_select_se_sh(adev, se, sh, 0xffffffff);
+       tmp = RREG32(CC_GC_SHADER_ARRAY_CONFIG);
+       tmp1 = RREG32(GC_USER_SHADER_ARRAY_CONFIG);
+       gfx_v6_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+       mutex_unlock(&adev->grbm_idx_mutex);
+
+       tmp &= 0xffff0000;
+
+       tmp |= tmp1;
+       tmp >>= 16;
+
+       for (i = 0; i < adev->gfx.config.max_cu_per_sh; i ++) {
+               mask <<= 1;
+               mask |= 1;
+       }
+
+       return (~tmp) & mask;
+}
+
+static void gfx_v6_0_init_ao_cu_mask(struct amdgpu_device *adev)
+{
+       u32 i, j, k, active_cu_number = 0;
+
+       u32 mask, counter, cu_bitmap;
+       u32 tmp = 0;
+
+       for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
+               for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) {
+                       mask = 1;
+                       cu_bitmap = 0;
+                       counter  = 0;
+                       for (k = 0; k < adev->gfx.config.max_cu_per_sh; k++) {
+                               if (gfx_v6_0_get_cu_active_bitmap(adev, i, j) & mask) {
+                                       if (counter < 2)
+                                               cu_bitmap |= mask;
+                                       counter++;
+                               }
+                               mask <<= 1;
+                       }
+
+                       active_cu_number += counter;
+                       tmp |= (cu_bitmap << (i * 16 + j * 8));
+               }
+       }
+
+       WREG32(RLC_PG_AO_CU_MASK, tmp);
+
+       tmp = RREG32(RLC_MAX_PG_CU);
+       tmp &= ~MAX_PU_CU_MASK;
+       tmp |= MAX_PU_CU(active_cu_number);
+       WREG32(RLC_MAX_PG_CU, tmp);
+}
+
+static void gfx_v6_0_enable_gfx_static_mgpg(struct amdgpu_device *adev,
+                                           bool enable)
+{
+       u32 data, orig;
+
+       orig = data = RREG32(RLC_PG_CNTL);
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG))
+               data |= STATIC_PER_CU_PG_ENABLE;
+       else
+               data &= ~STATIC_PER_CU_PG_ENABLE;
+       if (orig != data)
+               WREG32(RLC_PG_CNTL, data);
+}
+
+static void gfx_v6_0_enable_gfx_dynamic_mgpg(struct amdgpu_device *adev,
+                                            bool enable)
+{
+       u32 data, orig;
+
+       orig = data = RREG32(RLC_PG_CNTL);
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_DMG))
+               data |= DYN_PER_CU_PG_ENABLE;
+       else
+               data &= ~DYN_PER_CU_PG_ENABLE;
+       if (orig != data)
+               WREG32(RLC_PG_CNTL, data);
+}
+
+static void gfx_v6_0_init_gfx_cgpg(struct amdgpu_device *adev)
+{
+       u32 tmp;
+
+       WREG32(RLC_SAVE_AND_RESTORE_BASE, adev->gfx.rlc.save_restore_gpu_addr >> 8);
+
+       tmp = RREG32(RLC_PG_CNTL);
+       tmp |= GFX_PG_SRC;
+       WREG32(RLC_PG_CNTL, tmp);
+
+       WREG32(RLC_CLEAR_STATE_RESTORE_BASE, adev->gfx.rlc.clear_state_gpu_addr >> 8);
+
+       tmp = RREG32(RLC_AUTO_PG_CTRL);
+
+       tmp &= ~GRBM_REG_SGIT_MASK;
+       tmp |= GRBM_REG_SGIT(0x700);
+       tmp &= ~PG_AFTER_GRBM_REG_ST_MASK;
+       WREG32(RLC_AUTO_PG_CTRL, tmp);
+}
+
+static void gfx_v6_0_update_gfx_pg(struct amdgpu_device *adev, bool enable)
+{
+       gfx_v6_0_enable_gfx_cgpg(adev, enable);
+       gfx_v6_0_enable_gfx_static_mgpg(adev, enable);
+       gfx_v6_0_enable_gfx_dynamic_mgpg(adev, enable);
+}
+
+static u32 gfx_v6_0_get_csb_size(struct amdgpu_device *adev)
+{
+       u32 count = 0;
+       const struct cs_section_def *sect = NULL;
+       const struct cs_extent_def *ext = NULL;
+
+       if (adev->gfx.rlc.cs_data == NULL)
+               return 0;
+
+       /* begin clear state */
+       count += 2;
+       /* context control state */
+       count += 3;
+
+       for (sect = adev->gfx.rlc.cs_data; sect->section != NULL; ++sect) {
+               for (ext = sect->section; ext->extent != NULL; ++ext) {
+                       if (sect->id == SECT_CONTEXT)
+                               count += 2 + ext->reg_count;
+                       else
+                               return 0;
+               }
+       }
+       /* pa_sc_raster_config */
+       count += 3;
+       /* end clear state */
+       count += 2;
+       /* clear state */
+       count += 2;
+
+       return count;
+}
+
+static void gfx_v6_0_get_csb_buffer(struct amdgpu_device *adev,
+                                   volatile u32 *buffer)
+{
+       u32 count = 0, i;
+       const struct cs_section_def *sect = NULL;
+       const struct cs_extent_def *ext = NULL;
+
+       if (adev->gfx.rlc.cs_data == NULL)
+               return;
+       if (buffer == NULL)
+               return;
+
+       buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+       buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_BEGIN_CLEAR_STATE);
+
+       buffer[count++] = cpu_to_le32(PACKET3(PACKET3_CONTEXT_CONTROL, 1));
+       buffer[count++] = cpu_to_le32(0x80000000);
+       buffer[count++] = cpu_to_le32(0x80000000);
+
+       for (sect = adev->gfx.rlc.cs_data; sect->section != NULL; ++sect) {
+               for (ext = sect->section; ext->extent != NULL; ++ext) {
+                       if (sect->id == SECT_CONTEXT) {
+                               buffer[count++] =
+                                       cpu_to_le32(PACKET3(PACKET3_SET_CONTEXT_REG, ext->reg_count));
+                               buffer[count++] = cpu_to_le32(ext->reg_index - 0xa000);
+                               for (i = 0; i < ext->reg_count; i++)
+                                       buffer[count++] = cpu_to_le32(ext->extent[i]);
+                       } else {
+                               return;
+                       }
+               }
+       }
+
+       buffer[count++] = cpu_to_le32(PACKET3(PACKET3_SET_CONTEXT_REG, 1));
+       buffer[count++] = cpu_to_le32(PA_SC_RASTER_CONFIG - PACKET3_SET_CONTEXT_REG_START);
+
+       switch (adev->asic_type) {
+       case CHIP_TAHITI:
+       case CHIP_PITCAIRN:
+               buffer[count++] = cpu_to_le32(0x2a00126a);
+               break;
+       case CHIP_VERDE:
+               buffer[count++] = cpu_to_le32(0x0000124a);
+               break;
+       case CHIP_OLAND:
+               buffer[count++] = cpu_to_le32(0x00000082);
+               break;
+       case CHIP_HAINAN:
+               buffer[count++] = cpu_to_le32(0x00000000);
+               break;
+       default:
+               buffer[count++] = cpu_to_le32(0x00000000);
+               break;
+       }
+
+       buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+       buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_END_CLEAR_STATE);
+
+       buffer[count++] = cpu_to_le32(PACKET3(PACKET3_CLEAR_STATE, 0));
+       buffer[count++] = cpu_to_le32(0);
+}
+
+static void gfx_v6_0_init_pg(struct amdgpu_device *adev)
+{
+       if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
+                             AMD_PG_SUPPORT_GFX_SMG |
+                             AMD_PG_SUPPORT_GFX_DMG |
+                             AMD_PG_SUPPORT_CP |
+                             AMD_PG_SUPPORT_GDS |
+                             AMD_PG_SUPPORT_RLC_SMU_HS)) {
+               gfx_v6_0_enable_sclk_slowdown_on_pu(adev, true);
+               gfx_v6_0_enable_sclk_slowdown_on_pd(adev, true);
+               if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) {
+                       gfx_v6_0_init_gfx_cgpg(adev);
+                       gfx_v6_0_enable_cp_pg(adev, true);
+                       gfx_v6_0_enable_gds_pg(adev, true);
+               } else {
+                       WREG32(RLC_SAVE_AND_RESTORE_BASE, adev->gfx.rlc.save_restore_gpu_addr >> 8);
+                       WREG32(RLC_CLEAR_STATE_RESTORE_BASE, adev->gfx.rlc.clear_state_gpu_addr >> 8);
+
+               }
+               gfx_v6_0_init_ao_cu_mask(adev);
+               gfx_v6_0_update_gfx_pg(adev, true);
+       } else {
+
+               WREG32(RLC_SAVE_AND_RESTORE_BASE, adev->gfx.rlc.save_restore_gpu_addr >> 8);
+               WREG32(RLC_CLEAR_STATE_RESTORE_BASE, adev->gfx.rlc.clear_state_gpu_addr >> 8);
+       }
+}
+
+static void gfx_v6_0_fini_pg(struct amdgpu_device *adev)
+{
+       if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
+                             AMD_PG_SUPPORT_GFX_SMG |
+                             AMD_PG_SUPPORT_GFX_DMG |
+                             AMD_PG_SUPPORT_CP |
+                             AMD_PG_SUPPORT_GDS |
+                             AMD_PG_SUPPORT_RLC_SMU_HS)) {
+               gfx_v6_0_update_gfx_pg(adev, false);
+               if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) {
+                       gfx_v6_0_enable_cp_pg(adev, false);
+                       gfx_v6_0_enable_gds_pg(adev, false);
+               }
+       }
+}
+
+static uint64_t gfx_v6_0_get_gpu_clock_counter(struct amdgpu_device *adev)
+{
+       uint64_t clock;
+
+       mutex_lock(&adev->gfx.gpu_clock_mutex);
+       WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+       clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+               ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+       mutex_unlock(&adev->gfx.gpu_clock_mutex);
+       return clock;
+}
+
+static void gfx_v6_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
+{
+       amdgpu_ring_write(ring, PACKET3(PACKET3_CONTEXT_CONTROL, 1));
+       amdgpu_ring_write(ring, 0x80000000);
+       amdgpu_ring_write(ring, 0);
+}
+
+static unsigned gfx_v6_0_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               6; /* gfx_v6_0_ring_emit_ib */
+}
+
+static unsigned gfx_v6_0_ring_get_dma_frame_size_gfx(struct amdgpu_ring *ring)
+{
+       return
+               5 + /* gfx_v6_0_ring_emit_hdp_flush */
+               5 + /* gfx_v6_0_ring_emit_hdp_invalidate */
+               14 + 14 + 14 + /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */
+               7 + 4 + /* gfx_v6_0_ring_emit_pipeline_sync */
+               17 + 6 + /* gfx_v6_0_ring_emit_vm_flush */
+               3; /* gfx_v6_ring_emit_cntxcntl */
+}
+
+static unsigned gfx_v6_0_ring_get_dma_frame_size_compute(struct amdgpu_ring *ring)
+{
+       return
+               5 + /* gfx_v6_0_ring_emit_hdp_flush */
+               5 + /* gfx_v6_0_ring_emit_hdp_invalidate */
+               7 + /* gfx_v6_0_ring_emit_pipeline_sync */
+               17 + /* gfx_v6_0_ring_emit_vm_flush */
+               14 + 14 + 14; /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */
+}
+
+static const struct amdgpu_gfx_funcs gfx_v6_0_gfx_funcs = {
+       .get_gpu_clock_counter = &gfx_v6_0_get_gpu_clock_counter,
+       .select_se_sh = &gfx_v6_0_select_se_sh,
+};
+
+static int gfx_v6_0_early_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       adev->gfx.num_gfx_rings = GFX6_NUM_GFX_RINGS;
+       adev->gfx.num_compute_rings = GFX6_NUM_COMPUTE_RINGS;
+       adev->gfx.funcs = &gfx_v6_0_gfx_funcs;
+       gfx_v6_0_set_ring_funcs(adev);
+       gfx_v6_0_set_irq_funcs(adev);
+
+       return 0;
+}
+
+static int gfx_v6_0_sw_init(void *handle)
+{
+       struct amdgpu_ring *ring;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       int i, r;
+
+       r = amdgpu_irq_add_id(adev, 181, &adev->gfx.eop_irq);
+       if (r)
+               return r;
+
+       r = amdgpu_irq_add_id(adev, 184, &adev->gfx.priv_reg_irq);
+       if (r)
+               return r;
+
+       r = amdgpu_irq_add_id(adev, 185, &adev->gfx.priv_inst_irq);
+       if (r)
+               return r;
+
+       gfx_v6_0_scratch_init(adev);
+
+       r = gfx_v6_0_init_microcode(adev);
+       if (r) {
+               DRM_ERROR("Failed to load gfx firmware!\n");
+               return r;
+       }
+
+       r = gfx_v6_0_rlc_init(adev);
+       if (r) {
+               DRM_ERROR("Failed to init rlc BOs!\n");
+               return r;
+       }
+
+       for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
+               ring = &adev->gfx.gfx_ring[i];
+               ring->ring_obj = NULL;
+               sprintf(ring->name, "gfx");
+               r = amdgpu_ring_init(adev, ring, 1024,
+                                    0x80000000, 0xf,
+                                    &adev->gfx.eop_irq, AMDGPU_CP_IRQ_GFX_EOP,
+                                    AMDGPU_RING_TYPE_GFX);
+               if (r)
+                       return r;
+       }
+
+       for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+               unsigned irq_type;
+
+               if ((i >= 32) || (i >= AMDGPU_MAX_COMPUTE_RINGS)) {
+                       DRM_ERROR("Too many (%d) compute rings!\n", i);
+                       break;
+               }
+               ring = &adev->gfx.compute_ring[i];
+               ring->ring_obj = NULL;
+               ring->use_doorbell = false;
+               ring->doorbell_index = 0;
+               ring->me = 1;
+               ring->pipe = i;
+               ring->queue = i;
+               sprintf(ring->name, "comp %d.%d.%d", ring->me, ring->pipe, ring->queue);
+               irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP + ring->pipe;
+               r = amdgpu_ring_init(adev, ring, 1024,
+                                    0x80000000, 0xf,
+                                    &adev->gfx.eop_irq, irq_type,
+                                    AMDGPU_RING_TYPE_COMPUTE);
+               if (r)
+                       return r;
+       }
+
+       return r;
+}
+
+static int gfx_v6_0_sw_fini(void *handle)
+{
+       int i;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       amdgpu_bo_unref(&adev->gds.oa_gfx_bo);
+       amdgpu_bo_unref(&adev->gds.gws_gfx_bo);
+       amdgpu_bo_unref(&adev->gds.gds_gfx_bo);
+
+       for (i = 0; i < adev->gfx.num_gfx_rings; i++)
+               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_v6_0_rlc_fini(adev);
+
+       return 0;
+}
+
+static int gfx_v6_0_hw_init(void *handle)
+{
+       int r;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       gfx_v6_0_gpu_init(adev);
+
+       r = gfx_v6_0_rlc_resume(adev);
+       if (r)
+               return r;
+
+       r = gfx_v6_0_cp_resume(adev);
+       if (r)
+               return r;
+
+       adev->gfx.ce_ram_size = 0x8000;
+
+       return r;
+}
+
+static int gfx_v6_0_hw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       gfx_v6_0_cp_enable(adev, false);
+       gfx_v6_0_rlc_stop(adev);
+       gfx_v6_0_fini_pg(adev);
+
+       return 0;
+}
+
+static int gfx_v6_0_suspend(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return gfx_v6_0_hw_fini(adev);
+}
+
+static int gfx_v6_0_resume(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return gfx_v6_0_hw_init(adev);
+}
+
+static bool gfx_v6_0_is_idle(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (RREG32(GRBM_STATUS) & GRBM_STATUS__GUI_ACTIVE_MASK)
+               return false;
+       else
+               return true;
+}
+
+static int gfx_v6_0_wait_for_idle(void *handle)
+{
+       unsigned i;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (gfx_v6_0_is_idle(handle))
+                       return 0;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+}
+
+static int gfx_v6_0_soft_reset(void *handle)
+{
+       return 0;
+}
+
+static void gfx_v6_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
+                                                enum amdgpu_interrupt_state state)
+{
+       u32 cp_int_cntl;
+
+       switch (state) {
+       case AMDGPU_IRQ_STATE_DISABLE:
+               cp_int_cntl = RREG32(CP_INT_CNTL_RING0);
+               cp_int_cntl &= ~CP_INT_CNTL_RING__TIME_STAMP_INT_ENABLE_MASK;
+               WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+               break;
+       case AMDGPU_IRQ_STATE_ENABLE:
+               cp_int_cntl = RREG32(CP_INT_CNTL_RING0);
+               cp_int_cntl |= CP_INT_CNTL_RING__TIME_STAMP_INT_ENABLE_MASK;
+               WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+               break;
+       default:
+               break;
+       }
+}
+
+static void gfx_v6_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev,
+                                                    int ring,
+                                                    enum amdgpu_interrupt_state state)
+{
+       u32 cp_int_cntl;
+       switch (state){
+       case AMDGPU_IRQ_STATE_DISABLE:
+               if (ring == 0) {
+                       cp_int_cntl = RREG32(CP_INT_CNTL_RING1);
+                       cp_int_cntl &= ~CP_INT_CNTL_RING__TIME_STAMP_INT_ENABLE_MASK;
+                       WREG32(CP_INT_CNTL_RING1, cp_int_cntl);
+                       break;
+               } else {
+                       cp_int_cntl = RREG32(CP_INT_CNTL_RING2);
+                       cp_int_cntl &= ~CP_INT_CNTL_RING__TIME_STAMP_INT_ENABLE_MASK;
+                       WREG32(CP_INT_CNTL_RING2, cp_int_cntl);
+                       break;
+
+               }
+       case AMDGPU_IRQ_STATE_ENABLE:
+               if (ring == 0) {
+                       cp_int_cntl = RREG32(CP_INT_CNTL_RING1);
+                       cp_int_cntl |= CP_INT_CNTL_RING__TIME_STAMP_INT_ENABLE_MASK;
+                       WREG32(CP_INT_CNTL_RING1, cp_int_cntl);
+                       break;
+               } else {
+                       cp_int_cntl = RREG32(CP_INT_CNTL_RING2);
+                       cp_int_cntl |= CP_INT_CNTL_RING__TIME_STAMP_INT_ENABLE_MASK;
+                       WREG32(CP_INT_CNTL_RING2, cp_int_cntl);
+                       break;
+
+               }
+
+       default:
+               BUG();
+               break;
+
+       }
+}
+
+static int gfx_v6_0_set_priv_reg_fault_state(struct amdgpu_device *adev,
+                                            struct amdgpu_irq_src *src,
+                                            unsigned type,
+                                            enum amdgpu_interrupt_state state)
+{
+       u32 cp_int_cntl;
+
+       switch (state) {
+       case AMDGPU_IRQ_STATE_DISABLE:
+               cp_int_cntl = RREG32(CP_INT_CNTL_RING0);
+               cp_int_cntl &= ~CP_INT_CNTL_RING0__PRIV_REG_INT_ENABLE_MASK;
+               WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+               break;
+       case AMDGPU_IRQ_STATE_ENABLE:
+               cp_int_cntl = RREG32(CP_INT_CNTL_RING0);
+               cp_int_cntl |= CP_INT_CNTL_RING0__PRIV_REG_INT_ENABLE_MASK;
+               WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int gfx_v6_0_set_priv_inst_fault_state(struct amdgpu_device *adev,
+                                             struct amdgpu_irq_src *src,
+                                             unsigned type,
+                                             enum amdgpu_interrupt_state state)
+{
+       u32 cp_int_cntl;
+
+       switch (state) {
+       case AMDGPU_IRQ_STATE_DISABLE:
+               cp_int_cntl = RREG32(CP_INT_CNTL_RING0);
+               cp_int_cntl &= ~CP_INT_CNTL_RING0__PRIV_INSTR_INT_ENABLE_MASK;
+               WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+               break;
+       case AMDGPU_IRQ_STATE_ENABLE:
+               cp_int_cntl = RREG32(CP_INT_CNTL_RING0);
+               cp_int_cntl |= CP_INT_CNTL_RING0__PRIV_INSTR_INT_ENABLE_MASK;
+               WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int gfx_v6_0_set_eop_interrupt_state(struct amdgpu_device *adev,
+                                           struct amdgpu_irq_src *src,
+                                           unsigned type,
+                                           enum amdgpu_interrupt_state state)
+{
+       switch (type) {
+       case AMDGPU_CP_IRQ_GFX_EOP:
+               gfx_v6_0_set_gfx_eop_interrupt_state(adev, state);
+               break;
+       case AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP:
+               gfx_v6_0_set_compute_eop_interrupt_state(adev, 0, state);
+               break;
+       case AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE1_EOP:
+               gfx_v6_0_set_compute_eop_interrupt_state(adev, 1, state);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int gfx_v6_0_eop_irq(struct amdgpu_device *adev,
+                           struct amdgpu_irq_src *source,
+                           struct amdgpu_iv_entry *entry)
+{
+       switch (entry->ring_id) {
+       case 0:
+               amdgpu_fence_process(&adev->gfx.gfx_ring[0]);
+               break;
+       case 1:
+       case 2:
+               amdgpu_fence_process(&adev->gfx.compute_ring[entry->ring_id -1]);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int gfx_v6_0_priv_reg_irq(struct amdgpu_device *adev,
+                                struct amdgpu_irq_src *source,
+                                struct amdgpu_iv_entry *entry)
+{
+       DRM_ERROR("Illegal register access in command stream\n");
+       schedule_work(&adev->reset_work);
+       return 0;
+}
+
+static int gfx_v6_0_priv_inst_irq(struct amdgpu_device *adev,
+                                 struct amdgpu_irq_src *source,
+                                 struct amdgpu_iv_entry *entry)
+{
+       DRM_ERROR("Illegal instruction in command stream\n");
+       schedule_work(&adev->reset_work);
+       return 0;
+}
+
+static int gfx_v6_0_set_clockgating_state(void *handle,
+                                         enum amd_clockgating_state state)
+{
+       bool gate = false;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (state == AMD_CG_STATE_GATE)
+               gate = true;
+
+       gfx_v6_0_enable_gui_idle_interrupt(adev, false);
+       if (gate) {
+               gfx_v6_0_enable_mgcg(adev, true);
+               gfx_v6_0_enable_cgcg(adev, true);
+       } else {
+               gfx_v6_0_enable_cgcg(adev, false);
+               gfx_v6_0_enable_mgcg(adev, false);
+       }
+       gfx_v6_0_enable_gui_idle_interrupt(adev, true);
+
+       return 0;
+}
+
+static int gfx_v6_0_set_powergating_state(void *handle,
+                                         enum amd_powergating_state state)
+{
+       bool gate = false;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (state == AMD_PG_STATE_GATE)
+               gate = true;
+
+       if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
+                             AMD_PG_SUPPORT_GFX_SMG |
+                             AMD_PG_SUPPORT_GFX_DMG |
+                             AMD_PG_SUPPORT_CP |
+                             AMD_PG_SUPPORT_GDS |
+                             AMD_PG_SUPPORT_RLC_SMU_HS)) {
+               gfx_v6_0_update_gfx_pg(adev, gate);
+               if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) {
+                       gfx_v6_0_enable_cp_pg(adev, gate);
+                       gfx_v6_0_enable_gds_pg(adev, gate);
+               }
+       }
+
+       return 0;
+}
+
+const struct amd_ip_funcs gfx_v6_0_ip_funcs = {
+       .name = "gfx_v6_0",
+       .early_init = gfx_v6_0_early_init,
+       .late_init = NULL,
+       .sw_init = gfx_v6_0_sw_init,
+       .sw_fini = gfx_v6_0_sw_fini,
+       .hw_init = gfx_v6_0_hw_init,
+       .hw_fini = gfx_v6_0_hw_fini,
+       .suspend = gfx_v6_0_suspend,
+       .resume = gfx_v6_0_resume,
+       .is_idle = gfx_v6_0_is_idle,
+       .wait_for_idle = gfx_v6_0_wait_for_idle,
+       .soft_reset = gfx_v6_0_soft_reset,
+       .set_clockgating_state = gfx_v6_0_set_clockgating_state,
+       .set_powergating_state = gfx_v6_0_set_powergating_state,
+};
+
+static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {
+       .get_rptr = gfx_v6_0_ring_get_rptr,
+       .get_wptr = gfx_v6_0_ring_get_wptr,
+       .set_wptr = gfx_v6_0_ring_set_wptr_gfx,
+       .parse_cs = NULL,
+       .emit_ib = gfx_v6_0_ring_emit_ib,
+       .emit_fence = gfx_v6_0_ring_emit_fence,
+       .emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
+       .emit_vm_flush = gfx_v6_0_ring_emit_vm_flush,
+       .emit_hdp_flush = gfx_v6_0_ring_emit_hdp_flush,
+       .emit_hdp_invalidate = gfx_v6_0_ring_emit_hdp_invalidate,
+       .test_ring = gfx_v6_0_ring_test_ring,
+       .test_ib = gfx_v6_0_ring_test_ib,
+       .insert_nop = amdgpu_ring_insert_nop,
+       .emit_cntxcntl = gfx_v6_ring_emit_cntxcntl,
+       .get_emit_ib_size = gfx_v6_0_ring_get_emit_ib_size,
+       .get_dma_frame_size = gfx_v6_0_ring_get_dma_frame_size_gfx,
+};
+
+static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {
+       .get_rptr = gfx_v6_0_ring_get_rptr,
+       .get_wptr = gfx_v6_0_ring_get_wptr,
+       .set_wptr = gfx_v6_0_ring_set_wptr_compute,
+       .parse_cs = NULL,
+       .emit_ib = gfx_v6_0_ring_emit_ib,
+       .emit_fence = gfx_v6_0_ring_emit_fence,
+       .emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
+       .emit_vm_flush = gfx_v6_0_ring_emit_vm_flush,
+       .emit_hdp_flush = gfx_v6_0_ring_emit_hdp_flush,
+       .emit_hdp_invalidate = gfx_v6_0_ring_emit_hdp_invalidate,
+       .test_ring = gfx_v6_0_ring_test_ring,
+       .test_ib = gfx_v6_0_ring_test_ib,
+       .insert_nop = amdgpu_ring_insert_nop,
+       .get_emit_ib_size = gfx_v6_0_ring_get_emit_ib_size,
+       .get_dma_frame_size = gfx_v6_0_ring_get_dma_frame_size_compute,
+};
+
+static void gfx_v6_0_set_ring_funcs(struct amdgpu_device *adev)
+{
+       int i;
+
+       for (i = 0; i < adev->gfx.num_gfx_rings; i++)
+               adev->gfx.gfx_ring[i].funcs = &gfx_v6_0_ring_funcs_gfx;
+       for (i = 0; i < adev->gfx.num_compute_rings; i++)
+               adev->gfx.compute_ring[i].funcs = &gfx_v6_0_ring_funcs_compute;
+}
+
+static const struct amdgpu_irq_src_funcs gfx_v6_0_eop_irq_funcs = {
+       .set = gfx_v6_0_set_eop_interrupt_state,
+       .process = gfx_v6_0_eop_irq,
+};
+
+static const struct amdgpu_irq_src_funcs gfx_v6_0_priv_reg_irq_funcs = {
+       .set = gfx_v6_0_set_priv_reg_fault_state,
+       .process = gfx_v6_0_priv_reg_irq,
+};
+
+static const struct amdgpu_irq_src_funcs gfx_v6_0_priv_inst_irq_funcs = {
+       .set = gfx_v6_0_set_priv_inst_fault_state,
+       .process = gfx_v6_0_priv_inst_irq,
+};
+
+static void gfx_v6_0_set_irq_funcs(struct amdgpu_device *adev)
+{
+       adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST;
+       adev->gfx.eop_irq.funcs = &gfx_v6_0_eop_irq_funcs;
+
+       adev->gfx.priv_reg_irq.num_types = 1;
+       adev->gfx.priv_reg_irq.funcs = &gfx_v6_0_priv_reg_irq_funcs;
+
+       adev->gfx.priv_inst_irq.num_types = 1;
+       adev->gfx.priv_inst_irq.funcs = &gfx_v6_0_priv_inst_irq_funcs;
+}
+
+static void gfx_v6_0_get_cu_info(struct amdgpu_device *adev)
+{
+       int i, j, k, counter, active_cu_number = 0;
+       u32 mask, bitmap, ao_bitmap, ao_cu_mask = 0;
+       struct amdgpu_cu_info *cu_info = &adev->gfx.cu_info;
+
+       memset(cu_info, 0, sizeof(*cu_info));
+
+       for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
+               for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) {
+                       mask = 1;
+                       ao_bitmap = 0;
+                       counter = 0;
+                       bitmap = gfx_v6_0_get_cu_active_bitmap(adev, i, j);
+                       cu_info->bitmap[i][j] = bitmap;
+
+                       for (k = 0; k < adev->gfx.config.max_cu_per_sh; k ++) {
+                               if (bitmap & mask) {
+                                       if (counter < 2)
+                                               ao_bitmap |= mask;
+                                       counter ++;
+                               }
+                               mask <<= 1;
+                       }
+                       active_cu_number += counter;
+                       ao_cu_mask |= (ao_bitmap << (i * 16 + j * 8));
+               }
+       }
+
+       cu_info->number = active_cu_number;
+       cu_info->ao_cu_mask = ao_cu_mask;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.h b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.h
new file mode 100644 (file)
index 0000000..b9657e7
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 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 __GFX_V6_0_H__
+#define __GFX_V6_0_H__
+
+extern const struct amd_ip_funcs gfx_v6_0_ip_funcs;
+
+#endif
index 425413f..71116da 100644 (file)
@@ -1645,6 +1645,147 @@ static u32 gfx_v7_0_get_rb_active_bitmap(struct amdgpu_device *adev)
        return (~data) & mask;
 }
 
+static void
+gfx_v7_0_raster_config(struct amdgpu_device *adev, u32 *rconf, u32 *rconf1)
+{
+       switch (adev->asic_type) {
+       case CHIP_BONAIRE:
+               *rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) |
+                         SE_XSEL(1) | SE_YSEL(1);
+               *rconf1 |= 0x0;
+               break;
+       case CHIP_HAWAII:
+               *rconf |= RB_MAP_PKR0(2) | RB_MAP_PKR1(2) |
+                         RB_XSEL2(1) | PKR_MAP(2) | PKR_XSEL(1) |
+                         PKR_YSEL(1) | SE_MAP(2) | SE_XSEL(2) |
+                         SE_YSEL(3);
+               *rconf1 |= SE_PAIR_MAP(2) | SE_PAIR_XSEL(3) |
+                          SE_PAIR_YSEL(2);
+               break;
+       case CHIP_KAVERI:
+               *rconf |= RB_MAP_PKR0(2);
+               *rconf1 |= 0x0;
+               break;
+       case CHIP_KABINI:
+       case CHIP_MULLINS:
+               *rconf |= 0x0;
+               *rconf1 |= 0x0;
+               break;
+       default:
+               DRM_ERROR("unknown asic: 0x%x\n", adev->asic_type);
+               break;
+       }
+}
+
+static void
+gfx_v7_0_write_harvested_raster_configs(struct amdgpu_device *adev,
+                                       u32 raster_config, u32 raster_config_1,
+                                       unsigned rb_mask, unsigned num_rb)
+{
+       unsigned sh_per_se = max_t(unsigned, adev->gfx.config.max_sh_per_se, 1);
+       unsigned num_se = max_t(unsigned, adev->gfx.config.max_shader_engines, 1);
+       unsigned rb_per_pkr = min_t(unsigned, num_rb / num_se / sh_per_se, 2);
+       unsigned rb_per_se = num_rb / num_se;
+       unsigned se_mask[4];
+       unsigned se;
+
+       se_mask[0] = ((1 << rb_per_se) - 1) & rb_mask;
+       se_mask[1] = (se_mask[0] << rb_per_se) & rb_mask;
+       se_mask[2] = (se_mask[1] << rb_per_se) & rb_mask;
+       se_mask[3] = (se_mask[2] << rb_per_se) & rb_mask;
+
+       WARN_ON(!(num_se == 1 || num_se == 2 || num_se == 4));
+       WARN_ON(!(sh_per_se == 1 || sh_per_se == 2));
+       WARN_ON(!(rb_per_pkr == 1 || rb_per_pkr == 2));
+
+       if ((num_se > 2) && ((!se_mask[0] && !se_mask[1]) ||
+                            (!se_mask[2] && !se_mask[3]))) {
+               raster_config_1 &= ~SE_PAIR_MAP_MASK;
+
+               if (!se_mask[0] && !se_mask[1]) {
+                       raster_config_1 |=
+                               SE_PAIR_MAP(RASTER_CONFIG_SE_PAIR_MAP_3);
+               } else {
+                       raster_config_1 |=
+                               SE_PAIR_MAP(RASTER_CONFIG_SE_PAIR_MAP_0);
+               }
+       }
+
+       for (se = 0; se < num_se; se++) {
+               unsigned raster_config_se = raster_config;
+               unsigned pkr0_mask = ((1 << rb_per_pkr) - 1) << (se * rb_per_se);
+               unsigned pkr1_mask = pkr0_mask << rb_per_pkr;
+               int idx = (se / 2) * 2;
+
+               if ((num_se > 1) && (!se_mask[idx] || !se_mask[idx + 1])) {
+                       raster_config_se &= ~SE_MAP_MASK;
+
+                       if (!se_mask[idx]) {
+                               raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_3);
+                       } else {
+                               raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_0);
+                       }
+               }
+
+               pkr0_mask &= rb_mask;
+               pkr1_mask &= rb_mask;
+               if (rb_per_se > 2 && (!pkr0_mask || !pkr1_mask)) {
+                       raster_config_se &= ~PKR_MAP_MASK;
+
+                       if (!pkr0_mask) {
+                               raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_3);
+                       } else {
+                               raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_0);
+                       }
+               }
+
+               if (rb_per_se >= 2) {
+                       unsigned rb0_mask = 1 << (se * rb_per_se);
+                       unsigned rb1_mask = rb0_mask << 1;
+
+                       rb0_mask &= rb_mask;
+                       rb1_mask &= rb_mask;
+                       if (!rb0_mask || !rb1_mask) {
+                               raster_config_se &= ~RB_MAP_PKR0_MASK;
+
+                               if (!rb0_mask) {
+                                       raster_config_se |=
+                                               RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_3);
+                               } else {
+                                       raster_config_se |=
+                                               RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_0);
+                               }
+                       }
+
+                       if (rb_per_se > 2) {
+                               rb0_mask = 1 << (se * rb_per_se + rb_per_pkr);
+                               rb1_mask = rb0_mask << 1;
+                               rb0_mask &= rb_mask;
+                               rb1_mask &= rb_mask;
+                               if (!rb0_mask || !rb1_mask) {
+                                       raster_config_se &= ~RB_MAP_PKR1_MASK;
+
+                                       if (!rb0_mask) {
+                                               raster_config_se |=
+                                                       RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_3);
+                                       } else {
+                                               raster_config_se |=
+                                                       RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_0);
+                                       }
+                               }
+                       }
+               }
+
+               /* GRBM_GFX_INDEX has a different offset on CI+ */
+               gfx_v7_0_select_se_sh(adev, se, 0xffffffff, 0xffffffff);
+               WREG32(mmPA_SC_RASTER_CONFIG, raster_config_se);
+               WREG32(mmPA_SC_RASTER_CONFIG_1, raster_config_1);
+       }
+
+       /* GRBM_GFX_INDEX has a different offset on CI+ */
+       gfx_v7_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+}
+
 /**
  * gfx_v7_0_setup_rb - setup the RBs on the asic
  *
@@ -1658,9 +1799,11 @@ static void gfx_v7_0_setup_rb(struct amdgpu_device *adev)
 {
        int i, j;
        u32 data;
+       u32 raster_config = 0, raster_config_1 = 0;
        u32 active_rbs = 0;
        u32 rb_bitmap_width_per_sh = adev->gfx.config.max_backends_per_se /
                                        adev->gfx.config.max_sh_per_se;
+       unsigned num_rb_pipes;
 
        mutex_lock(&adev->grbm_idx_mutex);
        for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
@@ -1672,10 +1815,25 @@ static void gfx_v7_0_setup_rb(struct amdgpu_device *adev)
                }
        }
        gfx_v7_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
-       mutex_unlock(&adev->grbm_idx_mutex);
 
        adev->gfx.config.backend_enable_mask = active_rbs;
        adev->gfx.config.num_rbs = hweight32(active_rbs);
+
+       num_rb_pipes = min_t(unsigned, adev->gfx.config.max_backends_per_se *
+                            adev->gfx.config.max_shader_engines, 16);
+
+       gfx_v7_0_raster_config(adev, &raster_config, &raster_config_1);
+
+       if (!adev->gfx.config.backend_enable_mask ||
+                       adev->gfx.config.num_rbs >= num_rb_pipes) {
+               WREG32(mmPA_SC_RASTER_CONFIG, raster_config);
+               WREG32(mmPA_SC_RASTER_CONFIG_1, raster_config_1);
+       } else {
+               gfx_v7_0_write_harvested_raster_configs(adev, raster_config, raster_config_1,
+                                                       adev->gfx.config.backend_enable_mask,
+                                                       num_rb_pipes);
+       }
+       mutex_unlock(&adev->grbm_idx_mutex);
 }
 
 /**
@@ -2096,6 +2254,25 @@ static void gfx_v7_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, control);
 }
 
+static void gfx_v7_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
+{
+       uint32_t dw2 = 0;
+
+       dw2 |= 0x80000000; /* set load_enable otherwise this package is just NOPs */
+       if (flags & AMDGPU_HAVE_CTX_SWITCH) {
+               /* set load_global_config & load_global_uconfig */
+               dw2 |= 0x8001;
+               /* set load_cs_sh_regs */
+               dw2 |= 0x01000000;
+               /* set load_per_context_state & load_gfx_sh_regs */
+               dw2 |= 0x10002;
+       }
+
+       amdgpu_ring_write(ring, PACKET3(PACKET3_CONTEXT_CONTROL, 1));
+       amdgpu_ring_write(ring, dw2);
+       amdgpu_ring_write(ring, 0);
+}
+
 /**
  * gfx_v7_0_ring_test_ib - basic ring IB test
  *
@@ -2443,7 +2620,7 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev)
        return 0;
 }
 
-static u32 gfx_v7_0_ring_get_rptr_gfx(struct amdgpu_ring *ring)
+static u32 gfx_v7_0_ring_get_rptr(struct amdgpu_ring *ring)
 {
        return ring->adev->wb.wb[ring->rptr_offs];
 }
@@ -2463,11 +2640,6 @@ static void gfx_v7_0_ring_set_wptr_gfx(struct amdgpu_ring *ring)
        (void)RREG32(mmCP_RB0_WPTR);
 }
 
-static u32 gfx_v7_0_ring_get_rptr_compute(struct amdgpu_ring *ring)
-{
-       return ring->adev->wb.wb[ring->rptr_offs];
-}
-
 static u32 gfx_v7_0_ring_get_wptr_compute(struct amdgpu_ring *ring)
 {
        /* XXX check if swapping is necessary on BE */
@@ -4182,6 +4354,41 @@ static void gfx_v7_0_ring_emit_gds_switch(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, (1 << (oa_size + oa_base)) - (1 << oa_base));
 }
 
+static unsigned gfx_v7_0_ring_get_emit_ib_size_gfx(struct amdgpu_ring *ring)
+{
+       return
+               4; /* gfx_v7_0_ring_emit_ib_gfx */
+}
+
+static unsigned gfx_v7_0_ring_get_dma_frame_size_gfx(struct amdgpu_ring *ring)
+{
+       return
+               20 + /* gfx_v7_0_ring_emit_gds_switch */
+               7 + /* gfx_v7_0_ring_emit_hdp_flush */
+               5 + /* gfx_v7_0_ring_emit_hdp_invalidate */
+               12 + 12 + 12 + /* gfx_v7_0_ring_emit_fence_gfx x3 for user fence, vm fence */
+               7 + 4 + /* gfx_v7_0_ring_emit_pipeline_sync */
+               17 + 6 + /* gfx_v7_0_ring_emit_vm_flush */
+               3; /* gfx_v7_ring_emit_cntxcntl */
+}
+
+static unsigned gfx_v7_0_ring_get_emit_ib_size_compute(struct amdgpu_ring *ring)
+{
+       return
+               4; /* gfx_v7_0_ring_emit_ib_compute */
+}
+
+static unsigned gfx_v7_0_ring_get_dma_frame_size_compute(struct amdgpu_ring *ring)
+{
+       return
+               20 + /* gfx_v7_0_ring_emit_gds_switch */
+               7 + /* gfx_v7_0_ring_emit_hdp_flush */
+               5 + /* gfx_v7_0_ring_emit_hdp_invalidate */
+               7 + /* gfx_v7_0_ring_emit_pipeline_sync */
+               17 + /* gfx_v7_0_ring_emit_vm_flush */
+               7 + 7 + 7; /* gfx_v7_0_ring_emit_fence_compute x3 for user fence, vm fence */
+}
+
 static const struct amdgpu_gfx_funcs gfx_v7_0_gfx_funcs = {
        .get_gpu_clock_counter = &gfx_v7_0_get_gpu_clock_counter,
        .select_se_sh = &gfx_v7_0_select_se_sh,
@@ -4471,24 +4678,21 @@ static int gfx_v7_0_sw_init(void *handle)
        }
 
        /* reserve GDS, GWS and OA resource for gfx */
-       r = amdgpu_bo_create(adev, adev->gds.mem.gfx_partition_size,
-                       PAGE_SIZE, true,
-                       AMDGPU_GEM_DOMAIN_GDS, 0,
-                       NULL, NULL, &adev->gds.gds_gfx_bo);
+       r = amdgpu_bo_create_kernel(adev, adev->gds.mem.gfx_partition_size,
+                                   PAGE_SIZE, AMDGPU_GEM_DOMAIN_GDS,
+                                   &adev->gds.gds_gfx_bo, NULL, NULL);
        if (r)
                return r;
 
-       r = amdgpu_bo_create(adev, adev->gds.gws.gfx_partition_size,
-               PAGE_SIZE, true,
-               AMDGPU_GEM_DOMAIN_GWS, 0,
-               NULL, NULL, &adev->gds.gws_gfx_bo);
+       r = amdgpu_bo_create_kernel(adev, adev->gds.gws.gfx_partition_size,
+                                   PAGE_SIZE, AMDGPU_GEM_DOMAIN_GWS,
+                                   &adev->gds.gws_gfx_bo, NULL, NULL);
        if (r)
                return r;
 
-       r = amdgpu_bo_create(adev, adev->gds.oa.gfx_partition_size,
-                       PAGE_SIZE, true,
-                       AMDGPU_GEM_DOMAIN_OA, 0,
-                       NULL, NULL, &adev->gds.oa_gfx_bo);
+       r = amdgpu_bo_create_kernel(adev, adev->gds.oa.gfx_partition_size,
+                                   PAGE_SIZE, AMDGPU_GEM_DOMAIN_OA,
+                                   &adev->gds.oa_gfx_bo, NULL, NULL);
        if (r)
                return r;
 
@@ -4504,9 +4708,9 @@ static int gfx_v7_0_sw_fini(void *handle)
        int i;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       amdgpu_bo_unref(&adev->gds.oa_gfx_bo);
-       amdgpu_bo_unref(&adev->gds.gws_gfx_bo);
-       amdgpu_bo_unref(&adev->gds.gds_gfx_bo);
+       amdgpu_bo_free_kernel(&adev->gds.oa_gfx_bo, NULL, NULL);
+       amdgpu_bo_free_kernel(&adev->gds.gws_gfx_bo, NULL, NULL);
+       amdgpu_bo_free_kernel(&adev->gds.gds_gfx_bo, NULL, NULL);
 
        for (i = 0; i < adev->gfx.num_gfx_rings; i++)
                amdgpu_ring_fini(&adev->gfx.gfx_ring[i]);
@@ -4937,7 +5141,7 @@ const struct amd_ip_funcs gfx_v7_0_ip_funcs = {
 };
 
 static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = {
-       .get_rptr = gfx_v7_0_ring_get_rptr_gfx,
+       .get_rptr = gfx_v7_0_ring_get_rptr,
        .get_wptr = gfx_v7_0_ring_get_wptr_gfx,
        .set_wptr = gfx_v7_0_ring_set_wptr_gfx,
        .parse_cs = NULL,
@@ -4952,10 +5156,13 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = {
        .test_ib = gfx_v7_0_ring_test_ib,
        .insert_nop = amdgpu_ring_insert_nop,
        .pad_ib = amdgpu_ring_generic_pad_ib,
+       .emit_cntxcntl = gfx_v7_ring_emit_cntxcntl,
+       .get_emit_ib_size = gfx_v7_0_ring_get_emit_ib_size_gfx,
+       .get_dma_frame_size = gfx_v7_0_ring_get_dma_frame_size_gfx,
 };
 
 static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = {
-       .get_rptr = gfx_v7_0_ring_get_rptr_compute,
+       .get_rptr = gfx_v7_0_ring_get_rptr,
        .get_wptr = gfx_v7_0_ring_get_wptr_compute,
        .set_wptr = gfx_v7_0_ring_set_wptr_compute,
        .parse_cs = NULL,
@@ -4970,6 +5177,8 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = {
        .test_ib = gfx_v7_0_ring_test_ib,
        .insert_nop = amdgpu_ring_insert_nop,
        .pad_ib = amdgpu_ring_generic_pad_ib,
+       .get_emit_ib_size = gfx_v7_0_ring_get_emit_ib_size_compute,
+       .get_dma_frame_size = gfx_v7_0_ring_get_dma_frame_size_compute,
 };
 
 static void gfx_v7_0_set_ring_funcs(struct amdgpu_device *adev)
index b818461..6c6ff57 100644 (file)
@@ -703,7 +703,10 @@ static void gfx_v8_0_init_golden_registers(struct amdgpu_device *adev)
                                                 polaris10_golden_common_all,
                                                 (const u32)ARRAY_SIZE(polaris10_golden_common_all));
                WREG32_SMC(ixCG_ACLK_CNTL, 0x0000001C);
-               if (adev->pdev->revision == 0xc7) {
+               if (adev->pdev->revision == 0xc7 &&
+                   ((adev->pdev->subsystem_device == 0xb37 && adev->pdev->subsystem_vendor == 0x1002) ||
+                    (adev->pdev->subsystem_device == 0x4a8 && adev->pdev->subsystem_vendor == 0x1043) ||
+                    (adev->pdev->subsystem_device == 0x9480 && adev->pdev->subsystem_vendor == 0x1682))) {
                        amdgpu_atombios_i2c_channel_trans(adev, 0x10, 0x96, 0x1E, 0xDD);
                        amdgpu_atombios_i2c_channel_trans(adev, 0x10, 0x96, 0x1F, 0xD0);
                }
@@ -1233,10 +1236,9 @@ static void gfx_v8_0_rlc_fini(struct amdgpu_device *adev)
        if (adev->gfx.rlc.clear_state_obj) {
                r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false);
                if (unlikely(r != 0))
-                       dev_warn(adev->dev, "(%d) reserve RLC c bo failed\n", r);
+                       dev_warn(adev->dev, "(%d) reserve RLC cbs bo failed\n", r);
                amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
                amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
-
                amdgpu_bo_unref(&adev->gfx.rlc.clear_state_obj);
                adev->gfx.rlc.clear_state_obj = NULL;
        }
@@ -1248,7 +1250,6 @@ static void gfx_v8_0_rlc_fini(struct amdgpu_device *adev)
                        dev_warn(adev->dev, "(%d) reserve RLC cp table bo failed\n", r);
                amdgpu_bo_unpin(adev->gfx.rlc.cp_table_obj);
                amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
-
                amdgpu_bo_unref(&adev->gfx.rlc.cp_table_obj);
                adev->gfx.rlc.cp_table_obj = NULL;
        }
@@ -1290,14 +1291,14 @@ static int gfx_v8_0_rlc_init(struct amdgpu_device *adev)
                                  &adev->gfx.rlc.clear_state_gpu_addr);
                if (r) {
                        amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
-                       dev_warn(adev->dev, "(%d) pin RLC c bo failed\n", r);
+                       dev_warn(adev->dev, "(%d) pin RLC cbs bo failed\n", r);
                        gfx_v8_0_rlc_fini(adev);
                        return r;
                }
 
                r = amdgpu_bo_kmap(adev->gfx.rlc.clear_state_obj, (void **)&adev->gfx.rlc.cs_ptr);
                if (r) {
-                       dev_warn(adev->dev, "(%d) map RLC c bo failed\n", r);
+                       dev_warn(adev->dev, "(%d) map RLC cbs bo failed\n", r);
                        gfx_v8_0_rlc_fini(adev);
                        return r;
                }
@@ -1332,7 +1333,7 @@ static int gfx_v8_0_rlc_init(struct amdgpu_device *adev)
                                  &adev->gfx.rlc.cp_table_gpu_addr);
                if (r) {
                        amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
-                       dev_warn(adev->dev, "(%d) pin RLC cp_table bo failed\n", r);
+                       dev_warn(adev->dev, "(%d) pin RLC cp table bo failed\n", r);
                        return r;
                }
                r = amdgpu_bo_kmap(adev->gfx.rlc.cp_table_obj, (void **)&adev->gfx.rlc.cp_table_ptr);
@@ -1345,7 +1346,6 @@ static int gfx_v8_0_rlc_init(struct amdgpu_device *adev)
 
                amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
                amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
-
        }
 
        return 0;
@@ -1361,7 +1361,6 @@ static void gfx_v8_0_mec_fini(struct amdgpu_device *adev)
                        dev_warn(adev->dev, "(%d) reserve HPD EOP bo failed\n", r);
                amdgpu_bo_unpin(adev->gfx.mec.hpd_eop_obj);
                amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj);
-
                amdgpu_bo_unref(&adev->gfx.mec.hpd_eop_obj);
                adev->gfx.mec.hpd_eop_obj = NULL;
        }
@@ -2082,24 +2081,21 @@ static int gfx_v8_0_sw_init(void *handle)
        }
 
        /* reserve GDS, GWS and OA resource for gfx */
-       r = amdgpu_bo_create(adev, adev->gds.mem.gfx_partition_size,
-                       PAGE_SIZE, true,
-                       AMDGPU_GEM_DOMAIN_GDS, 0, NULL,
-                       NULL, &adev->gds.gds_gfx_bo);
+       r = amdgpu_bo_create_kernel(adev, adev->gds.mem.gfx_partition_size,
+                                   PAGE_SIZE, AMDGPU_GEM_DOMAIN_GDS,
+                                   &adev->gds.gds_gfx_bo, NULL, NULL);
        if (r)
                return r;
 
-       r = amdgpu_bo_create(adev, adev->gds.gws.gfx_partition_size,
-               PAGE_SIZE, true,
-               AMDGPU_GEM_DOMAIN_GWS, 0, NULL,
-               NULL, &adev->gds.gws_gfx_bo);
+       r = amdgpu_bo_create_kernel(adev, adev->gds.gws.gfx_partition_size,
+                                   PAGE_SIZE, AMDGPU_GEM_DOMAIN_GWS,
+                                   &adev->gds.gws_gfx_bo, NULL, NULL);
        if (r)
                return r;
 
-       r = amdgpu_bo_create(adev, adev->gds.oa.gfx_partition_size,
-                       PAGE_SIZE, true,
-                       AMDGPU_GEM_DOMAIN_OA, 0, NULL,
-                       NULL, &adev->gds.oa_gfx_bo);
+       r = amdgpu_bo_create_kernel(adev, adev->gds.oa.gfx_partition_size,
+                                   PAGE_SIZE, AMDGPU_GEM_DOMAIN_OA,
+                                   &adev->gds.oa_gfx_bo, NULL, NULL);
        if (r)
                return r;
 
@@ -2117,9 +2113,9 @@ static int gfx_v8_0_sw_fini(void *handle)
        int i;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       amdgpu_bo_unref(&adev->gds.oa_gfx_bo);
-       amdgpu_bo_unref(&adev->gds.gws_gfx_bo);
-       amdgpu_bo_unref(&adev->gds.gds_gfx_bo);
+       amdgpu_bo_free_kernel(&adev->gds.oa_gfx_bo, NULL, NULL);
+       amdgpu_bo_free_kernel(&adev->gds.gws_gfx_bo, NULL, NULL);
+       amdgpu_bo_free_kernel(&adev->gds.gds_gfx_bo, NULL, NULL);
 
        for (i = 0; i < adev->gfx.num_gfx_rings; i++)
                amdgpu_ring_fini(&adev->gfx.gfx_ring[i]);
@@ -2127,9 +2123,7 @@ static int gfx_v8_0_sw_fini(void *handle)
                amdgpu_ring_fini(&adev->gfx.compute_ring[i]);
 
        gfx_v8_0_mec_fini(adev);
-
        gfx_v8_0_rlc_fini(adev);
-
        gfx_v8_0_free_microcode(adev);
 
        return 0;
@@ -3465,19 +3459,16 @@ static void gfx_v8_0_select_se_sh(struct amdgpu_device *adev,
        else
                data = REG_SET_FIELD(0, GRBM_GFX_INDEX, INSTANCE_INDEX, instance);
 
-       if ((se_num == 0xffffffff) && (sh_num == 0xffffffff)) {
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_BROADCAST_WRITES, 1);
+       if (se_num == 0xffffffff)
                data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_BROADCAST_WRITES, 1);
-       } else if (se_num == 0xffffffff) {
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_INDEX, sh_num);
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_BROADCAST_WRITES, 1);
-       } else if (sh_num == 0xffffffff) {
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_BROADCAST_WRITES, 1);
+       else
                data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_INDEX, se_num);
-       } else {
+
+       if (sh_num == 0xffffffff)
+               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_BROADCAST_WRITES, 1);
+       else
                data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_INDEX, sh_num);
-               data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_INDEX, se_num);
-       }
+
        WREG32(mmGRBM_GFX_INDEX, data);
 }
 
@@ -3490,11 +3481,10 @@ static u32 gfx_v8_0_get_rb_active_bitmap(struct amdgpu_device *adev)
 {
        u32 data, mask;
 
-       data = RREG32(mmCC_RB_BACKEND_DISABLE);
-       data |= RREG32(mmGC_USER_RB_BACKEND_DISABLE);
+       data =  RREG32(mmCC_RB_BACKEND_DISABLE) |
+               RREG32(mmGC_USER_RB_BACKEND_DISABLE);
 
-       data &= CC_RB_BACKEND_DISABLE__BACKEND_DISABLE_MASK;
-       data >>= GC_USER_RB_BACKEND_DISABLE__BACKEND_DISABLE__SHIFT;
+       data = REG_GET_FIELD(data, GC_USER_RB_BACKEND_DISABLE, BACKEND_DISABLE);
 
        mask = gfx_v8_0_create_bitmask(adev->gfx.config.max_backends_per_se /
                                       adev->gfx.config.max_sh_per_se);
@@ -3502,13 +3492,163 @@ static u32 gfx_v8_0_get_rb_active_bitmap(struct amdgpu_device *adev)
        return (~data) & mask;
 }
 
+static void
+gfx_v8_0_raster_config(struct amdgpu_device *adev, u32 *rconf, u32 *rconf1)
+{
+       switch (adev->asic_type) {
+       case CHIP_FIJI:
+               *rconf |= RB_MAP_PKR0(2) | RB_MAP_PKR1(2) |
+                         RB_XSEL2(1) | PKR_MAP(2) |
+                         PKR_XSEL(1) | PKR_YSEL(1) |
+                         SE_MAP(2) | SE_XSEL(2) | SE_YSEL(3);
+               *rconf1 |= SE_PAIR_MAP(2) | SE_PAIR_XSEL(3) |
+                          SE_PAIR_YSEL(2);
+               break;
+       case CHIP_TONGA:
+       case CHIP_POLARIS10:
+               *rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) |
+                         SE_XSEL(1) | SE_YSEL(1);
+               *rconf1 |= SE_PAIR_MAP(2) | SE_PAIR_XSEL(2) |
+                          SE_PAIR_YSEL(2);
+               break;
+       case CHIP_TOPAZ:
+       case CHIP_CARRIZO:
+               *rconf |= RB_MAP_PKR0(2);
+               *rconf1 |= 0x0;
+               break;
+       case CHIP_POLARIS11:
+               *rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) |
+                         SE_XSEL(1) | SE_YSEL(1);
+               *rconf1 |= 0x0;
+               break;
+       case CHIP_STONEY:
+               *rconf |= 0x0;
+               *rconf1 |= 0x0;
+               break;
+       default:
+               DRM_ERROR("unknown asic: 0x%x\n", adev->asic_type);
+               break;
+       }
+}
+
+static void
+gfx_v8_0_write_harvested_raster_configs(struct amdgpu_device *adev,
+                                       u32 raster_config, u32 raster_config_1,
+                                       unsigned rb_mask, unsigned num_rb)
+{
+       unsigned sh_per_se = max_t(unsigned, adev->gfx.config.max_sh_per_se, 1);
+       unsigned num_se = max_t(unsigned, adev->gfx.config.max_shader_engines, 1);
+       unsigned rb_per_pkr = min_t(unsigned, num_rb / num_se / sh_per_se, 2);
+       unsigned rb_per_se = num_rb / num_se;
+       unsigned se_mask[4];
+       unsigned se;
+
+       se_mask[0] = ((1 << rb_per_se) - 1) & rb_mask;
+       se_mask[1] = (se_mask[0] << rb_per_se) & rb_mask;
+       se_mask[2] = (se_mask[1] << rb_per_se) & rb_mask;
+       se_mask[3] = (se_mask[2] << rb_per_se) & rb_mask;
+
+       WARN_ON(!(num_se == 1 || num_se == 2 || num_se == 4));
+       WARN_ON(!(sh_per_se == 1 || sh_per_se == 2));
+       WARN_ON(!(rb_per_pkr == 1 || rb_per_pkr == 2));
+
+       if ((num_se > 2) && ((!se_mask[0] && !se_mask[1]) ||
+                            (!se_mask[2] && !se_mask[3]))) {
+               raster_config_1 &= ~SE_PAIR_MAP_MASK;
+
+               if (!se_mask[0] && !se_mask[1]) {
+                       raster_config_1 |=
+                               SE_PAIR_MAP(RASTER_CONFIG_SE_PAIR_MAP_3);
+               } else {
+                       raster_config_1 |=
+                               SE_PAIR_MAP(RASTER_CONFIG_SE_PAIR_MAP_0);
+               }
+       }
+
+       for (se = 0; se < num_se; se++) {
+               unsigned raster_config_se = raster_config;
+               unsigned pkr0_mask = ((1 << rb_per_pkr) - 1) << (se * rb_per_se);
+               unsigned pkr1_mask = pkr0_mask << rb_per_pkr;
+               int idx = (se / 2) * 2;
+
+               if ((num_se > 1) && (!se_mask[idx] || !se_mask[idx + 1])) {
+                       raster_config_se &= ~SE_MAP_MASK;
+
+                       if (!se_mask[idx]) {
+                               raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_3);
+                       } else {
+                               raster_config_se |= SE_MAP(RASTER_CONFIG_SE_MAP_0);
+                       }
+               }
+
+               pkr0_mask &= rb_mask;
+               pkr1_mask &= rb_mask;
+               if (rb_per_se > 2 && (!pkr0_mask || !pkr1_mask)) {
+                       raster_config_se &= ~PKR_MAP_MASK;
+
+                       if (!pkr0_mask) {
+                               raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_3);
+                       } else {
+                               raster_config_se |= PKR_MAP(RASTER_CONFIG_PKR_MAP_0);
+                       }
+               }
+
+               if (rb_per_se >= 2) {
+                       unsigned rb0_mask = 1 << (se * rb_per_se);
+                       unsigned rb1_mask = rb0_mask << 1;
+
+                       rb0_mask &= rb_mask;
+                       rb1_mask &= rb_mask;
+                       if (!rb0_mask || !rb1_mask) {
+                               raster_config_se &= ~RB_MAP_PKR0_MASK;
+
+                               if (!rb0_mask) {
+                                       raster_config_se |=
+                                               RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_3);
+                               } else {
+                                       raster_config_se |=
+                                               RB_MAP_PKR0(RASTER_CONFIG_RB_MAP_0);
+                               }
+                       }
+
+                       if (rb_per_se > 2) {
+                               rb0_mask = 1 << (se * rb_per_se + rb_per_pkr);
+                               rb1_mask = rb0_mask << 1;
+                               rb0_mask &= rb_mask;
+                               rb1_mask &= rb_mask;
+                               if (!rb0_mask || !rb1_mask) {
+                                       raster_config_se &= ~RB_MAP_PKR1_MASK;
+
+                                       if (!rb0_mask) {
+                                               raster_config_se |=
+                                                       RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_3);
+                                       } else {
+                                               raster_config_se |=
+                                                       RB_MAP_PKR1(RASTER_CONFIG_RB_MAP_0);
+                                       }
+                               }
+                       }
+               }
+
+               /* GRBM_GFX_INDEX has a different offset on VI */
+               gfx_v8_0_select_se_sh(adev, se, 0xffffffff, 0xffffffff);
+               WREG32(mmPA_SC_RASTER_CONFIG, raster_config_se);
+               WREG32(mmPA_SC_RASTER_CONFIG_1, raster_config_1);
+       }
+
+       /* GRBM_GFX_INDEX has a different offset on VI */
+       gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+}
+
 static void gfx_v8_0_setup_rb(struct amdgpu_device *adev)
 {
        int i, j;
        u32 data;
+       u32 raster_config = 0, raster_config_1 = 0;
        u32 active_rbs = 0;
        u32 rb_bitmap_width_per_sh = adev->gfx.config.max_backends_per_se /
                                        adev->gfx.config.max_sh_per_se;
+       unsigned num_rb_pipes;
 
        mutex_lock(&adev->grbm_idx_mutex);
        for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
@@ -3520,10 +3660,26 @@ static void gfx_v8_0_setup_rb(struct amdgpu_device *adev)
                }
        }
        gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
-       mutex_unlock(&adev->grbm_idx_mutex);
 
        adev->gfx.config.backend_enable_mask = active_rbs;
        adev->gfx.config.num_rbs = hweight32(active_rbs);
+
+       num_rb_pipes = min_t(unsigned, adev->gfx.config.max_backends_per_se *
+                            adev->gfx.config.max_shader_engines, 16);
+
+       gfx_v8_0_raster_config(adev, &raster_config, &raster_config_1);
+
+       if (!adev->gfx.config.backend_enable_mask ||
+                       adev->gfx.config.num_rbs >= num_rb_pipes) {
+               WREG32(mmPA_SC_RASTER_CONFIG, raster_config);
+               WREG32(mmPA_SC_RASTER_CONFIG_1, raster_config_1);
+       } else {
+               gfx_v8_0_write_harvested_raster_configs(adev, raster_config, raster_config_1,
+                                                       adev->gfx.config.backend_enable_mask,
+                                                       num_rb_pipes);
+       }
+
+       mutex_unlock(&adev->grbm_idx_mutex);
 }
 
 /**
@@ -3576,16 +3732,12 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
        u32 tmp;
        int i;
 
-       tmp = RREG32(mmGRBM_CNTL);
-       tmp = REG_SET_FIELD(tmp, GRBM_CNTL, READ_TIMEOUT, 0xff);
-       WREG32(mmGRBM_CNTL, tmp);
-
+       WREG32_FIELD(GRBM_CNTL, READ_TIMEOUT, 0xFF);
        WREG32(mmGB_ADDR_CONFIG, adev->gfx.config.gb_addr_config);
        WREG32(mmHDP_ADDR_CONFIG, adev->gfx.config.gb_addr_config);
        WREG32(mmDMIF_ADDR_CALC, adev->gfx.config.gb_addr_config);
 
        gfx_v8_0_tiling_mode_table_init(adev);
-
        gfx_v8_0_setup_rb(adev);
        gfx_v8_0_get_cu_info(adev);
 
@@ -3769,9 +3921,7 @@ static int gfx_v8_0_init_save_restore_list(struct amdgpu_device *adev)
                                sizeof(indirect_start_offsets)/sizeof(int));
 
        /* save and restore list */
-       temp = RREG32(mmRLC_SRM_CNTL);
-       temp |= RLC_SRM_CNTL__AUTO_INCR_ADDR_MASK;
-       WREG32(mmRLC_SRM_CNTL, temp);
+       WREG32_FIELD(RLC_SRM_CNTL, AUTO_INCR_ADDR, 1);
 
        WREG32(mmRLC_SRM_ARAM_ADDR, 0);
        for (i = 0; i < adev->gfx.rlc.reg_list_size_bytes >> 2; i++)
@@ -3808,11 +3958,7 @@ static int gfx_v8_0_init_save_restore_list(struct amdgpu_device *adev)
 
 static void gfx_v8_0_enable_save_restore_machine(struct amdgpu_device *adev)
 {
-       uint32_t data;
-
-       data = RREG32(mmRLC_SRM_CNTL);
-       data |= RLC_SRM_CNTL__SRM_ENABLE_MASK;
-       WREG32(mmRLC_SRM_CNTL, data);
+       WREG32_FIELD(RLC_SRM_CNTL, SRM_ENABLE, 1);
 }
 
 static void gfx_v8_0_init_power_gating(struct amdgpu_device *adev)
@@ -3822,75 +3968,34 @@ static void gfx_v8_0_init_power_gating(struct amdgpu_device *adev)
        if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
                              AMD_PG_SUPPORT_GFX_SMG |
                              AMD_PG_SUPPORT_GFX_DMG)) {
-               data = RREG32(mmCP_RB_WPTR_POLL_CNTL);
-               data &= ~CP_RB_WPTR_POLL_CNTL__IDLE_POLL_COUNT_MASK;
-               data |= (0x60 << CP_RB_WPTR_POLL_CNTL__IDLE_POLL_COUNT__SHIFT);
-               WREG32(mmCP_RB_WPTR_POLL_CNTL, data);
-
-               data = 0;
-               data |= (0x10 << RLC_PG_DELAY__POWER_UP_DELAY__SHIFT);
-               data |= (0x10 << RLC_PG_DELAY__POWER_DOWN_DELAY__SHIFT);
-               data |= (0x10 << RLC_PG_DELAY__CMD_PROPAGATE_DELAY__SHIFT);
-               data |= (0x10 << RLC_PG_DELAY__MEM_SLEEP_DELAY__SHIFT);
-               WREG32(mmRLC_PG_DELAY, data);
+               WREG32_FIELD(CP_RB_WPTR_POLL_CNTL, IDLE_POLL_COUNT, 0x60);
 
-               data = RREG32(mmRLC_PG_DELAY_2);
-               data &= ~RLC_PG_DELAY_2__SERDES_CMD_DELAY_MASK;
-               data |= (0x3 << RLC_PG_DELAY_2__SERDES_CMD_DELAY__SHIFT);
-               WREG32(mmRLC_PG_DELAY_2, data);
+               data = REG_SET_FIELD(0, RLC_PG_DELAY, POWER_UP_DELAY, 0x10);
+               data = REG_SET_FIELD(data, RLC_PG_DELAY, POWER_DOWN_DELAY, 0x10);
+               data = REG_SET_FIELD(data, RLC_PG_DELAY, CMD_PROPAGATE_DELAY, 0x10);
+               data = REG_SET_FIELD(data, RLC_PG_DELAY, MEM_SLEEP_DELAY, 0x10);
+               WREG32(mmRLC_PG_DELAY, data);
 
-               data = RREG32(mmRLC_AUTO_PG_CTRL);
-               data &= ~RLC_AUTO_PG_CTRL__GRBM_REG_SAVE_GFX_IDLE_THRESHOLD_MASK;
-               data |= (0x55f0 << RLC_AUTO_PG_CTRL__GRBM_REG_SAVE_GFX_IDLE_THRESHOLD__SHIFT);
-               WREG32(mmRLC_AUTO_PG_CTRL, data);
+               WREG32_FIELD(RLC_PG_DELAY_2, SERDES_CMD_DELAY, 0x3);
+               WREG32_FIELD(RLC_AUTO_PG_CTRL, GRBM_REG_SAVE_GFX_IDLE_THRESHOLD, 0x55f0);
        }
 }
 
 static void cz_enable_sck_slow_down_on_power_up(struct amdgpu_device *adev,
                                                bool enable)
 {
-       u32 data, orig;
-
-       orig = data = RREG32(mmRLC_PG_CNTL);
-
-       if (enable)
-               data |= RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PU_ENABLE_MASK;
-       else
-               data &= ~RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PU_ENABLE_MASK;
-
-       if (orig != data)
-               WREG32(mmRLC_PG_CNTL, data);
+       WREG32_FIELD(RLC_PG_CNTL, SMU_CLK_SLOWDOWN_ON_PU_ENABLE, enable ? 1 : 0);
 }
 
 static void cz_enable_sck_slow_down_on_power_down(struct amdgpu_device *adev,
                                                  bool enable)
 {
-       u32 data, orig;
-
-       orig = data = RREG32(mmRLC_PG_CNTL);
-
-       if (enable)
-               data |= RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PD_ENABLE_MASK;
-       else
-               data &= ~RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PD_ENABLE_MASK;
-
-       if (orig != data)
-               WREG32(mmRLC_PG_CNTL, data);
+       WREG32_FIELD(RLC_PG_CNTL, SMU_CLK_SLOWDOWN_ON_PD_ENABLE, enable ? 1 : 0);
 }
 
 static void cz_enable_cp_power_gating(struct amdgpu_device *adev, bool enable)
 {
-       u32 data, orig;
-
-       orig = data = RREG32(mmRLC_PG_CNTL);
-
-       if (enable)
-               data &= ~RLC_PG_CNTL__CP_PG_DISABLE_MASK;
-       else
-               data |= RLC_PG_CNTL__CP_PG_DISABLE_MASK;
-
-       if (orig != data)
-               WREG32(mmRLC_PG_CNTL, data);
+       WREG32_FIELD(RLC_PG_CNTL, CP_PG_DISABLE, enable ? 1 : 0);
 }
 
 static void gfx_v8_0_init_pg(struct amdgpu_device *adev)
@@ -3927,36 +4032,26 @@ static void gfx_v8_0_init_pg(struct amdgpu_device *adev)
        }
 }
 
-void gfx_v8_0_rlc_stop(struct amdgpu_device *adev)
+static void gfx_v8_0_rlc_stop(struct amdgpu_device *adev)
 {
-       u32 tmp = RREG32(mmRLC_CNTL);
-
-       tmp = REG_SET_FIELD(tmp, RLC_CNTL, RLC_ENABLE_F32, 0);
-       WREG32(mmRLC_CNTL, tmp);
+       WREG32_FIELD(RLC_CNTL, RLC_ENABLE_F32, 0);
 
        gfx_v8_0_enable_gui_idle_interrupt(adev, false);
-
        gfx_v8_0_wait_for_rlc_serdes(adev);
 }
 
 static void gfx_v8_0_rlc_reset(struct amdgpu_device *adev)
 {
-       u32 tmp = RREG32(mmGRBM_SOFT_RESET);
-
-       tmp = REG_SET_FIELD(tmp, GRBM_SOFT_RESET, SOFT_RESET_RLC, 1);
-       WREG32(mmGRBM_SOFT_RESET, tmp);
+       WREG32_FIELD(GRBM_SOFT_RESET, SOFT_RESET_RLC, 1);
        udelay(50);
-       tmp = REG_SET_FIELD(tmp, GRBM_SOFT_RESET, SOFT_RESET_RLC, 0);
-       WREG32(mmGRBM_SOFT_RESET, tmp);
+
+       WREG32_FIELD(GRBM_SOFT_RESET, SOFT_RESET_RLC, 0);
        udelay(50);
 }
 
 static void gfx_v8_0_rlc_start(struct amdgpu_device *adev)
 {
-       u32 tmp = RREG32(mmRLC_CNTL);
-
-       tmp = REG_SET_FIELD(tmp, RLC_CNTL, RLC_ENABLE_F32, 1);
-       WREG32(mmRLC_CNTL, tmp);
+       WREG32_FIELD(RLC_CNTL, RLC_ENABLE_F32, 1);
 
        /* carrizo do enable cp interrupt after cp inited */
        if (!(adev->flags & AMD_IS_APU))
@@ -3998,14 +4093,13 @@ static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev)
        /* disable CG */
        WREG32(mmRLC_CGCG_CGLS_CTRL, 0);
        if (adev->asic_type == CHIP_POLARIS11 ||
-               adev->asic_type == CHIP_POLARIS10)
+           adev->asic_type == CHIP_POLARIS10)
                WREG32(mmRLC_CGCG_CGLS_CTRL_3D, 0);
 
        /* disable PG */
        WREG32(mmRLC_PG_CNTL, 0);
 
        gfx_v8_0_rlc_reset(adev);
-
        gfx_v8_0_init_pg(adev);
 
        if (!adev->pp_enabled) {
@@ -4300,12 +4394,10 @@ static int gfx_v8_0_cp_gfx_resume(struct amdgpu_device *adev)
        gfx_v8_0_cp_gfx_start(adev);
        ring->ready = true;
        r = amdgpu_ring_test_ring(ring);
-       if (r) {
+       if (r)
                ring->ready = false;
-               return r;
-       }
 
-       return 0;
+       return r;
 }
 
 static void gfx_v8_0_cp_compute_enable(struct amdgpu_device *adev, bool enable)
@@ -4980,7 +5072,6 @@ static int gfx_v8_0_hw_init(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        gfx_v8_0_init_golden_registers(adev);
-
        gfx_v8_0_gpu_init(adev);
 
        r = gfx_v8_0_rlc_resume(adev);
@@ -4988,8 +5079,6 @@ static int gfx_v8_0_hw_init(void *handle)
                return r;
 
        r = gfx_v8_0_cp_resume(adev);
-       if (r)
-               return r;
 
        return r;
 }
@@ -5037,25 +5126,22 @@ static bool gfx_v8_0_is_idle(void *handle)
 static int gfx_v8_0_wait_for_idle(void *handle)
 {
        unsigned i;
-       u32 tmp;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        for (i = 0; i < adev->usec_timeout; i++) {
-               /* read MC_STATUS */
-               tmp = RREG32(mmGRBM_STATUS) & GRBM_STATUS__GUI_ACTIVE_MASK;
-
-               if (!REG_GET_FIELD(tmp, GRBM_STATUS, GUI_ACTIVE))
+               if (gfx_v8_0_is_idle(handle))
                        return 0;
+
                udelay(1);
        }
        return -ETIMEDOUT;
 }
 
-static int gfx_v8_0_soft_reset(void *handle)
+static int gfx_v8_0_check_soft_reset(void *handle)
 {
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
        u32 tmp;
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        /* GRBM_STATUS */
        tmp = RREG32(mmGRBM_STATUS);
@@ -5064,16 +5150,12 @@ static int gfx_v8_0_soft_reset(void *handle)
                   GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__VGT_BUSY_MASK |
                   GRBM_STATUS__DB_BUSY_MASK | GRBM_STATUS__CB_BUSY_MASK |
                   GRBM_STATUS__GDS_BUSY_MASK | GRBM_STATUS__SPI_BUSY_MASK |
-                  GRBM_STATUS__IA_BUSY_MASK | GRBM_STATUS__IA_BUSY_NO_DMA_MASK)) {
+                  GRBM_STATUS__IA_BUSY_MASK | GRBM_STATUS__IA_BUSY_NO_DMA_MASK |
+                  GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK)) {
                grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
                                                GRBM_SOFT_RESET, SOFT_RESET_CP, 1);
                grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
                                                GRBM_SOFT_RESET, SOFT_RESET_GFX, 1);
-       }
-
-       if (tmp & (GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK)) {
-               grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
-                                               GRBM_SOFT_RESET, SOFT_RESET_CP, 1);
                srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
                                                SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1);
        }
@@ -5084,73 +5166,199 @@ static int gfx_v8_0_soft_reset(void *handle)
                grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
                                                GRBM_SOFT_RESET, SOFT_RESET_RLC, 1);
 
+       if (REG_GET_FIELD(tmp, GRBM_STATUS2, CPF_BUSY) ||
+           REG_GET_FIELD(tmp, GRBM_STATUS2, CPC_BUSY) ||
+           REG_GET_FIELD(tmp, GRBM_STATUS2, CPG_BUSY)) {
+               grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                               SOFT_RESET_CPF, 1);
+               grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                               SOFT_RESET_CPC, 1);
+               grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                               SOFT_RESET_CPG, 1);
+               srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET,
+                                               SOFT_RESET_GRBM, 1);
+       }
+
        /* SRBM_STATUS */
        tmp = RREG32(mmSRBM_STATUS);
        if (REG_GET_FIELD(tmp, SRBM_STATUS, GRBM_RQ_PENDING))
                srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
                                                SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1);
+       if (REG_GET_FIELD(tmp, SRBM_STATUS, SEM_BUSY))
+               srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
+                                               SRBM_SOFT_RESET, SOFT_RESET_SEM, 1);
 
        if (grbm_soft_reset || srbm_soft_reset) {
-               /* stop the rlc */
-               gfx_v8_0_rlc_stop(adev);
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang = true;
+               adev->gfx.grbm_soft_reset = grbm_soft_reset;
+               adev->gfx.srbm_soft_reset = srbm_soft_reset;
+       } else {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang = false;
+               adev->gfx.grbm_soft_reset = 0;
+               adev->gfx.srbm_soft_reset = 0;
+       }
+
+       return 0;
+}
+
+static void gfx_v8_0_inactive_hqd(struct amdgpu_device *adev,
+                                 struct amdgpu_ring *ring)
+{
+       int i;
+
+       vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
+       if (RREG32(mmCP_HQD_ACTIVE) & CP_HQD_ACTIVE__ACTIVE_MASK) {
+               u32 tmp;
+               tmp = RREG32(mmCP_HQD_DEQUEUE_REQUEST);
+               tmp = REG_SET_FIELD(tmp, CP_HQD_DEQUEUE_REQUEST,
+                                   DEQUEUE_REQ, 2);
+               WREG32(mmCP_HQD_DEQUEUE_REQUEST, tmp);
+               for (i = 0; i < adev->usec_timeout; i++) {
+                       if (!(RREG32(mmCP_HQD_ACTIVE) & CP_HQD_ACTIVE__ACTIVE_MASK))
+                               break;
+                       udelay(1);
+               }
+       }
+}
+
+static int gfx_v8_0_pre_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang)
+               return 0;
+
+       grbm_soft_reset = adev->gfx.grbm_soft_reset;
+       srbm_soft_reset = adev->gfx.srbm_soft_reset;
+
+       /* stop the rlc */
+       gfx_v8_0_rlc_stop(adev);
 
+       if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
+           REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX))
                /* Disable GFX parsing/prefetching */
                gfx_v8_0_cp_gfx_enable(adev, false);
 
+       if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
+           REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPF) ||
+           REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPC) ||
+           REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPG)) {
+               int i;
+
+               for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+                       struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
+
+                       gfx_v8_0_inactive_hqd(adev, ring);
+               }
                /* Disable MEC parsing/prefetching */
                gfx_v8_0_cp_compute_enable(adev, false);
+       }
 
-               if (grbm_soft_reset || srbm_soft_reset) {
-                       tmp = RREG32(mmGMCON_DEBUG);
-                       tmp = REG_SET_FIELD(tmp,
-                                           GMCON_DEBUG, GFX_STALL, 1);
-                       tmp = REG_SET_FIELD(tmp,
-                                           GMCON_DEBUG, GFX_CLEAR, 1);
-                       WREG32(mmGMCON_DEBUG, tmp);
+       return 0;
+}
 
-                       udelay(50);
-               }
+static int gfx_v8_0_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+       u32 tmp;
 
-               if (grbm_soft_reset) {
-                       tmp = RREG32(mmGRBM_SOFT_RESET);
-                       tmp |= grbm_soft_reset;
-                       dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
-                       WREG32(mmGRBM_SOFT_RESET, tmp);
-                       tmp = RREG32(mmGRBM_SOFT_RESET);
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang)
+               return 0;
 
-                       udelay(50);
+       grbm_soft_reset = adev->gfx.grbm_soft_reset;
+       srbm_soft_reset = adev->gfx.srbm_soft_reset;
 
-                       tmp &= ~grbm_soft_reset;
-                       WREG32(mmGRBM_SOFT_RESET, tmp);
-                       tmp = RREG32(mmGRBM_SOFT_RESET);
-               }
+       if (grbm_soft_reset || srbm_soft_reset) {
+               tmp = RREG32(mmGMCON_DEBUG);
+               tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 1);
+               tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 1);
+               WREG32(mmGMCON_DEBUG, tmp);
+               udelay(50);
+       }
 
-               if (srbm_soft_reset) {
-                       tmp = RREG32(mmSRBM_SOFT_RESET);
-                       tmp |= srbm_soft_reset;
-                       dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
-                       WREG32(mmSRBM_SOFT_RESET, tmp);
-                       tmp = RREG32(mmSRBM_SOFT_RESET);
+       if (grbm_soft_reset) {
+               tmp = RREG32(mmGRBM_SOFT_RESET);
+               tmp |= grbm_soft_reset;
+               dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
+               WREG32(mmGRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmGRBM_SOFT_RESET);
 
-                       udelay(50);
+               udelay(50);
 
-                       tmp &= ~srbm_soft_reset;
-                       WREG32(mmSRBM_SOFT_RESET, tmp);
-                       tmp = RREG32(mmSRBM_SOFT_RESET);
-               }
+               tmp &= ~grbm_soft_reset;
+               WREG32(mmGRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmGRBM_SOFT_RESET);
+       }
 
-               if (grbm_soft_reset || srbm_soft_reset) {
-                       tmp = RREG32(mmGMCON_DEBUG);
-                       tmp = REG_SET_FIELD(tmp,
-                                           GMCON_DEBUG, GFX_STALL, 0);
-                       tmp = REG_SET_FIELD(tmp,
-                                           GMCON_DEBUG, GFX_CLEAR, 0);
-                       WREG32(mmGMCON_DEBUG, tmp);
-               }
+       if (srbm_soft_reset) {
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+               tmp |= srbm_soft_reset;
+               dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+               WREG32(mmSRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmSRBM_SOFT_RESET);
 
-               /* Wait a little for things to settle down */
                udelay(50);
+
+               tmp &= ~srbm_soft_reset;
+               WREG32(mmSRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+       }
+
+       if (grbm_soft_reset || srbm_soft_reset) {
+               tmp = RREG32(mmGMCON_DEBUG);
+               tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 0);
+               tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 0);
+               WREG32(mmGMCON_DEBUG, tmp);
        }
+
+       /* Wait a little for things to settle down */
+       udelay(50);
+
+       return 0;
+}
+
+static void gfx_v8_0_init_hqd(struct amdgpu_device *adev,
+                             struct amdgpu_ring *ring)
+{
+       vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
+       WREG32(mmCP_HQD_DEQUEUE_REQUEST, 0);
+       WREG32(mmCP_HQD_PQ_RPTR, 0);
+       WREG32(mmCP_HQD_PQ_WPTR, 0);
+       vi_srbm_select(adev, 0, 0, 0, 0);
+}
+
+static int gfx_v8_0_post_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang)
+               return 0;
+
+       grbm_soft_reset = adev->gfx.grbm_soft_reset;
+       srbm_soft_reset = adev->gfx.srbm_soft_reset;
+
+       if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
+           REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX))
+               gfx_v8_0_cp_gfx_resume(adev);
+
+       if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
+           REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPF) ||
+           REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPC) ||
+           REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPG)) {
+               int i;
+
+               for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+                       struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
+
+                       gfx_v8_0_init_hqd(adev, ring);
+               }
+               gfx_v8_0_cp_compute_resume(adev);
+       }
+       gfx_v8_0_rlc_start(adev);
+
        return 0;
 }
 
@@ -5269,8 +5477,6 @@ 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)
 {
-       uint32_t data, temp;
-
        if (adev->asic_type == CHIP_POLARIS11)
                /* Send msg to SMU via Powerplay */
                amdgpu_set_powergating_state(adev,
@@ -5278,83 +5484,35 @@ static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *ade
                                             enable ?
                                             AMD_PG_STATE_GATE : AMD_PG_STATE_UNGATE);
 
-       temp = data = RREG32(mmRLC_PG_CNTL);
-       /* Enable static MGPG */
-       if (enable)
-               data |= RLC_PG_CNTL__STATIC_PER_CU_PG_ENABLE_MASK;
-       else
-               data &= ~RLC_PG_CNTL__STATIC_PER_CU_PG_ENABLE_MASK;
-
-       if (temp != data)
-               WREG32(mmRLC_PG_CNTL, data);
+       WREG32_FIELD(RLC_PG_CNTL, STATIC_PER_CU_PG_ENABLE, enable ? 1 : 0);
 }
 
 static void gfx_v8_0_enable_gfx_dynamic_mg_power_gating(struct amdgpu_device *adev,
                                                        bool enable)
 {
-       uint32_t data, temp;
-
-       temp = data = RREG32(mmRLC_PG_CNTL);
-       /* Enable dynamic MGPG */
-       if (enable)
-               data |= RLC_PG_CNTL__DYN_PER_CU_PG_ENABLE_MASK;
-       else
-               data &= ~RLC_PG_CNTL__DYN_PER_CU_PG_ENABLE_MASK;
-
-       if (temp != data)
-               WREG32(mmRLC_PG_CNTL, data);
+       WREG32_FIELD(RLC_PG_CNTL, DYN_PER_CU_PG_ENABLE, enable ? 1 : 0);
 }
 
 static void polaris11_enable_gfx_quick_mg_power_gating(struct amdgpu_device *adev,
                bool enable)
 {
-       uint32_t data, temp;
-
-       temp = data = RREG32(mmRLC_PG_CNTL);
-       /* Enable quick PG */
-       if (enable)
-               data |= RLC_PG_CNTL__QUICK_PG_ENABLE_MASK;
-       else
-               data &= ~RLC_PG_CNTL__QUICK_PG_ENABLE_MASK;
-
-       if (temp != data)
-               WREG32(mmRLC_PG_CNTL, data);
+       WREG32_FIELD(RLC_PG_CNTL, QUICK_PG_ENABLE, enable ? 1 : 0);
 }
 
 static void cz_enable_gfx_cg_power_gating(struct amdgpu_device *adev,
                                          bool enable)
 {
-       u32 data, orig;
-
-       orig = data = RREG32(mmRLC_PG_CNTL);
-
-       if (enable)
-               data |= RLC_PG_CNTL__GFX_POWER_GATING_ENABLE_MASK;
-       else
-               data &= ~RLC_PG_CNTL__GFX_POWER_GATING_ENABLE_MASK;
-
-       if (orig != data)
-               WREG32(mmRLC_PG_CNTL, data);
+       WREG32_FIELD(RLC_PG_CNTL, GFX_POWER_GATING_ENABLE, enable ? 1 : 0);
 }
 
 static void cz_enable_gfx_pipeline_power_gating(struct amdgpu_device *adev,
                                                bool enable)
 {
-       u32 data, orig;
-
-       orig = data = RREG32(mmRLC_PG_CNTL);
-
-       if (enable)
-               data |= RLC_PG_CNTL__GFX_PIPELINE_PG_ENABLE_MASK;
-       else
-               data &= ~RLC_PG_CNTL__GFX_PIPELINE_PG_ENABLE_MASK;
-
-       if (orig != data)
-               WREG32(mmRLC_PG_CNTL, data);
+       WREG32_FIELD(RLC_PG_CNTL, GFX_PIPELINE_PG_ENABLE, enable ? 1 : 0);
 
        /* Read any GFX register to wake up GFX. */
        if (!enable)
-               data = RREG32(mmDB_RENDER_CONTROL);
+               RREG32(mmDB_RENDER_CONTROL);
 }
 
 static void cz_update_gfx_cg_power_gating(struct amdgpu_device *adev,
@@ -5430,15 +5588,15 @@ static void gfx_v8_0_send_serdes_cmd(struct amdgpu_device *adev,
 
        data = RREG32(mmRLC_SERDES_WR_CTRL);
        if (adev->asic_type == CHIP_STONEY)
-                       data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK |
-                       RLC_SERDES_WR_CTRL__READ_COMMAND_MASK |
-                       RLC_SERDES_WR_CTRL__P1_SELECT_MASK |
-                       RLC_SERDES_WR_CTRL__P2_SELECT_MASK |
-                       RLC_SERDES_WR_CTRL__RDDATA_RESET_MASK |
-                       RLC_SERDES_WR_CTRL__POWER_DOWN_MASK |
-                       RLC_SERDES_WR_CTRL__POWER_UP_MASK |
-                       RLC_SERDES_WR_CTRL__SHORT_FORMAT_MASK |
-                       RLC_SERDES_WR_CTRL__SRBM_OVERRIDE_MASK);
+               data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK |
+                         RLC_SERDES_WR_CTRL__READ_COMMAND_MASK |
+                         RLC_SERDES_WR_CTRL__P1_SELECT_MASK |
+                         RLC_SERDES_WR_CTRL__P2_SELECT_MASK |
+                         RLC_SERDES_WR_CTRL__RDDATA_RESET_MASK |
+                         RLC_SERDES_WR_CTRL__POWER_DOWN_MASK |
+                         RLC_SERDES_WR_CTRL__POWER_UP_MASK |
+                         RLC_SERDES_WR_CTRL__SHORT_FORMAT_MASK |
+                         RLC_SERDES_WR_CTRL__SRBM_OVERRIDE_MASK);
        else
                data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK |
                          RLC_SERDES_WR_CTRL__READ_COMMAND_MASK |
@@ -5461,10 +5619,10 @@ static void gfx_v8_0_send_serdes_cmd(struct amdgpu_device *adev,
 
 #define MSG_ENTER_RLC_SAFE_MODE     1
 #define MSG_EXIT_RLC_SAFE_MODE      0
-
-#define RLC_GPR_REG2__REQ_MASK           0x00000001
-#define RLC_GPR_REG2__MESSAGE__SHIFT     0x00000001
-#define RLC_GPR_REG2__MESSAGE_MASK       0x0000001e
+#define RLC_GPR_REG2__REQ_MASK 0x00000001
+#define RLC_GPR_REG2__REQ__SHIFT 0
+#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)
 {
@@ -5494,7 +5652,7 @@ static void cz_enter_rlc_safe_mode(struct amdgpu_device *adev)
                }
 
                for (i = 0; i < adev->usec_timeout; i++) {
-                       if ((RREG32(mmRLC_GPR_REG2) & RLC_GPR_REG2__REQ_MASK) == 0)
+                       if (!REG_GET_FIELD(RREG32(mmRLC_GPR_REG2), RLC_GPR_REG2, REQ))
                                break;
                        udelay(1);
                }
@@ -5522,7 +5680,7 @@ static void cz_exit_rlc_safe_mode(struct amdgpu_device *adev)
        }
 
        for (i = 0; i < adev->usec_timeout; i++) {
-               if ((RREG32(mmRLC_GPR_REG2) & RLC_GPR_REG2__REQ_MASK) == 0)
+               if (!REG_GET_FIELD(RREG32(mmRLC_GPR_REG2), RLC_GPR_REG2, REQ))
                        break;
                udelay(1);
        }
@@ -5554,7 +5712,7 @@ static void iceland_enter_rlc_safe_mode(struct amdgpu_device *adev)
                }
 
                for (i = 0; i < adev->usec_timeout; i++) {
-                       if ((RREG32(mmRLC_SAFE_MODE) & RLC_SAFE_MODE__CMD_MASK) == 0)
+                       if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
                                break;
                        udelay(1);
                }
@@ -5581,7 +5739,7 @@ static void iceland_exit_rlc_safe_mode(struct amdgpu_device *adev)
        }
 
        for (i = 0; i < adev->usec_timeout; i++) {
-               if ((RREG32(mmRLC_SAFE_MODE) & RLC_SAFE_MODE__CMD_MASK) == 0)
+               if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
                        break;
                udelay(1);
        }
@@ -5622,21 +5780,12 @@ static void gfx_v8_0_update_medium_grain_clock_gating(struct amdgpu_device *adev
        /* It is disabled by HW by default */
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
                if (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGLS) {
-                       if (adev->cg_flags & AMD_CG_SUPPORT_GFX_RLC_LS) {
+                       if (adev->cg_flags & AMD_CG_SUPPORT_GFX_RLC_LS)
                                /* 1 - RLC memory Light sleep */
-                               temp = data = RREG32(mmRLC_MEM_SLP_CNTL);
-                               data |= RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK;
-                               if (temp != data)
-                                       WREG32(mmRLC_MEM_SLP_CNTL, data);
-                       }
+                               WREG32_FIELD(RLC_MEM_SLP_CNTL, RLC_MEM_LS_EN, 1);
 
-                       if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CP_LS) {
-                               /* 2 - CP memory Light sleep */
-                               temp = data = RREG32(mmCP_MEM_SLP_CNTL);
-                               data |= CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
-                               if (temp != data)
-                                       WREG32(mmCP_MEM_SLP_CNTL, data);
-                       }
+                       if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CP_LS)
+                               WREG32_FIELD(CP_MEM_SLP_CNTL, CP_MEM_LS_EN, 1);
                }
 
                /* 3 - RLC_CGTT_MGCG_OVERRIDE */
@@ -5834,6 +5983,76 @@ static int gfx_v8_0_update_gfx_clock_gating(struct amdgpu_device *adev,
        return 0;
 }
 
+static int gfx_v8_0_tonga_update_gfx_clock_gating(struct amdgpu_device *adev,
+                                         enum amd_clockgating_state state)
+{
+       uint32_t msg_id, pp_state;
+       void *pp_handle = adev->powerplay.pp_handle;
+
+       if (state == AMD_CG_STATE_UNGATE)
+               pp_state = 0;
+       else
+               pp_state = PP_STATE_CG | PP_STATE_LS;
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
+                       PP_BLOCK_GFX_CG,
+                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                       pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
+                       PP_BLOCK_GFX_MG,
+                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                       pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       return 0;
+}
+
+static int gfx_v8_0_polaris_update_gfx_clock_gating(struct amdgpu_device *adev,
+                                         enum amd_clockgating_state state)
+{
+       uint32_t msg_id, pp_state;
+       void *pp_handle = adev->powerplay.pp_handle;
+
+       if (state == AMD_CG_STATE_UNGATE)
+               pp_state = 0;
+       else
+               pp_state = PP_STATE_CG | PP_STATE_LS;
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
+                       PP_BLOCK_GFX_CG,
+                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                       pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
+                       PP_BLOCK_GFX_3D,
+                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                       pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
+                       PP_BLOCK_GFX_MG,
+                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                       pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
+                       PP_BLOCK_GFX_RLC,
+                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                       pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
+                       PP_BLOCK_GFX_CP,
+                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                       pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       return 0;
+}
+
 static int gfx_v8_0_set_clockgating_state(void *handle,
                                          enum amd_clockgating_state state)
 {
@@ -5846,33 +6065,33 @@ static int gfx_v8_0_set_clockgating_state(void *handle,
                gfx_v8_0_update_gfx_clock_gating(adev,
                                                 state == AMD_CG_STATE_GATE ? true : false);
                break;
+       case CHIP_TONGA:
+               gfx_v8_0_tonga_update_gfx_clock_gating(adev, state);
+               break;
+       case CHIP_POLARIS10:
+       case CHIP_POLARIS11:
+               gfx_v8_0_polaris_update_gfx_clock_gating(adev, state);
+               break;
        default:
                break;
        }
        return 0;
 }
 
-static u32 gfx_v8_0_ring_get_rptr_gfx(struct amdgpu_ring *ring)
+static u32 gfx_v8_0_ring_get_rptr(struct amdgpu_ring *ring)
 {
-       u32 rptr;
-
-       rptr = ring->adev->wb.wb[ring->rptr_offs];
-
-       return rptr;
+       return ring->adev->wb.wb[ring->rptr_offs];
 }
 
 static u32 gfx_v8_0_ring_get_wptr_gfx(struct amdgpu_ring *ring)
 {
        struct amdgpu_device *adev = ring->adev;
-       u32 wptr;
 
        if (ring->use_doorbell)
                /* XXX check if swapping is necessary on BE */
-               wptr = ring->adev->wb.wb[ring->wptr_offs];
+               return ring->adev->wb.wb[ring->wptr_offs];
        else
-               wptr = RREG32(mmCP_RB0_WPTR);
-
-       return wptr;
+               return RREG32(mmCP_RB0_WPTR);
 }
 
 static void gfx_v8_0_ring_set_wptr_gfx(struct amdgpu_ring *ring)
@@ -5939,12 +6158,6 @@ static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
 {
        u32 header, control = 0;
 
-       /* insert SWITCH_BUFFER packet before first IB in the ring frame */
-       if (ctx_switch) {
-               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
-               amdgpu_ring_write(ring, 0);
-       }
-
        if (ib->flags & AMDGPU_IB_FLAG_CE)
                header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2);
        else
@@ -5971,9 +6184,9 @@ static void gfx_v8_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
        amdgpu_ring_write(ring,
 #ifdef __BIG_ENDIAN
-                                         (2 << 0) |
+                               (2 << 0) |
 #endif
-                                         (ib->gpu_addr & 0xFFFFFFFC));
+                               (ib->gpu_addr & 0xFFFFFFFC));
        amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
        amdgpu_ring_write(ring, control);
 }
@@ -6014,14 +6227,6 @@ static void gfx_v8_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
        amdgpu_ring_write(ring, seq);
        amdgpu_ring_write(ring, 0xffffffff);
        amdgpu_ring_write(ring, 4); /* poll interval */
-
-       if (usepfp) {
-               /* synce CE with ME to prevent CE fetch CEIB before context switch done */
-               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
-               amdgpu_ring_write(ring, 0);
-               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
-               amdgpu_ring_write(ring, 0);
-       }
 }
 
 static void gfx_v8_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
@@ -6029,6 +6234,10 @@ static void gfx_v8_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
 {
        int usepfp = (ring->type == AMDGPU_RING_TYPE_GFX);
 
+       /* GFX8 emits 128 dw nop to prevent DE do vm_flush before CE finish CEIB */
+       if (usepfp)
+               amdgpu_ring_insert_nop(ring, 128);
+
        amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
        amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
                                 WRITE_DATA_DST_SEL(0)) |
@@ -6068,18 +6277,11 @@ static void gfx_v8_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
                /* sync PFP to ME, otherwise we might get invalid PFP reads */
                amdgpu_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
                amdgpu_ring_write(ring, 0x0);
-               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
-               amdgpu_ring_write(ring, 0);
-               amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
-               amdgpu_ring_write(ring, 0);
+               /* GFX8 emits 128 dw nop to prevent CE access VM before vm_flush finish */
+               amdgpu_ring_insert_nop(ring, 128);
        }
 }
 
-static u32 gfx_v8_0_ring_get_rptr_compute(struct amdgpu_ring *ring)
-{
-       return ring->adev->wb.wb[ring->rptr_offs];
-}
-
 static u32 gfx_v8_0_ring_get_wptr_compute(struct amdgpu_ring *ring)
 {
        return ring->adev->wb.wb[ring->wptr_offs];
@@ -6115,36 +6317,88 @@ 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_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
-                                                enum amdgpu_interrupt_state state)
+static void gfx_v8_ring_emit_sb(struct amdgpu_ring *ring)
 {
-       u32 cp_int_cntl;
+       amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+       amdgpu_ring_write(ring, 0);
+}
 
-       switch (state) {
-       case AMDGPU_IRQ_STATE_DISABLE:
-               cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
-               cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
-                                           TIME_STAMP_INT_ENABLE, 0);
-               WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
-               break;
-       case AMDGPU_IRQ_STATE_ENABLE:
-               cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
-               cp_int_cntl =
-                       REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
-                                     TIME_STAMP_INT_ENABLE, 1);
-               WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
-               break;
-       default:
-               break;
+static void gfx_v8_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
+{
+       uint32_t dw2 = 0;
+
+       dw2 |= 0x80000000; /* set load_enable otherwise this package is just NOPs */
+       if (flags & AMDGPU_HAVE_CTX_SWITCH) {
+               /* set load_global_config & load_global_uconfig */
+               dw2 |= 0x8001;
+               /* set load_cs_sh_regs */
+               dw2 |= 0x01000000;
+               /* set load_per_context_state & load_gfx_sh_regs for GFX */
+               dw2 |= 0x10002;
+
+               /* set load_ce_ram if preamble presented */
+               if (AMDGPU_PREAMBLE_IB_PRESENT & flags)
+                       dw2 |= 0x10000000;
+       } else {
+               /* still load_ce_ram if this is the first time preamble presented
+                * although there is no context switch happens.
+                */
+               if (AMDGPU_PREAMBLE_IB_PRESENT_FIRST & flags)
+                       dw2 |= 0x10000000;
        }
+
+       amdgpu_ring_write(ring, PACKET3(PACKET3_CONTEXT_CONTROL, 1));
+       amdgpu_ring_write(ring, dw2);
+       amdgpu_ring_write(ring, 0);
+}
+
+static unsigned gfx_v8_0_ring_get_emit_ib_size_gfx(struct amdgpu_ring *ring)
+{
+       return
+               4; /* gfx_v8_0_ring_emit_ib_gfx */
+}
+
+static unsigned gfx_v8_0_ring_get_dma_frame_size_gfx(struct amdgpu_ring *ring)
+{
+       return
+               20 + /* gfx_v8_0_ring_emit_gds_switch */
+               7 + /* gfx_v8_0_ring_emit_hdp_flush */
+               5 + /* gfx_v8_0_ring_emit_hdp_invalidate */
+               6 + 6 + 6 +/* gfx_v8_0_ring_emit_fence_gfx x3 for user fence, vm fence */
+               7 + /* gfx_v8_0_ring_emit_pipeline_sync */
+               256 + 19 + /* gfx_v8_0_ring_emit_vm_flush */
+               2 + /* gfx_v8_ring_emit_sb */
+               3; /* gfx_v8_ring_emit_cntxcntl */
+}
+
+static unsigned gfx_v8_0_ring_get_emit_ib_size_compute(struct amdgpu_ring *ring)
+{
+       return
+               4; /* gfx_v8_0_ring_emit_ib_compute */
+}
+
+static unsigned gfx_v8_0_ring_get_dma_frame_size_compute(struct amdgpu_ring *ring)
+{
+       return
+               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_compute x3 for user fence, vm fence */
+}
+
+static void gfx_v8_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
+                                                enum amdgpu_interrupt_state state)
+{
+       WREG32_FIELD(CP_INT_CNTL_RING0, TIME_STAMP_INT_ENABLE,
+                    state == AMDGPU_IRQ_STATE_DISABLE ? 0 : 1);
 }
 
 static void gfx_v8_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev,
                                                     int me, int pipe,
                                                     enum amdgpu_interrupt_state state)
 {
-       u32 mec_int_cntl, mec_int_cntl_reg;
-
        /*
         * amdgpu controls only pipe 0 of MEC1. That's why this function only
         * handles the setting of interrupts for this specific pipe. All other
@@ -6154,7 +6408,6 @@ static void gfx_v8_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev,
        if (me == 1) {
                switch (pipe) {
                case 0:
-                       mec_int_cntl_reg = mmCP_ME1_PIPE0_INT_CNTL;
                        break;
                default:
                        DRM_DEBUG("invalid pipe %d\n", pipe);
@@ -6165,22 +6418,8 @@ static void gfx_v8_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev,
                return;
        }
 
-       switch (state) {
-       case AMDGPU_IRQ_STATE_DISABLE:
-               mec_int_cntl = RREG32(mec_int_cntl_reg);
-               mec_int_cntl = REG_SET_FIELD(mec_int_cntl, CP_ME1_PIPE0_INT_CNTL,
-                                            TIME_STAMP_INT_ENABLE, 0);
-               WREG32(mec_int_cntl_reg, mec_int_cntl);
-               break;
-       case AMDGPU_IRQ_STATE_ENABLE:
-               mec_int_cntl = RREG32(mec_int_cntl_reg);
-               mec_int_cntl = REG_SET_FIELD(mec_int_cntl, CP_ME1_PIPE0_INT_CNTL,
-                                            TIME_STAMP_INT_ENABLE, 1);
-               WREG32(mec_int_cntl_reg, mec_int_cntl);
-               break;
-       default:
-               break;
-       }
+       WREG32_FIELD(CP_ME1_PIPE0_INT_CNTL, TIME_STAMP_INT_ENABLE,
+                    state == AMDGPU_IRQ_STATE_DISABLE ? 0 : 1);
 }
 
 static int gfx_v8_0_set_priv_reg_fault_state(struct amdgpu_device *adev,
@@ -6188,24 +6427,8 @@ static int gfx_v8_0_set_priv_reg_fault_state(struct amdgpu_device *adev,
                                             unsigned type,
                                             enum amdgpu_interrupt_state state)
 {
-       u32 cp_int_cntl;
-
-       switch (state) {
-       case AMDGPU_IRQ_STATE_DISABLE:
-               cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
-               cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
-                                           PRIV_REG_INT_ENABLE, 0);
-               WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
-               break;
-       case AMDGPU_IRQ_STATE_ENABLE:
-               cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
-               cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
-                                           PRIV_REG_INT_ENABLE, 1);
-               WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
-               break;
-       default:
-               break;
-       }
+       WREG32_FIELD(CP_INT_CNTL_RING0, PRIV_REG_INT_ENABLE,
+                    state == AMDGPU_IRQ_STATE_DISABLE ? 0 : 1);
 
        return 0;
 }
@@ -6215,24 +6438,8 @@ static int gfx_v8_0_set_priv_inst_fault_state(struct amdgpu_device *adev,
                                              unsigned type,
                                              enum amdgpu_interrupt_state state)
 {
-       u32 cp_int_cntl;
-
-       switch (state) {
-       case AMDGPU_IRQ_STATE_DISABLE:
-               cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
-               cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
-                                           PRIV_INSTR_INT_ENABLE, 0);
-               WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
-               break;
-       case AMDGPU_IRQ_STATE_ENABLE:
-               cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
-               cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
-                                           PRIV_INSTR_INT_ENABLE, 1);
-               WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
-               break;
-       default:
-               break;
-       }
+       WREG32_FIELD(CP_INT_CNTL_RING0, PRIV_INSTR_INT_ENABLE,
+                    state == AMDGPU_IRQ_STATE_DISABLE ? 0 : 1);
 
        return 0;
 }
@@ -6338,13 +6545,16 @@ const struct amd_ip_funcs gfx_v8_0_ip_funcs = {
        .resume = gfx_v8_0_resume,
        .is_idle = gfx_v8_0_is_idle,
        .wait_for_idle = gfx_v8_0_wait_for_idle,
+       .check_soft_reset = gfx_v8_0_check_soft_reset,
+       .pre_soft_reset = gfx_v8_0_pre_soft_reset,
        .soft_reset = gfx_v8_0_soft_reset,
+       .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,
 };
 
 static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {
-       .get_rptr = gfx_v8_0_ring_get_rptr_gfx,
+       .get_rptr = gfx_v8_0_ring_get_rptr,
        .get_wptr = gfx_v8_0_ring_get_wptr_gfx,
        .set_wptr = gfx_v8_0_ring_set_wptr_gfx,
        .parse_cs = NULL,
@@ -6359,10 +6569,14 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {
        .test_ib = gfx_v8_0_ring_test_ib,
        .insert_nop = amdgpu_ring_insert_nop,
        .pad_ib = amdgpu_ring_generic_pad_ib,
+       .emit_switch_buffer = gfx_v8_ring_emit_sb,
+       .emit_cntxcntl = gfx_v8_ring_emit_cntxcntl,
+       .get_emit_ib_size = gfx_v8_0_ring_get_emit_ib_size_gfx,
+       .get_dma_frame_size = gfx_v8_0_ring_get_dma_frame_size_gfx,
 };
 
 static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {
-       .get_rptr = gfx_v8_0_ring_get_rptr_compute,
+       .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,
        .parse_cs = NULL,
@@ -6377,6 +6591,8 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {
        .test_ib = gfx_v8_0_ring_test_ib,
        .insert_nop = amdgpu_ring_insert_nop,
        .pad_ib = amdgpu_ring_generic_pad_ib,
+       .get_emit_ib_size = gfx_v8_0_ring_get_emit_ib_size_compute,
+       .get_dma_frame_size = gfx_v8_0_ring_get_dma_frame_size_compute,
 };
 
 static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev)
@@ -6479,15 +6695,12 @@ static u32 gfx_v8_0_get_cu_active_bitmap(struct amdgpu_device *adev)
 {
        u32 data, mask;
 
-       data = RREG32(mmCC_GC_SHADER_ARRAY_CONFIG);
-       data |= RREG32(mmGC_USER_SHADER_ARRAY_CONFIG);
-
-       data &= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_CUS_MASK;
-       data >>= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_CUS__SHIFT;
+       data =  RREG32(mmCC_GC_SHADER_ARRAY_CONFIG) |
+               RREG32(mmGC_USER_SHADER_ARRAY_CONFIG);
 
        mask = gfx_v8_0_create_bitmask(adev->gfx.config.max_cu_per_sh);
 
-       return (~data) & mask;
+       return ~REG_GET_FIELD(data, CC_GC_SHADER_ARRAY_CONFIG, INACTIVE_CUS) & mask;
 }
 
 static void gfx_v8_0_get_cu_info(struct amdgpu_device *adev)
index bc82c79..ebed1f8 100644 (file)
@@ -26,6 +26,4 @@
 
 extern const struct amd_ip_funcs gfx_v8_0_ip_funcs;
 
-void gfx_v8_0_select_se_sh(struct amdgpu_device *adev, u32 se_num, u32 sh_num);
-
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
new file mode 100644 (file)
index 0000000..b13c8aa
--- /dev/null
@@ -0,0 +1,1071 @@
+
+/*
+ * 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 "gmc_v6_0.h"
+#include "amdgpu_ucode.h"
+#include "si/sid.h"
+
+static void gmc_v6_0_set_gart_funcs(struct amdgpu_device *adev);
+static void gmc_v6_0_set_irq_funcs(struct amdgpu_device *adev);
+static int gmc_v6_0_wait_for_idle(void *handle);
+
+MODULE_FIRMWARE("radeon/tahiti_mc.bin");
+MODULE_FIRMWARE("radeon/pitcairn_mc.bin");
+MODULE_FIRMWARE("radeon/verde_mc.bin");
+MODULE_FIRMWARE("radeon/oland_mc.bin");
+
+static const u32 crtc_offsets[6] =
+{
+       SI_CRTC0_REGISTER_OFFSET,
+       SI_CRTC1_REGISTER_OFFSET,
+       SI_CRTC2_REGISTER_OFFSET,
+       SI_CRTC3_REGISTER_OFFSET,
+       SI_CRTC4_REGISTER_OFFSET,
+       SI_CRTC5_REGISTER_OFFSET
+};
+
+static void gmc_v6_0_mc_stop(struct amdgpu_device *adev,
+                            struct amdgpu_mode_mc_save *save)
+{
+       u32 blackout;
+
+       if (adev->mode_info.num_crtc)
+               amdgpu_display_stop_mc_access(adev, save);
+
+       gmc_v6_0_wait_for_idle((void *)adev);
+
+       blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
+       if (REG_GET_FIELD(blackout, mmMC_SHARED_BLACKOUT_CNTL, xxBLACKOUT_MODE) != 1) {
+               /* Block CPU access */
+               WREG32(BIF_FB_EN, 0);
+               /* blackout the MC */
+               blackout = REG_SET_FIELD(blackout,
+                                        mmMC_SHARED_BLACKOUT_CNTL, xxBLACKOUT_MODE, 0);
+               WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
+       }
+       /* wait for the MC to settle */
+       udelay(100);
+
+}
+
+static void gmc_v6_0_mc_resume(struct amdgpu_device *adev,
+                              struct amdgpu_mode_mc_save *save)
+{
+       u32 tmp;
+
+       /* unblackout the MC */
+       tmp = RREG32(MC_SHARED_BLACKOUT_CNTL);
+       tmp = REG_SET_FIELD(tmp, mmMC_SHARED_BLACKOUT_CNTL, xxBLACKOUT_MODE, 0);
+       WREG32(MC_SHARED_BLACKOUT_CNTL, tmp);
+       /* allow CPU access */
+       tmp = REG_SET_FIELD(0, mmBIF_FB_EN, xxFB_READ_EN, 1);
+       tmp = REG_SET_FIELD(tmp, mmBIF_FB_EN, xxFB_WRITE_EN, 1);
+       WREG32(BIF_FB_EN, tmp);
+
+       if (adev->mode_info.num_crtc)
+               amdgpu_display_resume_mc_access(adev, save);
+
+}
+
+static int gmc_v6_0_init_microcode(struct amdgpu_device *adev)
+{
+       const char *chip_name;
+       char fw_name[30];
+       int err;
+
+       DRM_DEBUG("\n");
+
+       switch (adev->asic_type) {
+       case CHIP_TAHITI:
+               chip_name = "tahiti";
+               break;
+       case CHIP_PITCAIRN:
+               chip_name = "pitcairn";
+               break;
+       case CHIP_VERDE:
+               chip_name = "verde";
+               break;
+       case CHIP_OLAND:
+               chip_name = "oland";
+               break;
+       case CHIP_HAINAN:
+               chip_name = "hainan";
+               break;
+       default: BUG();
+       }
+
+       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;
+
+       err = amdgpu_ucode_validate(adev->mc.fw);
+
+out:
+       if (err) {
+               dev_err(adev->dev,
+                      "si_mc: Failed to load firmware \"%s\"\n",
+                      fw_name);
+               release_firmware(adev->mc.fw);
+               adev->mc.fw = NULL;
+       }
+       return err;
+}
+
+static int gmc_v6_0_mc_load_microcode(struct amdgpu_device *adev)
+{
+       const __le32 *new_fw_data = NULL;
+       u32 running;
+       const __le32 *new_io_mc_regs = NULL;
+       int i, regs_size, ucode_size;
+       const struct mc_firmware_header_v1_0 *hdr;
+
+       if (!adev->mc.fw)
+               return -EINVAL;
+
+       hdr = (const struct mc_firmware_header_v1_0 *)adev->mc.fw->data;
+
+       amdgpu_ucode_print_mc_hdr(&hdr->header);
+
+       adev->mc.fw_version = le32_to_cpu(hdr->header.ucode_version);
+       regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2);
+       new_io_mc_regs = (const __le32 *)
+               (adev->mc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes));
+       ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
+       new_fw_data = (const __le32 *)
+               (adev->mc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+
+       running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
+
+       if (running == 0) {
+
+               /* reset the engine and set to writable */
+               WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+               WREG32(MC_SEQ_SUP_CNTL, 0x00000010);
+
+               /* load mc io regs */
+               for (i = 0; i < regs_size; i++) {
+                       WREG32(MC_SEQ_IO_DEBUG_INDEX, le32_to_cpup(new_io_mc_regs++));
+                       WREG32(MC_SEQ_IO_DEBUG_DATA, le32_to_cpup(new_io_mc_regs++));
+               }
+               /* load the MC ucode */
+               for (i = 0; i < ucode_size; i++) {
+                       WREG32(MC_SEQ_SUP_PGM, le32_to_cpup(new_fw_data++));
+               }
+
+               /* put the engine back into the active state */
+               WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+               WREG32(MC_SEQ_SUP_CNTL, 0x00000004);
+               WREG32(MC_SEQ_SUP_CNTL, 0x00000001);
+
+               /* wait for training to complete */
+               for (i = 0; i < adev->usec_timeout; i++) {
+                       if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D0)
+                               break;
+                       udelay(1);
+               }
+               for (i = 0; i < adev->usec_timeout; i++) {
+                       if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D1)
+                               break;
+                       udelay(1);
+               }
+
+       }
+
+       return 0;
+}
+
+static void gmc_v6_0_vram_gtt_location(struct amdgpu_device *adev,
+                                      struct amdgpu_mc *mc)
+{
+       if (mc->mc_vram_size > 0xFFC0000000ULL) {
+               dev_warn(adev->dev, "limiting VRAM\n");
+               mc->real_vram_size = 0xFFC0000000ULL;
+               mc->mc_vram_size = 0xFFC0000000ULL;
+       }
+       amdgpu_vram_location(adev, &adev->mc, 0);
+       adev->mc.gtt_base_align = 0;
+       amdgpu_gtt_location(adev, mc);
+}
+
+static void gmc_v6_0_mc_program(struct amdgpu_device *adev)
+{
+       struct amdgpu_mode_mc_save save;
+       u32 tmp;
+       int i, j;
+
+       /* Initialize HDP */
+       for (i = 0, j = 0; i < 32; i++, j += 0x6) {
+               WREG32((0xb05 + j), 0x00000000);
+               WREG32((0xb06 + j), 0x00000000);
+               WREG32((0xb07 + j), 0x00000000);
+               WREG32((0xb08 + j), 0x00000000);
+               WREG32((0xb09 + j), 0x00000000);
+       }
+       WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
+
+       gmc_v6_0_mc_stop(adev, &save);
+
+       if (gmc_v6_0_wait_for_idle((void *)adev)) {
+               dev_warn(adev->dev, "Wait for MC idle timedout !\n");
+       }
+
+       WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
+       /* Update configuration */
+       WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+              adev->mc.vram_start >> 12);
+       WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+              adev->mc.vram_end >> 12);
+       WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR,
+              adev->vram_scratch.gpu_addr >> 12);
+       tmp = ((adev->mc.vram_end >> 24) & 0xFFFF) << 16;
+       tmp |= ((adev->mc.vram_start >> 24) & 0xFFFF);
+       WREG32(MC_VM_FB_LOCATION, tmp);
+       /* XXX double check these! */
+       WREG32(HDP_NONSURFACE_BASE, (adev->mc.vram_start >> 8));
+       WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30));
+       WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF);
+       WREG32(MC_VM_AGP_BASE, 0);
+       WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF);
+       WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF);
+
+       if (gmc_v6_0_wait_for_idle((void *)adev)) {
+               dev_warn(adev->dev, "Wait for MC idle timedout !\n");
+       }
+       gmc_v6_0_mc_resume(adev, &save);
+       amdgpu_display_set_vga_render_state(adev, false);
+}
+
+static int gmc_v6_0_mc_init(struct amdgpu_device *adev)
+{
+
+       u32 tmp;
+       int chansize, numchan;
+
+       tmp = RREG32(MC_ARB_RAMCFG);
+       if (tmp & CHANSIZE_OVERRIDE) {
+               chansize = 16;
+       } else if (tmp & CHANSIZE_MASK) {
+               chansize = 64;
+       } else {
+               chansize = 32;
+       }
+       tmp = RREG32(MC_SHARED_CHMAP);
+       switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+       case 0:
+       default:
+               numchan = 1;
+               break;
+       case 1:
+               numchan = 2;
+               break;
+       case 2:
+               numchan = 4;
+               break;
+       case 3:
+               numchan = 8;
+               break;
+       case 4:
+               numchan = 3;
+               break;
+       case 5:
+               numchan = 6;
+               break;
+       case 6:
+               numchan = 10;
+               break;
+       case 7:
+               numchan = 12;
+               break;
+       case 8:
+               numchan = 16;
+               break;
+       }
+       adev->mc.vram_width = numchan * chansize;
+       /* Could aper size report 0 ? */
+       adev->mc.aper_base = pci_resource_start(adev->pdev, 0);
+       adev->mc.aper_size = pci_resource_len(adev->pdev, 0);
+       /* size in MB on si */
+       adev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
+       adev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
+       adev->mc.visible_vram_size = adev->mc.aper_size;
+
+       /* unless the user had overridden it, set the gart
+        * size equal to the 1024 or vram, whichever is larger.
+        */
+       if (amdgpu_gart_size == -1)
+               adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev);
+       else
+               adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
+
+       gmc_v6_0_vram_gtt_location(adev, &adev->mc);
+
+       return 0;
+}
+
+static void gmc_v6_0_gart_flush_gpu_tlb(struct amdgpu_device *adev,
+                                       uint32_t vmid)
+{
+       WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0);
+
+       WREG32(VM_INVALIDATE_REQUEST, 1 << vmid);
+}
+
+static int gmc_v6_0_gart_set_pte_pde(struct amdgpu_device *adev,
+                                    void *cpu_pt_addr,
+                                    uint32_t gpu_page_idx,
+                                    uint64_t addr,
+                                    uint32_t flags)
+{
+       void __iomem *ptr = (void *)cpu_pt_addr;
+       uint64_t value;
+
+       value = addr & 0xFFFFFFFFFFFFF000ULL;
+       value |= flags;
+       writeq(value, ptr + (gpu_page_idx * 8));
+
+       return 0;
+}
+
+static void gmc_v6_0_set_fault_enable_default(struct amdgpu_device *adev,
+                                             bool value)
+{
+       u32 tmp;
+
+       tmp = RREG32(VM_CONTEXT1_CNTL);
+       tmp = REG_SET_FIELD(tmp, mmVM_CONTEXT1_CNTL,
+                           xxRANGE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
+       tmp = REG_SET_FIELD(tmp, mmVM_CONTEXT1_CNTL,
+                           xxDUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
+       tmp = REG_SET_FIELD(tmp, mmVM_CONTEXT1_CNTL,
+                           xxPDE0_PROTECTION_FAULT_ENABLE_DEFAULT, value);
+       tmp = REG_SET_FIELD(tmp, mmVM_CONTEXT1_CNTL,
+                           xxVALID_PROTECTION_FAULT_ENABLE_DEFAULT, value);
+       tmp = REG_SET_FIELD(tmp, mmVM_CONTEXT1_CNTL,
+                           xxREAD_PROTECTION_FAULT_ENABLE_DEFAULT, value);
+       tmp = REG_SET_FIELD(tmp, mmVM_CONTEXT1_CNTL,
+                           xxWRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
+       WREG32(VM_CONTEXT1_CNTL, tmp);
+}
+
+static int gmc_v6_0_gart_enable(struct amdgpu_device *adev)
+{
+       int r, i;
+
+       if (adev->gart.robj == NULL) {
+               dev_err(adev->dev, "No VRAM object for PCIE GART.\n");
+               return -EINVAL;
+       }
+       r = amdgpu_gart_table_vram_pin(adev);
+       if (r)
+               return r;
+       /* Setup TLB control */
+       WREG32(MC_VM_MX_L1_TLB_CNTL,
+              (0xA << 7) |
+              ENABLE_L1_TLB |
+              ENABLE_L1_FRAGMENT_PROCESSING |
+              SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+              ENABLE_ADVANCED_DRIVER_MODEL |
+              SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+       /* Setup L2 cache */
+       WREG32(VM_L2_CNTL, ENABLE_L2_CACHE |
+              ENABLE_L2_FRAGMENT_PROCESSING |
+              ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+              ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+              EFFECTIVE_L2_QUEUE_SIZE(7) |
+              CONTEXT1_IDENTITY_ACCESS_MODE(1));
+       WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);
+       WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+              BANK_SELECT(4) |
+              L2_CACHE_BIGK_FRAGMENT_SIZE(4));
+       /* setup context0 */
+       WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gtt_start >> 12);
+       WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gtt_end >> 12);
+       WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12);
+       WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
+                       (u32)(adev->dummy_page.addr >> 12));
+       WREG32(VM_CONTEXT0_CNTL2, 0);
+       WREG32(VM_CONTEXT0_CNTL, (ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
+                                 RANGE_PROTECTION_FAULT_ENABLE_DEFAULT));
+
+       WREG32(0x575, 0);
+       WREG32(0x576, 0);
+       WREG32(0x577, 0);
+
+       /* empty context1-15 */
+       /* set vm size, must be a multiple of 4 */
+       WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
+       WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, adev->vm_manager.max_pfn - 1);
+       /* Assign the pt base to something valid for now; the pts used for
+        * the VMs are determined by the application and setup and assigned
+        * on the fly in the vm part of radeon_gart.c
+        */
+       for (i = 1; i < 16; i++) {
+               if (i < 8)
+                       WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + i,
+                              adev->gart.table_addr >> 12);
+               else
+                       WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + i - 8,
+                              adev->gart.table_addr >> 12);
+       }
+
+       /* enable context1-15 */
+       WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
+              (u32)(adev->dummy_page.addr >> 12));
+       WREG32(VM_CONTEXT1_CNTL2, 4);
+       WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
+                               PAGE_TABLE_BLOCK_SIZE(amdgpu_vm_block_size - 9) |
+                               RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+                               RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |
+                               DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+                               DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT |
+                               PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT |
+                               PDE0_PROTECTION_FAULT_ENABLE_DEFAULT |
+                               VALID_PROTECTION_FAULT_ENABLE_INTERRUPT |
+                               VALID_PROTECTION_FAULT_ENABLE_DEFAULT |
+                               READ_PROTECTION_FAULT_ENABLE_INTERRUPT |
+                               READ_PROTECTION_FAULT_ENABLE_DEFAULT |
+                               WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+                               WRITE_PROTECTION_FAULT_ENABLE_DEFAULT);
+
+       gmc_v6_0_gart_flush_gpu_tlb(adev, 0);
+       dev_info(adev->dev, "PCIE GART of %uM enabled (table at 0x%016llX).\n",
+                (unsigned)(adev->mc.gtt_size >> 20),
+                (unsigned long long)adev->gart.table_addr);
+       adev->gart.ready = true;
+       return 0;
+}
+
+static int gmc_v6_0_gart_init(struct amdgpu_device *adev)
+{
+       int r;
+
+       if (adev->gart.robj) {
+               dev_warn(adev->dev, "gmc_v6_0 PCIE GART already initialized\n");
+               return 0;
+       }
+       r = amdgpu_gart_init(adev);
+       if (r)
+               return r;
+       adev->gart.table_size = adev->gart.num_gpu_pages * 8;
+       return amdgpu_gart_table_vram_alloc(adev);
+}
+
+static void gmc_v6_0_gart_disable(struct amdgpu_device *adev)
+{
+       /*unsigned i;
+
+       for (i = 1; i < 16; ++i) {
+               uint32_t reg;
+               if (i < 8)
+                       reg = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + i ;
+               else
+                       reg = VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + (i - 8);
+               adev->vm_manager.saved_table_addr[i] = RREG32(reg);
+       }*/
+
+       /* Disable all tables */
+       WREG32(VM_CONTEXT0_CNTL, 0);
+       WREG32(VM_CONTEXT1_CNTL, 0);
+       /* Setup TLB control */
+       WREG32(MC_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+              SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+       /* Setup L2 cache */
+       WREG32(VM_L2_CNTL, ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+              ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+              EFFECTIVE_L2_QUEUE_SIZE(7) |
+              CONTEXT1_IDENTITY_ACCESS_MODE(1));
+       WREG32(VM_L2_CNTL2, 0);
+       WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+              L2_CACHE_BIGK_FRAGMENT_SIZE(0));
+       amdgpu_gart_table_vram_unpin(adev);
+}
+
+static void gmc_v6_0_gart_fini(struct amdgpu_device *adev)
+{
+       amdgpu_gart_table_vram_free(adev);
+       amdgpu_gart_fini(adev);
+}
+
+static int gmc_v6_0_vm_init(struct amdgpu_device *adev)
+{
+       /*
+        * number of VMs
+        * VMID 0 is reserved for System
+        * amdgpu graphics/compute will use VMIDs 1-7
+        * amdkfd will use VMIDs 8-15
+        */
+       adev->vm_manager.num_ids = AMDGPU_NUM_OF_VMIDS;
+       amdgpu_vm_manager_init(adev);
+
+       /* base offset of vram pages */
+       if (adev->flags & AMD_IS_APU) {
+               u64 tmp = RREG32(MC_VM_FB_OFFSET);
+               tmp <<= 22;
+               adev->vm_manager.vram_base_offset = tmp;
+       } else
+               adev->vm_manager.vram_base_offset = 0;
+
+       return 0;
+}
+
+static void gmc_v6_0_vm_fini(struct amdgpu_device *adev)
+{
+}
+
+static void gmc_v6_0_vm_decode_fault(struct amdgpu_device *adev,
+                                    u32 status, u32 addr, u32 mc_client)
+{
+       u32 mc_id;
+       u32 vmid = REG_GET_FIELD(status, mmVM_CONTEXT1_PROTECTION_FAULT_STATUS, xxVMID);
+       u32 protections = REG_GET_FIELD(status, mmVM_CONTEXT1_PROTECTION_FAULT_STATUS,
+                                       xxPROTECTIONS);
+       char block[5] = { mc_client >> 24, (mc_client >> 16) & 0xff,
+               (mc_client >> 8) & 0xff, mc_client & 0xff, 0 };
+
+       mc_id = REG_GET_FIELD(status, mmVM_CONTEXT1_PROTECTION_FAULT_STATUS,
+                             xxMEMORY_CLIENT_ID);
+
+       dev_err(adev->dev, "VM fault (0x%02x, vmid %d) at page %u, %s from '%s' (0x%08x) (%d)\n",
+              protections, vmid, addr,
+              REG_GET_FIELD(status, mmVM_CONTEXT1_PROTECTION_FAULT_STATUS,
+                            xxMEMORY_CLIENT_RW) ?
+              "write" : "read", block, mc_client, mc_id);
+}
+
+/*
+static const u32 mc_cg_registers[] = {
+       MC_HUB_MISC_HUB_CG,
+       MC_HUB_MISC_SIP_CG,
+       MC_HUB_MISC_VM_CG,
+       MC_XPB_CLK_GAT,
+       ATC_MISC_CG,
+       MC_CITF_MISC_WR_CG,
+       MC_CITF_MISC_RD_CG,
+       MC_CITF_MISC_VM_CG,
+       VM_L2_CG,
+};
+
+static const u32 mc_cg_ls_en[] = {
+       MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK,
+       MC_HUB_MISC_SIP_CG__MEM_LS_ENABLE_MASK,
+       MC_HUB_MISC_VM_CG__MEM_LS_ENABLE_MASK,
+       MC_XPB_CLK_GAT__MEM_LS_ENABLE_MASK,
+       ATC_MISC_CG__MEM_LS_ENABLE_MASK,
+       MC_CITF_MISC_WR_CG__MEM_LS_ENABLE_MASK,
+       MC_CITF_MISC_RD_CG__MEM_LS_ENABLE_MASK,
+       MC_CITF_MISC_VM_CG__MEM_LS_ENABLE_MASK,
+       VM_L2_CG__MEM_LS_ENABLE_MASK,
+};
+
+static const u32 mc_cg_en[] = {
+       MC_HUB_MISC_HUB_CG__ENABLE_MASK,
+       MC_HUB_MISC_SIP_CG__ENABLE_MASK,
+       MC_HUB_MISC_VM_CG__ENABLE_MASK,
+       MC_XPB_CLK_GAT__ENABLE_MASK,
+       ATC_MISC_CG__ENABLE_MASK,
+       MC_CITF_MISC_WR_CG__ENABLE_MASK,
+       MC_CITF_MISC_RD_CG__ENABLE_MASK,
+       MC_CITF_MISC_VM_CG__ENABLE_MASK,
+       VM_L2_CG__ENABLE_MASK,
+};
+
+static void gmc_v6_0_enable_mc_ls(struct amdgpu_device *adev,
+                                 bool enable)
+{
+       int i;
+       u32 orig, data;
+
+       for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) {
+               orig = data = RREG32(mc_cg_registers[i]);
+               if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_MC_LS))
+                       data |= mc_cg_ls_en[i];
+               else
+                       data &= ~mc_cg_ls_en[i];
+               if (data != orig)
+                       WREG32(mc_cg_registers[i], data);
+       }
+}
+
+static void gmc_v6_0_enable_mc_mgcg(struct amdgpu_device *adev,
+                                   bool enable)
+{
+       int i;
+       u32 orig, data;
+
+       for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) {
+               orig = data = RREG32(mc_cg_registers[i]);
+               if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_MC_MGCG))
+                       data |= mc_cg_en[i];
+               else
+                       data &= ~mc_cg_en[i];
+               if (data != orig)
+                       WREG32(mc_cg_registers[i], data);
+       }
+}
+
+static void gmc_v6_0_enable_bif_mgls(struct amdgpu_device *adev,
+                                    bool enable)
+{
+       u32 orig, data;
+
+       orig = data = RREG32_PCIE(ixPCIE_CNTL2);
+
+       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_BIF_LS)) {
+               data = REG_SET_FIELD(data, PCIE_CNTL2, SLV_MEM_LS_EN, 1);
+               data = REG_SET_FIELD(data, PCIE_CNTL2, MST_MEM_LS_EN, 1);
+               data = REG_SET_FIELD(data, PCIE_CNTL2, REPLAY_MEM_LS_EN, 1);
+               data = REG_SET_FIELD(data, PCIE_CNTL2, SLV_MEM_AGGRESSIVE_LS_EN, 1);
+       } else {
+               data = REG_SET_FIELD(data, PCIE_CNTL2, SLV_MEM_LS_EN, 0);
+               data = REG_SET_FIELD(data, PCIE_CNTL2, MST_MEM_LS_EN, 0);
+               data = REG_SET_FIELD(data, PCIE_CNTL2, REPLAY_MEM_LS_EN, 0);
+               data = REG_SET_FIELD(data, PCIE_CNTL2, SLV_MEM_AGGRESSIVE_LS_EN, 0);
+       }
+
+       if (orig != data)
+               WREG32_PCIE(ixPCIE_CNTL2, data);
+}
+
+static void gmc_v6_0_enable_hdp_mgcg(struct amdgpu_device *adev,
+                                    bool enable)
+{
+       u32 orig, data;
+
+       orig = data = RREG32(HDP_HOST_PATH_CNTL);
+
+       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_HDP_MGCG))
+               data = REG_SET_FIELD(data, HDP_HOST_PATH_CNTL, CLOCK_GATING_DIS, 0);
+       else
+               data = REG_SET_FIELD(data, HDP_HOST_PATH_CNTL, CLOCK_GATING_DIS, 1);
+
+       if (orig != data)
+               WREG32(HDP_HOST_PATH_CNTL, data);
+}
+
+static void gmc_v6_0_enable_hdp_ls(struct amdgpu_device *adev,
+                                  bool enable)
+{
+       u32 orig, data;
+
+       orig = data = RREG32(HDP_MEM_POWER_LS);
+
+       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_HDP_LS))
+               data = REG_SET_FIELD(data, HDP_MEM_POWER_LS, LS_ENABLE, 1);
+       else
+               data = REG_SET_FIELD(data, HDP_MEM_POWER_LS, LS_ENABLE, 0);
+
+       if (orig != data)
+               WREG32(HDP_MEM_POWER_LS, data);
+}
+*/
+
+static int gmc_v6_0_convert_vram_type(int mc_seq_vram_type)
+{
+       switch (mc_seq_vram_type) {
+       case MC_SEQ_MISC0__MT__GDDR1:
+               return AMDGPU_VRAM_TYPE_GDDR1;
+       case MC_SEQ_MISC0__MT__DDR2:
+               return AMDGPU_VRAM_TYPE_DDR2;
+       case MC_SEQ_MISC0__MT__GDDR3:
+               return AMDGPU_VRAM_TYPE_GDDR3;
+       case MC_SEQ_MISC0__MT__GDDR4:
+               return AMDGPU_VRAM_TYPE_GDDR4;
+       case MC_SEQ_MISC0__MT__GDDR5:
+               return AMDGPU_VRAM_TYPE_GDDR5;
+       case MC_SEQ_MISC0__MT__DDR3:
+               return AMDGPU_VRAM_TYPE_DDR3;
+       default:
+               return AMDGPU_VRAM_TYPE_UNKNOWN;
+       }
+}
+
+static int gmc_v6_0_early_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       gmc_v6_0_set_gart_funcs(adev);
+       gmc_v6_0_set_irq_funcs(adev);
+
+       if (adev->flags & AMD_IS_APU) {
+               adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
+       } else {
+               u32 tmp = RREG32(MC_SEQ_MISC0);
+               tmp &= MC_SEQ_MISC0__MT__MASK;
+               adev->mc.vram_type = gmc_v6_0_convert_vram_type(tmp);
+       }
+
+       return 0;
+}
+
+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);
+}
+
+static int gmc_v6_0_sw_init(void *handle)
+{
+       int r;
+       int dma_bits;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       r = amdgpu_irq_add_id(adev, 146, &adev->mc.vm_fault);
+       if (r)
+               return r;
+
+       r = amdgpu_irq_add_id(adev, 147, &adev->mc.vm_fault);
+       if (r)
+               return r;
+
+       adev->vm_manager.max_pfn = amdgpu_vm_size << 18;
+
+       adev->mc.mc_mask = 0xffffffffffULL;
+
+       adev->need_dma32 = false;
+       dma_bits = adev->need_dma32 ? 32 : 40;
+       r = pci_set_dma_mask(adev->pdev, DMA_BIT_MASK(dma_bits));
+       if (r) {
+               adev->need_dma32 = true;
+               dma_bits = 32;
+               dev_warn(adev->dev, "amdgpu: No suitable DMA available.\n");
+       }
+       r = pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(dma_bits));
+       if (r) {
+               pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32));
+               dev_warn(adev->dev, "amdgpu: No coherent DMA available.\n");
+       }
+
+       r = gmc_v6_0_init_microcode(adev);
+       if (r) {
+               dev_err(adev->dev, "Failed to load mc firmware!\n");
+               return r;
+       }
+
+       r = amdgpu_ttm_global_init(adev);
+       if (r) {
+               return r;
+       }
+
+       r = gmc_v6_0_mc_init(adev);
+       if (r)
+               return r;
+
+       r = amdgpu_bo_init(adev);
+       if (r)
+               return r;
+
+       r = gmc_v6_0_gart_init(adev);
+       if (r)
+               return r;
+
+       if (!adev->vm_manager.enabled) {
+               r = gmc_v6_0_vm_init(adev);
+               if (r) {
+                       dev_err(adev->dev, "vm manager initialization failed (%d).\n", r);
+                       return r;
+               }
+               adev->vm_manager.enabled = true;
+       }
+
+       return r;
+}
+
+static int gmc_v6_0_sw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (adev->vm_manager.enabled) {
+               gmc_v6_0_vm_fini(adev);
+               adev->vm_manager.enabled = false;
+       }
+       gmc_v6_0_gart_fini(adev);
+       amdgpu_gem_force_release(adev);
+       amdgpu_bo_fini(adev);
+
+       return 0;
+}
+
+static int gmc_v6_0_hw_init(void *handle)
+{
+       int r;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       gmc_v6_0_mc_program(adev);
+
+       if (!(adev->flags & AMD_IS_APU)) {
+               r = gmc_v6_0_mc_load_microcode(adev);
+               if (r) {
+                       dev_err(adev->dev, "Failed to load MC firmware!\n");
+                       return r;
+               }
+       }
+
+       r = gmc_v6_0_gart_enable(adev);
+       if (r)
+               return r;
+
+       return r;
+}
+
+static int gmc_v6_0_hw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       amdgpu_irq_put(adev, &adev->mc.vm_fault, 0);
+       gmc_v6_0_gart_disable(adev);
+
+       return 0;
+}
+
+static int gmc_v6_0_suspend(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (adev->vm_manager.enabled) {
+               gmc_v6_0_vm_fini(adev);
+               adev->vm_manager.enabled = false;
+       }
+       gmc_v6_0_hw_fini(adev);
+
+       return 0;
+}
+
+static int gmc_v6_0_resume(void *handle)
+{
+       int r;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       r = gmc_v6_0_hw_init(adev);
+       if (r)
+               return r;
+
+       if (!adev->vm_manager.enabled) {
+               r = gmc_v6_0_vm_init(adev);
+               if (r) {
+                       dev_err(adev->dev, "vm manager initialization failed (%d).\n", r);
+                       return r;
+               }
+               adev->vm_manager.enabled = true;
+       }
+
+       return r;
+}
+
+static bool gmc_v6_0_is_idle(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 tmp = RREG32(SRBM_STATUS);
+
+       if (tmp & (SRBM_STATUS__MCB_BUSY_MASK | SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK |
+                  SRBM_STATUS__MCC_BUSY_MASK | SRBM_STATUS__MCD_BUSY_MASK | SRBM_STATUS__VMC_BUSY_MASK))
+               return false;
+
+       return true;
+}
+
+static int gmc_v6_0_wait_for_idle(void *handle)
+{
+       unsigned i;
+       u32 tmp;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               tmp = RREG32(SRBM_STATUS) & (SRBM_STATUS__MCB_BUSY_MASK |
+                                              SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK |
+                                              SRBM_STATUS__MCC_BUSY_MASK |
+                                              SRBM_STATUS__MCD_BUSY_MASK |
+                                              SRBM_STATUS__VMC_BUSY_MASK);
+               if (!tmp)
+                       return 0;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+
+}
+
+static int gmc_v6_0_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       struct amdgpu_mode_mc_save save;
+       u32 srbm_soft_reset = 0;
+       u32 tmp = RREG32(SRBM_STATUS);
+
+       if (tmp & SRBM_STATUS__VMC_BUSY_MASK)
+               srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
+                                               mmSRBM_SOFT_RESET, xxSOFT_RESET_VMC, 1);
+
+       if (tmp & (SRBM_STATUS__MCB_BUSY_MASK | SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK |
+                  SRBM_STATUS__MCC_BUSY_MASK | SRBM_STATUS__MCD_BUSY_MASK)) {
+               if (!(adev->flags & AMD_IS_APU))
+                       srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
+                                                       mmSRBM_SOFT_RESET, xxSOFT_RESET_MC, 1);
+       }
+
+       if (srbm_soft_reset) {
+               gmc_v6_0_mc_stop(adev, &save);
+               if (gmc_v6_0_wait_for_idle(adev)) {
+                       dev_warn(adev->dev, "Wait for GMC idle timed out !\n");
+               }
+
+
+               tmp = RREG32(SRBM_SOFT_RESET);
+               tmp |= srbm_soft_reset;
+               dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+               WREG32(SRBM_SOFT_RESET, tmp);
+               tmp = RREG32(SRBM_SOFT_RESET);
+
+               udelay(50);
+
+               tmp &= ~srbm_soft_reset;
+               WREG32(SRBM_SOFT_RESET, tmp);
+               tmp = RREG32(SRBM_SOFT_RESET);
+
+               udelay(50);
+
+               gmc_v6_0_mc_resume(adev, &save);
+               udelay(50);
+       }
+
+       return 0;
+}
+
+static int gmc_v6_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
+                                            struct amdgpu_irq_src *src,
+                                            unsigned type,
+                                            enum amdgpu_interrupt_state state)
+{
+       u32 tmp;
+       u32 bits = (VM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
+                   VM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
+                   VM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
+                   VM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
+                   VM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
+                   VM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK);
+
+       switch (state) {
+       case AMDGPU_IRQ_STATE_DISABLE:
+               tmp = RREG32(VM_CONTEXT0_CNTL);
+               tmp &= ~bits;
+               WREG32(VM_CONTEXT0_CNTL, tmp);
+               tmp = RREG32(VM_CONTEXT1_CNTL);
+               tmp &= ~bits;
+               WREG32(VM_CONTEXT1_CNTL, tmp);
+               break;
+       case AMDGPU_IRQ_STATE_ENABLE:
+               tmp = RREG32(VM_CONTEXT0_CNTL);
+               tmp |= bits;
+               WREG32(VM_CONTEXT0_CNTL, tmp);
+               tmp = RREG32(VM_CONTEXT1_CNTL);
+               tmp |= bits;
+               WREG32(VM_CONTEXT1_CNTL, tmp);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int gmc_v6_0_process_interrupt(struct amdgpu_device *adev,
+                                     struct amdgpu_irq_src *source,
+                                     struct amdgpu_iv_entry *entry)
+{
+       u32 addr, status;
+
+       addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);
+       status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS);
+       WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
+
+       if (!addr && !status)
+               return 0;
+
+       if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_FIRST)
+               gmc_v6_0_set_fault_enable_default(adev, false);
+
+       dev_err(adev->dev, "GPU fault detected: %d 0x%08x\n",
+               entry->src_id, entry->src_data);
+       dev_err(adev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
+               addr);
+       dev_err(adev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+               status);
+       gmc_v6_0_vm_decode_fault(adev, status, addr, 0);
+
+       return 0;
+}
+
+static int gmc_v6_0_set_clockgating_state(void *handle,
+                                         enum amd_clockgating_state state)
+{
+       return 0;
+}
+
+static int gmc_v6_0_set_powergating_state(void *handle,
+                                         enum amd_powergating_state state)
+{
+       return 0;
+}
+
+const struct amd_ip_funcs gmc_v6_0_ip_funcs = {
+       .name = "gmc_v6_0",
+       .early_init = gmc_v6_0_early_init,
+       .late_init = gmc_v6_0_late_init,
+       .sw_init = gmc_v6_0_sw_init,
+       .sw_fini = gmc_v6_0_sw_fini,
+       .hw_init = gmc_v6_0_hw_init,
+       .hw_fini = gmc_v6_0_hw_fini,
+       .suspend = gmc_v6_0_suspend,
+       .resume = gmc_v6_0_resume,
+       .is_idle = gmc_v6_0_is_idle,
+       .wait_for_idle = gmc_v6_0_wait_for_idle,
+       .soft_reset = gmc_v6_0_soft_reset,
+       .set_clockgating_state = gmc_v6_0_set_clockgating_state,
+       .set_powergating_state = gmc_v6_0_set_powergating_state,
+};
+
+static const struct amdgpu_gart_funcs gmc_v6_0_gart_funcs = {
+       .flush_gpu_tlb = gmc_v6_0_gart_flush_gpu_tlb,
+       .set_pte_pde = gmc_v6_0_gart_set_pte_pde,
+};
+
+static const struct amdgpu_irq_src_funcs gmc_v6_0_irq_funcs = {
+       .set = gmc_v6_0_vm_fault_interrupt_state,
+       .process = gmc_v6_0_process_interrupt,
+};
+
+static void gmc_v6_0_set_gart_funcs(struct amdgpu_device *adev)
+{
+       if (adev->gart.gart_funcs == NULL)
+               adev->gart.gart_funcs = &gmc_v6_0_gart_funcs;
+}
+
+static void gmc_v6_0_set_irq_funcs(struct amdgpu_device *adev)
+{
+       adev->mc.vm_fault.num_types = 1;
+       adev->mc.vm_fault.funcs = &gmc_v6_0_irq_funcs;
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.h b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.h
new file mode 100644 (file)
index 0000000..42c4fc6
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 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 __GMC_V6_0_H__
+#define __GMC_V6_0_H__
+
+extern const struct amd_ip_funcs gmc_v6_0_ip_funcs;
+
+#endif
index 0b0f086..aa0c4b9 100644 (file)
@@ -183,7 +183,7 @@ static int gmc_v7_0_mc_load_microcode(struct amdgpu_device *adev)
        const struct mc_firmware_header_v1_0 *hdr;
        const __le32 *fw_data = NULL;
        const __le32 *io_mc_regs = NULL;
-       u32 running, blackout = 0;
+       u32 running;
        int i, ucode_size, regs_size;
 
        if (!adev->mc.fw)
@@ -203,11 +203,6 @@ static int gmc_v7_0_mc_load_microcode(struct amdgpu_device *adev)
        running = REG_GET_FIELD(RREG32(mmMC_SEQ_SUP_CNTL), MC_SEQ_SUP_CNTL, RUN);
 
        if (running == 0) {
-               if (running) {
-                       blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL);
-                       WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout | 1);
-               }
-
                /* reset the engine and set to writable */
                WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008);
                WREG32(mmMC_SEQ_SUP_CNTL, 0x00000010);
@@ -239,9 +234,6 @@ static int gmc_v7_0_mc_load_microcode(struct amdgpu_device *adev)
                                break;
                        udelay(1);
                }
-
-               if (running)
-                       WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout);
        }
 
        return 0;
@@ -393,7 +385,7 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev)
         * size equal to the 1024 or vram, whichever is larger.
         */
        if (amdgpu_gart_size == -1)
-               adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size);
+               adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev);
        else
                adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
 
@@ -953,6 +945,11 @@ static int gmc_v7_0_sw_init(void *handle)
                return r;
        }
 
+       r = amdgpu_ttm_global_init(adev);
+       if (r) {
+               return r;
+       }
+
        r = gmc_v7_0_mc_init(adev);
        if (r)
                return r;
index 2aee2c6..1b319f5 100644 (file)
@@ -261,7 +261,7 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev)
        const struct mc_firmware_header_v1_0 *hdr;
        const __le32 *fw_data = NULL;
        const __le32 *io_mc_regs = NULL;
-       u32 running, blackout = 0;
+       u32 running;
        int i, ucode_size, regs_size;
 
        if (!adev->mc.fw)
@@ -269,8 +269,10 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev)
 
        /* Skip MC ucode loading on SR-IOV capable boards.
         * vbios does this for us in asic_init in that case.
+        * Skip MC ucode loading on VF, because hypervisor will do that
+        * for this adaptor.
         */
-       if (adev->virtualization.supports_sr_iov)
+       if (amdgpu_sriov_bios(adev))
                return 0;
 
        hdr = (const struct mc_firmware_header_v1_0 *)adev->mc.fw->data;
@@ -287,11 +289,6 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev)
        running = REG_GET_FIELD(RREG32(mmMC_SEQ_SUP_CNTL), MC_SEQ_SUP_CNTL, RUN);
 
        if (running == 0) {
-               if (running) {
-                       blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL);
-                       WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout | 1);
-               }
-
                /* reset the engine and set to writable */
                WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008);
                WREG32(mmMC_SEQ_SUP_CNTL, 0x00000010);
@@ -323,9 +320,6 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev)
                                break;
                        udelay(1);
                }
-
-               if (running)
-                       WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout);
        }
 
        return 0;
@@ -477,7 +471,7 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
         * size equal to the 1024 or vram, whichever is larger.
         */
        if (amdgpu_gart_size == -1)
-               adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size);
+               adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev);
        else
                adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
 
@@ -957,6 +951,11 @@ static int gmc_v8_0_sw_init(void *handle)
                return r;
        }
 
+       r = amdgpu_ttm_global_init(adev);
+       if (r) {
+               return r;
+       }
+
        r = gmc_v8_0_mc_init(adev);
        if (r)
                return r;
@@ -1100,9 +1099,8 @@ static int gmc_v8_0_wait_for_idle(void *handle)
 
 }
 
-static int gmc_v8_0_soft_reset(void *handle)
+static int gmc_v8_0_check_soft_reset(void *handle)
 {
-       struct amdgpu_mode_mc_save save;
        u32 srbm_soft_reset = 0;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 tmp = RREG32(mmSRBM_STATUS);
@@ -1117,13 +1115,42 @@ static int gmc_v8_0_soft_reset(void *handle)
                        srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
                                                        SRBM_SOFT_RESET, SOFT_RESET_MC, 1);
        }
-
        if (srbm_soft_reset) {
-               gmc_v8_0_mc_stop(adev, &save);
-               if (gmc_v8_0_wait_for_idle((void *)adev)) {
-                       dev_warn(adev->dev, "Wait for GMC idle timed out !\n");
-               }
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang = true;
+               adev->mc.srbm_soft_reset = srbm_soft_reset;
+       } else {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang = false;
+               adev->mc.srbm_soft_reset = 0;
+       }
+       return 0;
+}
 
+static int gmc_v8_0_pre_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang)
+               return 0;
+
+       gmc_v8_0_mc_stop(adev, &adev->mc.save);
+       if (gmc_v8_0_wait_for_idle(adev)) {
+               dev_warn(adev->dev, "Wait for GMC idle timed out !\n");
+       }
+
+       return 0;
+}
+
+static int gmc_v8_0_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang)
+               return 0;
+       srbm_soft_reset = adev->mc.srbm_soft_reset;
+
+       if (srbm_soft_reset) {
+               u32 tmp;
 
                tmp = RREG32(mmSRBM_SOFT_RESET);
                tmp |= srbm_soft_reset;
@@ -1139,14 +1166,22 @@ static int gmc_v8_0_soft_reset(void *handle)
 
                /* Wait a little for things to settle down */
                udelay(50);
-
-               gmc_v8_0_mc_resume(adev, &save);
-               udelay(50);
        }
 
        return 0;
 }
 
+static int gmc_v8_0_post_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang)
+               return 0;
+
+       gmc_v8_0_mc_resume(adev, &adev->mc.save);
+       return 0;
+}
+
 static int gmc_v8_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
                                             struct amdgpu_irq_src *src,
                                             unsigned type,
@@ -1414,7 +1449,10 @@ const struct amd_ip_funcs gmc_v8_0_ip_funcs = {
        .resume = gmc_v8_0_resume,
        .is_idle = gmc_v8_0_is_idle,
        .wait_for_idle = gmc_v8_0_wait_for_idle,
+       .check_soft_reset = gmc_v8_0_check_soft_reset,
+       .pre_soft_reset = gmc_v8_0_pre_soft_reset,
        .soft_reset = gmc_v8_0_soft_reset,
+       .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,
 };
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_dpm.c b/drivers/gpu/drm/amd/amdgpu/iceland_dpm.c
deleted file mode 100644 (file)
index 2f078ad..0000000
+++ /dev/null
@@ -1,200 +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 "iceland_smum.h"
-
-MODULE_FIRMWARE("amdgpu/topaz_smc.bin");
-
-static void iceland_dpm_set_funcs(struct amdgpu_device *adev);
-
-static int iceland_dpm_early_init(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       iceland_dpm_set_funcs(adev);
-
-       return 0;
-}
-
-static int iceland_dpm_init_microcode(struct amdgpu_device *adev)
-{
-       char fw_name[30] = "amdgpu/topaz_smc.bin";
-       int err;
-
-       err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
-       if (err)
-               goto out;
-       err = amdgpu_ucode_validate(adev->pm.fw);
-
-out:
-       if (err) {
-               DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
-               release_firmware(adev->pm.fw);
-               adev->pm.fw = NULL;
-       }
-       return err;
-}
-
-static int iceland_dpm_sw_init(void *handle)
-{
-       int ret;
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       ret = iceland_dpm_init_microcode(adev);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int iceland_dpm_sw_fini(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       release_firmware(adev->pm.fw);
-       adev->pm.fw = NULL;
-
-       return 0;
-}
-
-static int iceland_dpm_hw_init(void *handle)
-{
-       int ret;
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       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 = iceland_smu_init(adev);
-       if (ret) {
-               DRM_ERROR("SMU initialization failed\n");
-               goto fail;
-       }
-
-       ret = iceland_smu_start(adev);
-       if (ret) {
-               DRM_ERROR("SMU start failed\n");
-               goto fail;
-       }
-
-       mutex_unlock(&adev->pm.mutex);
-       return 0;
-
-fail:
-       adev->firmware.smu_load = false;
-       mutex_unlock(&adev->pm.mutex);
-       return -EINVAL;
-}
-
-static int iceland_dpm_hw_fini(void *handle)
-{
-       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.
-        */
-       iceland_smu_fini(adev);
-       mutex_unlock(&adev->pm.mutex);
-       return 0;
-}
-
-static int iceland_dpm_suspend(void *handle)
-{
-       return 0;
-}
-
-static int iceland_dpm_resume(void *handle)
-{
-       int ret;
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       mutex_lock(&adev->pm.mutex);
-
-       ret = iceland_smu_start(adev);
-       if (ret) {
-               DRM_ERROR("SMU start failed\n");
-               goto fail;
-       }
-
-fail:
-       mutex_unlock(&adev->pm.mutex);
-       return ret;
-}
-
-static int iceland_dpm_set_clockgating_state(void *handle,
-                       enum amd_clockgating_state state)
-{
-       return 0;
-}
-
-static int iceland_dpm_set_powergating_state(void *handle,
-                       enum amd_powergating_state state)
-{
-       return 0;
-}
-
-const struct amd_ip_funcs iceland_dpm_ip_funcs = {
-       .name = "iceland_dpm",
-       .early_init = iceland_dpm_early_init,
-       .late_init = NULL,
-       .sw_init = iceland_dpm_sw_init,
-       .sw_fini = iceland_dpm_sw_fini,
-       .hw_init = iceland_dpm_hw_init,
-       .hw_fini = iceland_dpm_hw_fini,
-       .suspend = iceland_dpm_suspend,
-       .resume = iceland_dpm_resume,
-       .is_idle = NULL,
-       .wait_for_idle = NULL,
-       .soft_reset = NULL,
-       .set_clockgating_state = iceland_dpm_set_clockgating_state,
-       .set_powergating_state = iceland_dpm_set_powergating_state,
-};
-
-static const struct amdgpu_dpm_funcs iceland_dpm_funcs = {
-       .get_temperature = NULL,
-       .pre_set_power_state = NULL,
-       .set_power_state = NULL,
-       .post_set_power_state = NULL,
-       .display_configuration_changed = NULL,
-       .get_sclk = NULL,
-       .get_mclk = NULL,
-       .print_power_state = NULL,
-       .debugfs_print_current_performance_level = NULL,
-       .force_performance_level = NULL,
-       .vblank_too_short = NULL,
-       .powergate_uvd = NULL,
-};
-
-static void iceland_dpm_set_funcs(struct amdgpu_device *adev)
-{
-       if (NULL == adev->pm.funcs)
-               adev->pm.funcs = &iceland_dpm_funcs;
-}
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_smc.c b/drivers/gpu/drm/amd/amdgpu/iceland_smc.c
deleted file mode 100644 (file)
index 2118399..0000000
+++ /dev/null
@@ -1,677 +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 "ppsmc.h"
-#include "iceland_smum.h"
-#include "smu_ucode_xfer_vi.h"
-#include "amdgpu_ucode.h"
-
-#include "smu/smu_7_1_1_d.h"
-#include "smu/smu_7_1_1_sh_mask.h"
-
-#define ICELAND_SMC_SIZE 0x20000
-
-static int iceland_set_smc_sram_address(struct amdgpu_device *adev,
-                                       uint32_t smc_address, uint32_t limit)
-{
-       uint32_t val;
-
-       if (smc_address & 3)
-               return -EINVAL;
-
-       if ((smc_address + 3) > limit)
-               return -EINVAL;
-
-       WREG32(mmSMC_IND_INDEX_0, smc_address);
-
-       val = RREG32(mmSMC_IND_ACCESS_CNTL);
-       val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
-       WREG32(mmSMC_IND_ACCESS_CNTL, val);
-
-       return 0;
-}
-
-static int iceland_copy_bytes_to_smc(struct amdgpu_device *adev,
-                                    uint32_t smc_start_address,
-                                    const uint8_t *src,
-                                    uint32_t byte_count, uint32_t limit)
-{
-       uint32_t addr;
-       uint32_t data, orig_data;
-       int result = 0;
-       uint32_t extra_shift;
-       unsigned long flags;
-
-       if (smc_start_address & 3)
-               return -EINVAL;
-
-       if ((smc_start_address + byte_count) > limit)
-               return -EINVAL;
-
-       addr = smc_start_address;
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       while (byte_count >= 4) {
-               /* Bytes are written into the SMC addres space with the MSB first */
-               data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
-
-               result = iceland_set_smc_sram_address(adev, addr, limit);
-
-               if (result)
-                       goto out;
-
-               WREG32(mmSMC_IND_DATA_0, data);
-
-               src += 4;
-               byte_count -= 4;
-               addr += 4;
-       }
-
-       if (0 != byte_count) {
-               /* Now write odd bytes left, do a read modify write cycle */
-               data = 0;
-
-               result = iceland_set_smc_sram_address(adev, addr, limit);
-               if (result)
-                       goto out;
-
-               orig_data = RREG32(mmSMC_IND_DATA_0);
-               extra_shift = 8 * (4 - byte_count);
-
-               while (byte_count > 0) {
-                       data = (data << 8) + *src++;
-                       byte_count--;
-               }
-
-               data <<= extra_shift;
-               data |= (orig_data & ~((~0UL) << extra_shift));
-
-               result = iceland_set_smc_sram_address(adev, addr, limit);
-               if (result)
-                       goto out;
-
-               WREG32(mmSMC_IND_DATA_0, data);
-       }
-
-out:
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-       return result;
-}
-
-void iceland_start_smc(struct amdgpu_device *adev)
-{
-       uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-}
-
-void iceland_reset_smc(struct amdgpu_device *adev)
-{
-       uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-}
-
-static int iceland_program_jump_on_start(struct amdgpu_device *adev)
-{
-       static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40};
-       iceland_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
-
-       return 0;
-}
-
-void iceland_stop_smc_clock(struct amdgpu_device *adev)
-{
-       uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-
-       val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1);
-       WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
-}
-
-void iceland_start_smc_clock(struct amdgpu_device *adev)
-{
-       uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-
-       val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
-       WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
-}
-
-static bool iceland_is_smc_ram_running(struct amdgpu_device *adev)
-{
-       uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-       val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable);
-
-       return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C)));
-}
-
-static int wait_smu_response(struct amdgpu_device *adev)
-{
-       int i;
-       uint32_t val;
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32(mmSMC_RESP_0);
-               if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int iceland_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg)
-{
-       if (!iceland_is_smc_ram_running(adev))
-               return -EINVAL;
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MESSAGE_0, msg);
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send message\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int iceland_send_msg_to_smc_without_waiting(struct amdgpu_device *adev,
-                                                  PPSMC_Msg msg)
-{
-       if (!iceland_is_smc_ram_running(adev))
-               return -EINVAL;
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MESSAGE_0, msg);
-
-       return 0;
-}
-
-static int iceland_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
-                                                 PPSMC_Msg msg,
-                                                 uint32_t parameter)
-{
-       WREG32(mmSMC_MSG_ARG_0, parameter);
-
-       return iceland_send_msg_to_smc(adev, msg);
-}
-
-static int iceland_send_msg_to_smc_with_parameter_without_waiting(
-                                       struct amdgpu_device *adev,
-                                       PPSMC_Msg msg, uint32_t parameter)
-{
-       WREG32(mmSMC_MSG_ARG_0, parameter);
-
-       return iceland_send_msg_to_smc_without_waiting(adev, msg);
-}
-
-#if 0 /* not used yet */
-static int iceland_wait_for_smc_inactive(struct amdgpu_device *adev)
-{
-       int i;
-       uint32_t val;
-
-       if (!iceland_is_smc_ram_running(adev))
-               return -EINVAL;
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-               if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0)
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout)
-               return -EINVAL;
-
-       return 0;
-}
-#endif
-
-static int iceland_smu_upload_firmware_image(struct amdgpu_device *adev)
-{
-       const struct smc_firmware_header_v1_0 *hdr;
-       uint32_t ucode_size;
-       uint32_t ucode_start_address;
-       const uint8_t *src;
-       uint32_t val;
-       uint32_t byte_count;
-       uint32_t data;
-       unsigned long flags;
-       int i;
-
-       if (!adev->pm.fw)
-               return -EINVAL;
-
-       /* Skip SMC ucode loading on SR-IOV capable boards.
-        * vbios does this for us in asic_init in that case.
-        */
-       if (adev->virtualization.supports_sr_iov)
-               return 0;
-
-       hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
-       amdgpu_ucode_print_smc_hdr(&hdr->header);
-
-       adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
-       ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
-       ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
-       src = (const uint8_t *)
-               (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-
-       if (ucode_size & 3) {
-               DRM_ERROR("SMC ucode is not 4 bytes aligned\n");
-               return -EINVAL;
-       }
-
-       if (ucode_size > ICELAND_SMC_SIZE) {
-               DRM_ERROR("SMC address is beyond the SMC RAM area\n");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixRCU_UC_EVENTS);
-               if (REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done) == 0)
-                       break;
-               udelay(1);
-       }
-       val = RREG32_SMC(ixSMC_SYSCON_MISC_CNTL);
-       WREG32_SMC(ixSMC_SYSCON_MISC_CNTL, val | 1);
-
-       iceland_stop_smc_clock(adev);
-       iceland_reset_smc(adev);
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
-
-       val = RREG32(mmSMC_IND_ACCESS_CNTL);
-       val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
-       WREG32(mmSMC_IND_ACCESS_CNTL, val);
-
-       byte_count = ucode_size;
-       while (byte_count >= 4) {
-               data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
-               WREG32(mmSMC_IND_DATA_0, data);
-               src += 4;
-               byte_count -= 4;
-       }
-       val = RREG32(mmSMC_IND_ACCESS_CNTL);
-       val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
-       WREG32(mmSMC_IND_ACCESS_CNTL, val);
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-
-       return 0;
-}
-
-#if 0 /* not used yet */
-static int iceland_read_smc_sram_dword(struct amdgpu_device *adev,
-                                      uint32_t smc_address,
-                                      uint32_t *value,
-                                      uint32_t limit)
-{
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       result = iceland_set_smc_sram_address(adev, smc_address, limit);
-       if (result == 0)
-               *value = RREG32(mmSMC_IND_DATA_0);
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-       return result;
-}
-
-static int iceland_write_smc_sram_dword(struct amdgpu_device *adev,
-                                       uint32_t smc_address,
-                                       uint32_t value,
-                                       uint32_t limit)
-{
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       result = iceland_set_smc_sram_address(adev, smc_address, limit);
-       if (result == 0)
-               WREG32(mmSMC_IND_DATA_0, value);
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-       return result;
-}
-
-static int iceland_smu_stop_smc(struct amdgpu_device *adev)
-{
-       iceland_reset_smc(adev);
-       iceland_stop_smc_clock(adev);
-
-       return 0;
-}
-#endif
-
-static int iceland_smu_start_smc(struct amdgpu_device *adev)
-{
-       int i;
-       uint32_t val;
-
-       iceland_program_jump_on_start(adev);
-       iceland_start_smc_clock(adev);
-       iceland_start_smc(adev);
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixFIRMWARE_FLAGS);
-               if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED) == 1)
-                       break;
-               udelay(1);
-       }
-       return 0;
-}
-
-static enum AMDGPU_UCODE_ID iceland_convert_fw_type(uint32_t fw_type)
-{
-       switch (fw_type) {
-               case UCODE_ID_SDMA0:
-                       return AMDGPU_UCODE_ID_SDMA0;
-               case UCODE_ID_SDMA1:
-                       return AMDGPU_UCODE_ID_SDMA1;
-               case UCODE_ID_CP_CE:
-                       return AMDGPU_UCODE_ID_CP_CE;
-               case UCODE_ID_CP_PFP:
-                       return AMDGPU_UCODE_ID_CP_PFP;
-               case UCODE_ID_CP_ME:
-                       return AMDGPU_UCODE_ID_CP_ME;
-               case UCODE_ID_CP_MEC:
-               case UCODE_ID_CP_MEC_JT1:
-                       return AMDGPU_UCODE_ID_CP_MEC1;
-               case UCODE_ID_CP_MEC_JT2:
-                       return AMDGPU_UCODE_ID_CP_MEC2;
-               case UCODE_ID_RLC_G:
-                       return AMDGPU_UCODE_ID_RLC_G;
-               default:
-                       DRM_ERROR("ucode type is out of range!\n");
-                       return AMDGPU_UCODE_ID_MAXIMUM;
-       }
-}
-
-static uint32_t iceland_smu_get_mask_for_fw_type(uint32_t fw_type)
-{
-       switch (fw_type) {
-               case AMDGPU_UCODE_ID_SDMA0:
-                       return UCODE_ID_SDMA0_MASK;
-               case AMDGPU_UCODE_ID_SDMA1:
-                       return UCODE_ID_SDMA1_MASK;
-               case AMDGPU_UCODE_ID_CP_CE:
-                       return UCODE_ID_CP_CE_MASK;
-               case AMDGPU_UCODE_ID_CP_PFP:
-                       return UCODE_ID_CP_PFP_MASK;
-               case AMDGPU_UCODE_ID_CP_ME:
-                       return UCODE_ID_CP_ME_MASK;
-               case AMDGPU_UCODE_ID_CP_MEC1:
-                       return UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK;
-               case AMDGPU_UCODE_ID_CP_MEC2:
-                       return UCODE_ID_CP_MEC_MASK;
-               case AMDGPU_UCODE_ID_RLC_G:
-                       return UCODE_ID_RLC_G_MASK;
-               default:
-                       DRM_ERROR("ucode type is out of range!\n");
-                       return 0;
-       }
-}
-
-static int iceland_smu_populate_single_firmware_entry(struct amdgpu_device *adev,
-                                                     uint32_t fw_type,
-                                                     struct SMU_Entry *entry)
-{
-       enum AMDGPU_UCODE_ID id = iceland_convert_fw_type(fw_type);
-       struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id];
-       const struct gfx_firmware_header_v1_0 *header = NULL;
-       uint64_t gpu_addr;
-       uint32_t data_size;
-
-       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);
-
-       entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
-       entry->id = (uint16_t)fw_type;
-       entry->image_addr_high = upper_32_bits(gpu_addr);
-       entry->image_addr_low = lower_32_bits(gpu_addr);
-       entry->meta_data_addr_high = 0;
-       entry->meta_data_addr_low = 0;
-       entry->data_size_byte = data_size;
-       entry->num_register_entries = 0;
-       entry->flags = 0;
-
-       return 0;
-}
-
-static int iceland_smu_request_load_fw(struct amdgpu_device *adev)
-{
-       struct iceland_smu_private_data *private = (struct iceland_smu_private_data *)adev->smu.priv;
-       struct SMU_DRAMData_TOC *toc;
-       uint32_t fw_to_load;
-
-       toc = (struct SMU_DRAMData_TOC *)private->header;
-       toc->num_entries = 0;
-       toc->structure_version = 1;
-
-       if (!adev->firmware.smu_load)
-               return 0;
-
-       if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for RLC\n");
-               return -EINVAL;
-       }
-
-       if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for CE\n");
-               return -EINVAL;
-       }
-
-       if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for PFP\n");
-               return -EINVAL;
-       }
-
-       if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for ME\n");
-               return -EINVAL;
-       }
-
-       if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for MEC\n");
-               return -EINVAL;
-       }
-
-       if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for MEC_JT1\n");
-               return -EINVAL;
-       }
-
-       if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for SDMA0\n");
-               return -EINVAL;
-       }
-
-       if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for SDMA1\n");
-               return -EINVAL;
-       }
-
-       iceland_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high);
-       iceland_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low);
-
-       fw_to_load = 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_MASK |
-                       UCODE_ID_CP_MEC_JT1_MASK;
-
-
-       if (iceland_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) {
-               DRM_ERROR("Fail to request SMU load ucode\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int iceland_smu_check_fw_load_finish(struct amdgpu_device *adev,
-                                           uint32_t fw_type)
-{
-       uint32_t fw_mask = iceland_smu_get_mask_for_fw_type(fw_type);
-       int i;
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_27) & fw_mask))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("check firmware loading failed\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int iceland_smu_start(struct amdgpu_device *adev)
-{
-       int result;
-
-       result = iceland_smu_upload_firmware_image(adev);
-       if (result)
-               return result;
-       result = iceland_smu_start_smc(adev);
-       if (result)
-               return result;
-
-       return iceland_smu_request_load_fw(adev);
-}
-
-static const struct amdgpu_smumgr_funcs iceland_smumgr_funcs = {
-       .check_fw_load_finish = iceland_smu_check_fw_load_finish,
-       .request_smu_load_fw = NULL,
-       .request_smu_specific_fw = NULL,
-};
-
-int iceland_smu_init(struct amdgpu_device *adev)
-{
-       struct iceland_smu_private_data *private;
-       uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
-       struct amdgpu_bo **toc_buf = &adev->smu.toc_buf;
-       uint64_t mc_addr;
-       void *toc_buf_ptr;
-       int ret;
-
-       private = kzalloc(sizeof(struct iceland_smu_private_data), GFP_KERNEL);
-       if (NULL == private)
-               return -ENOMEM;
-
-       /* allocate firmware buffers */
-       if (adev->firmware.smu_load)
-               amdgpu_ucode_init_bo(adev);
-
-       adev->smu.priv = private;
-       adev->smu.fw_flags = 0;
-
-       /* Allocate FW image data structure and header buffer */
-       ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE,
-                              true, AMDGPU_GEM_DOMAIN_VRAM,
-                              AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
-                              NULL, NULL, toc_buf);
-       if (ret) {
-               DRM_ERROR("Failed to allocate memory for TOC buffer\n");
-               return -ENOMEM;
-       }
-
-       /* Retrieve GPU address for header buffer and internal buffer */
-       ret = amdgpu_bo_reserve(adev->smu.toc_buf, false);
-       if (ret) {
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to reserve the TOC buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.toc_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to pin the TOC buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.toc_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to map the TOC buffer\n");
-               return -EINVAL;
-       }
-
-       amdgpu_bo_unreserve(adev->smu.toc_buf);
-       private->header_addr_low = lower_32_bits(mc_addr);
-       private->header_addr_high = upper_32_bits(mc_addr);
-       private->header = toc_buf_ptr;
-
-       adev->smu.smumgr_funcs = &iceland_smumgr_funcs;
-
-       return 0;
-}
-
-int iceland_smu_fini(struct amdgpu_device *adev)
-{
-       amdgpu_bo_unref(&adev->smu.toc_buf);
-       kfree(adev->smu.priv);
-       adev->smu.priv = NULL;
-       if (adev->firmware.fw_buf)
-               amdgpu_ucode_fini_bo(adev);
-
-       return 0;
-}
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_smum.h b/drivers/gpu/drm/amd/amdgpu/iceland_smum.h
deleted file mode 100644 (file)
index 5983e31..0000000
+++ /dev/null
@@ -1,41 +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 ICELAND_SMUM_H
-#define ICELAND_SMUM_H
-
-#include "ppsmc.h"
-
-extern int iceland_smu_init(struct amdgpu_device *adev);
-extern int iceland_smu_fini(struct amdgpu_device *adev);
-extern int iceland_smu_start(struct amdgpu_device *adev);
-
-struct iceland_smu_private_data
-{
-       uint8_t *header;
-       uint8_t *mec_image;
-       uint32_t header_addr_high;
-       uint32_t header_addr_low;
-};
-
-#endif
index a845e88..f8618a3 100644 (file)
@@ -2845,7 +2845,11 @@ static int kv_dpm_init(struct amdgpu_device *adev)
                pi->caps_tcp_ramping = true;
        }
 
-       pi->caps_sclk_ds = true;
+       if (amdgpu_sclk_deep_sleep_en)
+               pi->caps_sclk_ds = true;
+       else
+               pi->caps_sclk_ds = false;
+
        pi->enable_auto_thermal_throttling = true;
        pi->disable_nb_ps3_in_battery = false;
        if (amdgpu_bapm == 0)
diff --git a/drivers/gpu/drm/amd/amdgpu/r600_dpm.h b/drivers/gpu/drm/amd/amdgpu/r600_dpm.h
new file mode 100644 (file)
index 0000000..055321f
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __R600_DPM_H__
+#define __R600_DPM_H__
+
+#define R600_ASI_DFLT                                10000
+#define R600_BSP_DFLT                                0x41EB
+#define R600_BSU_DFLT                                0x2
+#define R600_AH_DFLT                                 5
+#define R600_RLP_DFLT                                25
+#define R600_RMP_DFLT                                65
+#define R600_LHP_DFLT                                40
+#define R600_LMP_DFLT                                15
+#define R600_TD_DFLT                                 0
+#define R600_UTC_DFLT_00                             0x24
+#define R600_UTC_DFLT_01                             0x22
+#define R600_UTC_DFLT_02                             0x22
+#define R600_UTC_DFLT_03                             0x22
+#define R600_UTC_DFLT_04                             0x22
+#define R600_UTC_DFLT_05                             0x22
+#define R600_UTC_DFLT_06                             0x22
+#define R600_UTC_DFLT_07                             0x22
+#define R600_UTC_DFLT_08                             0x22
+#define R600_UTC_DFLT_09                             0x22
+#define R600_UTC_DFLT_10                             0x22
+#define R600_UTC_DFLT_11                             0x22
+#define R600_UTC_DFLT_12                             0x22
+#define R600_UTC_DFLT_13                             0x22
+#define R600_UTC_DFLT_14                             0x22
+#define R600_DTC_DFLT_00                             0x24
+#define R600_DTC_DFLT_01                             0x22
+#define R600_DTC_DFLT_02                             0x22
+#define R600_DTC_DFLT_03                             0x22
+#define R600_DTC_DFLT_04                             0x22
+#define R600_DTC_DFLT_05                             0x22
+#define R600_DTC_DFLT_06                             0x22
+#define R600_DTC_DFLT_07                             0x22
+#define R600_DTC_DFLT_08                             0x22
+#define R600_DTC_DFLT_09                             0x22
+#define R600_DTC_DFLT_10                             0x22
+#define R600_DTC_DFLT_11                             0x22
+#define R600_DTC_DFLT_12                             0x22
+#define R600_DTC_DFLT_13                             0x22
+#define R600_DTC_DFLT_14                             0x22
+#define R600_VRC_DFLT                                0x0000C003
+#define R600_VOLTAGERESPONSETIME_DFLT                1000
+#define R600_BACKBIASRESPONSETIME_DFLT               1000
+#define R600_VRU_DFLT                                0x3
+#define R600_SPLLSTEPTIME_DFLT                       0x1000
+#define R600_SPLLSTEPUNIT_DFLT                       0x3
+#define R600_TPU_DFLT                                0
+#define R600_TPC_DFLT                                0x200
+#define R600_SSTU_DFLT                               0
+#define R600_SST_DFLT                                0x00C8
+#define R600_GICST_DFLT                              0x200
+#define R600_FCT_DFLT                                0x0400
+#define R600_FCTU_DFLT                               0
+#define R600_CTXCGTT3DRPHC_DFLT                      0x20
+#define R600_CTXCGTT3DRSDC_DFLT                      0x40
+#define R600_VDDC3DOORPHC_DFLT                       0x100
+#define R600_VDDC3DOORSDC_DFLT                       0x7
+#define R600_VDDC3DOORSU_DFLT                        0
+#define R600_MPLLLOCKTIME_DFLT                       100
+#define R600_MPLLRESETTIME_DFLT                      150
+#define R600_VCOSTEPPCT_DFLT                          20
+#define R600_ENDINGVCOSTEPPCT_DFLT                    5
+#define R600_REFERENCEDIVIDER_DFLT                    4
+
+#define R600_PM_NUMBER_OF_TC 15
+#define R600_PM_NUMBER_OF_SCLKS 20
+#define R600_PM_NUMBER_OF_MCLKS 4
+#define R600_PM_NUMBER_OF_VOLTAGE_LEVELS 4
+#define R600_PM_NUMBER_OF_ACTIVITY_LEVELS 3
+
+/* XXX are these ok? */
+#define R600_TEMP_RANGE_MIN (90 * 1000)
+#define R600_TEMP_RANGE_MAX (120 * 1000)
+
+#define FDO_PWM_MODE_STATIC  1
+#define FDO_PWM_MODE_STATIC_RPM 5
+
+enum r600_power_level {
+       R600_POWER_LEVEL_LOW = 0,
+       R600_POWER_LEVEL_MEDIUM = 1,
+       R600_POWER_LEVEL_HIGH = 2,
+       R600_POWER_LEVEL_CTXSW = 3,
+};
+
+enum r600_td {
+       R600_TD_AUTO,
+       R600_TD_UP,
+       R600_TD_DOWN,
+};
+
+enum r600_display_watermark {
+       R600_DISPLAY_WATERMARK_LOW = 0,
+       R600_DISPLAY_WATERMARK_HIGH = 1,
+};
+
+enum r600_display_gap
+{
+    R600_PM_DISPLAY_GAP_VBLANK_OR_WM = 0,
+    R600_PM_DISPLAY_GAP_VBLANK       = 1,
+    R600_PM_DISPLAY_GAP_WATERMARK    = 2,
+    R600_PM_DISPLAY_GAP_IGNORE       = 3,
+};
+#endif
index a64715d..565dab3 100644 (file)
@@ -190,12 +190,8 @@ out:
  */
 static uint32_t sdma_v2_4_ring_get_rptr(struct amdgpu_ring *ring)
 {
-       u32 rptr;
-
        /* XXX check if swapping is necessary on BE */
-       rptr = ring->adev->wb.wb[ring->rptr_offs] >> 2;
-
-       return rptr;
+       return ring->adev->wb.wb[ring->rptr_offs] >> 2;
 }
 
 /**
@@ -749,24 +745,16 @@ static void sdma_v2_4_vm_copy_pte(struct amdgpu_ib *ib,
                                  uint64_t pe, uint64_t src,
                                  unsigned count)
 {
-       while (count) {
-               unsigned bytes = count * 8;
-               if (bytes > 0x1FFFF8)
-                       bytes = 0x1FFFF8;
-
-               ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) |
-                       SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR);
-               ib->ptr[ib->length_dw++] = bytes;
-               ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */
-               ib->ptr[ib->length_dw++] = lower_32_bits(src);
-               ib->ptr[ib->length_dw++] = upper_32_bits(src);
-               ib->ptr[ib->length_dw++] = lower_32_bits(pe);
-               ib->ptr[ib->length_dw++] = upper_32_bits(pe);
-
-               pe += bytes;
-               src += bytes;
-               count -= bytes / 8;
-       }
+       unsigned bytes = count * 8;
+
+       ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) |
+               SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR);
+       ib->ptr[ib->length_dw++] = bytes;
+       ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */
+       ib->ptr[ib->length_dw++] = lower_32_bits(src);
+       ib->ptr[ib->length_dw++] = upper_32_bits(src);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe);
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
 }
 
 /**
@@ -774,39 +762,27 @@ static void sdma_v2_4_vm_copy_pte(struct amdgpu_ib *ib,
  *
  * @ib: indirect buffer to fill with commands
  * @pe: addr of the page entry
- * @addr: dst addr to write into pe
+ * @value: dst addr to write into pe
  * @count: number of page entries to update
  * @incr: increase next addr by incr bytes
- * @flags: access flags
  *
  * Update PTEs by writing them manually using sDMA (CIK).
  */
-static void sdma_v2_4_vm_write_pte(struct amdgpu_ib *ib,
-                                  const dma_addr_t *pages_addr, uint64_t pe,
-                                  uint64_t addr, unsigned count,
-                                  uint32_t incr, uint32_t flags)
+static void sdma_v2_4_vm_write_pte(struct amdgpu_ib *ib, uint64_t pe,
+                                  uint64_t value, unsigned count,
+                                  uint32_t incr)
 {
-       uint64_t value;
-       unsigned ndw;
-
-       while (count) {
-               ndw = count * 2;
-               if (ndw > 0xFFFFE)
-                       ndw = 0xFFFFE;
-
-               /* for non-physically contiguous pages (system) */
-               ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
-                       SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR);
-               ib->ptr[ib->length_dw++] = pe;
-               ib->ptr[ib->length_dw++] = upper_32_bits(pe);
-               ib->ptr[ib->length_dw++] = ndw;
-               for (; ndw > 0; ndw -= 2, --count, pe += 8) {
-                       value = amdgpu_vm_map_gart(pages_addr, addr);
-                       addr += incr;
-                       value |= flags;
-                       ib->ptr[ib->length_dw++] = value;
-                       ib->ptr[ib->length_dw++] = upper_32_bits(value);
-               }
+       unsigned ndw = count * 2;
+
+       ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
+               SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR);
+       ib->ptr[ib->length_dw++] = pe;
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+       ib->ptr[ib->length_dw++] = ndw;
+       for (; ndw > 0; ndw -= 2, --count, pe += 8) {
+               ib->ptr[ib->length_dw++] = lower_32_bits(value);
+               ib->ptr[ib->length_dw++] = upper_32_bits(value);
+               value += incr;
        }
 }
 
@@ -822,40 +798,21 @@ static void sdma_v2_4_vm_write_pte(struct amdgpu_ib *ib,
  *
  * Update the page tables using sDMA (CIK).
  */
-static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib,
-                                    uint64_t pe,
+static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
                                     uint64_t addr, unsigned count,
                                     uint32_t incr, uint32_t flags)
 {
-       uint64_t value;
-       unsigned ndw;
-
-       while (count) {
-               ndw = count;
-               if (ndw > 0x7FFFF)
-                       ndw = 0x7FFFF;
-
-               if (flags & AMDGPU_PTE_VALID)
-                       value = addr;
-               else
-                       value = 0;
-
-               /* for physically contiguous pages (vram) */
-               ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_GEN_PTEPDE);
-               ib->ptr[ib->length_dw++] = pe; /* dst addr */
-               ib->ptr[ib->length_dw++] = upper_32_bits(pe);
-               ib->ptr[ib->length_dw++] = flags; /* mask */
-               ib->ptr[ib->length_dw++] = 0;
-               ib->ptr[ib->length_dw++] = value; /* value */
-               ib->ptr[ib->length_dw++] = upper_32_bits(value);
-               ib->ptr[ib->length_dw++] = incr; /* increment size */
-               ib->ptr[ib->length_dw++] = 0;
-               ib->ptr[ib->length_dw++] = ndw; /* number of entries */
-
-               pe += ndw * 8;
-               addr += ndw * incr;
-               count -= ndw;
-       }
+       /* for physically contiguous pages (vram) */
+       ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_GEN_PTEPDE);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe); /* dst addr */
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+       ib->ptr[ib->length_dw++] = flags; /* mask */
+       ib->ptr[ib->length_dw++] = 0;
+       ib->ptr[ib->length_dw++] = lower_32_bits(addr); /* value */
+       ib->ptr[ib->length_dw++] = upper_32_bits(addr);
+       ib->ptr[ib->length_dw++] = incr; /* increment size */
+       ib->ptr[ib->length_dw++] = 0;
+       ib->ptr[ib->length_dw++] = count; /* number of entries */
 }
 
 /**
@@ -945,6 +902,22 @@ static void sdma_v2_4_ring_emit_vm_flush(struct amdgpu_ring *ring,
                          SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); /* retry count, poll interval */
 }
 
+static unsigned sdma_v2_4_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               7 + 6; /* sdma_v2_4_ring_emit_ib */
+}
+
+static unsigned sdma_v2_4_ring_get_dma_frame_size(struct amdgpu_ring *ring)
+{
+       return
+               6 + /* sdma_v2_4_ring_emit_hdp_flush */
+               3 + /* sdma_v2_4_ring_emit_hdp_invalidate */
+               6 + /* sdma_v2_4_ring_emit_pipeline_sync */
+               12 + /* sdma_v2_4_ring_emit_vm_flush */
+               10 + 10 + 10; /* sdma_v2_4_ring_emit_fence x3 for user fence, vm fence */
+}
+
 static int sdma_v2_4_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1263,6 +1236,8 @@ static const struct amdgpu_ring_funcs sdma_v2_4_ring_funcs = {
        .test_ib = sdma_v2_4_ring_test_ib,
        .insert_nop = sdma_v2_4_ring_insert_nop,
        .pad_ib = sdma_v2_4_ring_pad_ib,
+       .get_emit_ib_size = sdma_v2_4_ring_get_emit_ib_size,
+       .get_dma_frame_size = sdma_v2_4_ring_get_dma_frame_size,
 };
 
 static void sdma_v2_4_set_ring_funcs(struct amdgpu_device *adev)
index 653ce5e..f325fd8 100644 (file)
@@ -335,12 +335,8 @@ out:
  */
 static uint32_t sdma_v3_0_ring_get_rptr(struct amdgpu_ring *ring)
 {
-       u32 rptr;
-
        /* XXX check if swapping is necessary on BE */
-       rptr = ring->adev->wb.wb[ring->rptr_offs] >> 2;
-
-       return rptr;
+       return ring->adev->wb.wb[ring->rptr_offs] >> 2;
 }
 
 /**
@@ -499,31 +495,6 @@ static void sdma_v3_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
        amdgpu_ring_write(ring, SDMA_PKT_TRAP_INT_CONTEXT_INT_CONTEXT(0));
 }
 
-unsigned init_cond_exec(struct amdgpu_ring *ring)
-{
-       unsigned ret;
-       amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_COND_EXE));
-       amdgpu_ring_write(ring, lower_32_bits(ring->cond_exe_gpu_addr));
-       amdgpu_ring_write(ring, upper_32_bits(ring->cond_exe_gpu_addr));
-       amdgpu_ring_write(ring, 1);
-       ret = ring->wptr;/* this is the offset we need patch later */
-       amdgpu_ring_write(ring, 0x55aa55aa);/* insert dummy here and patch it later */
-       return ret;
-}
-
-void patch_cond_exec(struct amdgpu_ring *ring, unsigned offset)
-{
-       unsigned cur;
-       BUG_ON(ring->ring[offset] != 0x55aa55aa);
-
-       cur = ring->wptr - 1;
-       if (likely(cur > offset))
-               ring->ring[offset] = cur - offset;
-       else
-               ring->ring[offset] = (ring->ring_size>>2) - offset + cur;
-}
-
-
 /**
  * sdma_v3_0_gfx_stop - stop the gfx async dma engines
  *
@@ -976,24 +947,16 @@ static void sdma_v3_0_vm_copy_pte(struct amdgpu_ib *ib,
                                  uint64_t pe, uint64_t src,
                                  unsigned count)
 {
-       while (count) {
-               unsigned bytes = count * 8;
-               if (bytes > 0x1FFFF8)
-                       bytes = 0x1FFFF8;
-
-               ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) |
-                       SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR);
-               ib->ptr[ib->length_dw++] = bytes;
-               ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */
-               ib->ptr[ib->length_dw++] = lower_32_bits(src);
-               ib->ptr[ib->length_dw++] = upper_32_bits(src);
-               ib->ptr[ib->length_dw++] = lower_32_bits(pe);
-               ib->ptr[ib->length_dw++] = upper_32_bits(pe);
-
-               pe += bytes;
-               src += bytes;
-               count -= bytes / 8;
-       }
+       unsigned bytes = count * 8;
+
+       ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) |
+               SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR);
+       ib->ptr[ib->length_dw++] = bytes;
+       ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */
+       ib->ptr[ib->length_dw++] = lower_32_bits(src);
+       ib->ptr[ib->length_dw++] = upper_32_bits(src);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe);
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
 }
 
 /**
@@ -1001,39 +964,27 @@ static void sdma_v3_0_vm_copy_pte(struct amdgpu_ib *ib,
  *
  * @ib: indirect buffer to fill with commands
  * @pe: addr of the page entry
- * @addr: dst addr to write into pe
+ * @value: dst addr to write into pe
  * @count: number of page entries to update
  * @incr: increase next addr by incr bytes
- * @flags: access flags
  *
  * Update PTEs by writing them manually using sDMA (CIK).
  */
-static void sdma_v3_0_vm_write_pte(struct amdgpu_ib *ib,
-                                  const dma_addr_t *pages_addr, uint64_t pe,
-                                  uint64_t addr, unsigned count,
-                                  uint32_t incr, uint32_t flags)
-{
-       uint64_t value;
-       unsigned ndw;
-
-       while (count) {
-               ndw = count * 2;
-               if (ndw > 0xFFFFE)
-                       ndw = 0xFFFFE;
-
-               /* for non-physically contiguous pages (system) */
-               ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
-                       SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR);
-               ib->ptr[ib->length_dw++] = pe;
-               ib->ptr[ib->length_dw++] = upper_32_bits(pe);
-               ib->ptr[ib->length_dw++] = ndw;
-               for (; ndw > 0; ndw -= 2, --count, pe += 8) {
-                       value = amdgpu_vm_map_gart(pages_addr, addr);
-                       addr += incr;
-                       value |= flags;
-                       ib->ptr[ib->length_dw++] = value;
-                       ib->ptr[ib->length_dw++] = upper_32_bits(value);
-               }
+static void sdma_v3_0_vm_write_pte(struct amdgpu_ib *ib, uint64_t pe,
+                                  uint64_t value, unsigned count,
+                                  uint32_t incr)
+{
+       unsigned ndw = count * 2;
+
+       ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
+               SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe);
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+       ib->ptr[ib->length_dw++] = ndw;
+       for (; ndw > 0; ndw -= 2, --count, pe += 8) {
+               ib->ptr[ib->length_dw++] = lower_32_bits(value);
+               ib->ptr[ib->length_dw++] = upper_32_bits(value);
+               value += incr;
        }
 }
 
@@ -1049,40 +1000,21 @@ static void sdma_v3_0_vm_write_pte(struct amdgpu_ib *ib,
  *
  * Update the page tables using sDMA (CIK).
  */
-static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib,
-                                    uint64_t pe,
+static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
                                     uint64_t addr, unsigned count,
                                     uint32_t incr, uint32_t flags)
 {
-       uint64_t value;
-       unsigned ndw;
-
-       while (count) {
-               ndw = count;
-               if (ndw > 0x7FFFF)
-                       ndw = 0x7FFFF;
-
-               if (flags & AMDGPU_PTE_VALID)
-                       value = addr;
-               else
-                       value = 0;
-
-               /* for physically contiguous pages (vram) */
-               ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_GEN_PTEPDE);
-               ib->ptr[ib->length_dw++] = pe; /* dst addr */
-               ib->ptr[ib->length_dw++] = upper_32_bits(pe);
-               ib->ptr[ib->length_dw++] = flags; /* mask */
-               ib->ptr[ib->length_dw++] = 0;
-               ib->ptr[ib->length_dw++] = value; /* value */
-               ib->ptr[ib->length_dw++] = upper_32_bits(value);
-               ib->ptr[ib->length_dw++] = incr; /* increment size */
-               ib->ptr[ib->length_dw++] = 0;
-               ib->ptr[ib->length_dw++] = ndw; /* number of entries */
-
-               pe += ndw * 8;
-               addr += ndw * incr;
-               count -= ndw;
-       }
+       /* for physically contiguous pages (vram) */
+       ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_GEN_PTEPDE);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe); /* dst addr */
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+       ib->ptr[ib->length_dw++] = flags; /* mask */
+       ib->ptr[ib->length_dw++] = 0;
+       ib->ptr[ib->length_dw++] = lower_32_bits(addr); /* value */
+       ib->ptr[ib->length_dw++] = upper_32_bits(addr);
+       ib->ptr[ib->length_dw++] = incr; /* increment size */
+       ib->ptr[ib->length_dw++] = 0;
+       ib->ptr[ib->length_dw++] = count; /* number of entries */
 }
 
 /**
@@ -1172,6 +1104,22 @@ static void sdma_v3_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
                          SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); /* retry count, poll interval */
 }
 
+static unsigned sdma_v3_0_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               7 + 6; /* sdma_v3_0_ring_emit_ib */
+}
+
+static unsigned sdma_v3_0_ring_get_dma_frame_size(struct amdgpu_ring *ring)
+{
+       return
+               6 + /* sdma_v3_0_ring_emit_hdp_flush */
+               3 + /* sdma_v3_0_ring_emit_hdp_invalidate */
+               6 + /* sdma_v3_0_ring_emit_pipeline_sync */
+               12 + /* sdma_v3_0_ring_emit_vm_flush */
+               10 + 10 + 10; /* sdma_v3_0_ring_emit_fence x3 for user fence, vm fence */
+}
+
 static int sdma_v3_0_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1320,27 +1268,78 @@ static int sdma_v3_0_wait_for_idle(void *handle)
        return -ETIMEDOUT;
 }
 
-static int sdma_v3_0_soft_reset(void *handle)
+static int sdma_v3_0_check_soft_reset(void *handle)
 {
-       u32 srbm_soft_reset = 0;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset = 0;
        u32 tmp = RREG32(mmSRBM_STATUS2);
 
-       if (tmp & SRBM_STATUS2__SDMA_BUSY_MASK) {
-               /* sdma0 */
-               tmp = RREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET);
-               tmp = REG_SET_FIELD(tmp, SDMA0_F32_CNTL, HALT, 0);
-               WREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+       if ((tmp & SRBM_STATUS2__SDMA_BUSY_MASK) ||
+           (tmp & SRBM_STATUS2__SDMA1_BUSY_MASK)) {
                srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK;
-       }
-       if (tmp & SRBM_STATUS2__SDMA1_BUSY_MASK) {
-               /* sdma1 */
-               tmp = RREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET);
-               tmp = REG_SET_FIELD(tmp, SDMA0_F32_CNTL, HALT, 0);
-               WREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET, tmp);
                srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK;
        }
 
+       if (srbm_soft_reset) {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang = true;
+               adev->sdma.srbm_soft_reset = srbm_soft_reset;
+       } else {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang = false;
+               adev->sdma.srbm_soft_reset = 0;
+       }
+
+       return 0;
+}
+
+static int sdma_v3_0_pre_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset = 0;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang)
+               return 0;
+
+       srbm_soft_reset = adev->sdma.srbm_soft_reset;
+
+       if (REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA) ||
+           REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA1)) {
+               sdma_v3_0_ctx_switch_enable(adev, false);
+               sdma_v3_0_enable(adev, false);
+       }
+
+       return 0;
+}
+
+static int sdma_v3_0_post_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset = 0;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang)
+               return 0;
+
+       srbm_soft_reset = adev->sdma.srbm_soft_reset;
+
+       if (REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA) ||
+           REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA1)) {
+               sdma_v3_0_gfx_resume(adev);
+               sdma_v3_0_rlc_resume(adev);
+       }
+
+       return 0;
+}
+
+static int sdma_v3_0_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset = 0;
+       u32 tmp;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang)
+               return 0;
+
+       srbm_soft_reset = adev->sdma.srbm_soft_reset;
+
        if (srbm_soft_reset) {
                tmp = RREG32(mmSRBM_SOFT_RESET);
                tmp |= srbm_soft_reset;
@@ -1559,6 +1558,9 @@ const struct amd_ip_funcs sdma_v3_0_ip_funcs = {
        .resume = sdma_v3_0_resume,
        .is_idle = sdma_v3_0_is_idle,
        .wait_for_idle = sdma_v3_0_wait_for_idle,
+       .check_soft_reset = sdma_v3_0_check_soft_reset,
+       .pre_soft_reset = sdma_v3_0_pre_soft_reset,
+       .post_soft_reset = sdma_v3_0_post_soft_reset,
        .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,
@@ -1579,6 +1581,8 @@ static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = {
        .test_ib = sdma_v3_0_ring_test_ib,
        .insert_nop = sdma_v3_0_ring_insert_nop,
        .pad_ib = sdma_v3_0_ring_pad_ib,
+       .get_emit_ib_size = sdma_v3_0_ring_get_emit_ib_size,
+       .get_dma_frame_size = sdma_v3_0_ring_get_dma_frame_size,
 };
 
 static void sdma_v3_0_set_ring_funcs(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
new file mode 100644 (file)
index 0000000..dc9511c
--- /dev/null
@@ -0,0 +1,1965 @@
+/*
+ * Copyright 2015 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/slab.h>
+#include <linux/module.h>
+#include "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_atombios.h"
+#include "amdgpu_ih.h"
+#include "amdgpu_uvd.h"
+#include "amdgpu_vce.h"
+#include "atom.h"
+#include "amdgpu_powerplay.h"
+#include "si/sid.h"
+#include "si_ih.h"
+#include "gfx_v6_0.h"
+#include "gmc_v6_0.h"
+#include "si_dma.h"
+#include "dce_v6_0.h"
+#include "si.h"
+
+static const u32 tahiti_golden_registers[] =
+{
+       0x2684, 0x00010000, 0x00018208,
+       0x260c, 0xffffffff, 0x00000000,
+       0x260d, 0xf00fffff, 0x00000400,
+       0x260e, 0x0002021c, 0x00020200,
+       0x031e, 0x00000080, 0x00000000,
+       0x340c, 0x000300c0, 0x00800040,
+       0x360c, 0x000300c0, 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,
+       0x000c, 0x000000ff, 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
+};
+
+static const u32 tahiti_golden_registers2[] =
+{
+       0x0319, 0x00000001, 0x00000001
+};
+
+static const u32 tahiti_golden_rlc_registers[] =
+{
+       0x3109, 0xffffffff, 0x00601005,
+       0x311f, 0xffffffff, 0x10104040,
+       0x3122, 0xffffffff, 0x0100000a,
+       0x30c5, 0xffffffff, 0x00000800,
+       0x30c3, 0xffffffff, 0x800000f4,
+       0x3d2a, 0xffffffff, 0x00000000
+};
+
+static const u32 pitcairn_golden_registers[] =
+{
+       0x2684, 0x00010000, 0x00018208,
+       0x260c, 0xffffffff, 0x00000000,
+       0x260d, 0xf00fffff, 0x00000400,
+       0x260e, 0x0002021c, 0x00020200,
+       0x031e, 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,
+       0x000c, 0x000000ff, 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
+};
+
+static const u32 pitcairn_golden_rlc_registers[] =
+{
+       0x3109, 0xffffffff, 0x00601004,
+       0x311f, 0xffffffff, 0x10102020,
+       0x3122, 0xffffffff, 0x01000020,
+       0x30c5, 0xffffffff, 0x00000800,
+       0x30c3, 0xffffffff, 0x800000a4
+};
+
+static const u32 verde_pg_init[] =
+{
+       0xd4f, 0xffffffff, 0x40000,
+       0xd4e, 0xffffffff, 0x200010ff,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x7007,
+       0xd4e, 0xffffffff, 0x300010ff,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x400000,
+       0xd4e, 0xffffffff, 0x100010ff,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x120200,
+       0xd4e, 0xffffffff, 0x500010ff,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x1e1e16,
+       0xd4e, 0xffffffff, 0x600010ff,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x171f1e,
+       0xd4e, 0xffffffff, 0x700010ff,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4f, 0xffffffff, 0x0,
+       0xd4e, 0xffffffff, 0x9ff,
+       0xd40, 0xffffffff, 0x0,
+       0xd41, 0xffffffff, 0x10000800,
+       0xd41, 0xffffffff, 0xf,
+       0xd41, 0xffffffff, 0xf,
+       0xd40, 0xffffffff, 0x4,
+       0xd41, 0xffffffff, 0x1000051e,
+       0xd41, 0xffffffff, 0xffff,
+       0xd41, 0xffffffff, 0xffff,
+       0xd40, 0xffffffff, 0x8,
+       0xd41, 0xffffffff, 0x80500,
+       0xd40, 0xffffffff, 0x12,
+       0xd41, 0xffffffff, 0x9050c,
+       0xd40, 0xffffffff, 0x1d,
+       0xd41, 0xffffffff, 0xb052c,
+       0xd40, 0xffffffff, 0x2a,
+       0xd41, 0xffffffff, 0x1053e,
+       0xd40, 0xffffffff, 0x2d,
+       0xd41, 0xffffffff, 0x10546,
+       0xd40, 0xffffffff, 0x30,
+       0xd41, 0xffffffff, 0xa054e,
+       0xd40, 0xffffffff, 0x3c,
+       0xd41, 0xffffffff, 0x1055f,
+       0xd40, 0xffffffff, 0x3f,
+       0xd41, 0xffffffff, 0x10567,
+       0xd40, 0xffffffff, 0x42,
+       0xd41, 0xffffffff, 0x1056f,
+       0xd40, 0xffffffff, 0x45,
+       0xd41, 0xffffffff, 0x10572,
+       0xd40, 0xffffffff, 0x48,
+       0xd41, 0xffffffff, 0x20575,
+       0xd40, 0xffffffff, 0x4c,
+       0xd41, 0xffffffff, 0x190801,
+       0xd40, 0xffffffff, 0x67,
+       0xd41, 0xffffffff, 0x1082a,
+       0xd40, 0xffffffff, 0x6a,
+       0xd41, 0xffffffff, 0x1b082d,
+       0xd40, 0xffffffff, 0x87,
+       0xd41, 0xffffffff, 0x310851,
+       0xd40, 0xffffffff, 0xba,
+       0xd41, 0xffffffff, 0x891,
+       0xd40, 0xffffffff, 0xbc,
+       0xd41, 0xffffffff, 0x893,
+       0xd40, 0xffffffff, 0xbe,
+       0xd41, 0xffffffff, 0x20895,
+       0xd40, 0xffffffff, 0xc2,
+       0xd41, 0xffffffff, 0x20899,
+       0xd40, 0xffffffff, 0xc6,
+       0xd41, 0xffffffff, 0x2089d,
+       0xd40, 0xffffffff, 0xca,
+       0xd41, 0xffffffff, 0x8a1,
+       0xd40, 0xffffffff, 0xcc,
+       0xd41, 0xffffffff, 0x8a3,
+       0xd40, 0xffffffff, 0xce,
+       0xd41, 0xffffffff, 0x308a5,
+       0xd40, 0xffffffff, 0xd3,
+       0xd41, 0xffffffff, 0x6d08cd,
+       0xd40, 0xffffffff, 0x142,
+       0xd41, 0xffffffff, 0x2000095a,
+       0xd41, 0xffffffff, 0x1,
+       0xd40, 0xffffffff, 0x144,
+       0xd41, 0xffffffff, 0x301f095b,
+       0xd40, 0xffffffff, 0x165,
+       0xd41, 0xffffffff, 0xc094d,
+       0xd40, 0xffffffff, 0x173,
+       0xd41, 0xffffffff, 0xf096d,
+       0xd40, 0xffffffff, 0x184,
+       0xd41, 0xffffffff, 0x15097f,
+       0xd40, 0xffffffff, 0x19b,
+       0xd41, 0xffffffff, 0xc0998,
+       0xd40, 0xffffffff, 0x1a9,
+       0xd41, 0xffffffff, 0x409a7,
+       0xd40, 0xffffffff, 0x1af,
+       0xd41, 0xffffffff, 0xcdc,
+       0xd40, 0xffffffff, 0x1b1,
+       0xd41, 0xffffffff, 0x800,
+       0xd42, 0xffffffff, 0x6c9b2000,
+       0xd44, 0xfc00, 0x2000,
+       0xd51, 0xffffffff, 0xfc0,
+       0xa35, 0x00000100, 0x100
+};
+
+static const u32 verde_golden_rlc_registers[] =
+{
+       0x3109, 0xffffffff, 0x033f1005,
+       0x311f, 0xffffffff, 0x10808020,
+       0x3122, 0xffffffff, 0x00800008,
+       0x30c5, 0xffffffff, 0x00001000,
+       0x30c3, 0xffffffff, 0x80010014
+};
+
+static const u32 verde_golden_registers[] =
+{
+       0x2684, 0x00010000, 0x00018208,
+       0x260c, 0xffffffff, 0x00000000,
+       0x260d, 0xf00fffff, 0x00000400,
+       0x260e, 0x0002021c, 0x00020200,
+       0x031e, 0x00000080, 0x00000000,
+       0x340c, 0x000300c0, 0x00800040,
+       0x340c, 0x000300c0, 0x00800040,
+       0x360c, 0x000300c0, 0x00800040,
+       0x360c, 0x000300c0, 0x00800040,
+       0x16ec, 0x000000f0, 0x00000070,
+       0x16f0, 0x00200000, 0x50100000,
+
+       0x1c0c, 0x31000311, 0x00000011,
+       0x0ab9, 0x00073ffe, 0x000022a2,
+       0x0ab9, 0x00073ffe, 0x000022a2,
+       0x0ab9, 0x00073ffe, 0x000022a2,
+       0x0903, 0x000007ff, 0x00000000,
+       0x0903, 0x000007ff, 0x00000000,
+       0x0903, 0x000007ff, 0x00000000,
+       0x2285, 0xf000001f, 0x00000007,
+       0x2285, 0xf000001f, 0x00000007,
+       0x2285, 0xf000001f, 0x00000007,
+       0x2285, 0xffffffff, 0x00ffffff,
+       0x22c4, 0x0000ff0f, 0x00000000,
+
+       0xa293, 0x07ffffff, 0x4e000000,
+       0xa0d4, 0x3f3f3fff, 0x0000124a,
+       0xa0d4, 0x3f3f3fff, 0x0000124a,
+       0xa0d4, 0x3f3f3fff, 0x0000124a,
+       0x000c, 0x000000ff, 0x0040,
+       0x000d, 0x00000040, 0x00004040,
+       0x2440, 0x07ffffff, 0x03000000,
+       0x2440, 0x07ffffff, 0x03000000,
+       0x23a2, 0x01ff1f3f, 0x00000000,
+       0x23a3, 0x01ff1f3f, 0x00000000,
+       0x23a2, 0x01ff1f3f, 0x00000000,
+       0x23a1, 0x01ff1f3f, 0x00000000,
+       0x23a1, 0x01ff1f3f, 0x00000000,
+
+       0x23a1, 0x01ff1f3f, 0x00000000,
+       0x2418, 0x0000007f, 0x00000020,
+       0x2542, 0x00010000, 0x00010000,
+       0x2b01, 0x000003ff, 0x00000003,
+       0x2b05, 0x000003ff, 0x00000003,
+       0x2b05, 0x000003ff, 0x00000003,
+       0x2b04, 0xffffffff, 0x00000000,
+       0x2b04, 0xffffffff, 0x00000000,
+       0x2b04, 0xffffffff, 0x00000000,
+       0x2b03, 0xffffffff, 0x00001032,
+       0x2b03, 0xffffffff, 0x00001032,
+       0x2b03, 0xffffffff, 0x00001032,
+       0x2235, 0x0000001f, 0x00000010,
+       0x2235, 0x0000001f, 0x00000010,
+       0x2235, 0x0000001f, 0x00000010,
+       0x0570, 0x000c0fc0, 0x000c0400
+};
+
+static const u32 oland_golden_registers[] =
+{
+       0x2684, 0x00010000, 0x00018208,
+       0x260c, 0xffffffff, 0x00000000,
+       0x260d, 0xf00fffff, 0x00000400,
+       0x260e, 0x0002021c, 0x00020200,
+       0x031e, 0x00000080, 0x00000000,
+       0x340c, 0x000300c0, 0x00800040,
+       0x360c, 0x000300c0, 0x00800040,
+       0x16ec, 0x000000f0, 0x00000070,
+       0x16f9, 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,
+       0x000c, 0x000000ff, 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
+};
+
+static const u32 oland_golden_rlc_registers[] =
+{
+       0x3109, 0xffffffff, 0x00601005,
+       0x311f, 0xffffffff, 0x10104040,
+       0x3122, 0xffffffff, 0x0100000a,
+       0x30c5, 0xffffffff, 0x00000800,
+       0x30c3, 0xffffffff, 0x800000f4
+};
+
+static const u32 hainan_golden_registers[] =
+{
+       0x2684, 0x00010000, 0x00018208,
+       0x260c, 0xffffffff, 0x00000000,
+       0x260d, 0xf00fffff, 0x00000400,
+       0x260e, 0x0002021c, 0x00020200,
+       0x4595, 0xff000fff, 0x00000100,
+       0x340c, 0x000300c0, 0x00800040,
+       0x3630, 0xff000fff, 0x00000100,
+       0x360c, 0x000300c0, 0x00800040,
+       0x0ab9, 0x00073ffe, 0x000022a2,
+       0x0903, 0x000007ff, 0x00000000,
+       0x2285, 0xf000001f, 0x00000007,
+       0x22c9, 0xffffffff, 0x00ffffff,
+       0x22c4, 0x0000ff0f, 0x00000000,
+       0xa393, 0x07ffffff, 0x4e000000,
+       0xa0d4, 0x3f3f3fff, 0x00000000,
+       0x000c, 0x000000ff, 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
+};
+
+static const u32 hainan_golden_registers2[] =
+{
+       0x263e, 0xffffffff, 0x02010001
+};
+
+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,
+       0x2458, 0xffffffff, 0x00010000,
+       0x2459, 0xffffffff, 0x00030002,
+       0x245a, 0xffffffff, 0x00040007,
+       0x245b, 0xffffffff, 0x00060005,
+       0x245c, 0xffffffff, 0x00090008,
+       0x245d, 0xffffffff, 0x00020001,
+       0x245e, 0xffffffff, 0x00040003,
+       0x245f, 0xffffffff, 0x00000007,
+       0x2460, 0xffffffff, 0x00060005,
+       0x2461, 0xffffffff, 0x00090008,
+       0x2462, 0xffffffff, 0x00030002,
+       0x2463, 0xffffffff, 0x00050004,
+       0x2464, 0xffffffff, 0x00000008,
+       0x2465, 0xffffffff, 0x00070006,
+       0x2466, 0xffffffff, 0x000a0009,
+       0x2467, 0xffffffff, 0x00040003,
+       0x2468, 0xffffffff, 0x00060005,
+       0x2469, 0xffffffff, 0x00000009,
+       0x246a, 0xffffffff, 0x00080007,
+       0x246b, 0xffffffff, 0x000b000a,
+       0x246c, 0xffffffff, 0x00050004,
+       0x246d, 0xffffffff, 0x00070006,
+       0x246e, 0xffffffff, 0x0008000b,
+       0x246f, 0xffffffff, 0x000a0009,
+       0x2470, 0xffffffff, 0x000d000c,
+       0x2471, 0xffffffff, 0x00060005,
+       0x2472, 0xffffffff, 0x00080007,
+       0x2473, 0xffffffff, 0x0000000b,
+       0x2474, 0xffffffff, 0x000a0009,
+       0x2475, 0xffffffff, 0x000d000c,
+       0x2476, 0xffffffff, 0x00070006,
+       0x2477, 0xffffffff, 0x00090008,
+       0x2478, 0xffffffff, 0x0000000c,
+       0x2479, 0xffffffff, 0x000b000a,
+       0x247a, 0xffffffff, 0x000e000d,
+       0x247b, 0xffffffff, 0x00080007,
+       0x247c, 0xffffffff, 0x000a0009,
+       0x247d, 0xffffffff, 0x0000000d,
+       0x247e, 0xffffffff, 0x000c000b,
+       0x247f, 0xffffffff, 0x000f000e,
+       0x2480, 0xffffffff, 0x00090008,
+       0x2481, 0xffffffff, 0x000b000a,
+       0x2482, 0xffffffff, 0x000c000f,
+       0x2483, 0xffffffff, 0x000e000d,
+       0x2484, 0xffffffff, 0x00110010,
+       0x2485, 0xffffffff, 0x000a0009,
+       0x2486, 0xffffffff, 0x000c000b,
+       0x2487, 0xffffffff, 0x0000000f,
+       0x2488, 0xffffffff, 0x000e000d,
+       0x2489, 0xffffffff, 0x00110010,
+       0x248a, 0xffffffff, 0x000b000a,
+       0x248b, 0xffffffff, 0x000d000c,
+       0x248c, 0xffffffff, 0x00000010,
+       0x248d, 0xffffffff, 0x000f000e,
+       0x248e, 0xffffffff, 0x00120011,
+       0x248f, 0xffffffff, 0x000c000b,
+       0x2490, 0xffffffff, 0x000e000d,
+       0x2491, 0xffffffff, 0x00000011,
+       0x2492, 0xffffffff, 0x0010000f,
+       0x2493, 0xffffffff, 0x00130012,
+       0x2494, 0xffffffff, 0x000d000c,
+       0x2495, 0xffffffff, 0x000f000e,
+       0x2496, 0xffffffff, 0x00100013,
+       0x2497, 0xffffffff, 0x00120011,
+       0x2498, 0xffffffff, 0x00150014,
+       0x2499, 0xffffffff, 0x000e000d,
+       0x249a, 0xffffffff, 0x0010000f,
+       0x249b, 0xffffffff, 0x00000013,
+       0x249c, 0xffffffff, 0x00120011,
+       0x249d, 0xffffffff, 0x00150014,
+       0x249e, 0xffffffff, 0x000f000e,
+       0x249f, 0xffffffff, 0x00110010,
+       0x24a0, 0xffffffff, 0x00000014,
+       0x24a1, 0xffffffff, 0x00130012,
+       0x24a2, 0xffffffff, 0x00160015,
+       0x24a3, 0xffffffff, 0x0010000f,
+       0x24a4, 0xffffffff, 0x00120011,
+       0x24a5, 0xffffffff, 0x00000015,
+       0x24a6, 0xffffffff, 0x00140013,
+       0x24a7, 0xffffffff, 0x00170016,
+       0x2454, 0xffffffff, 0x96940200,
+       0x21c2, 0xffffffff, 0x00900100,
+       0x311e, 0xffffffff, 0x00000080,
+       0x3101, 0xffffffff, 0x0020003f,
+       0xc, 0xffffffff, 0x0000001c,
+       0xd, 0x000f0000, 0x000f0000,
+       0x583, 0xffffffff, 0x00000100,
+       0x409, 0xffffffff, 0x00000100,
+       0x40b, 0x00000101, 0x00000000,
+       0x82a, 0xffffffff, 0x00000104,
+       0x993, 0x000c0000, 0x000c0000,
+       0x992, 0x000c0000, 0x000c0000,
+       0x1579, 0xff000fff, 0x00000100,
+       0x157a, 0x00000001, 0x00000001,
+       0xbd4, 0x00000001, 0x00000001,
+       0xc33, 0xc0000fff, 0x00000104,
+       0x3079, 0x00000001, 0x00000001,
+       0x3430, 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,
+       0x2458, 0xffffffff, 0x00010000,
+       0x2459, 0xffffffff, 0x00030002,
+       0x245a, 0xffffffff, 0x00040007,
+       0x245b, 0xffffffff, 0x00060005,
+       0x245c, 0xffffffff, 0x00090008,
+       0x245d, 0xffffffff, 0x00020001,
+       0x245e, 0xffffffff, 0x00040003,
+       0x245f, 0xffffffff, 0x00000007,
+       0x2460, 0xffffffff, 0x00060005,
+       0x2461, 0xffffffff, 0x00090008,
+       0x2462, 0xffffffff, 0x00030002,
+       0x2463, 0xffffffff, 0x00050004,
+       0x2464, 0xffffffff, 0x00000008,
+       0x2465, 0xffffffff, 0x00070006,
+       0x2466, 0xffffffff, 0x000a0009,
+       0x2467, 0xffffffff, 0x00040003,
+       0x2468, 0xffffffff, 0x00060005,
+       0x2469, 0xffffffff, 0x00000009,
+       0x246a, 0xffffffff, 0x00080007,
+       0x246b, 0xffffffff, 0x000b000a,
+       0x246c, 0xffffffff, 0x00050004,
+       0x246d, 0xffffffff, 0x00070006,
+       0x246e, 0xffffffff, 0x0008000b,
+       0x246f, 0xffffffff, 0x000a0009,
+       0x2470, 0xffffffff, 0x000d000c,
+       0x2480, 0xffffffff, 0x00090008,
+       0x2481, 0xffffffff, 0x000b000a,
+       0x2482, 0xffffffff, 0x000c000f,
+       0x2483, 0xffffffff, 0x000e000d,
+       0x2484, 0xffffffff, 0x00110010,
+       0x2485, 0xffffffff, 0x000a0009,
+       0x2486, 0xffffffff, 0x000c000b,
+       0x2487, 0xffffffff, 0x0000000f,
+       0x2488, 0xffffffff, 0x000e000d,
+       0x2489, 0xffffffff, 0x00110010,
+       0x248a, 0xffffffff, 0x000b000a,
+       0x248b, 0xffffffff, 0x000d000c,
+       0x248c, 0xffffffff, 0x00000010,
+       0x248d, 0xffffffff, 0x000f000e,
+       0x248e, 0xffffffff, 0x00120011,
+       0x248f, 0xffffffff, 0x000c000b,
+       0x2490, 0xffffffff, 0x000e000d,
+       0x2491, 0xffffffff, 0x00000011,
+       0x2492, 0xffffffff, 0x0010000f,
+       0x2493, 0xffffffff, 0x00130012,
+       0x2494, 0xffffffff, 0x000d000c,
+       0x2495, 0xffffffff, 0x000f000e,
+       0x2496, 0xffffffff, 0x00100013,
+       0x2497, 0xffffffff, 0x00120011,
+       0x2498, 0xffffffff, 0x00150014,
+       0x2454, 0xffffffff, 0x96940200,
+       0x21c2, 0xffffffff, 0x00900100,
+       0x311e, 0xffffffff, 0x00000080,
+       0x3101, 0xffffffff, 0x0020003f,
+       0xc, 0xffffffff, 0x0000001c,
+       0xd, 0x000f0000, 0x000f0000,
+       0x583, 0xffffffff, 0x00000100,
+       0x409, 0xffffffff, 0x00000100,
+       0x40b, 0x00000101, 0x00000000,
+       0x82a, 0xffffffff, 0x00000104,
+       0x1579, 0xff000fff, 0x00000100,
+       0x157a, 0x00000001, 0x00000001,
+       0xbd4, 0x00000001, 0x00000001,
+       0xc33, 0xc0000fff, 0x00000104,
+       0x3079, 0x00000001, 0x00000001,
+       0x3430, 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,
+       0x2458, 0xffffffff, 0x00010000,
+       0x2459, 0xffffffff, 0x00030002,
+       0x245a, 0xffffffff, 0x00040007,
+       0x245b, 0xffffffff, 0x00060005,
+       0x245c, 0xffffffff, 0x00090008,
+       0x245d, 0xffffffff, 0x00020001,
+       0x245e, 0xffffffff, 0x00040003,
+       0x245f, 0xffffffff, 0x00000007,
+       0x2460, 0xffffffff, 0x00060005,
+       0x2461, 0xffffffff, 0x00090008,
+       0x2462, 0xffffffff, 0x00030002,
+       0x2463, 0xffffffff, 0x00050004,
+       0x2464, 0xffffffff, 0x00000008,
+       0x2465, 0xffffffff, 0x00070006,
+       0x2466, 0xffffffff, 0x000a0009,
+       0x2467, 0xffffffff, 0x00040003,
+       0x2468, 0xffffffff, 0x00060005,
+       0x2469, 0xffffffff, 0x00000009,
+       0x246a, 0xffffffff, 0x00080007,
+       0x246b, 0xffffffff, 0x000b000a,
+       0x246c, 0xffffffff, 0x00050004,
+       0x246d, 0xffffffff, 0x00070006,
+       0x246e, 0xffffffff, 0x0008000b,
+       0x246f, 0xffffffff, 0x000a0009,
+       0x2470, 0xffffffff, 0x000d000c,
+       0x2480, 0xffffffff, 0x00090008,
+       0x2481, 0xffffffff, 0x000b000a,
+       0x2482, 0xffffffff, 0x000c000f,
+       0x2483, 0xffffffff, 0x000e000d,
+       0x2484, 0xffffffff, 0x00110010,
+       0x2485, 0xffffffff, 0x000a0009,
+       0x2486, 0xffffffff, 0x000c000b,
+       0x2487, 0xffffffff, 0x0000000f,
+       0x2488, 0xffffffff, 0x000e000d,
+       0x2489, 0xffffffff, 0x00110010,
+       0x248a, 0xffffffff, 0x000b000a,
+       0x248b, 0xffffffff, 0x000d000c,
+       0x248c, 0xffffffff, 0x00000010,
+       0x248d, 0xffffffff, 0x000f000e,
+       0x248e, 0xffffffff, 0x00120011,
+       0x248f, 0xffffffff, 0x000c000b,
+       0x2490, 0xffffffff, 0x000e000d,
+       0x2491, 0xffffffff, 0x00000011,
+       0x2492, 0xffffffff, 0x0010000f,
+       0x2493, 0xffffffff, 0x00130012,
+       0x2494, 0xffffffff, 0x000d000c,
+       0x2495, 0xffffffff, 0x000f000e,
+       0x2496, 0xffffffff, 0x00100013,
+       0x2497, 0xffffffff, 0x00120011,
+       0x2498, 0xffffffff, 0x00150014,
+       0x2454, 0xffffffff, 0x96940200,
+       0x21c2, 0xffffffff, 0x00900100,
+       0x311e, 0xffffffff, 0x00000080,
+       0x3101, 0xffffffff, 0x0020003f,
+       0xc, 0xffffffff, 0x0000001c,
+       0xd, 0x000f0000, 0x000f0000,
+       0x583, 0xffffffff, 0x00000100,
+       0x409, 0xffffffff, 0x00000100,
+       0x40b, 0x00000101, 0x00000000,
+       0x82a, 0xffffffff, 0x00000104,
+       0x993, 0x000c0000, 0x000c0000,
+       0x992, 0x000c0000, 0x000c0000,
+       0x1579, 0xff000fff, 0x00000100,
+       0x157a, 0x00000001, 0x00000001,
+       0xbd4, 0x00000001, 0x00000001,
+       0xc33, 0xc0000fff, 0x00000104,
+       0x3079, 0x00000001, 0x00000001,
+       0x3430, 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,
+       0x2458, 0xffffffff, 0x00010000,
+       0x2459, 0xffffffff, 0x00030002,
+       0x245a, 0xffffffff, 0x00040007,
+       0x245b, 0xffffffff, 0x00060005,
+       0x245c, 0xffffffff, 0x00090008,
+       0x245d, 0xffffffff, 0x00020001,
+       0x245e, 0xffffffff, 0x00040003,
+       0x245f, 0xffffffff, 0x00000007,
+       0x2460, 0xffffffff, 0x00060005,
+       0x2461, 0xffffffff, 0x00090008,
+       0x2462, 0xffffffff, 0x00030002,
+       0x2463, 0xffffffff, 0x00050004,
+       0x2464, 0xffffffff, 0x00000008,
+       0x2465, 0xffffffff, 0x00070006,
+       0x2466, 0xffffffff, 0x000a0009,
+       0x2467, 0xffffffff, 0x00040003,
+       0x2468, 0xffffffff, 0x00060005,
+       0x2469, 0xffffffff, 0x00000009,
+       0x246a, 0xffffffff, 0x00080007,
+       0x246b, 0xffffffff, 0x000b000a,
+       0x246c, 0xffffffff, 0x00050004,
+       0x246d, 0xffffffff, 0x00070006,
+       0x246e, 0xffffffff, 0x0008000b,
+       0x246f, 0xffffffff, 0x000a0009,
+       0x2470, 0xffffffff, 0x000d000c,
+       0x2471, 0xffffffff, 0x00060005,
+       0x2472, 0xffffffff, 0x00080007,
+       0x2473, 0xffffffff, 0x0000000b,
+       0x2474, 0xffffffff, 0x000a0009,
+       0x2475, 0xffffffff, 0x000d000c,
+       0x2454, 0xffffffff, 0x96940200,
+       0x21c2, 0xffffffff, 0x00900100,
+       0x311e, 0xffffffff, 0x00000080,
+       0x3101, 0xffffffff, 0x0020003f,
+       0xc, 0xffffffff, 0x0000001c,
+       0xd, 0x000f0000, 0x000f0000,
+       0x583, 0xffffffff, 0x00000100,
+       0x409, 0xffffffff, 0x00000100,
+       0x40b, 0x00000101, 0x00000000,
+       0x82a, 0xffffffff, 0x00000104,
+       0x993, 0x000c0000, 0x000c0000,
+       0x992, 0x000c0000, 0x000c0000,
+       0x1579, 0xff000fff, 0x00000100,
+       0x157a, 0x00000001, 0x00000001,
+       0xbd4, 0x00000001, 0x00000001,
+       0xc33, 0xc0000fff, 0x00000104,
+       0x3079, 0x00000001, 0x00000001,
+       0x3430, 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,
+       0x2458, 0xffffffff, 0x00010000,
+       0x2459, 0xffffffff, 0x00030002,
+       0x245a, 0xffffffff, 0x00040007,
+       0x245b, 0xffffffff, 0x00060005,
+       0x245c, 0xffffffff, 0x00090008,
+       0x245d, 0xffffffff, 0x00020001,
+       0x245e, 0xffffffff, 0x00040003,
+       0x245f, 0xffffffff, 0x00000007,
+       0x2460, 0xffffffff, 0x00060005,
+       0x2461, 0xffffffff, 0x00090008,
+       0x2462, 0xffffffff, 0x00030002,
+       0x2463, 0xffffffff, 0x00050004,
+       0x2464, 0xffffffff, 0x00000008,
+       0x2465, 0xffffffff, 0x00070006,
+       0x2466, 0xffffffff, 0x000a0009,
+       0x2467, 0xffffffff, 0x00040003,
+       0x2468, 0xffffffff, 0x00060005,
+       0x2469, 0xffffffff, 0x00000009,
+       0x246a, 0xffffffff, 0x00080007,
+       0x246b, 0xffffffff, 0x000b000a,
+       0x246c, 0xffffffff, 0x00050004,
+       0x246d, 0xffffffff, 0x00070006,
+       0x246e, 0xffffffff, 0x0008000b,
+       0x246f, 0xffffffff, 0x000a0009,
+       0x2470, 0xffffffff, 0x000d000c,
+       0x2471, 0xffffffff, 0x00060005,
+       0x2472, 0xffffffff, 0x00080007,
+       0x2473, 0xffffffff, 0x0000000b,
+       0x2474, 0xffffffff, 0x000a0009,
+       0x2475, 0xffffffff, 0x000d000c,
+       0x2454, 0xffffffff, 0x96940200,
+       0x21c2, 0xffffffff, 0x00900100,
+       0x311e, 0xffffffff, 0x00000080,
+       0x3101, 0xffffffff, 0x0020003f,
+       0xc, 0xffffffff, 0x0000001c,
+       0xd, 0x000f0000, 0x000f0000,
+       0x583, 0xffffffff, 0x00000100,
+       0x409, 0xffffffff, 0x00000100,
+       0x82a, 0xffffffff, 0x00000104,
+       0x993, 0x000c0000, 0x000c0000,
+       0x992, 0x000c0000, 0x000c0000,
+       0xbd4, 0x00000001, 0x00000001,
+       0xc33, 0xc0000fff, 0x00000104,
+       0x3079, 0x00000001, 0x00000001,
+       0x3430, 0xfffffff0, 0x00000100,
+       0x3630, 0xfffffff0, 0x00000100
+};
+
+static u32 si_pcie_rreg(struct amdgpu_device *adev, u32 reg)
+{
+       unsigned long flags;
+       u32 r;
+
+       spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+       WREG32(AMDGPU_PCIE_INDEX, reg);
+       (void)RREG32(AMDGPU_PCIE_INDEX);
+       r = RREG32(AMDGPU_PCIE_DATA);
+       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+       return r;
+}
+
+static void si_pcie_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+       WREG32(AMDGPU_PCIE_INDEX, reg);
+       (void)RREG32(AMDGPU_PCIE_INDEX);
+       WREG32(AMDGPU_PCIE_DATA, v);
+       (void)RREG32(AMDGPU_PCIE_DATA);
+       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+}
+
+u32 si_pciep_rreg(struct amdgpu_device *adev, u32 reg)
+{
+       unsigned long flags;
+       u32 r;
+
+       spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+       WREG32(PCIE_PORT_INDEX, ((reg) & 0xff));
+       (void)RREG32(PCIE_PORT_INDEX);
+       r = RREG32(PCIE_PORT_DATA);
+       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+       return r;
+}
+
+void si_pciep_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+       WREG32(PCIE_PORT_INDEX, ((reg) & 0xff));
+       (void)RREG32(PCIE_PORT_INDEX);
+       WREG32(PCIE_PORT_DATA, (v));
+       (void)RREG32(PCIE_PORT_DATA);
+       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+}
+
+static u32 si_smc_rreg(struct amdgpu_device *adev, u32 reg)
+{
+       unsigned long flags;
+       u32 r;
+
+       spin_lock_irqsave(&adev->smc_idx_lock, flags);
+       WREG32(SMC_IND_INDEX_0, (reg));
+       r = RREG32(SMC_IND_DATA_0);
+       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+       return r;
+}
+
+static void si_smc_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&adev->smc_idx_lock, flags);
+       WREG32(SMC_IND_INDEX_0, (reg));
+       WREG32(SMC_IND_DATA_0, (v));
+       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+}
+
+static struct amdgpu_allowed_register_entry si_allowed_read_registers[] = {
+       {GRBM_STATUS, false},
+       {GB_ADDR_CONFIG, false},
+       {MC_ARB_RAMCFG, false},
+       {GB_TILE_MODE0, false},
+       {GB_TILE_MODE1, false},
+       {GB_TILE_MODE2, false},
+       {GB_TILE_MODE3, false},
+       {GB_TILE_MODE4, false},
+       {GB_TILE_MODE5, false},
+       {GB_TILE_MODE6, false},
+       {GB_TILE_MODE7, false},
+       {GB_TILE_MODE8, false},
+       {GB_TILE_MODE9, false},
+       {GB_TILE_MODE10, false},
+       {GB_TILE_MODE11, false},
+       {GB_TILE_MODE12, false},
+       {GB_TILE_MODE13, false},
+       {GB_TILE_MODE14, false},
+       {GB_TILE_MODE15, false},
+       {GB_TILE_MODE16, false},
+       {GB_TILE_MODE17, false},
+       {GB_TILE_MODE18, false},
+       {GB_TILE_MODE19, false},
+       {GB_TILE_MODE20, false},
+       {GB_TILE_MODE21, false},
+       {GB_TILE_MODE22, false},
+       {GB_TILE_MODE23, false},
+       {GB_TILE_MODE24, false},
+       {GB_TILE_MODE25, false},
+       {GB_TILE_MODE26, false},
+       {GB_TILE_MODE27, false},
+       {GB_TILE_MODE28, false},
+       {GB_TILE_MODE29, false},
+       {GB_TILE_MODE30, false},
+       {GB_TILE_MODE31, false},
+       {CC_RB_BACKEND_DISABLE, false, true},
+       {GC_USER_RB_BACKEND_DISABLE, false, true},
+       {PA_SC_RASTER_CONFIG, false, true},
+};
+
+static uint32_t si_read_indexed_register(struct amdgpu_device *adev,
+                                         u32 se_num, u32 sh_num,
+                                         u32 reg_offset)
+{
+       uint32_t val;
+
+       mutex_lock(&adev->grbm_idx_mutex);
+       if (se_num != 0xffffffff || sh_num != 0xffffffff)
+               amdgpu_gfx_select_se_sh(adev, se_num, sh_num, 0xffffffff);
+
+       val = RREG32(reg_offset);
+
+       if (se_num != 0xffffffff || sh_num != 0xffffffff)
+               amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+       mutex_unlock(&adev->grbm_idx_mutex);
+       return val;
+}
+
+static int si_read_register(struct amdgpu_device *adev, u32 se_num,
+                            u32 sh_num, u32 reg_offset, u32 *value)
+{
+       uint32_t i;
+
+       *value = 0;
+       for (i = 0; i < ARRAY_SIZE(si_allowed_read_registers); i++) {
+               if (reg_offset != si_allowed_read_registers[i].reg_offset)
+                       continue;
+
+               if (!si_allowed_read_registers[i].untouched)
+                       *value = si_allowed_read_registers[i].grbm_indexed ?
+                                si_read_indexed_register(adev, se_num,
+                                                          sh_num, reg_offset) :
+                                RREG32(reg_offset);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static bool si_read_disabled_bios(struct amdgpu_device *adev)
+{
+       u32 bus_cntl;
+       u32 d1vga_control = 0;
+       u32 d2vga_control = 0;
+       u32 vga_render_control = 0;
+       u32 rom_cntl;
+       bool r;
+
+       bus_cntl = RREG32(R600_BUS_CNTL);
+       if (adev->mode_info.num_crtc) {
+               d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
+               d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
+               vga_render_control = RREG32(VGA_RENDER_CONTROL);
+       }
+       rom_cntl = RREG32(R600_ROM_CNTL);
+
+       /* enable the rom */
+       WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
+       if (adev->mode_info.num_crtc) {
+               /* Disable VGA mode */
+               WREG32(AVIVO_D1VGA_CONTROL,
+                      (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+                                         AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+               WREG32(AVIVO_D2VGA_CONTROL,
+                      (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+                                         AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+               WREG32(VGA_RENDER_CONTROL,
+                      (vga_render_control & C_000300_VGA_VSTATUS_CNTL));
+       }
+       WREG32(R600_ROM_CNTL, rom_cntl | R600_SCK_OVERWRITE);
+
+       r = amdgpu_read_bios(adev);
+
+       /* restore regs */
+       WREG32(R600_BUS_CNTL, bus_cntl);
+       if (adev->mode_info.num_crtc) {
+               WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
+               WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
+               WREG32(VGA_RENDER_CONTROL, vga_render_control);
+       }
+       WREG32(R600_ROM_CNTL, rom_cntl);
+       return r;
+}
+
+//xxx: not implemented
+static int si_asic_reset(struct amdgpu_device *adev)
+{
+       return 0;
+}
+
+static void si_vga_set_state(struct amdgpu_device *adev, bool state)
+{
+       uint32_t temp;
+
+       temp = RREG32(CONFIG_CNTL);
+       if (state == false) {
+               temp &= ~(1<<0);
+               temp |= (1<<1);
+       } else {
+               temp &= ~(1<<1);
+       }
+       WREG32(CONFIG_CNTL, temp);
+}
+
+static u32 si_get_xclk(struct amdgpu_device *adev)
+{
+        u32 reference_clock = adev->clock.spll.reference_freq;
+       u32 tmp;
+
+       tmp = RREG32(CG_CLKPIN_CNTL_2);
+       if (tmp & MUX_TCLK_TO_XCLK)
+               return TCLK;
+
+       tmp = RREG32(CG_CLKPIN_CNTL);
+       if (tmp & XTALIN_DIVIDE)
+               return reference_clock / 4;
+
+       return reference_clock;
+}
+
+//xxx:not implemented
+static int si_set_uvd_clocks(struct amdgpu_device *adev, u32 vclk, u32 dclk)
+{
+       return 0;
+}
+
+static void si_detect_hw_virtualization(struct amdgpu_device *adev)
+{
+       if (is_virtual_machine()) /* passthrough mode */
+               adev->virtualization.virtual_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,
+       .get_xclk = &si_get_xclk,
+       .set_uvd_clocks = &si_set_uvd_clocks,
+       .set_vce_clocks = NULL,
+};
+
+static uint32_t si_get_rev_id(struct amdgpu_device *adev)
+{
+       return (RREG32(CC_DRM_ID_STRAPS) & CC_DRM_ID_STRAPS__ATI_REV_ID_MASK)
+               >> CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT;
+}
+
+static int si_common_early_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       adev->smc_rreg = &si_smc_rreg;
+       adev->smc_wreg = &si_smc_wreg;
+       adev->pcie_rreg = &si_pcie_rreg;
+       adev->pcie_wreg = &si_pcie_wreg;
+       adev->pciep_rreg = &si_pciep_rreg;
+       adev->pciep_wreg = &si_pciep_wreg;
+       adev->uvd_ctx_rreg = NULL;
+       adev->uvd_ctx_wreg = NULL;
+       adev->didt_rreg = NULL;
+       adev->didt_wreg = NULL;
+
+       adev->asic_funcs = &si_asic_funcs;
+
+       adev->rev_id = si_get_rev_id(adev);
+       adev->external_rev_id = 0xFF;
+       switch (adev->asic_type) {
+       case CHIP_TAHITI:
+               adev->cg_flags =
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_MGLS |
+                       /*AMD_CG_SUPPORT_GFX_CGCG |*/
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_CGTS |
+                       AMD_CG_SUPPORT_GFX_CP_LS |
+                       AMD_CG_SUPPORT_MC_MGCG |
+                       AMD_CG_SUPPORT_SDMA_MGCG |
+                       AMD_CG_SUPPORT_BIF_LS |
+                       AMD_CG_SUPPORT_VCE_MGCG |
+                       AMD_CG_SUPPORT_UVD_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG;
+                       adev->pg_flags = 0;
+               break;
+       case CHIP_PITCAIRN:
+               adev->cg_flags =
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_MGLS |
+                       /*AMD_CG_SUPPORT_GFX_CGCG |*/
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_CGTS |
+                       AMD_CG_SUPPORT_GFX_CP_LS |
+                       AMD_CG_SUPPORT_GFX_RLC_LS |
+                       AMD_CG_SUPPORT_MC_LS |
+                       AMD_CG_SUPPORT_MC_MGCG |
+                       AMD_CG_SUPPORT_SDMA_MGCG |
+                       AMD_CG_SUPPORT_BIF_LS |
+                       AMD_CG_SUPPORT_VCE_MGCG |
+                       AMD_CG_SUPPORT_UVD_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG;
+               adev->pg_flags = 0;
+               break;
+
+       case CHIP_VERDE:
+               adev->cg_flags =
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_MGLS |
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_CGTS |
+                       AMD_CG_SUPPORT_GFX_CGTS_LS |
+                       AMD_CG_SUPPORT_GFX_CP_LS |
+                       AMD_CG_SUPPORT_MC_LS |
+                       AMD_CG_SUPPORT_MC_MGCG |
+                       AMD_CG_SUPPORT_SDMA_MGCG |
+                       AMD_CG_SUPPORT_SDMA_LS |
+                       AMD_CG_SUPPORT_BIF_LS |
+                       AMD_CG_SUPPORT_VCE_MGCG |
+                       AMD_CG_SUPPORT_UVD_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG;
+               adev->pg_flags = 0;
+               //???
+               adev->external_rev_id = adev->rev_id + 0x14;
+               break;
+       case CHIP_OLAND:
+               adev->cg_flags =
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_MGLS |
+                       /*AMD_CG_SUPPORT_GFX_CGCG |*/
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_CGTS |
+                       AMD_CG_SUPPORT_GFX_CP_LS |
+                       AMD_CG_SUPPORT_GFX_RLC_LS |
+                       AMD_CG_SUPPORT_MC_LS |
+                       AMD_CG_SUPPORT_MC_MGCG |
+                       AMD_CG_SUPPORT_SDMA_MGCG |
+                       AMD_CG_SUPPORT_BIF_LS |
+                       AMD_CG_SUPPORT_UVD_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG;
+               adev->pg_flags = 0;
+               break;
+       case CHIP_HAINAN:
+               adev->cg_flags =
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_MGLS |
+                       /*AMD_CG_SUPPORT_GFX_CGCG |*/
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_CGTS |
+                       AMD_CG_SUPPORT_GFX_CP_LS |
+                       AMD_CG_SUPPORT_GFX_RLC_LS |
+                       AMD_CG_SUPPORT_MC_LS |
+                       AMD_CG_SUPPORT_MC_MGCG |
+                       AMD_CG_SUPPORT_SDMA_MGCG |
+                       AMD_CG_SUPPORT_BIF_LS |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG;
+               adev->pg_flags = 0;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int si_common_sw_init(void *handle)
+{
+       return 0;
+}
+
+static int si_common_sw_fini(void *handle)
+{
+       return 0;
+}
+
+
+static void si_init_golden_registers(struct amdgpu_device *adev)
+{
+       switch (adev->asic_type) {
+       case CHIP_TAHITI:
+               amdgpu_program_register_sequence(adev,
+                                                tahiti_golden_registers,
+                                                (const u32)ARRAY_SIZE(tahiti_golden_registers));
+               amdgpu_program_register_sequence(adev,
+                                                tahiti_golden_rlc_registers,
+                                                (const u32)ARRAY_SIZE(tahiti_golden_rlc_registers));
+               amdgpu_program_register_sequence(adev,
+                                                tahiti_mgcg_cgcg_init,
+                                                (const u32)ARRAY_SIZE(tahiti_mgcg_cgcg_init));
+               amdgpu_program_register_sequence(adev,
+                                                tahiti_golden_registers2,
+                                                (const u32)ARRAY_SIZE(tahiti_golden_registers2));
+               break;
+       case CHIP_PITCAIRN:
+               amdgpu_program_register_sequence(adev,
+                                                pitcairn_golden_registers,
+                                                (const u32)ARRAY_SIZE(pitcairn_golden_registers));
+               amdgpu_program_register_sequence(adev,
+                                                pitcairn_golden_rlc_registers,
+                                                (const u32)ARRAY_SIZE(pitcairn_golden_rlc_registers));
+               amdgpu_program_register_sequence(adev,
+                                                pitcairn_mgcg_cgcg_init,
+                                                (const u32)ARRAY_SIZE(pitcairn_mgcg_cgcg_init));
+       case CHIP_VERDE:
+               amdgpu_program_register_sequence(adev,
+                                                verde_golden_registers,
+                                                (const u32)ARRAY_SIZE(verde_golden_registers));
+               amdgpu_program_register_sequence(adev,
+                                                verde_golden_rlc_registers,
+                                                (const u32)ARRAY_SIZE(verde_golden_rlc_registers));
+               amdgpu_program_register_sequence(adev,
+                                                verde_mgcg_cgcg_init,
+                                                (const u32)ARRAY_SIZE(verde_mgcg_cgcg_init));
+               amdgpu_program_register_sequence(adev,
+                                                verde_pg_init,
+                                                (const u32)ARRAY_SIZE(verde_pg_init));
+               break;
+       case CHIP_OLAND:
+               amdgpu_program_register_sequence(adev,
+                                                oland_golden_registers,
+                                                (const u32)ARRAY_SIZE(oland_golden_registers));
+               amdgpu_program_register_sequence(adev,
+                                                oland_golden_rlc_registers,
+                                                (const u32)ARRAY_SIZE(oland_golden_rlc_registers));
+               amdgpu_program_register_sequence(adev,
+                                                oland_mgcg_cgcg_init,
+                                                (const u32)ARRAY_SIZE(oland_mgcg_cgcg_init));
+       case CHIP_HAINAN:
+               amdgpu_program_register_sequence(adev,
+                                                hainan_golden_registers,
+                                                (const u32)ARRAY_SIZE(hainan_golden_registers));
+               amdgpu_program_register_sequence(adev,
+                                                hainan_golden_registers2,
+                                                (const u32)ARRAY_SIZE(hainan_golden_registers2));
+               amdgpu_program_register_sequence(adev,
+                                                hainan_mgcg_cgcg_init,
+                                                (const u32)ARRAY_SIZE(hainan_mgcg_cgcg_init));
+               break;
+
+
+       default:
+               BUG();
+       }
+}
+
+static void si_pcie_gen3_enable(struct amdgpu_device *adev)
+{
+       struct pci_dev *root = adev->pdev->bus->self;
+       int bridge_pos, gpu_pos;
+       u32 speed_cntl, mask, current_data_rate;
+       int ret, i;
+       u16 tmp16;
+
+       if (pci_is_root_bus(adev->pdev->bus))
+               return;
+
+       if (amdgpu_pcie_gen2 == 0)
+               return;
+
+       if (adev->flags & AMD_IS_APU)
+               return;
+
+       ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
+       if (ret != 0)
+               return;
+
+       if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80)))
+               return;
+
+       speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+       current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >>
+               LC_CURRENT_DATA_RATE_SHIFT;
+       if (mask & DRM_PCIE_SPEED_80) {
+               if (current_data_rate == 2) {
+                       DRM_INFO("PCIE gen 3 link speeds already enabled\n");
+                       return;
+               }
+               DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n");
+       } else if (mask & DRM_PCIE_SPEED_50) {
+               if (current_data_rate == 1) {
+                       DRM_INFO("PCIE gen 2 link speeds already enabled\n");
+                       return;
+               }
+               DRM_INFO("enabling PCIE gen 2 link speeds, disable with amdgpu.pcie_gen2=0\n");
+       }
+
+       bridge_pos = pci_pcie_cap(root);
+       if (!bridge_pos)
+               return;
+
+       gpu_pos = pci_pcie_cap(adev->pdev);
+       if (!gpu_pos)
+               return;
+
+       if (mask & DRM_PCIE_SPEED_80) {
+               if (current_data_rate != 2) {
+                       u16 bridge_cfg, gpu_cfg;
+                       u16 bridge_cfg2, gpu_cfg2;
+                       u32 max_lw, current_lw, tmp;
+
+                       pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
+                       pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+
+                       tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
+                       pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+
+                       tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
+                       pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+
+                       tmp = RREG32_PCIE(PCIE_LC_STATUS1);
+                       max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
+                       current_lw = (tmp & LC_OPERATING_LINK_WIDTH_MASK) >> LC_OPERATING_LINK_WIDTH_SHIFT;
+
+                       if (current_lw < max_lw) {
+                               tmp = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
+                               if (tmp & LC_RENEGOTIATION_SUPPORT) {
+                                       tmp &= ~(LC_LINK_WIDTH_MASK | LC_UPCONFIGURE_DIS);
+                                       tmp |= (max_lw << LC_LINK_WIDTH_SHIFT);
+                                       tmp |= LC_UPCONFIGURE_SUPPORT | LC_RENEGOTIATE_EN | LC_RECONFIG_NOW;
+                                       WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, tmp);
+                               }
+                       }
+
+                       for (i = 0; i < 10; i++) {
+                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+                               if (tmp16 & PCI_EXP_DEVSTA_TRPND)
+                                       break;
+
+                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
+                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+
+                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
+                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+
+                               tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
+                               tmp |= LC_SET_QUIESCE;
+                               WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp);
+
+                               tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
+                               tmp |= LC_REDO_EQ;
+                               WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp);
+
+                               mdelay(100);
+
+                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
+                               tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
+                               tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
+                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+
+                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
+                               tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
+                               tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
+                               pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+
+                               pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
+                               tmp16 &= ~((1 << 4) | (7 << 9));
+                               tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
+                               pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
+
+                               pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
+                               tmp16 &= ~((1 << 4) | (7 << 9));
+                               tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
+                               pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+
+                               tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
+                               tmp &= ~LC_SET_QUIESCE;
+                               WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp);
+                       }
+               }
+       }
+
+       speed_cntl |= LC_FORCE_EN_SW_SPEED_CHANGE | LC_FORCE_DIS_HW_SPEED_CHANGE;
+       speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE;
+       WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+       pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
+       tmp16 &= ~0xf;
+       if (mask & DRM_PCIE_SPEED_80)
+               tmp16 |= 3;
+       else if (mask & DRM_PCIE_SPEED_50)
+               tmp16 |= 2;
+       else
+               tmp16 |= 1;
+       pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+
+       speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+       speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE;
+       WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+               if ((speed_cntl & LC_INITIATE_LINK_SPEED_CHANGE) == 0)
+                       break;
+               udelay(1);
+       }
+}
+
+static inline u32 si_pif_phy0_rreg(struct amdgpu_device *adev, u32 reg)
+{
+       unsigned long flags;
+       u32 r;
+
+       spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+       WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff));
+       r = RREG32(EVERGREEN_PIF_PHY0_DATA);
+       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+       return r;
+}
+
+static inline void si_pif_phy0_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+       WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff));
+       WREG32(EVERGREEN_PIF_PHY0_DATA, (v));
+       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+}
+
+static inline u32 si_pif_phy1_rreg(struct amdgpu_device *adev, u32 reg)
+{
+       unsigned long flags;
+       u32 r;
+
+       spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+       WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff));
+       r = RREG32(EVERGREEN_PIF_PHY1_DATA);
+       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+       return r;
+}
+
+static inline void si_pif_phy1_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+       WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff));
+       WREG32(EVERGREEN_PIF_PHY1_DATA, (v));
+       spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+}
+static void si_program_aspm(struct amdgpu_device *adev)
+{
+       u32 data, orig;
+       bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false;
+       bool disable_clkreq = false;
+
+       if (amdgpu_aspm == 0)
+               return;
+
+       if (adev->flags & AMD_IS_APU)
+               return;
+       orig = data = RREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL);
+       data &= ~LC_XMIT_N_FTS_MASK;
+       data |= LC_XMIT_N_FTS(0x24) | LC_XMIT_N_FTS_OVERRIDE_EN;
+       if (orig != data)
+               WREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL, data);
+
+       orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL3);
+       data |= LC_GO_TO_RECOVERY;
+       if (orig != data)
+               WREG32_PCIE_PORT(PCIE_LC_CNTL3, data);
+
+       orig = data = RREG32_PCIE(PCIE_P_CNTL);
+       data |= P_IGNORE_EDB_ERR;
+       if (orig != data)
+               WREG32_PCIE(PCIE_P_CNTL, data);
+
+       orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+       data &= ~(LC_L0S_INACTIVITY_MASK | LC_L1_INACTIVITY_MASK);
+       data |= LC_PMI_TO_L1_DIS;
+       if (!disable_l0s)
+               data |= LC_L0S_INACTIVITY(7);
+
+       if (!disable_l1) {
+               data |= LC_L1_INACTIVITY(7);
+               data &= ~LC_PMI_TO_L1_DIS;
+               if (orig != data)
+                       WREG32_PCIE_PORT(PCIE_LC_CNTL, data);
+
+               if (!disable_plloff_in_l1) {
+                       bool clk_req_support;
+
+                       orig = data = si_pif_phy0_rreg(adev,PB0_PIF_PWRDOWN_0);
+                       data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
+                       data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
+                       if (orig != data)
+                               si_pif_phy0_wreg(adev,PB0_PIF_PWRDOWN_0, data);
+
+                       orig = data = si_pif_phy0_rreg(adev,PB0_PIF_PWRDOWN_1);
+                       data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
+                       data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
+                       if (orig != data)
+                               si_pif_phy0_wreg(adev,PB0_PIF_PWRDOWN_1, data);
+
+                       orig = data = si_pif_phy1_rreg(adev,PB1_PIF_PWRDOWN_0);
+                       data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
+                       data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
+                       if (orig != data)
+                               si_pif_phy1_wreg(adev,PB1_PIF_PWRDOWN_0, data);
+
+                       orig = data = si_pif_phy1_rreg(adev,PB1_PIF_PWRDOWN_1);
+                       data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
+                       data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
+                       if (orig != data)
+                               si_pif_phy1_wreg(adev,PB1_PIF_PWRDOWN_1, data);
+
+                       if ((adev->family != CHIP_OLAND) && (adev->family != CHIP_HAINAN)) {
+                               orig = data = si_pif_phy0_rreg(adev,PB0_PIF_PWRDOWN_0);
+                               data &= ~PLL_RAMP_UP_TIME_0_MASK;
+                               if (orig != data)
+                                       si_pif_phy0_wreg(adev,PB0_PIF_PWRDOWN_0, data);
+
+                               orig = data = si_pif_phy0_rreg(adev,PB0_PIF_PWRDOWN_1);
+                               data &= ~PLL_RAMP_UP_TIME_1_MASK;
+                               if (orig != data)
+                                       si_pif_phy0_wreg(adev,PB0_PIF_PWRDOWN_1, data);
+
+                               orig = data = si_pif_phy0_rreg(adev,PB0_PIF_PWRDOWN_2);
+                               data &= ~PLL_RAMP_UP_TIME_2_MASK;
+                               if (orig != data)
+                                       si_pif_phy0_wreg(adev,PB0_PIF_PWRDOWN_2, data);
+
+                               orig = data = si_pif_phy0_rreg(adev,PB0_PIF_PWRDOWN_3);
+                               data &= ~PLL_RAMP_UP_TIME_3_MASK;
+                               if (orig != data)
+                                       si_pif_phy0_wreg(adev,PB0_PIF_PWRDOWN_3, data);
+
+                               orig = data = si_pif_phy1_rreg(adev,PB1_PIF_PWRDOWN_0);
+                               data &= ~PLL_RAMP_UP_TIME_0_MASK;
+                               if (orig != data)
+                                       si_pif_phy1_wreg(adev,PB1_PIF_PWRDOWN_0, data);
+
+                               orig = data = si_pif_phy1_rreg(adev,PB1_PIF_PWRDOWN_1);
+                               data &= ~PLL_RAMP_UP_TIME_1_MASK;
+                               if (orig != data)
+                                       si_pif_phy1_wreg(adev,PB1_PIF_PWRDOWN_1, data);
+
+                               orig = data = si_pif_phy1_rreg(adev,PB1_PIF_PWRDOWN_2);
+                               data &= ~PLL_RAMP_UP_TIME_2_MASK;
+                               if (orig != data)
+                                       si_pif_phy1_wreg(adev,PB1_PIF_PWRDOWN_2, data);
+
+                               orig = data = si_pif_phy1_rreg(adev,PB1_PIF_PWRDOWN_3);
+                               data &= ~PLL_RAMP_UP_TIME_3_MASK;
+                               if (orig != data)
+                                       si_pif_phy1_wreg(adev,PB1_PIF_PWRDOWN_3, data);
+                       }
+                       orig = data = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
+                       data &= ~LC_DYN_LANES_PWR_STATE_MASK;
+                       data |= LC_DYN_LANES_PWR_STATE(3);
+                       if (orig != data)
+                               WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data);
+
+                       orig = data = si_pif_phy0_rreg(adev,PB0_PIF_CNTL);
+                       data &= ~LS2_EXIT_TIME_MASK;
+                       if ((adev->family == CHIP_OLAND) || (adev->family == CHIP_HAINAN))
+                               data |= LS2_EXIT_TIME(5);
+                       if (orig != data)
+                               si_pif_phy0_wreg(adev,PB0_PIF_CNTL, data);
+
+                       orig = data = si_pif_phy1_rreg(adev,PB1_PIF_CNTL);
+                       data &= ~LS2_EXIT_TIME_MASK;
+                       if ((adev->family == CHIP_OLAND) || (adev->family == CHIP_HAINAN))
+                               data |= LS2_EXIT_TIME(5);
+                       if (orig != data)
+                               si_pif_phy1_wreg(adev,PB1_PIF_CNTL, data);
+
+                       if (!disable_clkreq &&
+                           !pci_is_root_bus(adev->pdev->bus)) {
+                               struct pci_dev *root = adev->pdev->bus->self;
+                               u32 lnkcap;
+
+                               clk_req_support = false;
+                               pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap);
+                               if (lnkcap & PCI_EXP_LNKCAP_CLKPM)
+                                       clk_req_support = true;
+                       } else {
+                               clk_req_support = false;
+                       }
+
+                       if (clk_req_support) {
+                               orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL2);
+                               data |= LC_ALLOW_PDWN_IN_L1 | LC_ALLOW_PDWN_IN_L23;
+                               if (orig != data)
+                                       WREG32_PCIE_PORT(PCIE_LC_CNTL2, data);
+
+                               orig = data = RREG32(THM_CLK_CNTL);
+                               data &= ~(CMON_CLK_SEL_MASK | TMON_CLK_SEL_MASK);
+                               data |= CMON_CLK_SEL(1) | TMON_CLK_SEL(1);
+                               if (orig != data)
+                                       WREG32(THM_CLK_CNTL, data);
+
+                               orig = data = RREG32(MISC_CLK_CNTL);
+                               data &= ~(DEEP_SLEEP_CLK_SEL_MASK | ZCLK_SEL_MASK);
+                               data |= DEEP_SLEEP_CLK_SEL(1) | ZCLK_SEL(1);
+                               if (orig != data)
+                                       WREG32(MISC_CLK_CNTL, data);
+
+                               orig = data = RREG32(CG_CLKPIN_CNTL);
+                               data &= ~BCLK_AS_XCLK;
+                               if (orig != data)
+                                       WREG32(CG_CLKPIN_CNTL, data);
+
+                               orig = data = RREG32(CG_CLKPIN_CNTL_2);
+                               data &= ~FORCE_BIF_REFCLK_EN;
+                               if (orig != data)
+                                       WREG32(CG_CLKPIN_CNTL_2, data);
+
+                               orig = data = RREG32(MPLL_BYPASSCLK_SEL);
+                               data &= ~MPLL_CLKOUT_SEL_MASK;
+                               data |= MPLL_CLKOUT_SEL(4);
+                               if (orig != data)
+                                       WREG32(MPLL_BYPASSCLK_SEL, data);
+
+                               orig = data = RREG32(SPLL_CNTL_MODE);
+                               data &= ~SPLL_REFCLK_SEL_MASK;
+                               if (orig != data)
+                                       WREG32(SPLL_CNTL_MODE, data);
+                       }
+               }
+       } else {
+               if (orig != data)
+                       WREG32_PCIE_PORT(PCIE_LC_CNTL, data);
+       }
+
+       orig = data = RREG32_PCIE(PCIE_CNTL2);
+       data |= SLV_MEM_LS_EN | MST_MEM_LS_EN | REPLAY_MEM_LS_EN;
+       if (orig != data)
+               WREG32_PCIE(PCIE_CNTL2, data);
+
+       if (!disable_l0s) {
+               data = RREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL);
+               if((data & LC_N_FTS_MASK) == LC_N_FTS_MASK) {
+                       data = RREG32_PCIE(PCIE_LC_STATUS1);
+                       if ((data & LC_REVERSE_XMIT) && (data & LC_REVERSE_RCVR)) {
+                               orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+                               data &= ~LC_L0S_INACTIVITY_MASK;
+                               if (orig != data)
+                                       WREG32_PCIE_PORT(PCIE_LC_CNTL, data);
+                       }
+               }
+       }
+}
+
+static void si_fix_pci_max_read_req_size(struct amdgpu_device *adev)
+{
+       int readrq;
+       u16 v;
+
+       readrq = pcie_get_readrq(adev->pdev);
+       v = ffs(readrq) - 8;
+       if ((v == 0) || (v == 6) || (v == 7))
+               pcie_set_readrq(adev->pdev, 512);
+}
+
+static int si_common_hw_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       si_fix_pci_max_read_req_size(adev);
+       si_init_golden_registers(adev);
+       si_pcie_gen3_enable(adev);
+       si_program_aspm(adev);
+
+       return 0;
+}
+
+static int si_common_hw_fini(void *handle)
+{
+       return 0;
+}
+
+static int si_common_suspend(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return si_common_hw_fini(adev);
+}
+
+static int si_common_resume(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return si_common_hw_init(adev);
+}
+
+static bool si_common_is_idle(void *handle)
+{
+       return true;
+}
+
+static int si_common_wait_for_idle(void *handle)
+{
+       return 0;
+}
+
+static int si_common_soft_reset(void *handle)
+{
+       return 0;
+}
+
+static int si_common_set_clockgating_state(void *handle,
+                                           enum amd_clockgating_state state)
+{
+       return 0;
+}
+
+static int si_common_set_powergating_state(void *handle,
+                                           enum amd_powergating_state state)
+{
+       return 0;
+}
+
+const struct amd_ip_funcs si_common_ip_funcs = {
+       .name = "si_common",
+       .early_init = si_common_early_init,
+       .late_init = NULL,
+       .sw_init = si_common_sw_init,
+       .sw_fini = si_common_sw_fini,
+       .hw_init = si_common_hw_init,
+       .hw_fini = si_common_hw_fini,
+       .suspend = si_common_suspend,
+       .resume = si_common_resume,
+       .is_idle = si_common_is_idle,
+       .wait_for_idle = si_common_wait_for_idle,
+       .soft_reset = si_common_soft_reset,
+       .set_clockgating_state = si_common_set_clockgating_state,
+       .set_powergating_state = si_common_set_powergating_state,
+};
+
+static const struct amdgpu_ip_block_version verde_ip_blocks[] =
+{
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &si_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 6,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gmc_v6_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &si_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 6,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 6,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &dce_v6_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 6,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gfx_v6_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &si_dma_ip_funcs,
+       },
+/*     {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 3,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &si_null_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &si_null_ip_funcs,
+       },
+       */
+};
+
+
+static const struct amdgpu_ip_block_version hainan_ip_blocks[] =
+{
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &si_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 6,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gmc_v6_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &si_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 6,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 6,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gfx_v6_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &si_dma_ip_funcs,
+       },
+};
+
+int si_set_ip_blocks(struct amdgpu_device *adev)
+{
+       switch (adev->asic_type) {
+       case CHIP_VERDE:
+       case CHIP_TAHITI:
+       case CHIP_PITCAIRN:
+       case CHIP_OLAND:
+               adev->ip_blocks = verde_ip_blocks;
+               adev->num_ip_blocks = ARRAY_SIZE(verde_ip_blocks);
+               break;
+       case CHIP_HAINAN:
+               adev->ip_blocks = hainan_ip_blocks;
+               adev->num_ip_blocks = ARRAY_SIZE(hainan_ip_blocks);
+               break;
+       default:
+               BUG();
+       }
+       return 0;
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/si.h b/drivers/gpu/drm/amd/amdgpu/si.h
new file mode 100644 (file)
index 0000000..959d7b6
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 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 __SI_H__
+#define __SI_H__
+
+extern const struct amd_ip_funcs si_common_ip_funcs;
+
+void si_srbm_select(struct amdgpu_device *adev,
+                    u32 me, u32 pipe, u32 queue, u32 vmid);
+int si_set_ip_blocks(struct amdgpu_device *adev);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c
new file mode 100644 (file)
index 0000000..de35819
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include "amdgpu_trace.h"
+#include "si/sid.h"
+
+const u32 sdma_offsets[SDMA_MAX_INSTANCE] =
+{
+       DMA0_REGISTER_OFFSET,
+       DMA1_REGISTER_OFFSET
+};
+
+static void si_dma_set_ring_funcs(struct amdgpu_device *adev);
+static void si_dma_set_buffer_funcs(struct amdgpu_device *adev);
+static void si_dma_set_vm_pte_funcs(struct amdgpu_device *adev);
+static void si_dma_set_irq_funcs(struct amdgpu_device *adev);
+
+static uint32_t si_dma_ring_get_rptr(struct amdgpu_ring *ring)
+{
+       return ring->adev->wb.wb[ring->rptr_offs>>2];
+}
+
+static uint32_t si_dma_ring_get_wptr(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+       u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1;
+
+       return (RREG32(DMA_RB_WPTR + sdma_offsets[me]) & 0x3fffc) >> 2;
+}
+
+static void si_dma_ring_set_wptr(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+       u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1;
+
+       WREG32(DMA_RB_WPTR + sdma_offsets[me], (ring->wptr << 2) & 0x3fffc);
+}
+
+static void si_dma_ring_emit_ib(struct amdgpu_ring *ring,
+                               struct amdgpu_ib *ib,
+                               unsigned vm_id, bool ctx_switch)
+{
+       /* The indirect buffer packet must end on an 8 DW boundary in the DMA ring.
+        * Pad as necessary with NOPs.
+        */
+       while ((ring->wptr & 7) != 5)
+               amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0));
+       amdgpu_ring_write(ring, DMA_IB_PACKET(DMA_PACKET_INDIRECT_BUFFER, vm_id, 0));
+       amdgpu_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0));
+       amdgpu_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF));
+
+}
+
+static void si_dma_ring_emit_hdp_flush(struct amdgpu_ring *ring)
+{
+       amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
+       amdgpu_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL));
+       amdgpu_ring_write(ring, 1);
+}
+
+static void si_dma_ring_emit_hdp_invalidate(struct amdgpu_ring *ring)
+{
+       amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
+       amdgpu_ring_write(ring, (0xf << 16) | (HDP_DEBUG0));
+       amdgpu_ring_write(ring, 1);
+}
+
+/**
+ * si_dma_ring_emit_fence - emit a fence on the DMA ring
+ *
+ * @ring: amdgpu ring pointer
+ * @fence: amdgpu fence object
+ *
+ * Add a DMA fence packet to the ring to write
+ * the fence seq number and DMA trap packet to generate
+ * an interrupt if needed (VI).
+ */
+static void si_dma_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
+                                     unsigned flags)
+{
+
+       bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT;
+       /* write the fence */
+       amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0, 0, 0));
+       amdgpu_ring_write(ring, addr & 0xfffffffc);
+       amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xff));
+       amdgpu_ring_write(ring, seq);
+       /* optionally write high bits as well */
+       if (write64bit) {
+               addr += 4;
+               amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0, 0, 0));
+               amdgpu_ring_write(ring, addr & 0xfffffffc);
+               amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xff));
+               amdgpu_ring_write(ring, upper_32_bits(seq));
+       }
+       /* generate an interrupt */
+       amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0, 0, 0));
+}
+
+static void si_dma_stop(struct amdgpu_device *adev)
+{
+       struct amdgpu_ring *ring;
+       u32 rb_cntl;
+       unsigned i;
+
+       for (i = 0; i < adev->sdma.num_instances; i++) {
+               ring = &adev->sdma.instance[i].ring;
+               /* dma0 */
+               rb_cntl = RREG32(DMA_RB_CNTL + sdma_offsets[i]);
+               rb_cntl &= ~DMA_RB_ENABLE;
+               WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl);
+
+               if (adev->mman.buffer_funcs_ring == ring)
+                       amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size);
+               ring->ready = false;
+       }
+}
+
+static int si_dma_start(struct amdgpu_device *adev)
+{
+       struct amdgpu_ring *ring;
+       u32 rb_cntl, dma_cntl, ib_cntl, rb_bufsz;
+       int i, r;
+       uint64_t rptr_addr;
+
+       for (i = 0; i < adev->sdma.num_instances; i++) {
+               ring = &adev->sdma.instance[i].ring;
+
+               WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL + sdma_offsets[i], 0);
+               WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL + sdma_offsets[i], 0);
+
+               /* Set ring buffer size in dwords */
+               rb_bufsz = order_base_2(ring->ring_size / 4);
+               rb_cntl = rb_bufsz << 1;
+#ifdef __BIG_ENDIAN
+               rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE;
+#endif
+               WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl);
+
+               /* Initialize the ring buffer's read and write pointers */
+               WREG32(DMA_RB_RPTR + sdma_offsets[i], 0);
+               WREG32(DMA_RB_WPTR + sdma_offsets[i], 0);
+
+               rptr_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4);
+
+               WREG32(DMA_RB_RPTR_ADDR_LO + sdma_offsets[i], lower_32_bits(rptr_addr));
+               WREG32(DMA_RB_RPTR_ADDR_HI + sdma_offsets[i], upper_32_bits(rptr_addr) & 0xFF);
+
+               rb_cntl |= DMA_RPTR_WRITEBACK_ENABLE;
+
+               WREG32(DMA_RB_BASE + sdma_offsets[i], ring->gpu_addr >> 8);
+
+               /* enable DMA IBs */
+               ib_cntl = DMA_IB_ENABLE | CMD_VMID_FORCE;
+#ifdef __BIG_ENDIAN
+               ib_cntl |= DMA_IB_SWAP_ENABLE;
+#endif
+               WREG32(DMA_IB_CNTL + sdma_offsets[i], ib_cntl);
+
+               dma_cntl = RREG32(DMA_CNTL + sdma_offsets[i]);
+               dma_cntl &= ~CTXEMPTY_INT_ENABLE;
+               WREG32(DMA_CNTL + sdma_offsets[i], dma_cntl);
+
+               ring->wptr = 0;
+               WREG32(DMA_RB_WPTR + sdma_offsets[i], ring->wptr << 2);
+               WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl | DMA_RB_ENABLE);
+
+               ring->ready = true;
+
+               r = amdgpu_ring_test_ring(ring);
+               if (r) {
+                       ring->ready = false;
+                       return r;
+               }
+
+               if (adev->mman.buffer_funcs_ring == ring)
+                       amdgpu_ttm_set_active_vram_size(adev, adev->mc.real_vram_size);
+       }
+
+       return 0;
+}
+
+/**
+ * si_dma_ring_test_ring - simple async dma engine test
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Test the DMA engine by writing using it to write an
+ * value to memory. (VI).
+ * Returns 0 for success, error for failure.
+ */
+static int si_dma_ring_test_ring(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+       unsigned i;
+       unsigned index;
+       int r;
+       u32 tmp;
+       u64 gpu_addr;
+
+       r = amdgpu_wb_get(adev, &index);
+       if (r) {
+               dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+               return r;
+       }
+
+       gpu_addr = adev->wb.gpu_addr + (index * 4);
+       tmp = 0xCAFEDEAD;
+       adev->wb.wb[index] = cpu_to_le32(tmp);
+
+       r = amdgpu_ring_alloc(ring, 4);
+       if (r) {
+               DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
+               amdgpu_wb_free(adev, index);
+               return r;
+       }
+
+       amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, 1));
+       amdgpu_ring_write(ring, lower_32_bits(gpu_addr));
+       amdgpu_ring_write(ring, upper_32_bits(gpu_addr) & 0xff);
+       amdgpu_ring_write(ring, 0xDEADBEEF);
+       amdgpu_ring_commit(ring);
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               tmp = le32_to_cpu(adev->wb.wb[index]);
+               if (tmp == 0xDEADBEEF)
+                       break;
+               DRM_UDELAY(1);
+       }
+
+       if (i < adev->usec_timeout) {
+               DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
+       } else {
+               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
+                         ring->idx, tmp);
+               r = -EINVAL;
+       }
+       amdgpu_wb_free(adev, index);
+
+       return r;
+}
+
+/**
+ * si_dma_ring_test_ib - test an IB on the DMA engine
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Test a simple IB in the DMA ring (VI).
+ * Returns 0 on success, error on failure.
+ */
+static int si_dma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
+{
+       struct amdgpu_device *adev = ring->adev;
+       struct amdgpu_ib ib;
+       struct fence *f = NULL;
+       unsigned index;
+       u32 tmp = 0;
+       u64 gpu_addr;
+       long r;
+
+       r = amdgpu_wb_get(adev, &index);
+       if (r) {
+               dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+               return r;
+       }
+
+       gpu_addr = adev->wb.gpu_addr + (index * 4);
+       tmp = 0xCAFEDEAD;
+       adev->wb.wb[index] = cpu_to_le32(tmp);
+       memset(&ib, 0, sizeof(ib));
+       r = amdgpu_ib_get(adev, NULL, 256, &ib);
+       if (r) {
+               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+               goto err0;
+       }
+
+       ib.ptr[0] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, 1);
+       ib.ptr[1] = lower_32_bits(gpu_addr);
+       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);
+       if (r)
+               goto err1;
+
+       r = fence_wait_timeout(f, false, timeout);
+       if (r == 0) {
+               DRM_ERROR("amdgpu: IB test timed out\n");
+               r = -ETIMEDOUT;
+               goto err1;
+       } else if (r < 0) {
+               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
+               goto err1;
+       }
+       tmp = le32_to_cpu(adev->wb.wb[index]);
+       if (tmp == 0xDEADBEEF) {
+               DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
+               r = 0;
+       } else {
+               DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+               r = -EINVAL;
+       }
+
+err1:
+       amdgpu_ib_free(adev, &ib, NULL);
+       fence_put(f);
+err0:
+       amdgpu_wb_free(adev, index);
+       return r;
+}
+
+/**
+ * cik_dma_vm_copy_pte - update PTEs by copying them from the GART
+ *
+ * @ib: indirect buffer to fill with commands
+ * @pe: addr of the page entry
+ * @src: src addr to copy from
+ * @count: number of page entries to update
+ *
+ * Update PTEs by copying them from the GART using DMA (SI).
+ */
+static void si_dma_vm_copy_pte(struct amdgpu_ib *ib,
+                              uint64_t pe, uint64_t src,
+                              unsigned count)
+{
+       unsigned bytes = count * 8;
+
+       ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY,
+                                             1, 0, 0, bytes);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe);
+       ib->ptr[ib->length_dw++] = lower_32_bits(src);
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff;
+       ib->ptr[ib->length_dw++] = upper_32_bits(src) & 0xff;
+}
+
+/**
+ * si_dma_vm_write_pte - update PTEs by writing them manually
+ *
+ * @ib: indirect buffer to fill with commands
+ * @pe: addr of the page entry
+ * @value: dst addr to write into pe
+ * @count: number of page entries to update
+ * @incr: increase next addr by incr bytes
+ *
+ * Update PTEs by writing them manually using DMA (SI).
+ */
+static void si_dma_vm_write_pte(struct amdgpu_ib *ib, uint64_t pe,
+                               uint64_t value, unsigned count,
+                               uint32_t incr)
+{
+       unsigned ndw = count * 2;
+
+       ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, ndw);
+       ib->ptr[ib->length_dw++] = lower_32_bits(pe);
+       ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+       for (; ndw > 0; ndw -= 2) {
+               ib->ptr[ib->length_dw++] = lower_32_bits(value);
+               ib->ptr[ib->length_dw++] = upper_32_bits(value);
+               value += incr;
+       }
+}
+
+/**
+ * si_dma_vm_set_pte_pde - update the page tables using sDMA
+ *
+ * @ib: indirect buffer to fill with commands
+ * @pe: addr of the page entry
+ * @addr: dst addr to write into pe
+ * @count: number of page entries to update
+ * @incr: increase next addr by incr bytes
+ * @flags: access flags
+ *
+ * Update the page tables using sDMA (CIK).
+ */
+static void si_dma_vm_set_pte_pde(struct amdgpu_ib *ib,
+                                    uint64_t pe,
+                                    uint64_t addr, unsigned count,
+                                    uint32_t incr, uint32_t flags)
+{
+       uint64_t value;
+       unsigned ndw;
+
+       while (count) {
+               ndw = count * 2;
+               if (ndw > 0xFFFFE)
+                       ndw = 0xFFFFE;
+
+               if (flags & AMDGPU_PTE_VALID)
+                       value = addr;
+               else
+                       value = 0;
+
+               /* for physically contiguous pages (vram) */
+               ib->ptr[ib->length_dw++] = DMA_PTE_PDE_PACKET(ndw);
+               ib->ptr[ib->length_dw++] = pe; /* dst addr */
+               ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff;
+               ib->ptr[ib->length_dw++] = flags; /* mask */
+               ib->ptr[ib->length_dw++] = 0;
+               ib->ptr[ib->length_dw++] = value; /* value */
+               ib->ptr[ib->length_dw++] = upper_32_bits(value);
+               ib->ptr[ib->length_dw++] = incr; /* increment size */
+               ib->ptr[ib->length_dw++] = 0;
+               pe += ndw * 4;
+               addr += (ndw / 2) * incr;
+               count -= ndw / 2;
+       }
+}
+
+/**
+ * si_dma_pad_ib - pad the IB to the required number of dw
+ *
+ * @ib: indirect buffer to fill with padding
+ *
+ */
+static void si_dma_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
+{
+       while (ib->length_dw & 0x7)
+               ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0);
+}
+
+/**
+ * cik_sdma_ring_emit_pipeline_sync - sync the pipeline
+ *
+ * @ring: amdgpu_ring pointer
+ *
+ * Make sure all previous operations are completed (CIK).
+ */
+static void si_dma_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
+{
+       uint32_t seq = ring->fence_drv.sync_seq;
+       uint64_t addr = ring->fence_drv.gpu_addr;
+
+       /* wait for idle */
+       amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_POLL_REG_MEM, 0, 0, 0, 0) |
+                         (1 << 27)); /* Poll memory */
+       amdgpu_ring_write(ring, lower_32_bits(addr));
+       amdgpu_ring_write(ring, (0xff << 16) | upper_32_bits(addr)); /* retry, addr_hi */
+       amdgpu_ring_write(ring, 0xffffffff); /* mask */
+       amdgpu_ring_write(ring, seq); /* value */
+       amdgpu_ring_write(ring, (3 << 28) | 0x20); /* func(equal) | poll interval */
+}
+
+/**
+ * si_dma_ring_emit_vm_flush - cik vm flush using sDMA
+ *
+ * @ring: amdgpu_ring pointer
+ * @vm: amdgpu_vm pointer
+ *
+ * Update the page table base and flush the VM TLB
+ * using sDMA (VI).
+ */
+static void si_dma_ring_emit_vm_flush(struct amdgpu_ring *ring,
+                                     unsigned vm_id, uint64_t pd_addr)
+{
+       amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
+       if (vm_id < 8)
+               amdgpu_ring_write(ring, (0xf << 16) | (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vm_id));
+       else
+               amdgpu_ring_write(ring, (0xf << 16) | (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + (vm_id - 8)));
+       amdgpu_ring_write(ring, pd_addr >> 12);
+
+       /* bits 0-7 are the VM contexts0-7 */
+       amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
+       amdgpu_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST));
+       amdgpu_ring_write(ring, 1 << vm_id);
+
+       /* wait for invalidate to complete */
+       amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_POLL_REG_MEM, 0, 0, 0, 0));
+       amdgpu_ring_write(ring, VM_INVALIDATE_REQUEST);
+       amdgpu_ring_write(ring, 0xff << 16); /* retry */
+       amdgpu_ring_write(ring, 1 << vm_id); /* mask */
+       amdgpu_ring_write(ring, 0); /* value */
+       amdgpu_ring_write(ring, (0 << 28) | 0x20); /* func(always) | poll interval */
+}
+
+static unsigned si_dma_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               7 + 3; /* si_dma_ring_emit_ib */
+}
+
+static unsigned si_dma_ring_get_dma_frame_size(struct amdgpu_ring *ring)
+{
+       return
+               3 + /* si_dma_ring_emit_hdp_flush */
+               3 + /* si_dma_ring_emit_hdp_invalidate */
+               6 + /* si_dma_ring_emit_pipeline_sync */
+               12 + /* si_dma_ring_emit_vm_flush */
+               9 + 9 + 9; /* si_dma_ring_emit_fence x3 for user fence, vm fence */
+}
+
+static int si_dma_early_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       adev->sdma.num_instances = 2;
+
+       si_dma_set_ring_funcs(adev);
+       si_dma_set_buffer_funcs(adev);
+       si_dma_set_vm_pte_funcs(adev);
+       si_dma_set_irq_funcs(adev);
+
+       return 0;
+}
+
+static int si_dma_sw_init(void *handle)
+{
+       struct amdgpu_ring *ring;
+       int r, i;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       /* DMA0 trap event */
+       r = amdgpu_irq_add_id(adev, 224, &adev->sdma.trap_irq);
+       if (r)
+               return r;
+
+       /* DMA1 trap event */
+       r = amdgpu_irq_add_id(adev, 244, &adev->sdma.trap_irq_1);
+       if (r)
+               return r;
+
+       for (i = 0; i < adev->sdma.num_instances; i++) {
+               ring = &adev->sdma.instance[i].ring;
+               ring->ring_obj = NULL;
+               ring->use_doorbell = false;
+               sprintf(ring->name, "sdma%d", i);
+               r = amdgpu_ring_init(adev, ring, 1024,
+                                    DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0), 0xf,
+                                    &adev->sdma.trap_irq,
+                                    (i == 0) ?
+                                    AMDGPU_SDMA_IRQ_TRAP0 : AMDGPU_SDMA_IRQ_TRAP1,
+                                    AMDGPU_RING_TYPE_SDMA);
+               if (r)
+                       return r;
+       }
+
+       return r;
+}
+
+static int si_dma_sw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       int i;
+
+       for (i = 0; i < adev->sdma.num_instances; i++)
+               amdgpu_ring_fini(&adev->sdma.instance[i].ring);
+
+       return 0;
+}
+
+static int si_dma_hw_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return si_dma_start(adev);
+}
+
+static int si_dma_hw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       si_dma_stop(adev);
+
+       return 0;
+}
+
+static int si_dma_suspend(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return si_dma_hw_fini(adev);
+}
+
+static int si_dma_resume(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return si_dma_hw_init(adev);
+}
+
+static bool si_dma_is_idle(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 tmp = RREG32(SRBM_STATUS2);
+
+       if (tmp & (DMA_BUSY_MASK | DMA1_BUSY_MASK))
+           return false;
+
+       return true;
+}
+
+static int si_dma_wait_for_idle(void *handle)
+{
+       unsigned i;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (si_dma_is_idle(handle))
+                       return 0;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+}
+
+static int si_dma_soft_reset(void *handle)
+{
+       DRM_INFO("si_dma_soft_reset --- not implemented !!!!!!!\n");
+       return 0;
+}
+
+static int si_dma_set_trap_irq_state(struct amdgpu_device *adev,
+                                       struct amdgpu_irq_src *src,
+                                       unsigned type,
+                                       enum amdgpu_interrupt_state state)
+{
+       u32 sdma_cntl;
+
+       switch (type) {
+       case AMDGPU_SDMA_IRQ_TRAP0:
+               switch (state) {
+               case AMDGPU_IRQ_STATE_DISABLE:
+                       sdma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET);
+                       sdma_cntl &= ~TRAP_ENABLE;
+                       WREG32(DMA_CNTL + DMA0_REGISTER_OFFSET, sdma_cntl);
+                       break;
+               case AMDGPU_IRQ_STATE_ENABLE:
+                       sdma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET);
+                       sdma_cntl |= TRAP_ENABLE;
+                       WREG32(DMA_CNTL + DMA0_REGISTER_OFFSET, sdma_cntl);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case AMDGPU_SDMA_IRQ_TRAP1:
+               switch (state) {
+               case AMDGPU_IRQ_STATE_DISABLE:
+                       sdma_cntl = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET);
+                       sdma_cntl &= ~TRAP_ENABLE;
+                       WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, sdma_cntl);
+                       break;
+               case AMDGPU_IRQ_STATE_ENABLE:
+                       sdma_cntl = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET);
+                       sdma_cntl |= TRAP_ENABLE;
+                       WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, sdma_cntl);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int si_dma_process_trap_irq(struct amdgpu_device *adev,
+                                     struct amdgpu_irq_src *source,
+                                     struct amdgpu_iv_entry *entry)
+{
+       amdgpu_fence_process(&adev->sdma.instance[0].ring);
+
+       return 0;
+}
+
+static int si_dma_process_trap_irq_1(struct amdgpu_device *adev,
+                                     struct amdgpu_irq_src *source,
+                                     struct amdgpu_iv_entry *entry)
+{
+       amdgpu_fence_process(&adev->sdma.instance[1].ring);
+
+       return 0;
+}
+
+static int si_dma_process_illegal_inst_irq(struct amdgpu_device *adev,
+                                             struct amdgpu_irq_src *source,
+                                             struct amdgpu_iv_entry *entry)
+{
+       DRM_ERROR("Illegal instruction in SDMA command stream\n");
+       schedule_work(&adev->reset_work);
+       return 0;
+}
+
+static int si_dma_set_clockgating_state(void *handle,
+                                         enum amd_clockgating_state state)
+{
+       u32 orig, data, offset;
+       int i;
+       bool enable;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       enable = (state == AMD_CG_STATE_GATE) ? true : false;
+
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_SDMA_MGCG)) {
+               for (i = 0; i < adev->sdma.num_instances; i++) {
+                       if (i == 0)
+                               offset = DMA0_REGISTER_OFFSET;
+                       else
+                               offset = DMA1_REGISTER_OFFSET;
+                       orig = data = RREG32(DMA_POWER_CNTL + offset);
+                       data &= ~MEM_POWER_OVERRIDE;
+                       if (data != orig)
+                               WREG32(DMA_POWER_CNTL + offset, data);
+                       WREG32(DMA_CLK_CTRL + offset, 0x00000100);
+               }
+       } else {
+               for (i = 0; i < adev->sdma.num_instances; i++) {
+                       if (i == 0)
+                               offset = DMA0_REGISTER_OFFSET;
+                       else
+                               offset = DMA1_REGISTER_OFFSET;
+                       orig = data = RREG32(DMA_POWER_CNTL + offset);
+                       data |= MEM_POWER_OVERRIDE;
+                       if (data != orig)
+                               WREG32(DMA_POWER_CNTL + offset, data);
+
+                       orig = data = RREG32(DMA_CLK_CTRL + offset);
+                       data = 0xff000000;
+                       if (data != orig)
+                               WREG32(DMA_CLK_CTRL + offset, data);
+               }
+       }
+
+       return 0;
+}
+
+static int si_dma_set_powergating_state(void *handle,
+                                         enum amd_powergating_state state)
+{
+       u32 tmp;
+
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       WREG32(DMA_PGFSM_WRITE,  0x00002000);
+       WREG32(DMA_PGFSM_CONFIG, 0x100010ff);
+
+       for (tmp = 0; tmp < 5; tmp++)
+               WREG32(DMA_PGFSM_WRITE, 0);
+
+       return 0;
+}
+
+const struct amd_ip_funcs si_dma_ip_funcs = {
+       .name = "si_dma",
+       .early_init = si_dma_early_init,
+       .late_init = NULL,
+       .sw_init = si_dma_sw_init,
+       .sw_fini = si_dma_sw_fini,
+       .hw_init = si_dma_hw_init,
+       .hw_fini = si_dma_hw_fini,
+       .suspend = si_dma_suspend,
+       .resume = si_dma_resume,
+       .is_idle = si_dma_is_idle,
+       .wait_for_idle = si_dma_wait_for_idle,
+       .soft_reset = si_dma_soft_reset,
+       .set_clockgating_state = si_dma_set_clockgating_state,
+       .set_powergating_state = si_dma_set_powergating_state,
+};
+
+static const struct amdgpu_ring_funcs si_dma_ring_funcs = {
+       .get_rptr = si_dma_ring_get_rptr,
+       .get_wptr = si_dma_ring_get_wptr,
+       .set_wptr = si_dma_ring_set_wptr,
+       .parse_cs = NULL,
+       .emit_ib = si_dma_ring_emit_ib,
+       .emit_fence = si_dma_ring_emit_fence,
+       .emit_pipeline_sync = si_dma_ring_emit_pipeline_sync,
+       .emit_vm_flush = si_dma_ring_emit_vm_flush,
+       .emit_hdp_flush = si_dma_ring_emit_hdp_flush,
+       .emit_hdp_invalidate = si_dma_ring_emit_hdp_invalidate,
+       .test_ring = si_dma_ring_test_ring,
+       .test_ib = si_dma_ring_test_ib,
+       .insert_nop = amdgpu_ring_insert_nop,
+       .pad_ib = si_dma_ring_pad_ib,
+       .get_emit_ib_size = si_dma_ring_get_emit_ib_size,
+       .get_dma_frame_size = si_dma_ring_get_dma_frame_size,
+};
+
+static void si_dma_set_ring_funcs(struct amdgpu_device *adev)
+{
+       int i;
+
+       for (i = 0; i < adev->sdma.num_instances; i++)
+               adev->sdma.instance[i].ring.funcs = &si_dma_ring_funcs;
+}
+
+static const struct amdgpu_irq_src_funcs si_dma_trap_irq_funcs = {
+       .set = si_dma_set_trap_irq_state,
+       .process = si_dma_process_trap_irq,
+};
+
+static const struct amdgpu_irq_src_funcs si_dma_trap_irq_funcs_1 = {
+       .set = si_dma_set_trap_irq_state,
+       .process = si_dma_process_trap_irq_1,
+};
+
+static const struct amdgpu_irq_src_funcs si_dma_illegal_inst_irq_funcs = {
+       .process = si_dma_process_illegal_inst_irq,
+};
+
+static void si_dma_set_irq_funcs(struct amdgpu_device *adev)
+{
+       adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST;
+       adev->sdma.trap_irq.funcs = &si_dma_trap_irq_funcs;
+       adev->sdma.trap_irq_1.funcs = &si_dma_trap_irq_funcs_1;
+       adev->sdma.illegal_inst_irq.funcs = &si_dma_illegal_inst_irq_funcs;
+}
+
+/**
+ * si_dma_emit_copy_buffer - copy buffer using the sDMA engine
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ * @src_offset: src GPU address
+ * @dst_offset: dst GPU address
+ * @byte_count: number of bytes to xfer
+ *
+ * Copy GPU buffers using the DMA engine (VI).
+ * Used by the amdgpu ttm implementation to move pages if
+ * registered as the asic copy callback.
+ */
+static void si_dma_emit_copy_buffer(struct amdgpu_ib *ib,
+                                      uint64_t src_offset,
+                                      uint64_t dst_offset,
+                                      uint32_t byte_count)
+{
+       ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY,
+                                             1, 0, 0, byte_count);
+       ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset);
+       ib->ptr[ib->length_dw++] = lower_32_bits(src_offset);
+       ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset) & 0xff;
+       ib->ptr[ib->length_dw++] = upper_32_bits(src_offset) & 0xff;
+}
+
+/**
+ * si_dma_emit_fill_buffer - fill buffer using the sDMA engine
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ * @src_data: value to write to buffer
+ * @dst_offset: dst GPU address
+ * @byte_count: number of bytes to xfer
+ *
+ * Fill GPU buffers using the DMA engine (VI).
+ */
+static void si_dma_emit_fill_buffer(struct amdgpu_ib *ib,
+                                      uint32_t src_data,
+                                      uint64_t dst_offset,
+                                      uint32_t byte_count)
+{
+       ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_CONSTANT_FILL,
+                                             0, 0, 0, byte_count / 4);
+       ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset);
+       ib->ptr[ib->length_dw++] = src_data;
+       ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset) << 16;
+}
+
+
+static const struct amdgpu_buffer_funcs si_dma_buffer_funcs = {
+       .copy_max_bytes = 0xffff8,
+       .copy_num_dw = 5,
+       .emit_copy_buffer = si_dma_emit_copy_buffer,
+
+       .fill_max_bytes = 0xffff8,
+       .fill_num_dw = 4,
+       .emit_fill_buffer = si_dma_emit_fill_buffer,
+};
+
+static void si_dma_set_buffer_funcs(struct amdgpu_device *adev)
+{
+       if (adev->mman.buffer_funcs == NULL) {
+               adev->mman.buffer_funcs = &si_dma_buffer_funcs;
+               adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].ring;
+       }
+}
+
+static const struct amdgpu_vm_pte_funcs si_dma_vm_pte_funcs = {
+       .copy_pte = si_dma_vm_copy_pte,
+       .write_pte = si_dma_vm_write_pte,
+       .set_pte_pde = si_dma_vm_set_pte_pde,
+};
+
+static void si_dma_set_vm_pte_funcs(struct amdgpu_device *adev)
+{
+       unsigned i;
+
+       if (adev->vm_manager.vm_pte_funcs == NULL) {
+               adev->vm_manager.vm_pte_funcs = &si_dma_vm_pte_funcs;
+               for (i = 0; i < adev->sdma.num_instances; i++)
+                       adev->vm_manager.vm_pte_rings[i] =
+                               &adev->sdma.instance[i].ring;
+
+               adev->vm_manager.vm_pte_num_rings = adev->sdma.num_instances;
+       }
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.h b/drivers/gpu/drm/amd/amdgpu/si_dma.h
new file mode 100644 (file)
index 0000000..3a3e0c7
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 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 __SI_DMA_H__
+#define __SI_DMA_H__
+
+extern const struct amd_ip_funcs si_dma_ip_funcs;
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
new file mode 100644 (file)
index 0000000..8bd0892
--- /dev/null
@@ -0,0 +1,8006 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_dpm.h"
+#include "amdgpu_atombios.h"
+#include "si/sid.h"
+#include "r600_dpm.h"
+#include "si_dpm.h"
+#include "atom.h"
+#include "../include/pptable.h"
+#include <linux/math64.h>
+#include <linux/seq_file.h>
+#include <linux/firmware.h>
+
+#define MC_CG_ARB_FREQ_F0           0x0a
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define MC_CG_ARB_FREQ_F2           0x0c
+#define MC_CG_ARB_FREQ_F3           0x0d
+
+#define SMC_RAM_END                 0x20000
+
+#define SCLK_MIN_DEEPSLEEP_FREQ     1350
+
+
+/* sizeof(ATOM_PPLIB_EXTENDEDHEADER) */
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
+
+#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");
+MODULE_FIRMWARE("radeon/verde_k_smc.bin");
+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");
+
+union power_info {
+       struct _ATOM_POWERPLAY_INFO info;
+       struct _ATOM_POWERPLAY_INFO_V2 info_2;
+       struct _ATOM_POWERPLAY_INFO_V3 info_3;
+       struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+       struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+       struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+       struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
+       struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
+};
+
+union fan_info {
+       struct _ATOM_PPLIB_FANTABLE fan;
+       struct _ATOM_PPLIB_FANTABLE2 fan2;
+       struct _ATOM_PPLIB_FANTABLE3 fan3;
+};
+
+union pplib_clock_info {
+       struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+       struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+       struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+       struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+       struct _ATOM_PPLIB_SI_CLOCK_INFO si;
+};
+
+static const u32 r600_utc[R600_PM_NUMBER_OF_TC] =
+{
+       R600_UTC_DFLT_00,
+       R600_UTC_DFLT_01,
+       R600_UTC_DFLT_02,
+       R600_UTC_DFLT_03,
+       R600_UTC_DFLT_04,
+       R600_UTC_DFLT_05,
+       R600_UTC_DFLT_06,
+       R600_UTC_DFLT_07,
+       R600_UTC_DFLT_08,
+       R600_UTC_DFLT_09,
+       R600_UTC_DFLT_10,
+       R600_UTC_DFLT_11,
+       R600_UTC_DFLT_12,
+       R600_UTC_DFLT_13,
+       R600_UTC_DFLT_14,
+};
+
+static const u32 r600_dtc[R600_PM_NUMBER_OF_TC] =
+{
+       R600_DTC_DFLT_00,
+       R600_DTC_DFLT_01,
+       R600_DTC_DFLT_02,
+       R600_DTC_DFLT_03,
+       R600_DTC_DFLT_04,
+       R600_DTC_DFLT_05,
+       R600_DTC_DFLT_06,
+       R600_DTC_DFLT_07,
+       R600_DTC_DFLT_08,
+       R600_DTC_DFLT_09,
+       R600_DTC_DFLT_10,
+       R600_DTC_DFLT_11,
+       R600_DTC_DFLT_12,
+       R600_DTC_DFLT_13,
+       R600_DTC_DFLT_14,
+};
+
+static const struct si_cac_config_reg cac_weights_tahiti[] =
+{
+       { 0x0, 0x0000ffff, 0, 0xc, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0x101, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0xc, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x8fc, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x95, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x34e, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x1a1, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0xda, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x46, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x208, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0xe7, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x948, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x167, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x31, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0x18e, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_tahiti[] =
+{
+       { 0x143, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x146, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x149, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0x149, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x14c, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0x14c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x9e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x9e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x101, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x101, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x10a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x10d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x8f, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x92, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x92, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x95, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x95, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x152, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x155, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x155, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x158, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x158, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x113, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x116, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x116, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x119, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+       { 0x119, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x122, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x122, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x125, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x125, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x128, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x128, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x12b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x12b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+
+};
+
+static const struct si_cac_config_reg cac_override_tahiti[] =
+{
+       { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_tahiti =
+{
+       ((1 << 16) | 27027),
+       6,
+       0,
+       4,
+       95,
+       {
+               0UL,
+               0UL,
+               4521550UL,
+               309631529UL,
+               -1270850L,
+               4513710L,
+               40
+       },
+       595000000UL,
+       12,
+       {
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0
+       },
+       true
+};
+
+static const struct si_dte_data dte_data_tahiti =
+{
+       { 1159409, 0, 0, 0, 0 },
+       { 777, 0, 0, 0, 0 },
+       2,
+       54000,
+       127000,
+       25,
+       2,
+       10,
+       13,
+       { 27, 31, 35, 39, 43, 47, 54, 61, 67, 74, 81, 88, 95, 0, 0, 0 },
+       { 240888759, 221057860, 235370597, 162287531, 158510299, 131423027, 116673180, 103067515, 87941937, 76209048, 68209175, 64090048, 58301890, 0, 0, 0 },
+       { 12024, 11189, 11451, 8411, 7939, 6666, 5681, 4905, 4241, 3720, 3354, 3122, 2890, 0, 0, 0 },
+       85,
+       false
+};
+
+#if 0
+static const struct si_dte_data dte_data_tahiti_le =
+{
+       { 0x1E8480, 0x7A1200, 0x2160EC0, 0x3938700, 0 },
+       { 0x7D, 0x7D, 0x4E4, 0xB00, 0 },
+       0x5,
+       0xAFC8,
+       0x64,
+       0x32,
+       1,
+       0,
+       0x10,
+       { 0x78, 0x7C, 0x82, 0x88, 0x8E, 0x94, 0x9A, 0xA0, 0xA6, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC, 0xC0, 0xC4 },
+       { 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700 },
+       { 0x2AF8, 0x2AF8, 0x29BB, 0x27F9, 0x2637, 0x2475, 0x22B3, 0x20F1, 0x1F2F, 0x1D6D, 0x1734, 0x1414, 0x10F4, 0xDD4, 0xAB4, 0x794 },
+       85,
+       true
+};
+#endif
+
+static const struct si_dte_data dte_data_tahiti_pro =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x0, 0x0, 0x0, 0x0, 0x0 },
+       5,
+       45000,
+       100,
+       0xA,
+       1,
+       0,
+       0x10,
+       { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+       { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+       { 0x7D0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_dte_data dte_data_new_zealand =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0 },
+       { 0x29B, 0x3E9, 0x537, 0x7D2, 0 },
+       0x5,
+       0xAFC8,
+       0x69,
+       0x32,
+       1,
+       0,
+       0x10,
+       { 0x82, 0xA0, 0xB4, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE },
+       { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+       { 0xDAC, 0x1388, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685 },
+       85,
+       true
+};
+
+static const struct si_dte_data dte_data_aruba_pro =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x0, 0x0, 0x0, 0x0, 0x0 },
+       5,
+       45000,
+       100,
+       0xA,
+       1,
+       0,
+       0x10,
+       { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+       { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+       { 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_dte_data dte_data_malta =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x0, 0x0, 0x0, 0x0, 0x0 },
+       5,
+       45000,
+       100,
+       0xA,
+       1,
+       0,
+       0x10,
+       { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+       { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+       { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_cac_config_reg cac_weights_pitcairn[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x8a, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x24d, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x19, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0xc11, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0x7f3, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x403, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x367, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x4c9, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x45d, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0x36d, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x534, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x5da, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x880, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0x201, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0x9f, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x1f, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x5de, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x7b, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x13, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0xf9, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x66, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x13, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0x186, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_pitcairn[] =
+{
+       { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x143, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x113, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x152, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x8f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x146, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x9e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x9e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x10a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x116, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x116, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x155, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x155, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x92, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x92, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x149, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x149, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x101, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x101, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x10d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x119, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x119, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x158, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x158, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x95, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x95, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x14c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x14c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x122, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x122, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x125, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x125, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x128, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x128, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x12b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x12b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_override_pitcairn[] =
+{
+    { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_pitcairn =
+{
+       ((1 << 16) | 27027),
+       5,
+       0,
+       6,
+       100,
+       {
+               51600000UL,
+               1800000UL,
+               7194395UL,
+               309631529UL,
+               -1270850L,
+               4513710L,
+               100
+       },
+       117830498UL,
+       12,
+       {
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0
+       },
+       true
+};
+
+static const struct si_dte_data dte_data_pitcairn =
+{
+       { 0, 0, 0, 0, 0 },
+       { 0, 0, 0, 0, 0 },
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       0,
+       false
+};
+
+static const struct si_dte_data dte_data_curacao_xt =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x0, 0x0, 0x0, 0x0, 0x0 },
+       5,
+       45000,
+       100,
+       0xA,
+       1,
+       0,
+       0x10,
+       { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+       { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+       { 0x1D17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_dte_data dte_data_curacao_pro =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x0, 0x0, 0x0, 0x0, 0x0 },
+       5,
+       45000,
+       100,
+       0xA,
+       1,
+       0,
+       0x10,
+       { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+       { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+       { 0x1D17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_dte_data dte_data_neptune_xt =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x0, 0x0, 0x0, 0x0, 0x0 },
+       5,
+       45000,
+       100,
+       0xA,
+       1,
+       0,
+       0x10,
+       { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+       { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+       { 0x3A2F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_cac_config_reg cac_weights_chelsea_pro[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x2BD, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_chelsea_xt[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x30A, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_heathrow[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x362, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_cape_verde_pro[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x315, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_cape_verde[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x3BA, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_cape_verde[] =
+{
+       { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x143, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x113, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x152, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x8f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x146, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_override_cape_verde[] =
+{
+    { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_cape_verde =
+{
+       ((1 << 16) | 0x6993),
+       5,
+       0,
+       7,
+       105,
+       {
+               0UL,
+               0UL,
+               7194395UL,
+               309631529UL,
+               -1270850L,
+               4513710L,
+               100
+       },
+       117830498UL,
+       12,
+       {
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0
+       },
+       true
+};
+
+static const struct si_dte_data dte_data_cape_verde =
+{
+       { 0, 0, 0, 0, 0 },
+       { 0, 0, 0, 0, 0 },
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       0,
+       false
+};
+
+static const struct si_dte_data dte_data_venus_xtx =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x71C, 0xAAB, 0xE39, 0x11C7, 0x0 },
+       5,
+       55000,
+       0x69,
+       0xA,
+       1,
+       0,
+       0x3,
+       { 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       { 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       { 0xD6D8, 0x88B8, 0x1555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_dte_data dte_data_venus_xt =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0xBDA, 0x11C7, 0x17B4, 0x1DA1, 0x0 },
+       5,
+       55000,
+       0x69,
+       0xA,
+       1,
+       0,
+       0x3,
+       { 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       { 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       { 0xAFC8, 0x88B8, 0x238E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_dte_data dte_data_venus_pro =
+{
+       {  0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x11C7, 0x1AAB, 0x238E, 0x2C72, 0x0 },
+       5,
+       55000,
+       0x69,
+       0xA,
+       1,
+       0,
+       0x3,
+       { 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       { 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       { 0x88B8, 0x88B8, 0x3555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_cac_config_reg cac_weights_oland[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x3BA, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_mars_pro[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_mars_xt[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x60, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_oland_pro[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x90, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_oland_xt[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x120, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_oland[] =
+{
+       { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x143, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+       { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_mars_pro[] =
+{
+       { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+       { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x143, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+       { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_override_oland[] =
+{
+       { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_oland =
+{
+       ((1 << 16) | 0x6993),
+       5,
+       0,
+       7,
+       105,
+       {
+               0UL,
+               0UL,
+               7194395UL,
+               309631529UL,
+               -1270850L,
+               4513710L,
+               100
+       },
+       117830498UL,
+       12,
+       {
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0
+       },
+       true
+};
+
+static const struct si_powertune_data powertune_data_mars_pro =
+{
+       ((1 << 16) | 0x6993),
+       5,
+       0,
+       7,
+       105,
+       {
+               0UL,
+               0UL,
+               7194395UL,
+               309631529UL,
+               -1270850L,
+               4513710L,
+               100
+       },
+       117830498UL,
+       12,
+       {
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0
+       },
+       true
+};
+
+static const struct si_dte_data dte_data_oland =
+{
+       { 0, 0, 0, 0, 0 },
+       { 0, 0, 0, 0, 0 },
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       0,
+       false
+};
+
+static const struct si_dte_data dte_data_mars_pro =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x0, 0x0, 0x0, 0x0, 0x0 },
+       5,
+       55000,
+       105,
+       0xA,
+       1,
+       0,
+       0x10,
+       { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+       { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+       { 0xF627, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+static const struct si_dte_data dte_data_sun_xt =
+{
+       { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+       { 0x0, 0x0, 0x0, 0x0, 0x0 },
+       5,
+       55000,
+       105,
+       0xA,
+       1,
+       0,
+       0x10,
+       { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+       { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+       { 0xD555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+       90,
+       true
+};
+
+
+static const struct si_cac_config_reg cac_weights_hainan[] =
+{
+       { 0x0, 0x0000ffff, 0, 0x2d9, SISLANDS_CACCONFIG_CGIND },
+       { 0x0, 0xffff0000, 16, 0x22b, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0x0000ffff, 0, 0x21c, SISLANDS_CACCONFIG_CGIND },
+       { 0x1, 0xffff0000, 16, 0x1dc, SISLANDS_CACCONFIG_CGIND },
+       { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0x0000ffff, 0, 0x24e, SISLANDS_CACCONFIG_CGIND },
+       { 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0x0000ffff, 0, 0x35e, SISLANDS_CACCONFIG_CGIND },
+       { 0x5, 0xffff0000, 16, 0x1143, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0x0000ffff, 0, 0xe17, SISLANDS_CACCONFIG_CGIND },
+       { 0x6, 0xffff0000, 16, 0x441, SISLANDS_CACCONFIG_CGIND },
+       { 0x18f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0x0000ffff, 0, 0x28b, SISLANDS_CACCONFIG_CGIND },
+       { 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x8, 0xffff0000, 16, 0xabe, SISLANDS_CACCONFIG_CGIND },
+       { 0x9, 0x0000ffff, 0, 0xf11, SISLANDS_CACCONFIG_CGIND },
+       { 0xa, 0x0000ffff, 0, 0x907, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0x0000ffff, 0, 0xb45, SISLANDS_CACCONFIG_CGIND },
+       { 0xb, 0xffff0000, 16, 0xd1e, SISLANDS_CACCONFIG_CGIND },
+       { 0xc, 0x0000ffff, 0, 0xa2c, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0x0000ffff, 0, 0x62, SISLANDS_CACCONFIG_CGIND },
+       { 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0xe, 0x0000ffff, 0, 0x1f3, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0x0000ffff, 0, 0x42, SISLANDS_CACCONFIG_CGIND },
+       { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0x0000ffff, 0, 0x709, SISLANDS_CACCONFIG_CGIND },
+       { 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x12, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x13, 0xffff0000, 16, 0x3a, SISLANDS_CACCONFIG_CGIND },
+       { 0x14, 0x0000ffff, 0, 0x357, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0x0000ffff, 0, 0x9f, SISLANDS_CACCONFIG_CGIND },
+       { 0x15, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0x0000ffff, 0, 0x314, SISLANDS_CACCONFIG_CGIND },
+       { 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x17, 0x0000ffff, 0, 0x6d, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+       { 0x6d, 0x0000ffff, 0, 0x1b9, SISLANDS_CACCONFIG_CGIND },
+       { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_hainan =
+{
+       ((1 << 16) | 0x6993),
+       5,
+       0,
+       9,
+       105,
+       {
+               0UL,
+               0UL,
+               7194395UL,
+               309631529UL,
+               -1270850L,
+               4513710L,
+               100
+       },
+       117830498UL,
+       12,
+       {
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0
+       },
+       true
+};
+
+static struct rv7xx_power_info *rv770_get_pi(struct amdgpu_device *adev);
+static struct evergreen_power_info *evergreen_get_pi(struct amdgpu_device *adev);
+static struct ni_power_info *ni_get_pi(struct amdgpu_device *adev);
+static struct  si_ps *si_get_ps(struct amdgpu_ps *rps);
+
+static int si_populate_voltage_value(struct amdgpu_device *adev,
+                                    const struct atom_voltage_table *table,
+                                    u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage);
+static int si_get_std_voltage_value(struct amdgpu_device *adev,
+                                   SISLANDS_SMC_VOLTAGE_VALUE *voltage,
+                                   u16 *std_voltage);
+static int si_write_smc_soft_register(struct amdgpu_device *adev,
+                                     u16 reg_offset, u32 value);
+static int si_convert_power_level_to_smc(struct amdgpu_device *adev,
+                                        struct rv7xx_pl *pl,
+                                        SISLANDS_SMC_HW_PERFORMANCE_LEVEL *level);
+static int si_calculate_sclk_params(struct amdgpu_device *adev,
+                                   u32 engine_clock,
+                                   SISLANDS_SMC_SCLK_VALUE *sclk);
+
+static void si_thermal_start_smc_fan_control(struct amdgpu_device *adev);
+static void si_fan_ctrl_set_default_mode(struct amdgpu_device *adev);
+static void si_dpm_set_dpm_funcs(struct amdgpu_device *adev);
+static void si_dpm_set_irq_funcs(struct amdgpu_device *adev);
+
+static struct si_power_info *si_get_pi(struct amdgpu_device *adev)
+{
+       struct si_power_info *pi = adev->pm.dpm.priv;
+       return pi;
+}
+
+static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coeffients *coeff,
+                                                    u16 v, s32 t, u32 ileakage, u32 *leakage)
+{
+       s64 kt, kv, leakage_w, i_leakage, vddc;
+       s64 temperature, t_slope, t_intercept, av, bv, t_ref;
+       s64 tmp;
+
+       i_leakage = div64_s64(drm_int2fixp(ileakage), 100);
+       vddc = div64_s64(drm_int2fixp(v), 1000);
+       temperature = div64_s64(drm_int2fixp(t), 1000);
+
+       t_slope = div64_s64(drm_int2fixp(coeff->t_slope), 100000000);
+       t_intercept = div64_s64(drm_int2fixp(coeff->t_intercept), 100000000);
+       av = div64_s64(drm_int2fixp(coeff->av), 100000000);
+       bv = div64_s64(drm_int2fixp(coeff->bv), 100000000);
+       t_ref = drm_int2fixp(coeff->t_ref);
+
+       tmp = drm_fixp_mul(t_slope, vddc) + t_intercept;
+       kt = drm_fixp_exp(drm_fixp_mul(tmp, temperature));
+       kt = drm_fixp_div(kt, drm_fixp_exp(drm_fixp_mul(tmp, t_ref)));
+       kv = drm_fixp_mul(av, drm_fixp_exp(drm_fixp_mul(bv, vddc)));
+
+       leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);
+
+       *leakage = drm_fixp2int(leakage_w * 1000);
+}
+
+static void si_calculate_leakage_for_v_and_t(struct amdgpu_device *adev,
+                                            const struct ni_leakage_coeffients *coeff,
+                                            u16 v,
+                                            s32 t,
+                                            u32 i_leakage,
+                                            u32 *leakage)
+{
+       si_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage);
+}
+
+static void si_calculate_leakage_for_v_formula(const struct ni_leakage_coeffients *coeff,
+                                              const u32 fixed_kt, u16 v,
+                                              u32 ileakage, u32 *leakage)
+{
+       s64 kt, kv, leakage_w, i_leakage, vddc;
+
+       i_leakage = div64_s64(drm_int2fixp(ileakage), 100);
+       vddc = div64_s64(drm_int2fixp(v), 1000);
+
+       kt = div64_s64(drm_int2fixp(fixed_kt), 100000000);
+       kv = drm_fixp_mul(div64_s64(drm_int2fixp(coeff->av), 100000000),
+                         drm_fixp_exp(drm_fixp_mul(div64_s64(drm_int2fixp(coeff->bv), 100000000), vddc)));
+
+       leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);
+
+       *leakage = drm_fixp2int(leakage_w * 1000);
+}
+
+static void si_calculate_leakage_for_v(struct amdgpu_device *adev,
+                                      const struct ni_leakage_coeffients *coeff,
+                                      const u32 fixed_kt,
+                                      u16 v,
+                                      u32 i_leakage,
+                                      u32 *leakage)
+{
+       si_calculate_leakage_for_v_formula(coeff, fixed_kt, v, i_leakage, leakage);
+}
+
+
+static void si_update_dte_from_pl2(struct amdgpu_device *adev,
+                                  struct si_dte_data *dte_data)
+{
+       u32 p_limit1 = adev->pm.dpm.tdp_limit;
+       u32 p_limit2 = adev->pm.dpm.near_tdp_limit;
+       u32 k = dte_data->k;
+       u32 t_max = dte_data->max_t;
+       u32 t_split[5] = { 10, 15, 20, 25, 30 };
+       u32 t_0 = dte_data->t0;
+       u32 i;
+
+       if (p_limit2 != 0 && p_limit2 <= p_limit1) {
+               dte_data->tdep_count = 3;
+
+               for (i = 0; i < k; i++) {
+                       dte_data->r[i] =
+                               (t_split[i] * (t_max - t_0/(u32)1000) * (1 << 14)) /
+                               (p_limit2  * (u32)100);
+               }
+
+               dte_data->tdep_r[1] = dte_data->r[4] * 2;
+
+               for (i = 2; i < SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE; i++) {
+                       dte_data->tdep_r[i] = dte_data->r[4];
+               }
+       } else {
+               DRM_ERROR("Invalid PL2! DTE will not be updated.\n");
+       }
+}
+
+static struct rv7xx_power_info *rv770_get_pi(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi = adev->pm.dpm.priv;
+
+       return pi;
+}
+
+static struct ni_power_info *ni_get_pi(struct amdgpu_device *adev)
+{
+       struct ni_power_info *pi = adev->pm.dpm.priv;
+
+       return pi;
+}
+
+static struct si_ps *si_get_ps(struct amdgpu_ps *aps)
+{
+       struct  si_ps *ps = aps->ps_priv;
+
+       return ps;
+}
+
+static void si_initialize_powertune_defaults(struct amdgpu_device *adev)
+{
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       bool update_dte_from_pl2 = false;
+
+       if (adev->asic_type == CHIP_TAHITI) {
+               si_pi->cac_weights = cac_weights_tahiti;
+               si_pi->lcac_config = lcac_tahiti;
+               si_pi->cac_override = cac_override_tahiti;
+               si_pi->powertune_data = &powertune_data_tahiti;
+               si_pi->dte_data = dte_data_tahiti;
+
+               switch (adev->pdev->device) {
+               case 0x6798:
+                       si_pi->dte_data.enable_dte_by_default = true;
+                       break;
+               case 0x6799:
+                       si_pi->dte_data = dte_data_new_zealand;
+                       break;
+               case 0x6790:
+               case 0x6791:
+               case 0x6792:
+               case 0x679E:
+                       si_pi->dte_data = dte_data_aruba_pro;
+                       update_dte_from_pl2 = true;
+                       break;
+               case 0x679B:
+                       si_pi->dte_data = dte_data_malta;
+                       update_dte_from_pl2 = true;
+                       break;
+               case 0x679A:
+                       si_pi->dte_data = dte_data_tahiti_pro;
+                       update_dte_from_pl2 = true;
+                       break;
+               default:
+                       if (si_pi->dte_data.enable_dte_by_default == true)
+                               DRM_ERROR("DTE is not enabled!\n");
+                       break;
+               }
+       } else if (adev->asic_type == CHIP_PITCAIRN) {
+               si_pi->cac_weights = cac_weights_pitcairn;
+               si_pi->lcac_config = lcac_pitcairn;
+               si_pi->cac_override = cac_override_pitcairn;
+               si_pi->powertune_data = &powertune_data_pitcairn;
+
+               switch (adev->pdev->device) {
+               case 0x6810:
+               case 0x6818:
+                       si_pi->dte_data = dte_data_curacao_xt;
+                       update_dte_from_pl2 = true;
+                       break;
+               case 0x6819:
+               case 0x6811:
+                       si_pi->dte_data = dte_data_curacao_pro;
+                       update_dte_from_pl2 = true;
+                       break;
+               case 0x6800:
+               case 0x6806:
+                       si_pi->dte_data = dte_data_neptune_xt;
+                       update_dte_from_pl2 = true;
+                       break;
+               default:
+                       si_pi->dte_data = dte_data_pitcairn;
+                       break;
+               }
+       } else if (adev->asic_type == CHIP_VERDE) {
+               si_pi->lcac_config = lcac_cape_verde;
+               si_pi->cac_override = cac_override_cape_verde;
+               si_pi->powertune_data = &powertune_data_cape_verde;
+
+               switch (adev->pdev->device) {
+               case 0x683B:
+               case 0x683F:
+               case 0x6829:
+               case 0x6835:
+                       si_pi->cac_weights = cac_weights_cape_verde_pro;
+                       si_pi->dte_data = dte_data_cape_verde;
+                       break;
+               case 0x682C:
+                       si_pi->cac_weights = cac_weights_cape_verde_pro;
+                       si_pi->dte_data = dte_data_sun_xt;
+                       break;
+               case 0x6825:
+               case 0x6827:
+                       si_pi->cac_weights = cac_weights_heathrow;
+                       si_pi->dte_data = dte_data_cape_verde;
+                       break;
+               case 0x6824:
+               case 0x682D:
+                       si_pi->cac_weights = cac_weights_chelsea_xt;
+                       si_pi->dte_data = dte_data_cape_verde;
+                       break;
+               case 0x682F:
+                       si_pi->cac_weights = cac_weights_chelsea_pro;
+                       si_pi->dte_data = dte_data_cape_verde;
+                       break;
+               case 0x6820:
+                       si_pi->cac_weights = cac_weights_heathrow;
+                       si_pi->dte_data = dte_data_venus_xtx;
+                       break;
+               case 0x6821:
+                       si_pi->cac_weights = cac_weights_heathrow;
+                       si_pi->dte_data = dte_data_venus_xt;
+                       break;
+               case 0x6823:
+               case 0x682B:
+               case 0x6822:
+               case 0x682A:
+                       si_pi->cac_weights = cac_weights_chelsea_pro;
+                       si_pi->dte_data = dte_data_venus_pro;
+                       break;
+               default:
+                       si_pi->cac_weights = cac_weights_cape_verde;
+                       si_pi->dte_data = dte_data_cape_verde;
+                       break;
+               }
+       } else if (adev->asic_type == CHIP_OLAND) {
+               si_pi->lcac_config = lcac_mars_pro;
+               si_pi->cac_override = cac_override_oland;
+               si_pi->powertune_data = &powertune_data_mars_pro;
+               si_pi->dte_data = dte_data_mars_pro;
+
+               switch (adev->pdev->device) {
+               case 0x6601:
+               case 0x6621:
+               case 0x6603:
+               case 0x6605:
+                       si_pi->cac_weights = cac_weights_mars_pro;
+                       update_dte_from_pl2 = true;
+                       break;
+               case 0x6600:
+               case 0x6606:
+               case 0x6620:
+               case 0x6604:
+                       si_pi->cac_weights = cac_weights_mars_xt;
+                       update_dte_from_pl2 = true;
+                       break;
+               case 0x6611:
+               case 0x6613:
+               case 0x6608:
+                       si_pi->cac_weights = cac_weights_oland_pro;
+                       update_dte_from_pl2 = true;
+                       break;
+               case 0x6610:
+                       si_pi->cac_weights = cac_weights_oland_xt;
+                       update_dte_from_pl2 = true;
+                       break;
+               default:
+                       si_pi->cac_weights = cac_weights_oland;
+                       si_pi->lcac_config = lcac_oland;
+                       si_pi->cac_override = cac_override_oland;
+                       si_pi->powertune_data = &powertune_data_oland;
+                       si_pi->dte_data = dte_data_oland;
+                       break;
+               }
+       } else if (adev->asic_type == CHIP_HAINAN) {
+               si_pi->cac_weights = cac_weights_hainan;
+               si_pi->lcac_config = lcac_oland;
+               si_pi->cac_override = cac_override_oland;
+               si_pi->powertune_data = &powertune_data_hainan;
+               si_pi->dte_data = dte_data_sun_xt;
+               update_dte_from_pl2 = true;
+       } else {
+               DRM_ERROR("Unknown SI asic revision, failed to initialize PowerTune!\n");
+               return;
+       }
+
+       ni_pi->enable_power_containment = false;
+       ni_pi->enable_cac = false;
+       ni_pi->enable_sq_ramping = false;
+       si_pi->enable_dte = false;
+
+       if (si_pi->powertune_data->enable_powertune_by_default) {
+               ni_pi->enable_power_containment = true;
+               ni_pi->enable_cac = true;
+               if (si_pi->dte_data.enable_dte_by_default) {
+                       si_pi->enable_dte = true;
+                       if (update_dte_from_pl2)
+                               si_update_dte_from_pl2(adev, &si_pi->dte_data);
+
+               }
+               ni_pi->enable_sq_ramping = true;
+       }
+
+       ni_pi->driver_calculate_cac_leakage = true;
+       ni_pi->cac_configuration_required = true;
+
+       if (ni_pi->cac_configuration_required) {
+               ni_pi->support_cac_long_term_average = true;
+               si_pi->dyn_powertune_data.l2_lta_window_size =
+                       si_pi->powertune_data->l2_lta_window_size_default;
+               si_pi->dyn_powertune_data.lts_truncate =
+                       si_pi->powertune_data->lts_truncate_default;
+       } else {
+               ni_pi->support_cac_long_term_average = false;
+               si_pi->dyn_powertune_data.l2_lta_window_size = 0;
+               si_pi->dyn_powertune_data.lts_truncate = 0;
+       }
+
+       si_pi->dyn_powertune_data.disable_uvd_powertune = false;
+}
+
+static u32 si_get_smc_power_scaling_factor(struct amdgpu_device *adev)
+{
+       return 1;
+}
+
+static u32 si_calculate_cac_wintime(struct amdgpu_device *adev)
+{
+       u32 xclk;
+       u32 wintime;
+       u32 cac_window;
+       u32 cac_window_size;
+
+       xclk = amdgpu_asic_get_xclk(adev);
+
+       if (xclk == 0)
+               return 0;
+
+       cac_window = RREG32(CG_CAC_CTRL) & CAC_WINDOW_MASK;
+       cac_window_size = ((cac_window & 0xFFFF0000) >> 16) * (cac_window & 0x0000FFFF);
+
+       wintime = (cac_window_size * 100) / xclk;
+
+       return wintime;
+}
+
+static u32 si_scale_power_for_smc(u32 power_in_watts, u32 scaling_factor)
+{
+       return power_in_watts;
+}
+
+static int si_calculate_adjusted_tdp_limits(struct amdgpu_device *adev,
+                                           bool adjust_polarity,
+                                           u32 tdp_adjustment,
+                                           u32 *tdp_limit,
+                                           u32 *near_tdp_limit)
+{
+       u32 adjustment_delta, max_tdp_limit;
+
+       if (tdp_adjustment > (u32)adev->pm.dpm.tdp_od_limit)
+               return -EINVAL;
+
+       max_tdp_limit = ((100 + 100) * adev->pm.dpm.tdp_limit) / 100;
+
+       if (adjust_polarity) {
+               *tdp_limit = ((100 + tdp_adjustment) * adev->pm.dpm.tdp_limit) / 100;
+               *near_tdp_limit = adev->pm.dpm.near_tdp_limit_adjusted + (*tdp_limit - adev->pm.dpm.tdp_limit);
+       } else {
+               *tdp_limit = ((100 - tdp_adjustment) * adev->pm.dpm.tdp_limit) / 100;
+               adjustment_delta  = adev->pm.dpm.tdp_limit - *tdp_limit;
+               if (adjustment_delta < adev->pm.dpm.near_tdp_limit_adjusted)
+                       *near_tdp_limit = adev->pm.dpm.near_tdp_limit_adjusted - adjustment_delta;
+               else
+                       *near_tdp_limit = 0;
+       }
+
+       if ((*tdp_limit <= 0) || (*tdp_limit > max_tdp_limit))
+               return -EINVAL;
+       if ((*near_tdp_limit <= 0) || (*near_tdp_limit > *tdp_limit))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int si_populate_smc_tdp_limits(struct amdgpu_device *adev,
+                                     struct amdgpu_ps *amdgpu_state)
+{
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       if (ni_pi->enable_power_containment) {
+               SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable;
+               PP_SIslands_PAPMParameters *papm_parm;
+               struct amdgpu_ppm_table *ppm = adev->pm.dpm.dyn_state.ppm_table;
+               u32 scaling_factor = si_get_smc_power_scaling_factor(adev);
+               u32 tdp_limit;
+               u32 near_tdp_limit;
+               int ret;
+
+               if (scaling_factor == 0)
+                       return -EINVAL;
+
+               memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE));
+
+               ret = si_calculate_adjusted_tdp_limits(adev,
+                                                      false, /* ??? */
+                                                      adev->pm.dpm.tdp_adjustment,
+                                                      &tdp_limit,
+                                                      &near_tdp_limit);
+               if (ret)
+                       return ret;
+
+               smc_table->dpm2Params.TDPLimit =
+                       cpu_to_be32(si_scale_power_for_smc(tdp_limit, scaling_factor) * 1000);
+               smc_table->dpm2Params.NearTDPLimit =
+                       cpu_to_be32(si_scale_power_for_smc(near_tdp_limit, scaling_factor) * 1000);
+               smc_table->dpm2Params.SafePowerLimit =
+                       cpu_to_be32(si_scale_power_for_smc((near_tdp_limit * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000);
+
+               ret = amdgpu_si_copy_bytes_to_smc(adev,
+                                                 (si_pi->state_table_start + offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) +
+                                                  offsetof(PP_SIslands_DPM2Parameters, TDPLimit)),
+                                                 (u8 *)(&(smc_table->dpm2Params.TDPLimit)),
+                                                 sizeof(u32) * 3,
+                                                 si_pi->sram_end);
+               if (ret)
+                       return ret;
+
+               if (si_pi->enable_ppm) {
+                       papm_parm = &si_pi->papm_parm;
+                       memset(papm_parm, 0, sizeof(PP_SIslands_PAPMParameters));
+                       papm_parm->NearTDPLimitTherm = cpu_to_be32(ppm->dgpu_tdp);
+                       papm_parm->dGPU_T_Limit = cpu_to_be32(ppm->tj_max);
+                       papm_parm->dGPU_T_Warning = cpu_to_be32(95);
+                       papm_parm->dGPU_T_Hysteresis = cpu_to_be32(5);
+                       papm_parm->PlatformPowerLimit = 0xffffffff;
+                       papm_parm->NearTDPLimitPAPM = 0xffffffff;
+
+                       ret = amdgpu_si_copy_bytes_to_smc(adev, si_pi->papm_cfg_table_start,
+                                                         (u8 *)papm_parm,
+                                                         sizeof(PP_SIslands_PAPMParameters),
+                                                         si_pi->sram_end);
+                       if (ret)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
+static int si_populate_smc_tdp_limits_2(struct amdgpu_device *adev,
+                                       struct amdgpu_ps *amdgpu_state)
+{
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       if (ni_pi->enable_power_containment) {
+               SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable;
+               u32 scaling_factor = si_get_smc_power_scaling_factor(adev);
+               int ret;
+
+               memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE));
+
+               smc_table->dpm2Params.NearTDPLimit =
+                       cpu_to_be32(si_scale_power_for_smc(adev->pm.dpm.near_tdp_limit_adjusted, scaling_factor) * 1000);
+               smc_table->dpm2Params.SafePowerLimit =
+                       cpu_to_be32(si_scale_power_for_smc((adev->pm.dpm.near_tdp_limit_adjusted * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000);
+
+               ret = amdgpu_si_copy_bytes_to_smc(adev,
+                                                 (si_pi->state_table_start +
+                                                  offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) +
+                                                  offsetof(PP_SIslands_DPM2Parameters, NearTDPLimit)),
+                                                 (u8 *)(&(smc_table->dpm2Params.NearTDPLimit)),
+                                                 sizeof(u32) * 2,
+                                                 si_pi->sram_end);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static u16 si_calculate_power_efficiency_ratio(struct amdgpu_device *adev,
+                                              const u16 prev_std_vddc,
+                                              const u16 curr_std_vddc)
+{
+       u64 margin = (u64)SISLANDS_DPM2_PWREFFICIENCYRATIO_MARGIN;
+       u64 prev_vddc = (u64)prev_std_vddc;
+       u64 curr_vddc = (u64)curr_std_vddc;
+       u64 pwr_efficiency_ratio, n, d;
+
+       if ((prev_vddc == 0) || (curr_vddc == 0))
+               return 0;
+
+       n = div64_u64((u64)1024 * curr_vddc * curr_vddc * ((u64)1000 + margin), (u64)1000);
+       d = prev_vddc * prev_vddc;
+       pwr_efficiency_ratio = div64_u64(n, d);
+
+       if (pwr_efficiency_ratio > (u64)0xFFFF)
+               return 0;
+
+       return (u16)pwr_efficiency_ratio;
+}
+
+static bool si_should_disable_uvd_powertune(struct amdgpu_device *adev,
+                                           struct amdgpu_ps *amdgpu_state)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       if (si_pi->dyn_powertune_data.disable_uvd_powertune &&
+           amdgpu_state->vclk && amdgpu_state->dclk)
+               return true;
+
+       return false;
+}
+
+struct evergreen_power_info *evergreen_get_pi(struct amdgpu_device *adev)
+{
+       struct evergreen_power_info *pi = adev->pm.dpm.priv;
+
+       return pi;
+}
+
+static int si_populate_power_containment_values(struct amdgpu_device *adev,
+                                               struct amdgpu_ps *amdgpu_state,
+                                               SISLANDS_SMC_SWSTATE *smc_state)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct  si_ps *state = si_get_ps(amdgpu_state);
+       SISLANDS_SMC_VOLTAGE_VALUE vddc;
+       u32 prev_sclk;
+       u32 max_sclk;
+       u32 min_sclk;
+       u16 prev_std_vddc;
+       u16 curr_std_vddc;
+       int i;
+       u16 pwr_efficiency_ratio;
+       u8 max_ps_percent;
+       bool disable_uvd_power_tune;
+       int ret;
+
+       if (ni_pi->enable_power_containment == false)
+               return 0;
+
+       if (state->performance_level_count == 0)
+               return -EINVAL;
+
+       if (smc_state->levelCount != state->performance_level_count)
+               return -EINVAL;
+
+       disable_uvd_power_tune = si_should_disable_uvd_powertune(adev, amdgpu_state);
+
+       smc_state->levels[0].dpm2.MaxPS = 0;
+       smc_state->levels[0].dpm2.NearTDPDec = 0;
+       smc_state->levels[0].dpm2.AboveSafeInc = 0;
+       smc_state->levels[0].dpm2.BelowSafeInc = 0;
+       smc_state->levels[0].dpm2.PwrEfficiencyRatio = 0;
+
+       for (i = 1; i < state->performance_level_count; i++) {
+               prev_sclk = state->performance_levels[i-1].sclk;
+               max_sclk  = state->performance_levels[i].sclk;
+               if (i == 1)
+                       max_ps_percent = SISLANDS_DPM2_MAXPS_PERCENT_M;
+               else
+                       max_ps_percent = SISLANDS_DPM2_MAXPS_PERCENT_H;
+
+               if (prev_sclk > max_sclk)
+                       return -EINVAL;
+
+               if ((max_ps_percent == 0) ||
+                   (prev_sclk == max_sclk) ||
+                   disable_uvd_power_tune)
+                       min_sclk = max_sclk;
+               else if (i == 1)
+                       min_sclk = prev_sclk;
+               else
+                       min_sclk = (prev_sclk * (u32)max_ps_percent) / 100;
+
+               if (min_sclk < state->performance_levels[0].sclk)
+                       min_sclk = state->performance_levels[0].sclk;
+
+               if (min_sclk == 0)
+                       return -EINVAL;
+
+               ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
+                                               state->performance_levels[i-1].vddc, &vddc);
+               if (ret)
+                       return ret;
+
+               ret = si_get_std_voltage_value(adev, &vddc, &prev_std_vddc);
+               if (ret)
+                       return ret;
+
+               ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
+                                               state->performance_levels[i].vddc, &vddc);
+               if (ret)
+                       return ret;
+
+               ret = si_get_std_voltage_value(adev, &vddc, &curr_std_vddc);
+               if (ret)
+                       return ret;
+
+               pwr_efficiency_ratio = si_calculate_power_efficiency_ratio(adev,
+                                                                          prev_std_vddc, curr_std_vddc);
+
+               smc_state->levels[i].dpm2.MaxPS = (u8)((SISLANDS_DPM2_MAX_PULSE_SKIP * (max_sclk - min_sclk)) / max_sclk);
+               smc_state->levels[i].dpm2.NearTDPDec = SISLANDS_DPM2_NEAR_TDP_DEC;
+               smc_state->levels[i].dpm2.AboveSafeInc = SISLANDS_DPM2_ABOVE_SAFE_INC;
+               smc_state->levels[i].dpm2.BelowSafeInc = SISLANDS_DPM2_BELOW_SAFE_INC;
+               smc_state->levels[i].dpm2.PwrEfficiencyRatio = cpu_to_be16(pwr_efficiency_ratio);
+       }
+
+       return 0;
+}
+
+static int si_populate_sq_ramping_values(struct amdgpu_device *adev,
+                                        struct amdgpu_ps *amdgpu_state,
+                                        SISLANDS_SMC_SWSTATE *smc_state)
+{
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct  si_ps *state = si_get_ps(amdgpu_state);
+       u32 sq_power_throttle, sq_power_throttle2;
+       bool enable_sq_ramping = ni_pi->enable_sq_ramping;
+       int i;
+
+       if (state->performance_level_count == 0)
+               return -EINVAL;
+
+       if (smc_state->levelCount != state->performance_level_count)
+               return -EINVAL;
+
+       if (adev->pm.dpm.sq_ramping_threshold == 0)
+               return -EINVAL;
+
+       if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT))
+               enable_sq_ramping = false;
+
+       if (SISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT))
+               enable_sq_ramping = false;
+
+       if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT))
+               enable_sq_ramping = false;
+
+       if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
+               enable_sq_ramping = false;
+
+       if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+               enable_sq_ramping = false;
+
+       for (i = 0; i < state->performance_level_count; i++) {
+               sq_power_throttle = 0;
+               sq_power_throttle2 = 0;
+
+               if ((state->performance_levels[i].sclk >= adev->pm.dpm.sq_ramping_threshold) &&
+                   enable_sq_ramping) {
+                       sq_power_throttle |= MAX_POWER(SISLANDS_DPM2_SQ_RAMP_MAX_POWER);
+                       sq_power_throttle |= MIN_POWER(SISLANDS_DPM2_SQ_RAMP_MIN_POWER);
+                       sq_power_throttle2 |= MAX_POWER_DELTA(SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA);
+                       sq_power_throttle2 |= STI_SIZE(SISLANDS_DPM2_SQ_RAMP_STI_SIZE);
+                       sq_power_throttle2 |= LTI_RATIO(SISLANDS_DPM2_SQ_RAMP_LTI_RATIO);
+               } else {
+                       sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK;
+                       sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+               }
+
+               smc_state->levels[i].SQPowerThrottle = cpu_to_be32(sq_power_throttle);
+               smc_state->levels[i].SQPowerThrottle_2 = cpu_to_be32(sq_power_throttle2);
+       }
+
+       return 0;
+}
+
+static int si_enable_power_containment(struct amdgpu_device *adev,
+                                      struct amdgpu_ps *amdgpu_new_state,
+                                      bool enable)
+{
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       PPSMC_Result smc_result;
+       int ret = 0;
+
+       if (ni_pi->enable_power_containment) {
+               if (enable) {
+                       if (!si_should_disable_uvd_powertune(adev, amdgpu_new_state)) {
+                               smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_TDPClampingActive);
+                               if (smc_result != PPSMC_Result_OK) {
+                                       ret = -EINVAL;
+                                       ni_pi->pc_enabled = false;
+                               } else {
+                                       ni_pi->pc_enabled = true;
+                               }
+                       }
+               } else {
+                       smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_TDPClampingInactive);
+                       if (smc_result != PPSMC_Result_OK)
+                               ret = -EINVAL;
+                       ni_pi->pc_enabled = false;
+               }
+       }
+
+       return ret;
+}
+
+static int si_initialize_smc_dte_tables(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       int ret = 0;
+       struct si_dte_data *dte_data = &si_pi->dte_data;
+       Smc_SIslands_DTE_Configuration *dte_tables = NULL;
+       u32 table_size;
+       u8 tdep_count;
+       u32 i;
+
+       if (dte_data == NULL)
+               si_pi->enable_dte = false;
+
+       if (si_pi->enable_dte == false)
+               return 0;
+
+       if (dte_data->k <= 0)
+               return -EINVAL;
+
+       dte_tables = kzalloc(sizeof(Smc_SIslands_DTE_Configuration), GFP_KERNEL);
+       if (dte_tables == NULL) {
+               si_pi->enable_dte = false;
+               return -ENOMEM;
+       }
+
+       table_size = dte_data->k;
+
+       if (table_size > SMC_SISLANDS_DTE_MAX_FILTER_STAGES)
+               table_size = SMC_SISLANDS_DTE_MAX_FILTER_STAGES;
+
+       tdep_count = dte_data->tdep_count;
+       if (tdep_count > SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE)
+               tdep_count = SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE;
+
+       dte_tables->K = cpu_to_be32(table_size);
+       dte_tables->T0 = cpu_to_be32(dte_data->t0);
+       dte_tables->MaxT = cpu_to_be32(dte_data->max_t);
+       dte_tables->WindowSize = dte_data->window_size;
+       dte_tables->temp_select = dte_data->temp_select;
+       dte_tables->DTE_mode = dte_data->dte_mode;
+       dte_tables->Tthreshold = cpu_to_be32(dte_data->t_threshold);
+
+       if (tdep_count > 0)
+               table_size--;
+
+       for (i = 0; i < table_size; i++) {
+               dte_tables->tau[i] = cpu_to_be32(dte_data->tau[i]);
+               dte_tables->R[i]   = cpu_to_be32(dte_data->r[i]);
+       }
+
+       dte_tables->Tdep_count = tdep_count;
+
+       for (i = 0; i < (u32)tdep_count; i++) {
+               dte_tables->T_limits[i] = dte_data->t_limits[i];
+               dte_tables->Tdep_tau[i] = cpu_to_be32(dte_data->tdep_tau[i]);
+               dte_tables->Tdep_R[i] = cpu_to_be32(dte_data->tdep_r[i]);
+       }
+
+       ret = amdgpu_si_copy_bytes_to_smc(adev, si_pi->dte_table_start,
+                                         (u8 *)dte_tables,
+                                         sizeof(Smc_SIslands_DTE_Configuration),
+                                         si_pi->sram_end);
+       kfree(dte_tables);
+
+       return ret;
+}
+
+static int si_get_cac_std_voltage_max_min(struct amdgpu_device *adev,
+                                         u16 *max, u16 *min)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct amdgpu_cac_leakage_table *table =
+               &adev->pm.dpm.dyn_state.cac_leakage_table;
+       u32 i;
+       u32 v0_loadline;
+
+       if (table == NULL)
+               return -EINVAL;
+
+       *max = 0;
+       *min = 0xFFFF;
+
+       for (i = 0; i < table->count; i++) {
+               if (table->entries[i].vddc > *max)
+                       *max = table->entries[i].vddc;
+               if (table->entries[i].vddc < *min)
+                       *min = table->entries[i].vddc;
+       }
+
+       if (si_pi->powertune_data->lkge_lut_v0_percent > 100)
+               return -EINVAL;
+
+       v0_loadline = (*min) * (100 - si_pi->powertune_data->lkge_lut_v0_percent) / 100;
+
+       if (v0_loadline > 0xFFFFUL)
+               return -EINVAL;
+
+       *min = (u16)v0_loadline;
+
+       if ((*min > *max) || (*max == 0) || (*min == 0))
+               return -EINVAL;
+
+       return 0;
+}
+
+static u16 si_get_cac_std_voltage_step(u16 max, u16 min)
+{
+       return ((max - min) + (SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES - 1)) /
+               SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES;
+}
+
+static int si_init_dte_leakage_table(struct amdgpu_device *adev,
+                                    PP_SIslands_CacConfig *cac_tables,
+                                    u16 vddc_max, u16 vddc_min, u16 vddc_step,
+                                    u16 t0, u16 t_step)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 leakage;
+       unsigned int i, j;
+       s32 t;
+       u32 smc_leakage;
+       u32 scaling_factor;
+       u16 voltage;
+
+       scaling_factor = si_get_smc_power_scaling_factor(adev);
+
+       for (i = 0; i < SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES ; i++) {
+               t = (1000 * (i * t_step + t0));
+
+               for (j = 0; j < SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
+                       voltage = vddc_max - (vddc_step * j);
+
+                       si_calculate_leakage_for_v_and_t(adev,
+                                                        &si_pi->powertune_data->leakage_coefficients,
+                                                        voltage,
+                                                        t,
+                                                        si_pi->dyn_powertune_data.cac_leakage,
+                                                        &leakage);
+
+                       smc_leakage = si_scale_power_for_smc(leakage, scaling_factor) / 4;
+
+                       if (smc_leakage > 0xFFFF)
+                               smc_leakage = 0xFFFF;
+
+                       cac_tables->cac_lkge_lut[i][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES-1-j] =
+                               cpu_to_be16((u16)smc_leakage);
+               }
+       }
+       return 0;
+}
+
+static int si_init_simplified_leakage_table(struct amdgpu_device *adev,
+                                           PP_SIslands_CacConfig *cac_tables,
+                                           u16 vddc_max, u16 vddc_min, u16 vddc_step)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 leakage;
+       unsigned int i, j;
+       u32 smc_leakage;
+       u32 scaling_factor;
+       u16 voltage;
+
+       scaling_factor = si_get_smc_power_scaling_factor(adev);
+
+       for (j = 0; j < SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
+               voltage = vddc_max - (vddc_step * j);
+
+               si_calculate_leakage_for_v(adev,
+                                          &si_pi->powertune_data->leakage_coefficients,
+                                          si_pi->powertune_data->fixed_kt,
+                                          voltage,
+                                          si_pi->dyn_powertune_data.cac_leakage,
+                                          &leakage);
+
+               smc_leakage = si_scale_power_for_smc(leakage, scaling_factor) / 4;
+
+               if (smc_leakage > 0xFFFF)
+                       smc_leakage = 0xFFFF;
+
+               for (i = 0; i < SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES ; i++)
+                       cac_tables->cac_lkge_lut[i][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES-1-j] =
+                               cpu_to_be16((u16)smc_leakage);
+       }
+       return 0;
+}
+
+static int si_initialize_smc_cac_tables(struct amdgpu_device *adev)
+{
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       PP_SIslands_CacConfig *cac_tables = NULL;
+       u16 vddc_max, vddc_min, vddc_step;
+       u16 t0, t_step;
+       u32 load_line_slope, reg;
+       int ret = 0;
+       u32 ticks_per_us = amdgpu_asic_get_xclk(adev) / 100;
+
+       if (ni_pi->enable_cac == false)
+               return 0;
+
+       cac_tables = kzalloc(sizeof(PP_SIslands_CacConfig), GFP_KERNEL);
+       if (!cac_tables)
+               return -ENOMEM;
+
+       reg = RREG32(CG_CAC_CTRL) & ~CAC_WINDOW_MASK;
+       reg |= CAC_WINDOW(si_pi->powertune_data->cac_window);
+       WREG32(CG_CAC_CTRL, reg);
+
+       si_pi->dyn_powertune_data.cac_leakage = adev->pm.dpm.cac_leakage;
+       si_pi->dyn_powertune_data.dc_pwr_value =
+               si_pi->powertune_data->dc_cac[NISLANDS_DCCAC_LEVEL_0];
+       si_pi->dyn_powertune_data.wintime = si_calculate_cac_wintime(adev);
+       si_pi->dyn_powertune_data.shift_n = si_pi->powertune_data->shift_n_default;
+
+       si_pi->dyn_powertune_data.leakage_minimum_temperature = 80 * 1000;
+
+       ret = si_get_cac_std_voltage_max_min(adev, &vddc_max, &vddc_min);
+       if (ret)
+               goto done_free;
+
+       vddc_step = si_get_cac_std_voltage_step(vddc_max, vddc_min);
+       vddc_min = vddc_max - (vddc_step * (SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES - 1));
+       t_step = 4;
+       t0 = 60;
+
+       if (si_pi->enable_dte || ni_pi->driver_calculate_cac_leakage)
+               ret = si_init_dte_leakage_table(adev, cac_tables,
+                                               vddc_max, vddc_min, vddc_step,
+                                               t0, t_step);
+       else
+               ret = si_init_simplified_leakage_table(adev, cac_tables,
+                                                      vddc_max, vddc_min, vddc_step);
+       if (ret)
+               goto done_free;
+
+       load_line_slope = ((u32)adev->pm.dpm.load_line_slope << SMC_SISLANDS_SCALE_R) / 100;
+
+       cac_tables->l2numWin_TDP = cpu_to_be32(si_pi->dyn_powertune_data.l2_lta_window_size);
+       cac_tables->lts_truncate_n = si_pi->dyn_powertune_data.lts_truncate;
+       cac_tables->SHIFT_N = si_pi->dyn_powertune_data.shift_n;
+       cac_tables->lkge_lut_V0 = cpu_to_be32((u32)vddc_min);
+       cac_tables->lkge_lut_Vstep = cpu_to_be32((u32)vddc_step);
+       cac_tables->R_LL = cpu_to_be32(load_line_slope);
+       cac_tables->WinTime = cpu_to_be32(si_pi->dyn_powertune_data.wintime);
+       cac_tables->calculation_repeats = cpu_to_be32(2);
+       cac_tables->dc_cac = cpu_to_be32(0);
+       cac_tables->log2_PG_LKG_SCALE = 12;
+       cac_tables->cac_temp = si_pi->powertune_data->operating_temp;
+       cac_tables->lkge_lut_T0 = cpu_to_be32((u32)t0);
+       cac_tables->lkge_lut_Tstep = cpu_to_be32((u32)t_step);
+
+       ret = amdgpu_si_copy_bytes_to_smc(adev, si_pi->cac_table_start,
+                                         (u8 *)cac_tables,
+                                         sizeof(PP_SIslands_CacConfig),
+                                         si_pi->sram_end);
+
+       if (ret)
+               goto done_free;
+
+       ret = si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_ticks_per_us, ticks_per_us);
+
+done_free:
+       if (ret) {
+               ni_pi->enable_cac = false;
+               ni_pi->enable_power_containment = false;
+       }
+
+       kfree(cac_tables);
+
+       return ret;
+}
+
+static int si_program_cac_config_registers(struct amdgpu_device *adev,
+                                          const struct si_cac_config_reg *cac_config_regs)
+{
+       const struct si_cac_config_reg *config_regs = cac_config_regs;
+       u32 data = 0, offset;
+
+       if (!config_regs)
+               return -EINVAL;
+
+       while (config_regs->offset != 0xFFFFFFFF) {
+               switch (config_regs->type) {
+               case SISLANDS_CACCONFIG_CGIND:
+                       offset = SMC_CG_IND_START + config_regs->offset;
+                       if (offset < SMC_CG_IND_END)
+                               data = RREG32_SMC(offset);
+                       break;
+               default:
+                       data = RREG32(config_regs->offset);
+                       break;
+               }
+
+               data &= ~config_regs->mask;
+               data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
+
+               switch (config_regs->type) {
+               case SISLANDS_CACCONFIG_CGIND:
+                       offset = SMC_CG_IND_START + config_regs->offset;
+                       if (offset < SMC_CG_IND_END)
+                               WREG32_SMC(offset, data);
+                       break;
+               default:
+                       WREG32(config_regs->offset, data);
+                       break;
+               }
+               config_regs++;
+       }
+       return 0;
+}
+
+static int si_initialize_hardware_cac_manager(struct amdgpu_device *adev)
+{
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       int ret;
+
+       if ((ni_pi->enable_cac == false) ||
+           (ni_pi->cac_configuration_required == false))
+               return 0;
+
+       ret = si_program_cac_config_registers(adev, si_pi->lcac_config);
+       if (ret)
+               return ret;
+       ret = si_program_cac_config_registers(adev, si_pi->cac_override);
+       if (ret)
+               return ret;
+       ret = si_program_cac_config_registers(adev, si_pi->cac_weights);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int si_enable_smc_cac(struct amdgpu_device *adev,
+                            struct amdgpu_ps *amdgpu_new_state,
+                            bool enable)
+{
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       PPSMC_Result smc_result;
+       int ret = 0;
+
+       if (ni_pi->enable_cac) {
+               if (enable) {
+                       if (!si_should_disable_uvd_powertune(adev, amdgpu_new_state)) {
+                               if (ni_pi->support_cac_long_term_average) {
+                                       smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_CACLongTermAvgEnable);
+                                       if (smc_result != PPSMC_Result_OK)
+                                               ni_pi->support_cac_long_term_average = false;
+                               }
+
+                               smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableCac);
+                               if (smc_result != PPSMC_Result_OK) {
+                                       ret = -EINVAL;
+                                       ni_pi->cac_enabled = false;
+                               } else {
+                                       ni_pi->cac_enabled = true;
+                               }
+
+                               if (si_pi->enable_dte) {
+                                       smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableDTE);
+                                       if (smc_result != PPSMC_Result_OK)
+                                               ret = -EINVAL;
+                               }
+                       }
+               } else if (ni_pi->cac_enabled) {
+                       if (si_pi->enable_dte)
+                               smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_DisableDTE);
+
+                       smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_DisableCac);
+
+                       ni_pi->cac_enabled = false;
+
+                       if (ni_pi->support_cac_long_term_average)
+                               smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_CACLongTermAvgDisable);
+               }
+       }
+       return ret;
+}
+
+static int si_init_smc_spll_table(struct amdgpu_device *adev)
+{
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       SMC_SISLANDS_SPLL_DIV_TABLE *spll_table;
+       SISLANDS_SMC_SCLK_VALUE sclk_params;
+       u32 fb_div, p_div;
+       u32 clk_s, clk_v;
+       u32 sclk = 0;
+       int ret = 0;
+       u32 tmp;
+       int i;
+
+       if (si_pi->spll_table_start == 0)
+               return -EINVAL;
+
+       spll_table = kzalloc(sizeof(SMC_SISLANDS_SPLL_DIV_TABLE), GFP_KERNEL);
+       if (spll_table == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < 256; i++) {
+               ret = si_calculate_sclk_params(adev, sclk, &sclk_params);
+               if (ret)
+                       break;
+               p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT;
+               fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
+               clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT;
+               clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT;
+
+               fb_div &= ~0x00001FFF;
+               fb_div >>= 1;
+               clk_v >>= 6;
+
+               if (p_div & ~(SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT))
+                       ret = -EINVAL;
+               if (fb_div & ~(SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT))
+                       ret = -EINVAL;
+               if (clk_s & ~(SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
+                       ret = -EINVAL;
+               if (clk_v & ~(SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT))
+                       ret = -EINVAL;
+
+               if (ret)
+                       break;
+
+               tmp = ((fb_div << SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK) |
+                       ((p_div << SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK);
+               spll_table->freq[i] = cpu_to_be32(tmp);
+
+               tmp = ((clk_v << SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK) |
+                       ((clk_s << SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK);
+               spll_table->ss[i] = cpu_to_be32(tmp);
+
+               sclk += 512;
+       }
+
+
+       if (!ret)
+               ret = amdgpu_si_copy_bytes_to_smc(adev, si_pi->spll_table_start,
+                                                 (u8 *)spll_table,
+                                                 sizeof(SMC_SISLANDS_SPLL_DIV_TABLE),
+                                                 si_pi->sram_end);
+
+       if (ret)
+               ni_pi->enable_power_containment = false;
+
+       kfree(spll_table);
+
+       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)
+{
+       u16 highest_leakage = 0;
+       struct si_power_info *si_pi = si_get_pi(adev);
+       int i;
+
+       for (i = 0; i < si_pi->leakage_voltage.count; i++){
+               if (highest_leakage < si_pi->leakage_voltage.entries[i].voltage)
+                       highest_leakage = si_pi->leakage_voltage.entries[i].voltage;
+       }
+
+       if (si_pi->leakage_voltage.count && (highest_leakage < vce_voltage))
+               return highest_leakage;
+
+       return vce_voltage;
+}
+
+static int si_get_vce_clock_voltage(struct amdgpu_device *adev,
+                                   u32 evclk, u32 ecclk, u16 *voltage)
+{
+       u32 i;
+       int ret = -EINVAL;
+       struct amdgpu_vce_clock_voltage_dependency_table *table =
+               &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+
+       if (((evclk == 0) && (ecclk == 0)) ||
+           (table && (table->count == 0))) {
+               *voltage = 0;
+               return 0;
+       }
+
+       for (i = 0; i < table->count; i++) {
+               if ((evclk <= table->entries[i].evclk) &&
+                   (ecclk <= table->entries[i].ecclk)) {
+                       *voltage = table->entries[i].v;
+                       ret = 0;
+                       break;
+               }
+       }
+
+       /* if no match return the highest voltage */
+       if (ret)
+               *voltage = table->entries[table->count - 1].v;
+
+       *voltage = si_get_lower_of_leakage_and_vce_voltage(adev, *voltage);
+
+       return ret;
+}
+
+static bool si_dpm_vblank_too_short(struct amdgpu_device *adev)
+{
+
+       u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
+       /* we never hit the non-gddr5 limit so disable it */
+       u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0;
+
+       if (vblank_time < switch_limit)
+               return true;
+       else
+               return false;
+
+}
+
+static int ni_copy_and_switch_arb_sets(struct amdgpu_device *adev,
+                               u32 arb_freq_src, u32 arb_freq_dest)
+{
+       u32 mc_arb_dram_timing;
+       u32 mc_arb_dram_timing2;
+       u32 burst_time;
+       u32 mc_cg_config;
+
+       switch (arb_freq_src) {
+       case MC_CG_ARB_FREQ_F0:
+               mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING);
+               mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+               burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE0_MASK) >> STATE0_SHIFT;
+               break;
+       case MC_CG_ARB_FREQ_F1:
+               mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_1);
+               mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_1);
+               burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE1_MASK) >> STATE1_SHIFT;
+               break;
+       case MC_CG_ARB_FREQ_F2:
+               mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_2);
+               mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_2);
+               burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE2_MASK) >> STATE2_SHIFT;
+               break;
+       case MC_CG_ARB_FREQ_F3:
+               mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_3);
+               mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_3);
+               burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE3_MASK) >> STATE3_SHIFT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (arb_freq_dest) {
+       case MC_CG_ARB_FREQ_F0:
+               WREG32(MC_ARB_DRAM_TIMING, mc_arb_dram_timing);
+               WREG32(MC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
+               WREG32_P(MC_ARB_BURST_TIME, STATE0(burst_time), ~STATE0_MASK);
+               break;
+       case MC_CG_ARB_FREQ_F1:
+               WREG32(MC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
+               WREG32(MC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
+               WREG32_P(MC_ARB_BURST_TIME, STATE1(burst_time), ~STATE1_MASK);
+               break;
+       case MC_CG_ARB_FREQ_F2:
+               WREG32(MC_ARB_DRAM_TIMING_2, mc_arb_dram_timing);
+               WREG32(MC_ARB_DRAM_TIMING2_2, mc_arb_dram_timing2);
+               WREG32_P(MC_ARB_BURST_TIME, STATE2(burst_time), ~STATE2_MASK);
+               break;
+       case MC_CG_ARB_FREQ_F3:
+               WREG32(MC_ARB_DRAM_TIMING_3, mc_arb_dram_timing);
+               WREG32(MC_ARB_DRAM_TIMING2_3, mc_arb_dram_timing2);
+               WREG32_P(MC_ARB_BURST_TIME, STATE3(burst_time), ~STATE3_MASK);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mc_cg_config = RREG32(MC_CG_CONFIG) | 0x0000000F;
+       WREG32(MC_CG_CONFIG, mc_cg_config);
+       WREG32_P(MC_ARB_CG, CG_ARB_REQ(arb_freq_dest), ~CG_ARB_REQ_MASK);
+
+       return 0;
+}
+
+static void ni_update_current_ps(struct amdgpu_device *adev,
+                         struct amdgpu_ps *rps)
+{
+       struct si_ps *new_ps = si_get_ps(rps);
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+
+       eg_pi->current_rps = *rps;
+       ni_pi->current_ps = *new_ps;
+       eg_pi->current_rps.ps_priv = &ni_pi->current_ps;
+}
+
+static void ni_update_requested_ps(struct amdgpu_device *adev,
+                           struct amdgpu_ps *rps)
+{
+       struct si_ps *new_ps = si_get_ps(rps);
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+
+       eg_pi->requested_rps = *rps;
+       ni_pi->requested_ps = *new_ps;
+       eg_pi->requested_rps.ps_priv = &ni_pi->requested_ps;
+}
+
+static void ni_set_uvd_clock_before_set_eng_clock(struct amdgpu_device *adev,
+                                          struct amdgpu_ps *new_ps,
+                                          struct amdgpu_ps *old_ps)
+{
+       struct si_ps *new_state = si_get_ps(new_ps);
+       struct si_ps *current_state = si_get_ps(old_ps);
+
+       if ((new_ps->vclk == old_ps->vclk) &&
+           (new_ps->dclk == old_ps->dclk))
+               return;
+
+       if (new_state->performance_levels[new_state->performance_level_count - 1].sclk >=
+           current_state->performance_levels[current_state->performance_level_count - 1].sclk)
+               return;
+
+       amdgpu_asic_set_uvd_clocks(adev, new_ps->vclk, new_ps->dclk);
+}
+
+static void ni_set_uvd_clock_after_set_eng_clock(struct amdgpu_device *adev,
+                                         struct amdgpu_ps *new_ps,
+                                         struct amdgpu_ps *old_ps)
+{
+       struct si_ps *new_state = si_get_ps(new_ps);
+       struct si_ps *current_state = si_get_ps(old_ps);
+
+       if ((new_ps->vclk == old_ps->vclk) &&
+           (new_ps->dclk == old_ps->dclk))
+               return;
+
+       if (new_state->performance_levels[new_state->performance_level_count - 1].sclk <
+           current_state->performance_levels[current_state->performance_level_count - 1].sclk)
+               return;
+
+       amdgpu_asic_set_uvd_clocks(adev, new_ps->vclk, new_ps->dclk);
+}
+
+static u16 btc_find_voltage(struct atom_voltage_table *table, u16 voltage)
+{
+       unsigned int i;
+
+       for (i = 0; i < table->count; i++)
+               if (voltage <= table->entries[i].value)
+                       return table->entries[i].value;
+
+       return table->entries[table->count - 1].value;
+}
+
+static u32 btc_find_valid_clock(struct amdgpu_clock_array *clocks,
+                               u32 max_clock, u32 requested_clock)
+{
+       unsigned int i;
+
+       if ((clocks == NULL) || (clocks->count == 0))
+               return (requested_clock < max_clock) ? requested_clock : max_clock;
+
+       for (i = 0; i < clocks->count; i++) {
+               if (clocks->values[i] >= requested_clock)
+                       return (clocks->values[i] < max_clock) ? clocks->values[i] : max_clock;
+       }
+
+       return (clocks->values[clocks->count - 1] < max_clock) ?
+               clocks->values[clocks->count - 1] : max_clock;
+}
+
+static u32 btc_get_valid_mclk(struct amdgpu_device *adev,
+                             u32 max_mclk, u32 requested_mclk)
+{
+       return btc_find_valid_clock(&adev->pm.dpm.dyn_state.valid_mclk_values,
+                                   max_mclk, requested_mclk);
+}
+
+static u32 btc_get_valid_sclk(struct amdgpu_device *adev,
+                             u32 max_sclk, u32 requested_sclk)
+{
+       return btc_find_valid_clock(&adev->pm.dpm.dyn_state.valid_sclk_values,
+                                   max_sclk, requested_sclk);
+}
+
+static void btc_get_max_clock_from_voltage_dependency_table(struct amdgpu_clock_voltage_dependency_table *table,
+                                                           u32 *max_clock)
+{
+       u32 i, clock = 0;
+
+       if ((table == NULL) || (table->count == 0)) {
+               *max_clock = clock;
+               return;
+       }
+
+       for (i = 0; i < table->count; i++) {
+               if (clock < table->entries[i].clk)
+                       clock = table->entries[i].clk;
+       }
+       *max_clock = clock;
+}
+
+static void btc_apply_voltage_dependency_rules(struct amdgpu_clock_voltage_dependency_table *table,
+                                              u32 clock, u16 max_voltage, u16 *voltage)
+{
+       u32 i;
+
+       if ((table == NULL) || (table->count == 0))
+               return;
+
+       for (i= 0; i < table->count; i++) {
+               if (clock <= table->entries[i].clk) {
+                       if (*voltage < table->entries[i].v)
+                               *voltage = (u16)((table->entries[i].v < max_voltage) ?
+                                          table->entries[i].v : max_voltage);
+                       return;
+               }
+       }
+
+       *voltage = (*voltage > max_voltage) ? *voltage : max_voltage;
+}
+
+static void btc_adjust_clock_combinations(struct amdgpu_device *adev,
+                                         const struct amdgpu_clock_and_voltage_limits *max_limits,
+                                         struct rv7xx_pl *pl)
+{
+
+       if ((pl->mclk == 0) || (pl->sclk == 0))
+               return;
+
+       if (pl->mclk == pl->sclk)
+               return;
+
+       if (pl->mclk > pl->sclk) {
+               if (((pl->mclk + (pl->sclk - 1)) / pl->sclk) > adev->pm.dpm.dyn_state.mclk_sclk_ratio)
+                       pl->sclk = btc_get_valid_sclk(adev,
+                                                     max_limits->sclk,
+                                                     (pl->mclk +
+                                                     (adev->pm.dpm.dyn_state.mclk_sclk_ratio - 1)) /
+                                                     adev->pm.dpm.dyn_state.mclk_sclk_ratio);
+       } else {
+               if ((pl->sclk - pl->mclk) > adev->pm.dpm.dyn_state.sclk_mclk_delta)
+                       pl->mclk = btc_get_valid_mclk(adev,
+                                                     max_limits->mclk,
+                                                     pl->sclk -
+                                                     adev->pm.dpm.dyn_state.sclk_mclk_delta);
+       }
+}
+
+static void btc_apply_voltage_delta_rules(struct amdgpu_device *adev,
+                                         u16 max_vddc, u16 max_vddci,
+                                         u16 *vddc, u16 *vddci)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       u16 new_voltage;
+
+       if ((0 == *vddc) || (0 == *vddci))
+               return;
+
+       if (*vddc > *vddci) {
+               if ((*vddc - *vddci) > adev->pm.dpm.dyn_state.vddc_vddci_delta) {
+                       new_voltage = btc_find_voltage(&eg_pi->vddci_voltage_table,
+                                                      (*vddc - adev->pm.dpm.dyn_state.vddc_vddci_delta));
+                       *vddci = (new_voltage < max_vddci) ? new_voltage : max_vddci;
+               }
+       } else {
+               if ((*vddci - *vddc) > adev->pm.dpm.dyn_state.vddc_vddci_delta) {
+                       new_voltage = btc_find_voltage(&eg_pi->vddc_voltage_table,
+                                                      (*vddci - adev->pm.dpm.dyn_state.vddc_vddci_delta));
+                       *vddc = (new_voltage < max_vddc) ? new_voltage : max_vddc;
+               }
+       }
+}
+
+static enum amdgpu_pcie_gen r600_get_pcie_gen_support(struct amdgpu_device *adev,
+                                              u32 sys_mask,
+                                              enum amdgpu_pcie_gen asic_gen,
+                                              enum amdgpu_pcie_gen default_gen)
+{
+       switch (asic_gen) {
+       case AMDGPU_PCIE_GEN1:
+               return AMDGPU_PCIE_GEN1;
+       case AMDGPU_PCIE_GEN2:
+               return AMDGPU_PCIE_GEN2;
+       case AMDGPU_PCIE_GEN3:
+               return AMDGPU_PCIE_GEN3;
+       default:
+               if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3))
+                       return AMDGPU_PCIE_GEN3;
+               else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2))
+                       return AMDGPU_PCIE_GEN2;
+               else
+                       return AMDGPU_PCIE_GEN1;
+       }
+       return AMDGPU_PCIE_GEN1;
+}
+
+static void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
+                           u32 *p, u32 *u)
+{
+       u32 b_c = 0;
+       u32 i_c;
+       u32 tmp;
+
+       i_c = (i * r_c) / 100;
+       tmp = i_c >> p_b;
+
+       while (tmp) {
+               b_c++;
+               tmp >>= 1;
+       }
+
+       *u = (b_c + 1) / 2;
+       *p = i_c / (1 << (2 * (*u)));
+}
+
+static int r600_calculate_at(u32 t, u32 h, u32 fh, u32 fl, u32 *tl, u32 *th)
+{
+       u32 k, a, ah, al;
+       u32 t1;
+
+       if ((fl == 0) || (fh == 0) || (fl > fh))
+               return -EINVAL;
+
+       k = (100 * fh) / fl;
+       t1 = (t * (k - 100));
+       a = (1000 * (100 * h + t1)) / (10000 + (t1 / 100));
+       a = (a + 5) / 10;
+       ah = ((a * t) + 5000) / 10000;
+       al = a - ah;
+
+       *th = t - ah;
+       *tl = t + al;
+
+       return 0;
+}
+
+static bool r600_is_uvd_state(u32 class, u32 class2)
+{
+       if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+               return true;
+       if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
+               return true;
+       if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
+               return true;
+       if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
+               return true;
+       if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
+               return true;
+       return false;
+}
+
+static u8 rv770_get_memory_module_index(struct amdgpu_device *adev)
+{
+       return (u8) ((RREG32(BIOS_SCRATCH_4) >> 16) & 0xff);
+}
+
+static void rv770_get_max_vddc(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       u16 vddc;
+
+       if (amdgpu_atombios_get_max_vddc(adev, 0, 0, &vddc))
+               pi->max_vddc = 0;
+       else
+               pi->max_vddc = vddc;
+}
+
+static void rv770_get_engine_memory_ss(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct amdgpu_atom_ss ss;
+
+       pi->sclk_ss = amdgpu_atombios_get_asic_ss_info(adev, &ss,
+                                                      ASIC_INTERNAL_ENGINE_SS, 0);
+       pi->mclk_ss = amdgpu_atombios_get_asic_ss_info(adev, &ss,
+                                                      ASIC_INTERNAL_MEMORY_SS, 0);
+
+       if (pi->sclk_ss || pi->mclk_ss)
+               pi->dynamic_ss = true;
+       else
+               pi->dynamic_ss = false;
+}
+
+
+static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
+                                       struct amdgpu_ps *rps)
+{
+       struct  si_ps *ps = si_get_ps(rps);
+       struct amdgpu_clock_and_voltage_limits *max_limits;
+       bool disable_mclk_switching = false;
+       bool disable_sclk_switching = false;
+       u32 mclk, sclk;
+       u16 vddc, vddci, min_vce_voltage = 0;
+       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;
+
+       /* 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;
+       }
+       /* limit mclk on all R7 370 parts for stability */
+       if (adev->pdev->device == 0x6811 &&
+           adev->pdev->revision == 0x81)
+               max_mclk = 120000;
+       /* limit sclk/mclk on Jet parts for stability */
+       if (adev->pdev->device == 0x6665 &&
+           adev->pdev->revision == 0xc3) {
+               max_sclk = 75000;
+               max_mclk = 80000;
+       }
+
+       if (rps->vce_active) {
+               rps->evclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].evclk;
+               rps->ecclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].ecclk;
+               si_get_vce_clock_voltage(adev, rps->evclk, rps->ecclk,
+                                        &min_vce_voltage);
+       } else {
+               rps->evclk = 0;
+               rps->ecclk = 0;
+       }
+
+       if ((adev->pm.dpm.new_active_crtc_count > 1) ||
+           si_dpm_vblank_too_short(adev))
+               disable_mclk_switching = true;
+
+       if (rps->vclk || rps->dclk) {
+               disable_mclk_switching = true;
+               disable_sclk_switching = true;
+       }
+
+       if (adev->pm.dpm.ac_power)
+               max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+       else
+               max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+       for (i = ps->performance_level_count - 2; i >= 0; i--) {
+               if (ps->performance_levels[i].vddc > ps->performance_levels[i+1].vddc)
+                       ps->performance_levels[i].vddc = ps->performance_levels[i+1].vddc;
+       }
+       if (adev->pm.dpm.ac_power == false) {
+               for (i = 0; i < ps->performance_level_count; i++) {
+                       if (ps->performance_levels[i].mclk > max_limits->mclk)
+                               ps->performance_levels[i].mclk = max_limits->mclk;
+                       if (ps->performance_levels[i].sclk > max_limits->sclk)
+                               ps->performance_levels[i].sclk = max_limits->sclk;
+                       if (ps->performance_levels[i].vddc > max_limits->vddc)
+                               ps->performance_levels[i].vddc = max_limits->vddc;
+                       if (ps->performance_levels[i].vddci > max_limits->vddci)
+                               ps->performance_levels[i].vddci = max_limits->vddci;
+               }
+       }
+
+       /* limit clocks to max supported clocks based on voltage dependency tables */
+       btc_get_max_clock_from_voltage_dependency_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+                                                       &max_sclk_vddc);
+       btc_get_max_clock_from_voltage_dependency_table(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+                                                       &max_mclk_vddci);
+       btc_get_max_clock_from_voltage_dependency_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+                                                       &max_mclk_vddc);
+
+       for (i = 0; i < ps->performance_level_count; i++) {
+               if (max_sclk_vddc) {
+                       if (ps->performance_levels[i].sclk > max_sclk_vddc)
+                               ps->performance_levels[i].sclk = max_sclk_vddc;
+               }
+               if (max_mclk_vddci) {
+                       if (ps->performance_levels[i].mclk > max_mclk_vddci)
+                               ps->performance_levels[i].mclk = max_mclk_vddci;
+               }
+               if (max_mclk_vddc) {
+                       if (ps->performance_levels[i].mclk > max_mclk_vddc)
+                               ps->performance_levels[i].mclk = max_mclk_vddc;
+               }
+               if (max_mclk) {
+                       if (ps->performance_levels[i].mclk > max_mclk)
+                               ps->performance_levels[i].mclk = max_mclk;
+               }
+               if (max_sclk) {
+                       if (ps->performance_levels[i].sclk > max_sclk)
+                               ps->performance_levels[i].sclk = max_sclk;
+               }
+       }
+
+       /* XXX validate the min clocks required for display */
+
+       if (disable_mclk_switching) {
+               mclk  = ps->performance_levels[ps->performance_level_count - 1].mclk;
+               vddci = ps->performance_levels[ps->performance_level_count - 1].vddci;
+       } else {
+               mclk = ps->performance_levels[0].mclk;
+               vddci = ps->performance_levels[0].vddci;
+       }
+
+       if (disable_sclk_switching) {
+               sclk = ps->performance_levels[ps->performance_level_count - 1].sclk;
+               vddc = ps->performance_levels[ps->performance_level_count - 1].vddc;
+       } else {
+               sclk = ps->performance_levels[0].sclk;
+               vddc = ps->performance_levels[0].vddc;
+       }
+
+       if (rps->vce_active) {
+               if (sclk < adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].sclk)
+                       sclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].sclk;
+               if (mclk < adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].mclk)
+                       mclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].mclk;
+       }
+
+       /* adjusted low state */
+       ps->performance_levels[0].sclk = sclk;
+       ps->performance_levels[0].mclk = mclk;
+       ps->performance_levels[0].vddc = vddc;
+       ps->performance_levels[0].vddci = vddci;
+
+       if (disable_sclk_switching) {
+               sclk = ps->performance_levels[0].sclk;
+               for (i = 1; i < ps->performance_level_count; i++) {
+                       if (sclk < ps->performance_levels[i].sclk)
+                               sclk = ps->performance_levels[i].sclk;
+               }
+               for (i = 0; i < ps->performance_level_count; i++) {
+                       ps->performance_levels[i].sclk = sclk;
+                       ps->performance_levels[i].vddc = vddc;
+               }
+       } else {
+               for (i = 1; i < ps->performance_level_count; i++) {
+                       if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
+                               ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
+                       if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
+                               ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
+               }
+       }
+
+       if (disable_mclk_switching) {
+               mclk = ps->performance_levels[0].mclk;
+               for (i = 1; i < ps->performance_level_count; i++) {
+                       if (mclk < ps->performance_levels[i].mclk)
+                               mclk = ps->performance_levels[i].mclk;
+               }
+               for (i = 0; i < ps->performance_level_count; i++) {
+                       ps->performance_levels[i].mclk = mclk;
+                       ps->performance_levels[i].vddci = vddci;
+               }
+       } else {
+               for (i = 1; i < ps->performance_level_count; i++) {
+                       if (ps->performance_levels[i].mclk < ps->performance_levels[i - 1].mclk)
+                               ps->performance_levels[i].mclk = ps->performance_levels[i - 1].mclk;
+                       if (ps->performance_levels[i].vddci < ps->performance_levels[i - 1].vddci)
+                               ps->performance_levels[i].vddci = ps->performance_levels[i - 1].vddci;
+               }
+       }
+
+       for (i = 0; i < ps->performance_level_count; i++)
+               btc_adjust_clock_combinations(adev, max_limits,
+                                             &ps->performance_levels[i]);
+
+       for (i = 0; i < ps->performance_level_count; i++) {
+               if (ps->performance_levels[i].vddc < min_vce_voltage)
+                       ps->performance_levels[i].vddc = min_vce_voltage;
+               btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+                                                  ps->performance_levels[i].sclk,
+                                                  max_limits->vddc,  &ps->performance_levels[i].vddc);
+               btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+                                                  ps->performance_levels[i].mclk,
+                                                  max_limits->vddci, &ps->performance_levels[i].vddci);
+               btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+                                                  ps->performance_levels[i].mclk,
+                                                  max_limits->vddc,  &ps->performance_levels[i].vddc);
+               btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk,
+                                                  adev->clock.current_dispclk,
+                                                  max_limits->vddc,  &ps->performance_levels[i].vddc);
+       }
+
+       for (i = 0; i < ps->performance_level_count; i++) {
+               btc_apply_voltage_delta_rules(adev,
+                                             max_limits->vddc, max_limits->vddci,
+                                             &ps->performance_levels[i].vddc,
+                                             &ps->performance_levels[i].vddci);
+       }
+
+       ps->dc_compatible = true;
+       for (i = 0; i < ps->performance_level_count; i++) {
+               if (ps->performance_levels[i].vddc > adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc)
+                       ps->dc_compatible = false;
+       }
+}
+
+#if 0
+static int si_read_smc_soft_register(struct amdgpu_device *adev,
+                                    u16 reg_offset, u32 *value)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       return amdgpu_si_read_smc_sram_dword(adev,
+                                            si_pi->soft_regs_start + reg_offset, value,
+                                            si_pi->sram_end);
+}
+#endif
+
+static int si_write_smc_soft_register(struct amdgpu_device *adev,
+                                     u16 reg_offset, u32 value)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       return amdgpu_si_write_smc_sram_dword(adev,
+                                             si_pi->soft_regs_start + reg_offset,
+                                             value, si_pi->sram_end);
+}
+
+static bool si_is_special_1gb_platform(struct amdgpu_device *adev)
+{
+       bool ret = false;
+       u32 tmp, width, row, column, bank, density;
+       bool is_memory_gddr5, is_special;
+
+       tmp = RREG32(MC_SEQ_MISC0);
+       is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE == ((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT));
+       is_special = (MC_SEQ_MISC0_REV_ID_VALUE == ((tmp & MC_SEQ_MISC0_REV_ID_MASK) >> MC_SEQ_MISC0_REV_ID_SHIFT))
+               & (MC_SEQ_MISC0_VEN_ID_VALUE == ((tmp & MC_SEQ_MISC0_VEN_ID_MASK) >> MC_SEQ_MISC0_VEN_ID_SHIFT));
+
+       WREG32(MC_SEQ_IO_DEBUG_INDEX, 0xb);
+       width = ((RREG32(MC_SEQ_IO_DEBUG_DATA) >> 1) & 1) ? 16 : 32;
+
+       tmp = RREG32(MC_ARB_RAMCFG);
+       row = ((tmp & NOOFROWS_MASK) >> NOOFROWS_SHIFT) + 10;
+       column = ((tmp & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT) + 8;
+       bank = ((tmp & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + 2;
+
+       density = (1 << (row + column - 20 + bank)) * width;
+
+       if ((adev->pdev->device == 0x6819) &&
+           is_memory_gddr5 && is_special && (density == 0x400))
+               ret = true;
+
+       return ret;
+}
+
+static void si_get_leakage_vddc(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u16 vddc, count = 0;
+       int i, ret;
+
+       for (i = 0; i < SISLANDS_MAX_LEAKAGE_COUNT; i++) {
+               ret = amdgpu_atombios_get_leakage_vddc_based_on_leakage_idx(adev, &vddc, SISLANDS_LEAKAGE_INDEX0 + i);
+
+               if (!ret && (vddc > 0) && (vddc != (SISLANDS_LEAKAGE_INDEX0 + i))) {
+                       si_pi->leakage_voltage.entries[count].voltage = vddc;
+                       si_pi->leakage_voltage.entries[count].leakage_index =
+                               SISLANDS_LEAKAGE_INDEX0 + i;
+                       count++;
+               }
+       }
+       si_pi->leakage_voltage.count = count;
+}
+
+static int si_get_leakage_voltage_from_leakage_index(struct amdgpu_device *adev,
+                                                    u32 index, u16 *leakage_voltage)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       int i;
+
+       if (leakage_voltage == NULL)
+               return -EINVAL;
+
+       if ((index & 0xff00) != 0xff00)
+               return -EINVAL;
+
+       if ((index & 0xff) > SISLANDS_MAX_LEAKAGE_COUNT + 1)
+               return -EINVAL;
+
+       if (index < SISLANDS_LEAKAGE_INDEX0)
+               return -EINVAL;
+
+       for (i = 0; i < si_pi->leakage_voltage.count; i++) {
+               if (si_pi->leakage_voltage.entries[i].leakage_index == index) {
+                       *leakage_voltage = si_pi->leakage_voltage.entries[i].voltage;
+                       return 0;
+               }
+       }
+       return -EAGAIN;
+}
+
+static void si_set_dpm_event_sources(struct amdgpu_device *adev, u32 sources)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       bool want_thermal_protection;
+       enum amdgpu_dpm_event_src dpm_event_src;
+
+       switch (sources) {
+       case 0:
+       default:
+               want_thermal_protection = false;
+               break;
+       case (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL):
+               want_thermal_protection = true;
+               dpm_event_src = AMDGPU_DPM_EVENT_SRC_DIGITAL;
+               break;
+       case (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
+               want_thermal_protection = true;
+               dpm_event_src = AMDGPU_DPM_EVENT_SRC_EXTERNAL;
+               break;
+       case ((1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
+             (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL)):
+               want_thermal_protection = true;
+               dpm_event_src = AMDGPU_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
+               break;
+       }
+
+       if (want_thermal_protection) {
+               WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
+               if (pi->thermal_protection)
+                       WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+       } else {
+               WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+       }
+}
+
+static void si_enable_auto_throttle_source(struct amdgpu_device *adev,
+                                          enum amdgpu_dpm_auto_throttle_src source,
+                                          bool enable)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+
+       if (enable) {
+               if (!(pi->active_auto_throttle_sources & (1 << source))) {
+                       pi->active_auto_throttle_sources |= 1 << source;
+                       si_set_dpm_event_sources(adev, pi->active_auto_throttle_sources);
+               }
+       } else {
+               if (pi->active_auto_throttle_sources & (1 << source)) {
+                       pi->active_auto_throttle_sources &= ~(1 << source);
+                       si_set_dpm_event_sources(adev, pi->active_auto_throttle_sources);
+               }
+       }
+}
+
+static void si_start_dpm(struct amdgpu_device *adev)
+{
+       WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+}
+
+static void si_stop_dpm(struct amdgpu_device *adev)
+{
+       WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+}
+
+static void si_enable_sclk_control(struct amdgpu_device *adev, bool enable)
+{
+       if (enable)
+               WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
+       else
+               WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+
+}
+
+#if 0
+static int si_notify_hardware_of_thermal_state(struct amdgpu_device *adev,
+                                              u32 thermal_level)
+{
+       PPSMC_Result ret;
+
+       if (thermal_level == 0) {
+               ret = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableThermalInterrupt);
+               if (ret == PPSMC_Result_OK)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static void si_notify_hardware_vpu_recovery_event(struct amdgpu_device *adev)
+{
+       si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen, true);
+}
+#endif
+
+#if 0
+static int si_notify_hw_of_powersource(struct amdgpu_device *adev, bool ac_power)
+{
+       if (ac_power)
+               return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ?
+                       0 : -EINVAL;
+
+       return 0;
+}
+#endif
+
+static PPSMC_Result si_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
+                                                     PPSMC_Msg msg, u32 parameter)
+{
+       WREG32(SMC_SCRATCH0, parameter);
+       return amdgpu_si_send_msg_to_smc(adev, msg);
+}
+
+static int si_restrict_performance_levels_before_switch(struct amdgpu_device *adev)
+{
+       if (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
+               return -EINVAL;
+
+       return (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetEnabledLevels, 1) == PPSMC_Result_OK) ?
+               0 : -EINVAL;
+}
+
+static int si_dpm_force_performance_level(struct amdgpu_device *adev,
+                                  enum amdgpu_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 (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) {
+               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) {
+               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, levels) != PPSMC_Result_OK)
+                       return -EINVAL;
+       }
+
+       adev->pm.dpm.forced_level = level;
+
+       return 0;
+}
+
+#if 0
+static int si_set_boot_state(struct amdgpu_device *adev)
+{
+       return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_SwitchToInitialState) == PPSMC_Result_OK) ?
+               0 : -EINVAL;
+}
+#endif
+
+static int si_set_sw_state(struct amdgpu_device *adev)
+{
+       return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_SwitchToSwState) == PPSMC_Result_OK) ?
+               0 : -EINVAL;
+}
+
+static int si_halt_smc(struct amdgpu_device *adev)
+{
+       if (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_Halt) != PPSMC_Result_OK)
+               return -EINVAL;
+
+       return (amdgpu_si_wait_for_smc_inactive(adev) == PPSMC_Result_OK) ?
+               0 : -EINVAL;
+}
+
+static int si_resume_smc(struct amdgpu_device *adev)
+{
+       if (amdgpu_si_send_msg_to_smc(adev, PPSMC_FlushDataCache) != PPSMC_Result_OK)
+               return -EINVAL;
+
+       return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_Resume) == PPSMC_Result_OK) ?
+               0 : -EINVAL;
+}
+
+static void si_dpm_start_smc(struct amdgpu_device *adev)
+{
+       amdgpu_si_program_jump_on_start(adev);
+       amdgpu_si_start_smc(adev);
+       amdgpu_si_smc_clock(adev, true);
+}
+
+static void si_dpm_stop_smc(struct amdgpu_device *adev)
+{
+       amdgpu_si_reset_smc(adev);
+       amdgpu_si_smc_clock(adev, false);
+}
+
+static int si_process_firmware_header(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 tmp;
+       int ret;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev,
+                                           SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                           SISLANDS_SMC_FIRMWARE_HEADER_stateTable,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->state_table_start = tmp;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev,
+                                           SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                           SISLANDS_SMC_FIRMWARE_HEADER_softRegisters,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->soft_regs_start = tmp;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev,
+                                           SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                           SISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->mc_reg_table_start = tmp;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev,
+                                           SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                           SISLANDS_SMC_FIRMWARE_HEADER_fanTable,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->fan_table_start = tmp;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev,
+                                           SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                           SISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->arb_table_start = tmp;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev,
+                                           SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                           SISLANDS_SMC_FIRMWARE_HEADER_CacConfigTable,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->cac_table_start = tmp;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev,
+                                           SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                           SISLANDS_SMC_FIRMWARE_HEADER_DteConfiguration,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->dte_table_start = tmp;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev,
+                                           SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                           SISLANDS_SMC_FIRMWARE_HEADER_spllTable,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->spll_table_start = tmp;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev,
+                                           SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                           SISLANDS_SMC_FIRMWARE_HEADER_PAPMParameters,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->papm_cfg_table_start = tmp;
+
+       return ret;
+}
+
+static void si_read_clock_registers(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       si_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
+       si_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2);
+       si_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3);
+       si_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4);
+       si_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM);
+       si_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+       si_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL);
+       si_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL);
+       si_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL);
+       si_pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL);
+       si_pi->clock_registers.mpll_func_cntl = RREG32(MPLL_FUNC_CNTL);
+       si_pi->clock_registers.mpll_func_cntl_1 = RREG32(MPLL_FUNC_CNTL_1);
+       si_pi->clock_registers.mpll_func_cntl_2 = RREG32(MPLL_FUNC_CNTL_2);
+       si_pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1);
+       si_pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2);
+}
+
+static void si_enable_thermal_protection(struct amdgpu_device *adev,
+                                         bool enable)
+{
+       if (enable)
+               WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+       else
+               WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+}
+
+static void si_enable_acpi_power_management(struct amdgpu_device *adev)
+{
+       WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
+}
+
+#if 0
+static int si_enter_ulp_state(struct amdgpu_device *adev)
+{
+       WREG32(SMC_MESSAGE_0, PPSMC_MSG_SwitchToMinimumPower);
+
+       udelay(25000);
+
+       return 0;
+}
+
+static int si_exit_ulp_state(struct amdgpu_device *adev)
+{
+       int i;
+
+       WREG32(SMC_MESSAGE_0, PPSMC_MSG_ResumeFromMinimumPower);
+
+       udelay(7000);
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (RREG32(SMC_RESP_0) == 1)
+                       break;
+               udelay(1000);
+       }
+
+       return 0;
+}
+#endif
+
+static int si_notify_smc_display_change(struct amdgpu_device *adev,
+                                    bool has_display)
+{
+       PPSMC_Msg msg = has_display ?
+               PPSMC_MSG_HasDisplay : PPSMC_MSG_NoDisplay;
+
+       return (amdgpu_si_send_msg_to_smc(adev, msg) == PPSMC_Result_OK) ?
+               0 : -EINVAL;
+}
+
+static void si_program_response_times(struct amdgpu_device *adev)
+{
+       u32 voltage_response_time, backbias_response_time, acpi_delay_time, vbi_time_out;
+       u32 vddc_dly, acpi_dly, vbi_dly;
+       u32 reference_clock;
+
+       si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_mvdd_chg_time, 1);
+
+       voltage_response_time = (u32)adev->pm.dpm.voltage_response_time;
+       backbias_response_time = (u32)adev->pm.dpm.backbias_response_time;
+
+       if (voltage_response_time == 0)
+               voltage_response_time = 1000;
+
+       acpi_delay_time = 15000;
+       vbi_time_out = 100000;
+
+       reference_clock = amdgpu_asic_get_xclk(adev);
+
+       vddc_dly = (voltage_response_time  * reference_clock) / 100;
+       acpi_dly = (acpi_delay_time * reference_clock) / 100;
+       vbi_dly  = (vbi_time_out * reference_clock) / 100;
+
+       si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_delay_vreg,  vddc_dly);
+       si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_delay_acpi,  acpi_dly);
+       si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly);
+       si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_mc_block_delay, 0xAA);
+}
+
+static void si_program_ds_registers(struct amdgpu_device *adev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       u32 tmp;
+
+       /* DEEP_SLEEP_CLK_SEL field should be 0x10 on tahiti A0 */
+       if (adev->asic_type == CHIP_TAHITI && adev->rev_id == 0x0)
+               tmp = 0x10;
+       else
+               tmp = 0x1;
+
+       if (eg_pi->sclk_deep_sleep) {
+               WREG32_P(MISC_CLK_CNTL, DEEP_SLEEP_CLK_SEL(tmp), ~DEEP_SLEEP_CLK_SEL_MASK);
+               WREG32_P(CG_SPLL_AUTOSCALE_CNTL, AUTOSCALE_ON_SS_CLEAR,
+                        ~AUTOSCALE_ON_SS_CLEAR);
+       }
+}
+
+static void si_program_display_gap(struct amdgpu_device *adev)
+{
+       u32 tmp, pipe;
+       int i;
+
+       tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+       if (adev->pm.dpm.new_active_crtc_count > 0)
+               tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+       else
+               tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+
+       if (adev->pm.dpm.new_active_crtc_count > 1)
+               tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+       else
+               tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+
+       WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+
+       tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG);
+       pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT;
+
+       if ((adev->pm.dpm.new_active_crtc_count > 0) &&
+           (!(adev->pm.dpm.new_active_crtcs & (1 << pipe)))) {
+               /* find the first active crtc */
+               for (i = 0; i < adev->mode_info.num_crtc; i++) {
+                       if (adev->pm.dpm.new_active_crtcs & (1 << i))
+                               break;
+               }
+               if (i == adev->mode_info.num_crtc)
+                       pipe = 0;
+               else
+                       pipe = i;
+
+               tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK;
+               tmp |= DCCG_DISP1_SLOW_SELECT(pipe);
+               WREG32(DCCG_DISP_SLOW_SELECT_REG, tmp);
+       }
+
+       /* Setting this to false forces the performance state to low if the crtcs are disabled.
+        * This can be a problem on PowerXpress systems or if you want to use the card
+        * for offscreen rendering or compute if there are no crtcs enabled.
+        */
+       si_notify_smc_display_change(adev, adev->pm.dpm.new_active_crtc_count > 0);
+}
+
+static void si_enable_spread_spectrum(struct amdgpu_device *adev, bool enable)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+
+       if (enable) {
+               if (pi->sclk_ss)
+                       WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
+       } else {
+               WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+               WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
+       }
+}
+
+static void si_setup_bsp(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       u32 xclk = amdgpu_asic_get_xclk(adev);
+
+       r600_calculate_u_and_p(pi->asi,
+                              xclk,
+                              16,
+                              &pi->bsp,
+                              &pi->bsu);
+
+       r600_calculate_u_and_p(pi->pasi,
+                              xclk,
+                              16,
+                              &pi->pbsp,
+                              &pi->pbsu);
+
+
+        pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
+       pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
+
+       WREG32(CG_BSP, pi->dsp);
+}
+
+static void si_program_git(struct amdgpu_device *adev)
+{
+       WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK);
+}
+
+static void si_program_tp(struct amdgpu_device *adev)
+{
+       int i;
+       enum r600_td td = R600_TD_DFLT;
+
+       for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
+               WREG32(CG_FFCT_0 + i, (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i])));
+
+       if (td == R600_TD_AUTO)
+               WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
+       else
+               WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
+
+       if (td == R600_TD_UP)
+               WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
+
+       if (td == R600_TD_DOWN)
+               WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
+}
+
+static void si_program_tpp(struct amdgpu_device *adev)
+{
+       WREG32(CG_TPC, R600_TPC_DFLT);
+}
+
+static void si_program_sstp(struct amdgpu_device *adev)
+{
+       WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT)));
+}
+
+static void si_enable_display_gap(struct amdgpu_device *adev)
+{
+       u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+       tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+       tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
+               DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE));
+
+       tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+       tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) |
+               DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
+       WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+static void si_program_vc(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+
+       WREG32(CG_FTV, pi->vrc);
+}
+
+static void si_clear_vc(struct amdgpu_device *adev)
+{
+       WREG32(CG_FTV, 0);
+}
+
+static u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock)
+{
+       u8 mc_para_index;
+
+       if (memory_clock < 10000)
+               mc_para_index = 0;
+       else if (memory_clock >= 80000)
+               mc_para_index = 0x0f;
+       else
+               mc_para_index = (u8)((memory_clock - 10000) / 5000 + 1);
+       return mc_para_index;
+}
+
+static u8 si_get_mclk_frequency_ratio(u32 memory_clock, bool strobe_mode)
+{
+       u8 mc_para_index;
+
+       if (strobe_mode) {
+               if (memory_clock < 12500)
+                       mc_para_index = 0x00;
+               else if (memory_clock > 47500)
+                       mc_para_index = 0x0f;
+               else
+                       mc_para_index = (u8)((memory_clock - 10000) / 2500);
+       } else {
+               if (memory_clock < 65000)
+                       mc_para_index = 0x00;
+               else if (memory_clock > 135000)
+                       mc_para_index = 0x0f;
+               else
+                       mc_para_index = (u8)((memory_clock - 60000) / 5000);
+       }
+       return mc_para_index;
+}
+
+static u8 si_get_strobe_mode_settings(struct amdgpu_device *adev, u32 mclk)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       bool strobe_mode = false;
+       u8 result = 0;
+
+       if (mclk <= pi->mclk_strobe_mode_threshold)
+               strobe_mode = true;
+
+       if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5)
+               result = si_get_mclk_frequency_ratio(mclk, strobe_mode);
+       else
+               result = si_get_ddr3_mclk_frequency_ratio(mclk);
+
+       if (strobe_mode)
+               result |= SISLANDS_SMC_STROBE_ENABLE;
+
+       return result;
+}
+
+static int si_upload_firmware(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       amdgpu_si_reset_smc(adev);
+       amdgpu_si_smc_clock(adev, false);
+
+       return amdgpu_si_load_smc_ucode(adev, si_pi->sram_end);
+}
+
+static bool si_validate_phase_shedding_tables(struct amdgpu_device *adev,
+                                             const struct atom_voltage_table *table,
+                                             const struct amdgpu_phase_shedding_limits_table *limits)
+{
+       u32 data, num_bits, num_levels;
+
+       if ((table == NULL) || (limits == NULL))
+               return false;
+
+       data = table->mask_low;
+
+       num_bits = hweight32(data);
+
+       if (num_bits == 0)
+               return false;
+
+       num_levels = (1 << num_bits);
+
+       if (table->count != num_levels)
+               return false;
+
+       if (limits->count != (num_levels - 1))
+               return false;
+
+       return true;
+}
+
+static void si_trim_voltage_table_to_fit_state_table(struct amdgpu_device *adev,
+                                             u32 max_voltage_steps,
+                                             struct atom_voltage_table *voltage_table)
+{
+       unsigned int i, diff;
+
+       if (voltage_table->count <= max_voltage_steps)
+               return;
+
+       diff = voltage_table->count - max_voltage_steps;
+
+       for (i= 0; i < max_voltage_steps; i++)
+               voltage_table->entries[i] = voltage_table->entries[i + diff];
+
+       voltage_table->count = max_voltage_steps;
+}
+
+static int si_get_svi2_voltage_table(struct amdgpu_device *adev,
+                                    struct amdgpu_clock_voltage_dependency_table *voltage_dependency_table,
+                                    struct atom_voltage_table *voltage_table)
+{
+       u32 i;
+
+       if (voltage_dependency_table == NULL)
+               return -EINVAL;
+
+       voltage_table->mask_low = 0;
+       voltage_table->phase_delay = 0;
+
+       voltage_table->count = voltage_dependency_table->count;
+       for (i = 0; i < voltage_table->count; i++) {
+               voltage_table->entries[i].value = voltage_dependency_table->entries[i].v;
+               voltage_table->entries[i].smio_low = 0;
+       }
+
+       return 0;
+}
+
+static int si_construct_voltage_tables(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       int ret;
+
+       if (pi->voltage_control) {
+               ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDC,
+                                                   VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table);
+               if (ret)
+                       return ret;
+
+               if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
+                       si_trim_voltage_table_to_fit_state_table(adev,
+                                                                SISLANDS_MAX_NO_VREG_STEPS,
+                                                                &eg_pi->vddc_voltage_table);
+       } else if (si_pi->voltage_control_svi2) {
+               ret = si_get_svi2_voltage_table(adev,
+                                               &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+                                               &eg_pi->vddc_voltage_table);
+               if (ret)
+                       return ret;
+       } else {
+               return -EINVAL;
+       }
+
+       if (eg_pi->vddci_control) {
+               ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDCI,
+                                                   VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddci_voltage_table);
+               if (ret)
+                       return ret;
+
+               if (eg_pi->vddci_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
+                       si_trim_voltage_table_to_fit_state_table(adev,
+                                                                SISLANDS_MAX_NO_VREG_STEPS,
+                                                                &eg_pi->vddci_voltage_table);
+       }
+       if (si_pi->vddci_control_svi2) {
+               ret = si_get_svi2_voltage_table(adev,
+                                               &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+                                               &eg_pi->vddci_voltage_table);
+               if (ret)
+                       return ret;
+       }
+
+       if (pi->mvdd_control) {
+               ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_MVDDC,
+                                                   VOLTAGE_OBJ_GPIO_LUT, &si_pi->mvdd_voltage_table);
+
+               if (ret) {
+                       pi->mvdd_control = false;
+                       return ret;
+               }
+
+               if (si_pi->mvdd_voltage_table.count == 0) {
+                       pi->mvdd_control = false;
+                       return -EINVAL;
+               }
+
+               if (si_pi->mvdd_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
+                       si_trim_voltage_table_to_fit_state_table(adev,
+                                                                SISLANDS_MAX_NO_VREG_STEPS,
+                                                                &si_pi->mvdd_voltage_table);
+       }
+
+       if (si_pi->vddc_phase_shed_control) {
+               ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDC,
+                                                   VOLTAGE_OBJ_PHASE_LUT, &si_pi->vddc_phase_shed_table);
+               if (ret)
+                       si_pi->vddc_phase_shed_control = false;
+
+               if ((si_pi->vddc_phase_shed_table.count == 0) ||
+                   (si_pi->vddc_phase_shed_table.count > SISLANDS_MAX_NO_VREG_STEPS))
+                       si_pi->vddc_phase_shed_control = false;
+       }
+
+       return 0;
+}
+
+static void si_populate_smc_voltage_table(struct amdgpu_device *adev,
+                                         const struct atom_voltage_table *voltage_table,
+                                         SISLANDS_SMC_STATETABLE *table)
+{
+       unsigned int i;
+
+       for (i = 0; i < voltage_table->count; i++)
+               table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low);
+}
+
+static int si_populate_smc_voltage_tables(struct amdgpu_device *adev,
+                                         SISLANDS_SMC_STATETABLE *table)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u8 i;
+
+       if (si_pi->voltage_control_svi2) {
+               si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc,
+                       si_pi->svc_gpio_id);
+               si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd,
+                       si_pi->svd_gpio_id);
+               si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_svi_rework_plat_type,
+                                          2);
+       } else {
+               if (eg_pi->vddc_voltage_table.count) {
+                       si_populate_smc_voltage_table(adev, &eg_pi->vddc_voltage_table, table);
+                       table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
+                               cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+
+                       for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
+                               if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) {
+                                       table->maxVDDCIndexInPPTable = i;
+                                       break;
+                               }
+                       }
+               }
+
+               if (eg_pi->vddci_voltage_table.count) {
+                       si_populate_smc_voltage_table(adev, &eg_pi->vddci_voltage_table, table);
+
+                       table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] =
+                               cpu_to_be32(eg_pi->vddci_voltage_table.mask_low);
+               }
+
+
+               if (si_pi->mvdd_voltage_table.count) {
+                       si_populate_smc_voltage_table(adev, &si_pi->mvdd_voltage_table, table);
+
+                       table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] =
+                               cpu_to_be32(si_pi->mvdd_voltage_table.mask_low);
+               }
+
+               if (si_pi->vddc_phase_shed_control) {
+                       if (si_validate_phase_shedding_tables(adev, &si_pi->vddc_phase_shed_table,
+                                                             &adev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
+                               si_populate_smc_voltage_table(adev, &si_pi->vddc_phase_shed_table, table);
+
+                               table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC_PHASE_SHEDDING] =
+                                       cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);
+
+                               si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
+                                                          (u32)si_pi->vddc_phase_shed_table.phase_delay);
+                       } else {
+                               si_pi->vddc_phase_shed_control = false;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int si_populate_voltage_value(struct amdgpu_device *adev,
+                                    const struct atom_voltage_table *table,
+                                    u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+       unsigned int i;
+
+       for (i = 0; i < table->count; i++) {
+               if (value <= table->entries[i].value) {
+                       voltage->index = (u8)i;
+                       voltage->value = cpu_to_be16(table->entries[i].value);
+                       break;
+               }
+       }
+
+       if (i >= table->count)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int si_populate_mvdd_value(struct amdgpu_device *adev, u32 mclk,
+                                 SISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       if (pi->mvdd_control) {
+               if (mclk <= pi->mvdd_split_frequency)
+                       voltage->index = 0;
+               else
+                       voltage->index = (u8)(si_pi->mvdd_voltage_table.count) - 1;
+
+               voltage->value = cpu_to_be16(si_pi->mvdd_voltage_table.entries[voltage->index].value);
+       }
+       return 0;
+}
+
+static int si_get_std_voltage_value(struct amdgpu_device *adev,
+                                   SISLANDS_SMC_VOLTAGE_VALUE *voltage,
+                                   u16 *std_voltage)
+{
+       u16 v_index;
+       bool voltage_found = false;
+       *std_voltage = be16_to_cpu(voltage->value);
+
+       if (adev->pm.dpm.dyn_state.cac_leakage_table.entries) {
+               if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE) {
+                       if (adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries == NULL)
+                               return -EINVAL;
+
+                       for (v_index = 0; (u32)v_index < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
+                               if (be16_to_cpu(voltage->value) ==
+                                   (u16)adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
+                                       voltage_found = true;
+                                       if ((u32)v_index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
+                                               *std_voltage =
+                                                       adev->pm.dpm.dyn_state.cac_leakage_table.entries[v_index].vddc;
+                                       else
+                                               *std_voltage =
+                                                       adev->pm.dpm.dyn_state.cac_leakage_table.entries[adev->pm.dpm.dyn_state.cac_leakage_table.count-1].vddc;
+                                       break;
+                               }
+                       }
+
+                       if (!voltage_found) {
+                               for (v_index = 0; (u32)v_index < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
+                                       if (be16_to_cpu(voltage->value) <=
+                                           (u16)adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
+                                               voltage_found = true;
+                                               if ((u32)v_index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
+                                                       *std_voltage =
+                                                               adev->pm.dpm.dyn_state.cac_leakage_table.entries[v_index].vddc;
+                                               else
+                                                       *std_voltage =
+                                                               adev->pm.dpm.dyn_state.cac_leakage_table.entries[adev->pm.dpm.dyn_state.cac_leakage_table.count-1].vddc;
+                                               break;
+                                       }
+                               }
+                       }
+               } else {
+                       if ((u32)voltage->index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
+                               *std_voltage = adev->pm.dpm.dyn_state.cac_leakage_table.entries[voltage->index].vddc;
+               }
+       }
+
+       return 0;
+}
+
+static int si_populate_std_voltage_value(struct amdgpu_device *adev,
+                                        u16 value, u8 index,
+                                        SISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+       voltage->index = index;
+       voltage->value = cpu_to_be16(value);
+
+       return 0;
+}
+
+static int si_populate_phase_shedding_value(struct amdgpu_device *adev,
+                                           const struct amdgpu_phase_shedding_limits_table *limits,
+                                           u16 voltage, u32 sclk, u32 mclk,
+                                           SISLANDS_SMC_VOLTAGE_VALUE *smc_voltage)
+{
+       unsigned int i;
+
+       for (i = 0; i < limits->count; i++) {
+               if ((voltage <= limits->entries[i].voltage) &&
+                   (sclk <= limits->entries[i].sclk) &&
+                   (mclk <= limits->entries[i].mclk))
+                       break;
+       }
+
+       smc_voltage->phase_settings = (u8)i;
+
+       return 0;
+}
+
+static int si_init_arb_table_index(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 tmp;
+       int ret;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev, si_pi->arb_table_start,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       tmp &= 0x00FFFFFF;
+       tmp |= MC_CG_ARB_FREQ_F1 << 24;
+
+       return amdgpu_si_write_smc_sram_dword(adev, si_pi->arb_table_start,
+                                             tmp, si_pi->sram_end);
+}
+
+static int si_initial_switch_from_arb_f0_to_f1(struct amdgpu_device *adev)
+{
+       return ni_copy_and_switch_arb_sets(adev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+static int si_reset_to_default(struct amdgpu_device *adev)
+{
+       return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_ResetToDefaults) == PPSMC_Result_OK) ?
+               0 : -EINVAL;
+}
+
+static int si_force_switch_to_arb_f0(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 tmp;
+       int ret;
+
+       ret = amdgpu_si_read_smc_sram_dword(adev, si_pi->arb_table_start,
+                                           &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       tmp = (tmp >> 24) & 0xff;
+
+       if (tmp == MC_CG_ARB_FREQ_F0)
+               return 0;
+
+       return ni_copy_and_switch_arb_sets(adev, tmp, MC_CG_ARB_FREQ_F0);
+}
+
+static u32 si_calculate_memory_refresh_rate(struct amdgpu_device *adev,
+                                           u32 engine_clock)
+{
+       u32 dram_rows;
+       u32 dram_refresh_rate;
+       u32 mc_arb_rfsh_rate;
+       u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
+
+       if (tmp >= 4)
+               dram_rows = 16384;
+       else
+               dram_rows = 1 << (tmp + 10);
+
+       dram_refresh_rate = 1 << ((RREG32(MC_SEQ_MISC0) & 0x3) + 3);
+       mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
+
+       return mc_arb_rfsh_rate;
+}
+
+static int si_populate_memory_timing_parameters(struct amdgpu_device *adev,
+                                               struct rv7xx_pl *pl,
+                                               SMC_SIslands_MCArbDramTimingRegisterSet *arb_regs)
+{
+       u32 dram_timing;
+       u32 dram_timing2;
+       u32 burst_time;
+
+       arb_regs->mc_arb_rfsh_rate =
+               (u8)si_calculate_memory_refresh_rate(adev, pl->sclk);
+
+       amdgpu_atombios_set_engine_dram_timings(adev,
+                                           pl->sclk,
+                                           pl->mclk);
+
+       dram_timing  = RREG32(MC_ARB_DRAM_TIMING);
+       dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+       burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK;
+
+       arb_regs->mc_arb_dram_timing  = cpu_to_be32(dram_timing);
+       arb_regs->mc_arb_dram_timing2 = cpu_to_be32(dram_timing2);
+       arb_regs->mc_arb_burst_time = (u8)burst_time;
+
+       return 0;
+}
+
+static int si_do_program_memory_timing_parameters(struct amdgpu_device *adev,
+                                                 struct amdgpu_ps *amdgpu_state,
+                                                 unsigned int first_arb_set)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct  si_ps *state = si_get_ps(amdgpu_state);
+       SMC_SIslands_MCArbDramTimingRegisterSet arb_regs = { 0 };
+       int i, ret = 0;
+
+       for (i = 0; i < state->performance_level_count; i++) {
+               ret = si_populate_memory_timing_parameters(adev, &state->performance_levels[i], &arb_regs);
+               if (ret)
+                       break;
+               ret = amdgpu_si_copy_bytes_to_smc(adev,
+                                                 si_pi->arb_table_start +
+                                                 offsetof(SMC_SIslands_MCArbDramTimingRegisters, data) +
+                                                 sizeof(SMC_SIslands_MCArbDramTimingRegisterSet) * (first_arb_set + i),
+                                                 (u8 *)&arb_regs,
+                                                 sizeof(SMC_SIslands_MCArbDramTimingRegisterSet),
+                                                 si_pi->sram_end);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int si_program_memory_timing_parameters(struct amdgpu_device *adev,
+                                              struct amdgpu_ps *amdgpu_new_state)
+{
+       return si_do_program_memory_timing_parameters(adev, amdgpu_new_state,
+                                                     SISLANDS_DRIVER_STATE_ARB_INDEX);
+}
+
+static int si_populate_initial_mvdd_value(struct amdgpu_device *adev,
+                                         struct SISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       if (pi->mvdd_control)
+               return si_populate_voltage_value(adev, &si_pi->mvdd_voltage_table,
+                                                si_pi->mvdd_bootup_value, voltage);
+
+       return 0;
+}
+
+static int si_populate_smc_initial_state(struct amdgpu_device *adev,
+                                        struct amdgpu_ps *amdgpu_initial_state,
+                                        SISLANDS_SMC_STATETABLE *table)
+{
+       struct  si_ps *initial_state = si_get_ps(amdgpu_initial_state);
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 reg;
+       int ret;
+
+       table->initialState.levels[0].mclk.vDLL_CNTL =
+               cpu_to_be32(si_pi->clock_registers.dll_cntl);
+       table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
+               cpu_to_be32(si_pi->clock_registers.mclk_pwrmgt_cntl);
+       table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
+               cpu_to_be32(si_pi->clock_registers.mpll_ad_func_cntl);
+       table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
+               cpu_to_be32(si_pi->clock_registers.mpll_dq_func_cntl);
+       table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL =
+               cpu_to_be32(si_pi->clock_registers.mpll_func_cntl);
+       table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_1 =
+               cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_1);
+       table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_2 =
+               cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_2);
+       table->initialState.levels[0].mclk.vMPLL_SS =
+               cpu_to_be32(si_pi->clock_registers.mpll_ss1);
+       table->initialState.levels[0].mclk.vMPLL_SS2 =
+               cpu_to_be32(si_pi->clock_registers.mpll_ss2);
+
+       table->initialState.levels[0].mclk.mclk_value =
+               cpu_to_be32(initial_state->performance_levels[0].mclk);
+
+       table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+               cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl);
+       table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+               cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_2);
+       table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+               cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_3);
+       table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
+               cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_4);
+       table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+               cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum);
+       table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2  =
+               cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum_2);
+
+       table->initialState.levels[0].sclk.sclk_value =
+               cpu_to_be32(initial_state->performance_levels[0].sclk);
+
+       table->initialState.levels[0].arbRefreshState =
+               SISLANDS_INITIAL_STATE_ARB_INDEX;
+
+       table->initialState.levels[0].ACIndex = 0;
+
+       ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
+                                       initial_state->performance_levels[0].vddc,
+                                       &table->initialState.levels[0].vddc);
+
+       if (!ret) {
+               u16 std_vddc;
+
+               ret = si_get_std_voltage_value(adev,
+                                              &table->initialState.levels[0].vddc,
+                                              &std_vddc);
+               if (!ret)
+                       si_populate_std_voltage_value(adev, std_vddc,
+                                                     table->initialState.levels[0].vddc.index,
+                                                     &table->initialState.levels[0].std_vddc);
+       }
+
+       if (eg_pi->vddci_control)
+               si_populate_voltage_value(adev,
+                                         &eg_pi->vddci_voltage_table,
+                                         initial_state->performance_levels[0].vddci,
+                                         &table->initialState.levels[0].vddci);
+
+       if (si_pi->vddc_phase_shed_control)
+               si_populate_phase_shedding_value(adev,
+                                                &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
+                                                initial_state->performance_levels[0].vddc,
+                                                initial_state->performance_levels[0].sclk,
+                                                initial_state->performance_levels[0].mclk,
+                                                &table->initialState.levels[0].vddc);
+
+       si_populate_initial_mvdd_value(adev, &table->initialState.levels[0].mvdd);
+
+       reg = CG_R(0xffff) | CG_L(0);
+       table->initialState.levels[0].aT = cpu_to_be32(reg);
+       table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+       table->initialState.levels[0].gen2PCIE = (u8)si_pi->boot_pcie_gen;
+
+       if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) {
+               table->initialState.levels[0].strobeMode =
+                       si_get_strobe_mode_settings(adev,
+                                                   initial_state->performance_levels[0].mclk);
+
+               if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold)
+                       table->initialState.levels[0].mcFlags = SISLANDS_SMC_MC_EDC_RD_FLAG | SISLANDS_SMC_MC_EDC_WR_FLAG;
+               else
+                       table->initialState.levels[0].mcFlags =  0;
+       }
+
+       table->initialState.levelCount = 1;
+
+       table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+       table->initialState.levels[0].dpm2.MaxPS = 0;
+       table->initialState.levels[0].dpm2.NearTDPDec = 0;
+       table->initialState.levels[0].dpm2.AboveSafeInc = 0;
+       table->initialState.levels[0].dpm2.BelowSafeInc = 0;
+       table->initialState.levels[0].dpm2.PwrEfficiencyRatio = 0;
+
+       reg = MIN_POWER_MASK | MAX_POWER_MASK;
+       table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
+
+       reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+       table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
+
+       return 0;
+}
+
+static int si_populate_smc_acpi_state(struct amdgpu_device *adev,
+                                     SISLANDS_SMC_STATETABLE *table)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 spll_func_cntl = si_pi->clock_registers.cg_spll_func_cntl;
+       u32 spll_func_cntl_2 = si_pi->clock_registers.cg_spll_func_cntl_2;
+       u32 spll_func_cntl_3 = si_pi->clock_registers.cg_spll_func_cntl_3;
+       u32 spll_func_cntl_4 = si_pi->clock_registers.cg_spll_func_cntl_4;
+       u32 dll_cntl = si_pi->clock_registers.dll_cntl;
+       u32 mclk_pwrmgt_cntl = si_pi->clock_registers.mclk_pwrmgt_cntl;
+       u32 mpll_ad_func_cntl = si_pi->clock_registers.mpll_ad_func_cntl;
+       u32 mpll_dq_func_cntl = si_pi->clock_registers.mpll_dq_func_cntl;
+       u32 mpll_func_cntl = si_pi->clock_registers.mpll_func_cntl;
+       u32 mpll_func_cntl_1 = si_pi->clock_registers.mpll_func_cntl_1;
+       u32 mpll_func_cntl_2 = si_pi->clock_registers.mpll_func_cntl_2;
+       u32 reg;
+       int ret;
+
+       table->ACPIState = table->initialState;
+
+       table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+       if (pi->acpi_vddc) {
+               ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
+                                               pi->acpi_vddc, &table->ACPIState.levels[0].vddc);
+               if (!ret) {
+                       u16 std_vddc;
+
+                       ret = si_get_std_voltage_value(adev,
+                                                      &table->ACPIState.levels[0].vddc, &std_vddc);
+                       if (!ret)
+                               si_populate_std_voltage_value(adev, std_vddc,
+                                                             table->ACPIState.levels[0].vddc.index,
+                                                             &table->ACPIState.levels[0].std_vddc);
+               }
+               table->ACPIState.levels[0].gen2PCIE = si_pi->acpi_pcie_gen;
+
+               if (si_pi->vddc_phase_shed_control) {
+                       si_populate_phase_shedding_value(adev,
+                                                        &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
+                                                        pi->acpi_vddc,
+                                                        0,
+                                                        0,
+                                                        &table->ACPIState.levels[0].vddc);
+               }
+       } else {
+               ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
+                                               pi->min_vddc_in_table, &table->ACPIState.levels[0].vddc);
+               if (!ret) {
+                       u16 std_vddc;
+
+                       ret = si_get_std_voltage_value(adev,
+                                                      &table->ACPIState.levels[0].vddc, &std_vddc);
+
+                       if (!ret)
+                               si_populate_std_voltage_value(adev, std_vddc,
+                                                             table->ACPIState.levels[0].vddc.index,
+                                                             &table->ACPIState.levels[0].std_vddc);
+               }
+               table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(adev,
+                                                                                   si_pi->sys_pcie_mask,
+                                                                                   si_pi->boot_pcie_gen,
+                                                                                   AMDGPU_PCIE_GEN1);
+
+               if (si_pi->vddc_phase_shed_control)
+                       si_populate_phase_shedding_value(adev,
+                                                        &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
+                                                        pi->min_vddc_in_table,
+                                                        0,
+                                                        0,
+                                                        &table->ACPIState.levels[0].vddc);
+       }
+
+       if (pi->acpi_vddc) {
+               if (eg_pi->acpi_vddci)
+                       si_populate_voltage_value(adev, &eg_pi->vddci_voltage_table,
+                                                 eg_pi->acpi_vddci,
+                                                 &table->ACPIState.levels[0].vddci);
+       }
+
+       mclk_pwrmgt_cntl |= MRDCK0_RESET | MRDCK1_RESET;
+       mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB);
+
+       dll_cntl &= ~(MRDCK0_BYPASS | MRDCK1_BYPASS);
+
+       spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+       spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+       table->ACPIState.levels[0].mclk.vDLL_CNTL =
+               cpu_to_be32(dll_cntl);
+       table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
+               cpu_to_be32(mclk_pwrmgt_cntl);
+       table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
+               cpu_to_be32(mpll_ad_func_cntl);
+       table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
+               cpu_to_be32(mpll_dq_func_cntl);
+       table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL =
+               cpu_to_be32(mpll_func_cntl);
+       table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_1 =
+               cpu_to_be32(mpll_func_cntl_1);
+       table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_2 =
+               cpu_to_be32(mpll_func_cntl_2);
+       table->ACPIState.levels[0].mclk.vMPLL_SS =
+               cpu_to_be32(si_pi->clock_registers.mpll_ss1);
+       table->ACPIState.levels[0].mclk.vMPLL_SS2 =
+               cpu_to_be32(si_pi->clock_registers.mpll_ss2);
+
+       table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+               cpu_to_be32(spll_func_cntl);
+       table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+               cpu_to_be32(spll_func_cntl_2);
+       table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+               cpu_to_be32(spll_func_cntl_3);
+       table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
+               cpu_to_be32(spll_func_cntl_4);
+
+       table->ACPIState.levels[0].mclk.mclk_value = 0;
+       table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+       si_populate_mvdd_value(adev, 0, &table->ACPIState.levels[0].mvdd);
+
+       if (eg_pi->dynamic_ac_timing)
+               table->ACPIState.levels[0].ACIndex = 0;
+
+       table->ACPIState.levels[0].dpm2.MaxPS = 0;
+       table->ACPIState.levels[0].dpm2.NearTDPDec = 0;
+       table->ACPIState.levels[0].dpm2.AboveSafeInc = 0;
+       table->ACPIState.levels[0].dpm2.BelowSafeInc = 0;
+       table->ACPIState.levels[0].dpm2.PwrEfficiencyRatio = 0;
+
+       reg = MIN_POWER_MASK | MAX_POWER_MASK;
+       table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
+
+       reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+       table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
+
+       return 0;
+}
+
+static int si_populate_ulv_state(struct amdgpu_device *adev,
+                                SISLANDS_SMC_SWSTATE *state)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct si_ulv_param *ulv = &si_pi->ulv;
+       u32 sclk_in_sr = 1350; /* ??? */
+       int ret;
+
+       ret = si_convert_power_level_to_smc(adev, &ulv->pl,
+                                           &state->levels[0]);
+       if (!ret) {
+               if (eg_pi->sclk_deep_sleep) {
+                       if (sclk_in_sr <= SCLK_MIN_DEEPSLEEP_FREQ)
+                               state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS;
+                       else
+                               state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE;
+               }
+               if (ulv->one_pcie_lane_in_ulv)
+                       state->flags |= PPSMC_SWSTATE_FLAG_PCIE_X1;
+               state->levels[0].arbRefreshState = (u8)(SISLANDS_ULV_STATE_ARB_INDEX);
+               state->levels[0].ACIndex = 1;
+               state->levels[0].std_vddc = state->levels[0].vddc;
+               state->levelCount = 1;
+
+               state->flags |= PPSMC_SWSTATE_FLAG_DC;
+       }
+
+       return ret;
+}
+
+static int si_program_ulv_memory_timing_parameters(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct si_ulv_param *ulv = &si_pi->ulv;
+       SMC_SIslands_MCArbDramTimingRegisterSet arb_regs = { 0 };
+       int ret;
+
+       ret = si_populate_memory_timing_parameters(adev, &ulv->pl,
+                                                  &arb_regs);
+       if (ret)
+               return ret;
+
+       si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_ulv_volt_change_delay,
+                                  ulv->volt_change_delay);
+
+       ret = amdgpu_si_copy_bytes_to_smc(adev,
+                                         si_pi->arb_table_start +
+                                         offsetof(SMC_SIslands_MCArbDramTimingRegisters, data) +
+                                         sizeof(SMC_SIslands_MCArbDramTimingRegisterSet) * SISLANDS_ULV_STATE_ARB_INDEX,
+                                         (u8 *)&arb_regs,
+                                         sizeof(SMC_SIslands_MCArbDramTimingRegisterSet),
+                                         si_pi->sram_end);
+
+       return ret;
+}
+
+static void si_get_mvdd_configuration(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+
+       pi->mvdd_split_frequency = 30000;
+}
+
+static int si_init_smc_table(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct amdgpu_ps *amdgpu_boot_state = adev->pm.dpm.boot_ps;
+       const struct si_ulv_param *ulv = &si_pi->ulv;
+       SISLANDS_SMC_STATETABLE  *table = &si_pi->smc_statetable;
+       int ret;
+       u32 lane_width;
+       u32 vr_hot_gpio;
+
+       si_populate_smc_voltage_tables(adev, table);
+
+       switch (adev->pm.int_thermal_type) {
+       case THERMAL_TYPE_SI:
+       case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+               table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+               break;
+       case THERMAL_TYPE_NONE:
+               table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+               break;
+       default:
+               table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+               break;
+       }
+
+       if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+               table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+       if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT) {
+               if ((adev->pdev->device != 0x6818) && (adev->pdev->device != 0x6819))
+                       table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT;
+       }
+
+       if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+               table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+       if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5)
+               table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+       if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY)
+               table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH;
+
+       if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE) {
+               table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT_PROG_GPIO;
+               vr_hot_gpio = adev->pm.dpm.backbias_response_time;
+               si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_vr_hot_gpio,
+                                          vr_hot_gpio);
+       }
+
+       ret = si_populate_smc_initial_state(adev, amdgpu_boot_state, table);
+       if (ret)
+               return ret;
+
+       ret = si_populate_smc_acpi_state(adev, table);
+       if (ret)
+               return ret;
+
+       table->driverState = table->initialState;
+
+       ret = si_do_program_memory_timing_parameters(adev, amdgpu_boot_state,
+                                                    SISLANDS_INITIAL_STATE_ARB_INDEX);
+       if (ret)
+               return ret;
+
+       if (ulv->supported && ulv->pl.vddc) {
+               ret = si_populate_ulv_state(adev, &table->ULVState);
+               if (ret)
+                       return ret;
+
+               ret = si_program_ulv_memory_timing_parameters(adev);
+               if (ret)
+                       return ret;
+
+               WREG32(CG_ULV_CONTROL, ulv->cg_ulv_control);
+               WREG32(CG_ULV_PARAMETER, ulv->cg_ulv_parameter);
+
+               lane_width = amdgpu_get_pcie_lanes(adev);
+               si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width, lane_width);
+       } else {
+               table->ULVState = table->initialState;
+       }
+
+       return amdgpu_si_copy_bytes_to_smc(adev, si_pi->state_table_start,
+                                          (u8 *)table, sizeof(SISLANDS_SMC_STATETABLE),
+                                          si_pi->sram_end);
+}
+
+static int si_calculate_sclk_params(struct amdgpu_device *adev,
+                                   u32 engine_clock,
+                                   SISLANDS_SMC_SCLK_VALUE *sclk)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct atom_clock_dividers dividers;
+       u32 spll_func_cntl = si_pi->clock_registers.cg_spll_func_cntl;
+       u32 spll_func_cntl_2 = si_pi->clock_registers.cg_spll_func_cntl_2;
+       u32 spll_func_cntl_3 = si_pi->clock_registers.cg_spll_func_cntl_3;
+       u32 spll_func_cntl_4 = si_pi->clock_registers.cg_spll_func_cntl_4;
+       u32 cg_spll_spread_spectrum = si_pi->clock_registers.cg_spll_spread_spectrum;
+       u32 cg_spll_spread_spectrum_2 = si_pi->clock_registers.cg_spll_spread_spectrum_2;
+       u64 tmp;
+       u32 reference_clock = adev->clock.spll.reference_freq;
+       u32 reference_divider;
+       u32 fbdiv;
+       int ret;
+
+       ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_ENGINE_PLL_PARAM,
+                                            engine_clock, false, &dividers);
+       if (ret)
+               return ret;
+
+       reference_divider = 1 + dividers.ref_div;
+
+       tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16384;
+       do_div(tmp, reference_clock);
+       fbdiv = (u32) tmp;
+
+       spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
+       spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+       spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
+
+       spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+       spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+       spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+       spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+       spll_func_cntl_3 |= SPLL_DITHEN;
+
+       if (pi->sclk_ss) {
+               struct amdgpu_atom_ss ss;
+               u32 vco_freq = engine_clock * dividers.post_div;
+
+               if (amdgpu_atombios_get_asic_ss_info(adev, &ss,
+                                                    ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+                       u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+                       u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
+
+                       cg_spll_spread_spectrum &= ~CLK_S_MASK;
+                       cg_spll_spread_spectrum |= CLK_S(clk_s);
+                       cg_spll_spread_spectrum |= SSEN;
+
+                       cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
+                       cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
+               }
+       }
+
+       sclk->sclk_value = engine_clock;
+       sclk->vCG_SPLL_FUNC_CNTL = spll_func_cntl;
+       sclk->vCG_SPLL_FUNC_CNTL_2 = spll_func_cntl_2;
+       sclk->vCG_SPLL_FUNC_CNTL_3 = spll_func_cntl_3;
+       sclk->vCG_SPLL_FUNC_CNTL_4 = spll_func_cntl_4;
+       sclk->vCG_SPLL_SPREAD_SPECTRUM = cg_spll_spread_spectrum;
+       sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cg_spll_spread_spectrum_2;
+
+       return 0;
+}
+
+static int si_populate_sclk_value(struct amdgpu_device *adev,
+                                 u32 engine_clock,
+                                 SISLANDS_SMC_SCLK_VALUE *sclk)
+{
+       SISLANDS_SMC_SCLK_VALUE sclk_tmp;
+       int ret;
+
+       ret = si_calculate_sclk_params(adev, engine_clock, &sclk_tmp);
+       if (!ret) {
+               sclk->sclk_value = cpu_to_be32(sclk_tmp.sclk_value);
+               sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL);
+               sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_2);
+               sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_3);
+               sclk->vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_4);
+               sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM);
+               sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM_2);
+       }
+
+       return ret;
+}
+
+static int si_populate_mclk_value(struct amdgpu_device *adev,
+                                 u32 engine_clock,
+                                 u32 memory_clock,
+                                 SISLANDS_SMC_MCLK_VALUE *mclk,
+                                 bool strobe_mode,
+                                 bool dll_state_on)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32  dll_cntl = si_pi->clock_registers.dll_cntl;
+       u32  mclk_pwrmgt_cntl = si_pi->clock_registers.mclk_pwrmgt_cntl;
+       u32  mpll_ad_func_cntl = si_pi->clock_registers.mpll_ad_func_cntl;
+       u32  mpll_dq_func_cntl = si_pi->clock_registers.mpll_dq_func_cntl;
+       u32  mpll_func_cntl = si_pi->clock_registers.mpll_func_cntl;
+       u32  mpll_func_cntl_1 = si_pi->clock_registers.mpll_func_cntl_1;
+       u32  mpll_func_cntl_2 = si_pi->clock_registers.mpll_func_cntl_2;
+       u32  mpll_ss1 = si_pi->clock_registers.mpll_ss1;
+       u32  mpll_ss2 = si_pi->clock_registers.mpll_ss2;
+       struct atom_mpll_param mpll_param;
+       int ret;
+
+       ret = amdgpu_atombios_get_memory_pll_dividers(adev, memory_clock, strobe_mode, &mpll_param);
+       if (ret)
+               return ret;
+
+       mpll_func_cntl &= ~BWCTRL_MASK;
+       mpll_func_cntl |= BWCTRL(mpll_param.bwcntl);
+
+       mpll_func_cntl_1 &= ~(CLKF_MASK | CLKFRAC_MASK | VCO_MODE_MASK);
+       mpll_func_cntl_1 |= CLKF(mpll_param.clkf) |
+               CLKFRAC(mpll_param.clkfrac) | VCO_MODE(mpll_param.vco_mode);
+
+       mpll_ad_func_cntl &= ~YCLK_POST_DIV_MASK;
+       mpll_ad_func_cntl |= YCLK_POST_DIV(mpll_param.post_div);
+
+       if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) {
+               mpll_dq_func_cntl &= ~(YCLK_SEL_MASK | YCLK_POST_DIV_MASK);
+               mpll_dq_func_cntl |= YCLK_SEL(mpll_param.yclk_sel) |
+                       YCLK_POST_DIV(mpll_param.post_div);
+       }
+
+       if (pi->mclk_ss) {
+               struct amdgpu_atom_ss ss;
+               u32 freq_nom;
+               u32 tmp;
+               u32 reference_clock = adev->clock.mpll.reference_freq;
+
+               if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5)
+                       freq_nom = memory_clock * 4;
+               else
+                       freq_nom = memory_clock * 2;
+
+               tmp = freq_nom / reference_clock;
+               tmp = tmp * tmp;
+               if (amdgpu_atombios_get_asic_ss_info(adev, &ss,
+                                                    ASIC_INTERNAL_MEMORY_SS, freq_nom)) {
+                       u32 clks = reference_clock * 5 / ss.rate;
+                       u32 clkv = (u32)((((131 * ss.percentage * ss.rate) / 100) * tmp) / freq_nom);
+
+                       mpll_ss1 &= ~CLKV_MASK;
+                       mpll_ss1 |= CLKV(clkv);
+
+                       mpll_ss2 &= ~CLKS_MASK;
+                       mpll_ss2 |= CLKS(clks);
+               }
+       }
+
+       mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
+       mclk_pwrmgt_cntl |= DLL_SPEED(mpll_param.dll_speed);
+
+       if (dll_state_on)
+               mclk_pwrmgt_cntl |= MRDCK0_PDNB | MRDCK1_PDNB;
+       else
+               mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB);
+
+       mclk->mclk_value = cpu_to_be32(memory_clock);
+       mclk->vMPLL_FUNC_CNTL = cpu_to_be32(mpll_func_cntl);
+       mclk->vMPLL_FUNC_CNTL_1 = cpu_to_be32(mpll_func_cntl_1);
+       mclk->vMPLL_FUNC_CNTL_2 = cpu_to_be32(mpll_func_cntl_2);
+       mclk->vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+       mclk->vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+       mclk->vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+       mclk->vDLL_CNTL = cpu_to_be32(dll_cntl);
+       mclk->vMPLL_SS = cpu_to_be32(mpll_ss1);
+       mclk->vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+       return 0;
+}
+
+static void si_populate_smc_sp(struct amdgpu_device *adev,
+                              struct amdgpu_ps *amdgpu_state,
+                              SISLANDS_SMC_SWSTATE *smc_state)
+{
+       struct  si_ps *ps = si_get_ps(amdgpu_state);
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       int i;
+
+       for (i = 0; i < ps->performance_level_count - 1; i++)
+               smc_state->levels[i].bSP = cpu_to_be32(pi->dsp);
+
+       smc_state->levels[ps->performance_level_count - 1].bSP =
+               cpu_to_be32(pi->psp);
+}
+
+static int si_convert_power_level_to_smc(struct amdgpu_device *adev,
+                                        struct rv7xx_pl *pl,
+                                        SISLANDS_SMC_HW_PERFORMANCE_LEVEL *level)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       int ret;
+       bool dll_state_on;
+       u16 std_vddc;
+       bool gmc_pg = false;
+
+       if (eg_pi->pcie_performance_request &&
+           (si_pi->force_pcie_gen != AMDGPU_PCIE_GEN_INVALID))
+               level->gen2PCIE = (u8)si_pi->force_pcie_gen;
+       else
+               level->gen2PCIE = (u8)pl->pcie_gen;
+
+       ret = si_populate_sclk_value(adev, pl->sclk, &level->sclk);
+       if (ret)
+               return ret;
+
+       level->mcFlags =  0;
+
+       if (pi->mclk_stutter_mode_threshold &&
+           (pl->mclk <= pi->mclk_stutter_mode_threshold) &&
+           !eg_pi->uvd_enabled &&
+           (RREG32(DPG_PIPE_STUTTER_CONTROL) & STUTTER_ENABLE) &&
+           (adev->pm.dpm.new_active_crtc_count <= 2)) {
+               level->mcFlags |= SISLANDS_SMC_MC_STUTTER_EN;
+
+               if (gmc_pg)
+                       level->mcFlags |= SISLANDS_SMC_MC_PG_EN;
+       }
+
+       if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) {
+               if (pl->mclk > pi->mclk_edc_enable_threshold)
+                       level->mcFlags |= SISLANDS_SMC_MC_EDC_RD_FLAG;
+
+               if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold)
+                       level->mcFlags |= SISLANDS_SMC_MC_EDC_WR_FLAG;
+
+               level->strobeMode = si_get_strobe_mode_settings(adev, pl->mclk);
+
+               if (level->strobeMode & SISLANDS_SMC_STROBE_ENABLE) {
+                       if (si_get_mclk_frequency_ratio(pl->mclk, true) >=
+                           ((RREG32(MC_SEQ_MISC7) >> 16) & 0xf))
+                               dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+                       else
+                               dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
+               } else {
+                       dll_state_on = false;
+               }
+       } else {
+               level->strobeMode = si_get_strobe_mode_settings(adev,
+                                                               pl->mclk);
+
+               dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+       }
+
+       ret = si_populate_mclk_value(adev,
+                                    pl->sclk,
+                                    pl->mclk,
+                                    &level->mclk,
+                                    (level->strobeMode & SISLANDS_SMC_STROBE_ENABLE) != 0, dll_state_on);
+       if (ret)
+               return ret;
+
+       ret = si_populate_voltage_value(adev,
+                                       &eg_pi->vddc_voltage_table,
+                                       pl->vddc, &level->vddc);
+       if (ret)
+               return ret;
+
+
+       ret = si_get_std_voltage_value(adev, &level->vddc, &std_vddc);
+       if (ret)
+               return ret;
+
+       ret = si_populate_std_voltage_value(adev, std_vddc,
+                                           level->vddc.index, &level->std_vddc);
+       if (ret)
+               return ret;
+
+       if (eg_pi->vddci_control) {
+               ret = si_populate_voltage_value(adev, &eg_pi->vddci_voltage_table,
+                                               pl->vddci, &level->vddci);
+               if (ret)
+                       return ret;
+       }
+
+       if (si_pi->vddc_phase_shed_control) {
+               ret = si_populate_phase_shedding_value(adev,
+                                                      &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
+                                                      pl->vddc,
+                                                      pl->sclk,
+                                                      pl->mclk,
+                                                      &level->vddc);
+               if (ret)
+                       return ret;
+       }
+
+       level->MaxPoweredUpCU = si_pi->max_cu;
+
+       ret = si_populate_mvdd_value(adev, pl->mclk, &level->mvdd);
+
+       return ret;
+}
+
+static int si_populate_smc_t(struct amdgpu_device *adev,
+                            struct amdgpu_ps *amdgpu_state,
+                            SISLANDS_SMC_SWSTATE *smc_state)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct  si_ps *state = si_get_ps(amdgpu_state);
+       u32 a_t;
+       u32 t_l, t_h;
+       u32 high_bsp;
+       int i, ret;
+
+       if (state->performance_level_count >= 9)
+               return -EINVAL;
+
+       if (state->performance_level_count < 2) {
+               a_t = CG_R(0xffff) | CG_L(0);
+               smc_state->levels[0].aT = cpu_to_be32(a_t);
+               return 0;
+       }
+
+       smc_state->levels[0].aT = cpu_to_be32(0);
+
+       for (i = 0; i <= state->performance_level_count - 2; i++) {
+               ret = r600_calculate_at(
+                       (50 / SISLANDS_MAX_HARDWARE_POWERLEVELS) * 100 * (i + 1),
+                       100 * R600_AH_DFLT,
+                       state->performance_levels[i + 1].sclk,
+                       state->performance_levels[i].sclk,
+                       &t_l,
+                       &t_h);
+
+               if (ret) {
+                       t_h = (i + 1) * 1000 - 50 * R600_AH_DFLT;
+                       t_l = (i + 1) * 1000 + 50 * R600_AH_DFLT;
+               }
+
+               a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_R_MASK;
+               a_t |= CG_R(t_l * pi->bsp / 20000);
+               smc_state->levels[i].aT = cpu_to_be32(a_t);
+
+               high_bsp = (i == state->performance_level_count - 2) ?
+                       pi->pbsp : pi->bsp;
+               a_t = CG_R(0xffff) | CG_L(t_h * high_bsp / 20000);
+               smc_state->levels[i + 1].aT = cpu_to_be32(a_t);
+       }
+
+       return 0;
+}
+
+static int si_disable_ulv(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct si_ulv_param *ulv = &si_pi->ulv;
+
+       if (ulv->supported)
+               return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ?
+                       0 : -EINVAL;
+
+       return 0;
+}
+
+static bool si_is_state_ulv_compatible(struct amdgpu_device *adev,
+                                      struct amdgpu_ps *amdgpu_state)
+{
+       const struct si_power_info *si_pi = si_get_pi(adev);
+       const struct si_ulv_param *ulv = &si_pi->ulv;
+       const struct  si_ps *state = si_get_ps(amdgpu_state);
+       int i;
+
+       if (state->performance_levels[0].mclk != ulv->pl.mclk)
+               return false;
+
+       /* XXX validate against display requirements! */
+
+       for (i = 0; i < adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count; i++) {
+               if (adev->clock.current_dispclk <=
+                   adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].clk) {
+                       if (ulv->pl.vddc <
+                           adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].v)
+                               return false;
+               }
+       }
+
+       if ((amdgpu_state->vclk != 0) || (amdgpu_state->dclk != 0))
+               return false;
+
+       return true;
+}
+
+static int si_set_power_state_conditionally_enable_ulv(struct amdgpu_device *adev,
+                                                      struct amdgpu_ps *amdgpu_new_state)
+{
+       const struct si_power_info *si_pi = si_get_pi(adev);
+       const struct si_ulv_param *ulv = &si_pi->ulv;
+
+       if (ulv->supported) {
+               if (si_is_state_ulv_compatible(adev, amdgpu_new_state))
+                       return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableULV) == PPSMC_Result_OK) ?
+                               0 : -EINVAL;
+       }
+       return 0;
+}
+
+static int si_convert_power_state_to_smc(struct amdgpu_device *adev,
+                                        struct amdgpu_ps *amdgpu_state,
+                                        SISLANDS_SMC_SWSTATE *smc_state)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct ni_power_info *ni_pi = ni_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct  si_ps *state = si_get_ps(amdgpu_state);
+       int i, ret;
+       u32 threshold;
+       u32 sclk_in_sr = 1350; /* ??? */
+
+       if (state->performance_level_count > SISLANDS_MAX_HARDWARE_POWERLEVELS)
+               return -EINVAL;
+
+       threshold = state->performance_levels[state->performance_level_count-1].sclk * 100 / 100;
+
+       if (amdgpu_state->vclk && amdgpu_state->dclk) {
+               eg_pi->uvd_enabled = true;
+               if (eg_pi->smu_uvd_hs)
+                       smc_state->flags |= PPSMC_SWSTATE_FLAG_UVD;
+       } else {
+               eg_pi->uvd_enabled = false;
+       }
+
+       if (state->dc_compatible)
+               smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
+
+       smc_state->levelCount = 0;
+       for (i = 0; i < state->performance_level_count; i++) {
+               if (eg_pi->sclk_deep_sleep) {
+                       if ((i == 0) || si_pi->sclk_deep_sleep_above_low) {
+                               if (sclk_in_sr <= SCLK_MIN_DEEPSLEEP_FREQ)
+                                       smc_state->levels[i].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS;
+                               else
+                                       smc_state->levels[i].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE;
+                       }
+               }
+
+               ret = si_convert_power_level_to_smc(adev, &state->performance_levels[i],
+                                                   &smc_state->levels[i]);
+               smc_state->levels[i].arbRefreshState =
+                       (u8)(SISLANDS_DRIVER_STATE_ARB_INDEX + i);
+
+               if (ret)
+                       return ret;
+
+               if (ni_pi->enable_power_containment)
+                       smc_state->levels[i].displayWatermark =
+                               (state->performance_levels[i].sclk < threshold) ?
+                               PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
+               else
+                       smc_state->levels[i].displayWatermark = (i < 2) ?
+                               PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
+
+               if (eg_pi->dynamic_ac_timing)
+                       smc_state->levels[i].ACIndex = SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i;
+               else
+                       smc_state->levels[i].ACIndex = 0;
+
+               smc_state->levelCount++;
+       }
+
+       si_write_smc_soft_register(adev,
+                                  SI_SMC_SOFT_REGISTER_watermark_threshold,
+                                  threshold / 512);
+
+       si_populate_smc_sp(adev, amdgpu_state, smc_state);
+
+       ret = si_populate_power_containment_values(adev, amdgpu_state, smc_state);
+       if (ret)
+               ni_pi->enable_power_containment = false;
+
+       ret = si_populate_sq_ramping_values(adev, amdgpu_state, smc_state);
+       if (ret)
+               ni_pi->enable_sq_ramping = false;
+
+       return si_populate_smc_t(adev, amdgpu_state, smc_state);
+}
+
+static int si_upload_sw_state(struct amdgpu_device *adev,
+                             struct amdgpu_ps *amdgpu_new_state)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct  si_ps *new_state = si_get_ps(amdgpu_new_state);
+       int ret;
+       u32 address = si_pi->state_table_start +
+               offsetof(SISLANDS_SMC_STATETABLE, driverState);
+       u32 state_size = sizeof(SISLANDS_SMC_SWSTATE) +
+               ((new_state->performance_level_count - 1) *
+                sizeof(SISLANDS_SMC_HW_PERFORMANCE_LEVEL));
+       SISLANDS_SMC_SWSTATE *smc_state = &si_pi->smc_statetable.driverState;
+
+       memset(smc_state, 0, state_size);
+
+       ret = si_convert_power_state_to_smc(adev, amdgpu_new_state, smc_state);
+       if (ret)
+               return ret;
+
+       return amdgpu_si_copy_bytes_to_smc(adev, address, (u8 *)smc_state,
+                                          state_size, si_pi->sram_end);
+}
+
+static int si_upload_ulv_state(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct si_ulv_param *ulv = &si_pi->ulv;
+       int ret = 0;
+
+       if (ulv->supported && ulv->pl.vddc) {
+               u32 address = si_pi->state_table_start +
+                       offsetof(SISLANDS_SMC_STATETABLE, ULVState);
+               SISLANDS_SMC_SWSTATE *smc_state = &si_pi->smc_statetable.ULVState;
+               u32 state_size = sizeof(SISLANDS_SMC_SWSTATE);
+
+               memset(smc_state, 0, state_size);
+
+               ret = si_populate_ulv_state(adev, smc_state);
+               if (!ret)
+                       ret = amdgpu_si_copy_bytes_to_smc(adev, address, (u8 *)smc_state,
+                                                         state_size, si_pi->sram_end);
+       }
+
+       return ret;
+}
+
+static int si_upload_smc_data(struct amdgpu_device *adev)
+{
+       struct amdgpu_crtc *amdgpu_crtc = NULL;
+       int i;
+
+       if (adev->pm.dpm.new_active_crtc_count == 0)
+               return 0;
+
+       for (i = 0; i < adev->mode_info.num_crtc; i++) {
+               if (adev->pm.dpm.new_active_crtcs & (1 << i)) {
+                       amdgpu_crtc = adev->mode_info.crtcs[i];
+                       break;
+               }
+       }
+
+       if (amdgpu_crtc == NULL)
+               return 0;
+
+       if (amdgpu_crtc->line_time <= 0)
+               return 0;
+
+       if (si_write_smc_soft_register(adev,
+                                      SI_SMC_SOFT_REGISTER_crtc_index,
+                                      amdgpu_crtc->crtc_id) != PPSMC_Result_OK)
+               return 0;
+
+       if (si_write_smc_soft_register(adev,
+                                      SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min,
+                                      amdgpu_crtc->wm_high / amdgpu_crtc->line_time) != PPSMC_Result_OK)
+               return 0;
+
+       if (si_write_smc_soft_register(adev,
+                                      SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max,
+                                      amdgpu_crtc->wm_low / amdgpu_crtc->line_time) != PPSMC_Result_OK)
+               return 0;
+
+       return 0;
+}
+
+static int si_set_mc_special_registers(struct amdgpu_device *adev,
+                                      struct si_mc_reg_table *table)
+{
+       u8 i, j, k;
+       u32 temp_reg;
+
+       for (i = 0, j = table->last; i < table->last; i++) {
+               if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                       return -EINVAL;
+               switch (table->mc_reg_address[i].s1) {
+               case MC_SEQ_MISC1:
+                       temp_reg = RREG32(MC_PMG_CMD_EMRS);
+                       table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS;
+                       table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP;
+                       for (k = 0; k < table->num_entries; k++)
+                               table->mc_reg_table_entry[k].mc_data[j] =
+                                       ((temp_reg & 0xffff0000)) |
+                                       ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
+                       j++;
+                       if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                               return -EINVAL;
+
+                       temp_reg = RREG32(MC_PMG_CMD_MRS);
+                       table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS;
+                       table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP;
+                       for (k = 0; k < table->num_entries; k++) {
+                               table->mc_reg_table_entry[k].mc_data[j] =
+                                       (temp_reg & 0xffff0000) |
+                                       (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+                               if (adev->mc.vram_type != AMDGPU_VRAM_TYPE_GDDR5)
+                                       table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+                       }
+                       j++;
+                       if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                               return -EINVAL;
+
+                       if (adev->mc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) {
+                               table->mc_reg_address[j].s1 = MC_PMG_AUTO_CMD;
+                               table->mc_reg_address[j].s0 = MC_PMG_AUTO_CMD;
+                               for (k = 0; k < table->num_entries; k++)
+                                       table->mc_reg_table_entry[k].mc_data[j] =
+                                               (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
+                               j++;
+                               if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                                       return -EINVAL;
+                       }
+                       break;
+               case MC_SEQ_RESERVE_M:
+                       temp_reg = RREG32(MC_PMG_CMD_MRS1);
+                       table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1;
+                       table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP;
+                       for(k = 0; k < table->num_entries; k++)
+                               table->mc_reg_table_entry[k].mc_data[j] =
+                                       (temp_reg & 0xffff0000) |
+                                       (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+                       j++;
+                       if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                               return -EINVAL;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       table->last = j;
+
+       return 0;
+}
+
+static bool si_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
+{
+       bool result = true;
+       switch (in_reg) {
+       case  MC_SEQ_RAS_TIMING:
+               *out_reg = MC_SEQ_RAS_TIMING_LP;
+               break;
+       case MC_SEQ_CAS_TIMING:
+               *out_reg = MC_SEQ_CAS_TIMING_LP;
+               break;
+       case MC_SEQ_MISC_TIMING:
+               *out_reg = MC_SEQ_MISC_TIMING_LP;
+               break;
+       case MC_SEQ_MISC_TIMING2:
+               *out_reg = MC_SEQ_MISC_TIMING2_LP;
+               break;
+       case MC_SEQ_RD_CTL_D0:
+               *out_reg = MC_SEQ_RD_CTL_D0_LP;
+               break;
+       case MC_SEQ_RD_CTL_D1:
+               *out_reg = MC_SEQ_RD_CTL_D1_LP;
+               break;
+       case MC_SEQ_WR_CTL_D0:
+               *out_reg = MC_SEQ_WR_CTL_D0_LP;
+               break;
+       case MC_SEQ_WR_CTL_D1:
+               *out_reg = MC_SEQ_WR_CTL_D1_LP;
+               break;
+       case MC_PMG_CMD_EMRS:
+               *out_reg = MC_SEQ_PMG_CMD_EMRS_LP;
+               break;
+       case MC_PMG_CMD_MRS:
+               *out_reg = MC_SEQ_PMG_CMD_MRS_LP;
+               break;
+       case MC_PMG_CMD_MRS1:
+               *out_reg = MC_SEQ_PMG_CMD_MRS1_LP;
+               break;
+       case MC_SEQ_PMG_TIMING:
+               *out_reg = MC_SEQ_PMG_TIMING_LP;
+               break;
+       case MC_PMG_CMD_MRS2:
+               *out_reg = MC_SEQ_PMG_CMD_MRS2_LP;
+               break;
+       case MC_SEQ_WR_CTL_2:
+               *out_reg = MC_SEQ_WR_CTL_2_LP;
+               break;
+       default:
+               result = false;
+               break;
+       }
+
+       return result;
+}
+
+static void si_set_valid_flag(struct si_mc_reg_table *table)
+{
+       u8 i, j;
+
+       for (i = 0; i < table->last; i++) {
+               for (j = 1; j < table->num_entries; j++) {
+                       if (table->mc_reg_table_entry[j-1].mc_data[i] != table->mc_reg_table_entry[j].mc_data[i]) {
+                               table->valid_flag |= 1 << i;
+                               break;
+                       }
+               }
+       }
+}
+
+static void si_set_s0_mc_reg_index(struct si_mc_reg_table *table)
+{
+       u32 i;
+       u16 address;
+
+       for (i = 0; i < table->last; i++)
+               table->mc_reg_address[i].s0 = si_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
+                       address : table->mc_reg_address[i].s1;
+
+}
+
+static int si_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table,
+                                     struct si_mc_reg_table *si_table)
+{
+       u8 i, j;
+
+       if (table->last > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+               return -EINVAL;
+       if (table->num_entries > MAX_AC_TIMING_ENTRIES)
+               return -EINVAL;
+
+       for (i = 0; i < table->last; i++)
+               si_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+       si_table->last = table->last;
+
+       for (i = 0; i < table->num_entries; i++) {
+               si_table->mc_reg_table_entry[i].mclk_max =
+                       table->mc_reg_table_entry[i].mclk_max;
+               for (j = 0; j < table->last; j++) {
+                       si_table->mc_reg_table_entry[i].mc_data[j] =
+                               table->mc_reg_table_entry[i].mc_data[j];
+               }
+       }
+       si_table->num_entries = table->num_entries;
+
+       return 0;
+}
+
+static int si_initialize_mc_reg_table(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct atom_mc_reg_table *table;
+       struct si_mc_reg_table *si_table = &si_pi->mc_reg_table;
+       u8 module_index = rv770_get_memory_module_index(adev);
+       int ret;
+
+       table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
+       if (!table)
+               return -ENOMEM;
+
+       WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING));
+       WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING));
+       WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING));
+       WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2));
+       WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS));
+       WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS));
+       WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1));
+       WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0));
+       WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1));
+       WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0));
+       WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1));
+       WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING));
+       WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2));
+       WREG32(MC_SEQ_WR_CTL_2_LP, RREG32(MC_SEQ_WR_CTL_2));
+
+       ret = amdgpu_atombios_init_mc_reg_table(adev, module_index, table);
+       if (ret)
+               goto init_mc_done;
+
+       ret = si_copy_vbios_mc_reg_table(table, si_table);
+       if (ret)
+               goto init_mc_done;
+
+       si_set_s0_mc_reg_index(si_table);
+
+       ret = si_set_mc_special_registers(adev, si_table);
+       if (ret)
+               goto init_mc_done;
+
+       si_set_valid_flag(si_table);
+
+init_mc_done:
+       kfree(table);
+
+       return ret;
+
+}
+
+static void si_populate_mc_reg_addresses(struct amdgpu_device *adev,
+                                        SMC_SIslands_MCRegisters *mc_reg_table)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 i, j;
+
+       for (i = 0, j = 0; j < si_pi->mc_reg_table.last; j++) {
+               if (si_pi->mc_reg_table.valid_flag & (1 << j)) {
+                       if (i >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                               break;
+                       mc_reg_table->address[i].s0 =
+                               cpu_to_be16(si_pi->mc_reg_table.mc_reg_address[j].s0);
+                       mc_reg_table->address[i].s1 =
+                               cpu_to_be16(si_pi->mc_reg_table.mc_reg_address[j].s1);
+                       i++;
+               }
+       }
+       mc_reg_table->last = (u8)i;
+}
+
+static void si_convert_mc_registers(const struct si_mc_reg_entry *entry,
+                                   SMC_SIslands_MCRegisterSet *data,
+                                   u32 num_entries, u32 valid_flag)
+{
+       u32 i, j;
+
+       for(i = 0, j = 0; j < num_entries; j++) {
+               if (valid_flag & (1 << j)) {
+                       data->value[i] = cpu_to_be32(entry->mc_data[j]);
+                       i++;
+               }
+       }
+}
+
+static void si_convert_mc_reg_table_entry_to_smc(struct amdgpu_device *adev,
+                                                struct rv7xx_pl *pl,
+                                                SMC_SIslands_MCRegisterSet *mc_reg_table_data)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 i = 0;
+
+       for (i = 0; i < si_pi->mc_reg_table.num_entries; i++) {
+               if (pl->mclk <= si_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
+                       break;
+       }
+
+       if ((i == si_pi->mc_reg_table.num_entries) && (i > 0))
+               --i;
+
+       si_convert_mc_registers(&si_pi->mc_reg_table.mc_reg_table_entry[i],
+                               mc_reg_table_data, si_pi->mc_reg_table.last,
+                               si_pi->mc_reg_table.valid_flag);
+}
+
+static void si_convert_mc_reg_table_to_smc(struct amdgpu_device *adev,
+                                          struct amdgpu_ps *amdgpu_state,
+                                          SMC_SIslands_MCRegisters *mc_reg_table)
+{
+       struct si_ps *state = si_get_ps(amdgpu_state);
+       int i;
+
+       for (i = 0; i < state->performance_level_count; i++) {
+               si_convert_mc_reg_table_entry_to_smc(adev,
+                                                    &state->performance_levels[i],
+                                                    &mc_reg_table->data[SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i]);
+       }
+}
+
+static int si_populate_mc_reg_table(struct amdgpu_device *adev,
+                                   struct amdgpu_ps *amdgpu_boot_state)
+{
+       struct  si_ps *boot_state = si_get_ps(amdgpu_boot_state);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct si_ulv_param *ulv = &si_pi->ulv;
+       SMC_SIslands_MCRegisters *smc_mc_reg_table = &si_pi->smc_mc_reg_table;
+
+       memset(smc_mc_reg_table, 0, sizeof(SMC_SIslands_MCRegisters));
+
+       si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_seq_index, 1);
+
+       si_populate_mc_reg_addresses(adev, smc_mc_reg_table);
+
+       si_convert_mc_reg_table_entry_to_smc(adev, &boot_state->performance_levels[0],
+                                            &smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_INITIAL_SLOT]);
+
+       si_convert_mc_registers(&si_pi->mc_reg_table.mc_reg_table_entry[0],
+                               &smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_ACPI_SLOT],
+                               si_pi->mc_reg_table.last,
+                               si_pi->mc_reg_table.valid_flag);
+
+       if (ulv->supported && ulv->pl.vddc != 0)
+               si_convert_mc_reg_table_entry_to_smc(adev, &ulv->pl,
+                                                    &smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_ULV_SLOT]);
+       else
+               si_convert_mc_registers(&si_pi->mc_reg_table.mc_reg_table_entry[0],
+                                       &smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_ULV_SLOT],
+                                       si_pi->mc_reg_table.last,
+                                       si_pi->mc_reg_table.valid_flag);
+
+       si_convert_mc_reg_table_to_smc(adev, amdgpu_boot_state, smc_mc_reg_table);
+
+       return amdgpu_si_copy_bytes_to_smc(adev, si_pi->mc_reg_table_start,
+                                          (u8 *)smc_mc_reg_table,
+                                          sizeof(SMC_SIslands_MCRegisters), si_pi->sram_end);
+}
+
+static int si_upload_mc_reg_table(struct amdgpu_device *adev,
+                                 struct amdgpu_ps *amdgpu_new_state)
+{
+       struct si_ps *new_state = si_get_ps(amdgpu_new_state);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 address = si_pi->mc_reg_table_start +
+               offsetof(SMC_SIslands_MCRegisters,
+                        data[SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT]);
+       SMC_SIslands_MCRegisters *smc_mc_reg_table = &si_pi->smc_mc_reg_table;
+
+       memset(smc_mc_reg_table, 0, sizeof(SMC_SIslands_MCRegisters));
+
+       si_convert_mc_reg_table_to_smc(adev, amdgpu_new_state, smc_mc_reg_table);
+
+       return amdgpu_si_copy_bytes_to_smc(adev, address,
+                                          (u8 *)&smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT],
+                                          sizeof(SMC_SIslands_MCRegisterSet) * new_state->performance_level_count,
+                                          si_pi->sram_end);
+}
+
+static void si_enable_voltage_control(struct amdgpu_device *adev, bool enable)
+{
+       if (enable)
+               WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN);
+       else
+               WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN);
+}
+
+static enum amdgpu_pcie_gen si_get_maximum_link_speed(struct amdgpu_device *adev,
+                                                     struct amdgpu_ps *amdgpu_state)
+{
+       struct si_ps *state = si_get_ps(amdgpu_state);
+       int i;
+       u16 pcie_speed, max_speed = 0;
+
+       for (i = 0; i < state->performance_level_count; i++) {
+               pcie_speed = state->performance_levels[i].pcie_gen;
+               if (max_speed < pcie_speed)
+                       max_speed = pcie_speed;
+       }
+       return max_speed;
+}
+
+static u16 si_get_current_pcie_speed(struct amdgpu_device *adev)
+{
+       u32 speed_cntl;
+
+       speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE_MASK;
+       speed_cntl >>= LC_CURRENT_DATA_RATE_SHIFT;
+
+       return (u16)speed_cntl;
+}
+
+static void si_request_link_speed_change_before_state_change(struct amdgpu_device *adev,
+                                                            struct amdgpu_ps *amdgpu_new_state,
+                                                            struct amdgpu_ps *amdgpu_current_state)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       enum amdgpu_pcie_gen target_link_speed = si_get_maximum_link_speed(adev, amdgpu_new_state);
+       enum amdgpu_pcie_gen current_link_speed;
+
+       if (si_pi->force_pcie_gen == AMDGPU_PCIE_GEN_INVALID)
+               current_link_speed = si_get_maximum_link_speed(adev, amdgpu_current_state);
+       else
+               current_link_speed = si_pi->force_pcie_gen;
+
+       si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID;
+       si_pi->pspp_notify_required = false;
+       if (target_link_speed > current_link_speed) {
+               switch (target_link_speed) {
+#if defined(CONFIG_ACPI)
+               case AMDGPU_PCIE_GEN3:
+                       if (amdgpu_acpi_pcie_performance_request(adev, PCIE_PERF_REQ_PECI_GEN3, false) == 0)
+                               break;
+                       si_pi->force_pcie_gen = AMDGPU_PCIE_GEN2;
+                       if (current_link_speed == AMDGPU_PCIE_GEN2)
+                               break;
+               case AMDGPU_PCIE_GEN2:
+                       if (amdgpu_acpi_pcie_performance_request(adev, PCIE_PERF_REQ_PECI_GEN2, false) == 0)
+                               break;
+#endif
+               default:
+                       si_pi->force_pcie_gen = si_get_current_pcie_speed(adev);
+                       break;
+               }
+       } else {
+               if (target_link_speed < current_link_speed)
+                       si_pi->pspp_notify_required = true;
+       }
+}
+
+static void si_notify_link_speed_change_after_state_change(struct amdgpu_device *adev,
+                                                          struct amdgpu_ps *amdgpu_new_state,
+                                                          struct amdgpu_ps *amdgpu_current_state)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       enum amdgpu_pcie_gen target_link_speed = si_get_maximum_link_speed(adev, amdgpu_new_state);
+       u8 request;
+
+       if (si_pi->pspp_notify_required) {
+               if (target_link_speed == AMDGPU_PCIE_GEN3)
+                       request = PCIE_PERF_REQ_PECI_GEN3;
+               else if (target_link_speed == AMDGPU_PCIE_GEN2)
+                       request = PCIE_PERF_REQ_PECI_GEN2;
+               else
+                       request = PCIE_PERF_REQ_PECI_GEN1;
+
+               if ((request == PCIE_PERF_REQ_PECI_GEN1) &&
+                   (si_get_current_pcie_speed(adev) > 0))
+                       return;
+
+#if defined(CONFIG_ACPI)
+               amdgpu_acpi_pcie_performance_request(adev, request, false);
+#endif
+       }
+}
+
+#if 0
+static int si_ds_request(struct amdgpu_device *adev,
+                        bool ds_status_on, u32 count_write)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+
+       if (eg_pi->sclk_deep_sleep) {
+               if (ds_status_on)
+                       return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_CancelThrottleOVRDSCLKDS) ==
+                               PPSMC_Result_OK) ?
+                               0 : -EINVAL;
+               else
+                       return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_ThrottleOVRDSCLKDS) ==
+                               PPSMC_Result_OK) ? 0 : -EINVAL;
+       }
+       return 0;
+}
+#endif
+
+static void si_set_max_cu_value(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+
+       if (adev->asic_type == CHIP_VERDE) {
+               switch (adev->pdev->device) {
+               case 0x6820:
+               case 0x6825:
+               case 0x6821:
+               case 0x6823:
+               case 0x6827:
+                       si_pi->max_cu = 10;
+                       break;
+               case 0x682D:
+               case 0x6824:
+               case 0x682F:
+               case 0x6826:
+                       si_pi->max_cu = 8;
+                       break;
+               case 0x6828:
+               case 0x6830:
+               case 0x6831:
+               case 0x6838:
+               case 0x6839:
+               case 0x683D:
+                       si_pi->max_cu = 10;
+                       break;
+               case 0x683B:
+               case 0x683F:
+               case 0x6829:
+                       si_pi->max_cu = 8;
+                       break;
+               default:
+                       si_pi->max_cu = 0;
+                       break;
+               }
+       } else {
+               si_pi->max_cu = 0;
+       }
+}
+
+static int si_patch_single_dependency_table_based_on_leakage(struct amdgpu_device *adev,
+                                                            struct amdgpu_clock_voltage_dependency_table *table)
+{
+       u32 i;
+       int j;
+       u16 leakage_voltage;
+
+       if (table) {
+               for (i = 0; i < table->count; i++) {
+                       switch (si_get_leakage_voltage_from_leakage_index(adev,
+                                                                         table->entries[i].v,
+                                                                         &leakage_voltage)) {
+                       case 0:
+                               table->entries[i].v = leakage_voltage;
+                               break;
+                       case -EAGAIN:
+                               return -EINVAL;
+                       case -EINVAL:
+                       default:
+                               break;
+                       }
+               }
+
+               for (j = (table->count - 2); j >= 0; j--) {
+                       table->entries[j].v = (table->entries[j].v <= table->entries[j + 1].v) ?
+                               table->entries[j].v : table->entries[j + 1].v;
+               }
+       }
+       return 0;
+}
+
+static int si_patch_dependency_tables_based_on_leakage(struct amdgpu_device *adev)
+{
+       int ret = 0;
+
+       ret = si_patch_single_dependency_table_based_on_leakage(adev,
+                                                               &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk);
+       if (ret)
+               DRM_ERROR("Could not patch vddc_on_sclk leakage table\n");
+       ret = si_patch_single_dependency_table_based_on_leakage(adev,
+                                                               &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk);
+       if (ret)
+               DRM_ERROR("Could not patch vddc_on_mclk leakage table\n");
+       ret = si_patch_single_dependency_table_based_on_leakage(adev,
+                                                               &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk);
+       if (ret)
+               DRM_ERROR("Could not patch vddci_on_mclk leakage table\n");
+       return ret;
+}
+
+static void si_set_pcie_lane_width_in_smc(struct amdgpu_device *adev,
+                                         struct amdgpu_ps *amdgpu_new_state,
+                                         struct amdgpu_ps *amdgpu_current_state)
+{
+       u32 lane_width;
+       u32 new_lane_width =
+               (amdgpu_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+       u32 current_lane_width =
+               (amdgpu_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+
+       if (new_lane_width != current_lane_width) {
+               amdgpu_set_pcie_lanes(adev, new_lane_width);
+               lane_width = amdgpu_get_pcie_lanes(adev);
+               si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width, lane_width);
+       }
+}
+
+static void si_dpm_setup_asic(struct amdgpu_device *adev)
+{
+       si_read_clock_registers(adev);
+       si_enable_acpi_power_management(adev);
+}
+
+static int si_thermal_enable_alert(struct amdgpu_device *adev,
+                                  bool enable)
+{
+       u32 thermal_int = RREG32(CG_THERMAL_INT);
+
+       if (enable) {
+               PPSMC_Result result;
+
+               thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+               WREG32(CG_THERMAL_INT, thermal_int);
+               result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableThermalInterrupt);
+               if (result != PPSMC_Result_OK) {
+                       DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+                       return -EINVAL;
+               }
+       } else {
+               thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
+               WREG32(CG_THERMAL_INT, thermal_int);
+       }
+
+       return 0;
+}
+
+static int si_thermal_set_temperature_range(struct amdgpu_device *adev,
+                                           int min_temp, int max_temp)
+{
+       int low_temp = 0 * 1000;
+       int high_temp = 255 * 1000;
+
+       if (low_temp < min_temp)
+               low_temp = min_temp;
+       if (high_temp > max_temp)
+               high_temp = max_temp;
+       if (high_temp < low_temp) {
+               DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
+               return -EINVAL;
+       }
+
+       WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
+       WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
+       WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);
+
+       adev->pm.dpm.thermal.min_temp = low_temp;
+       adev->pm.dpm.thermal.max_temp = high_temp;
+
+       return 0;
+}
+
+static void si_fan_ctrl_set_static_mode(struct amdgpu_device *adev, u32 mode)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 tmp;
+
+       if (si_pi->fan_ctrl_is_in_default_mode) {
+               tmp = (RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT;
+               si_pi->fan_ctrl_default_mode = tmp;
+               tmp = (RREG32(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT;
+               si_pi->t_min = tmp;
+               si_pi->fan_ctrl_is_in_default_mode = false;
+       }
+
+       tmp = RREG32(CG_FDO_CTRL2) & ~TMIN_MASK;
+       tmp |= TMIN(0);
+       WREG32(CG_FDO_CTRL2, tmp);
+
+       tmp = RREG32(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
+       tmp |= FDO_PWM_MODE(mode);
+       WREG32(CG_FDO_CTRL2, tmp);
+}
+
+static int si_thermal_setup_fan_table(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       PP_SIslands_FanTable fan_table = { FDO_MODE_HARDWARE };
+       u32 duty100;
+       u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+       u16 fdo_min, slope1, slope2;
+       u32 reference_clock, tmp;
+       int ret;
+       u64 tmp64;
+
+       if (!si_pi->fan_table_start) {
+               adev->pm.dpm.fan.ucode_fan_control = false;
+               return 0;
+       }
+
+       duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+
+       if (duty100 == 0) {
+               adev->pm.dpm.fan.ucode_fan_control = false;
+               return 0;
+       }
+
+       tmp64 = (u64)adev->pm.dpm.fan.pwm_min * duty100;
+       do_div(tmp64, 10000);
+       fdo_min = (u16)tmp64;
+
+       t_diff1 = adev->pm.dpm.fan.t_med - adev->pm.dpm.fan.t_min;
+       t_diff2 = adev->pm.dpm.fan.t_high - adev->pm.dpm.fan.t_med;
+
+       pwm_diff1 = adev->pm.dpm.fan.pwm_med - adev->pm.dpm.fan.pwm_min;
+       pwm_diff2 = adev->pm.dpm.fan.pwm_high - adev->pm.dpm.fan.pwm_med;
+
+       slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+       slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+       fan_table.temp_min = cpu_to_be16((50 + adev->pm.dpm.fan.t_min) / 100);
+       fan_table.temp_med = cpu_to_be16((50 + adev->pm.dpm.fan.t_med) / 100);
+       fan_table.temp_max = cpu_to_be16((50 + adev->pm.dpm.fan.t_max) / 100);
+       fan_table.slope1 = cpu_to_be16(slope1);
+       fan_table.slope2 = cpu_to_be16(slope2);
+       fan_table.fdo_min = cpu_to_be16(fdo_min);
+       fan_table.hys_down = cpu_to_be16(adev->pm.dpm.fan.t_hyst);
+       fan_table.hys_up = cpu_to_be16(1);
+       fan_table.hys_slope = cpu_to_be16(1);
+       fan_table.temp_resp_lim = cpu_to_be16(5);
+       reference_clock = amdgpu_asic_get_xclk(adev);
+
+       fan_table.refresh_period = cpu_to_be32((adev->pm.dpm.fan.cycle_delay *
+                                               reference_clock) / 1600);
+       fan_table.fdo_max = cpu_to_be16((u16)duty100);
+
+       tmp = (RREG32(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT;
+       fan_table.temp_src = (uint8_t)tmp;
+
+       ret = amdgpu_si_copy_bytes_to_smc(adev,
+                                         si_pi->fan_table_start,
+                                         (u8 *)(&fan_table),
+                                         sizeof(fan_table),
+                                         si_pi->sram_end);
+
+       if (ret) {
+               DRM_ERROR("Failed to load fan table to the SMC.");
+               adev->pm.dpm.fan.ucode_fan_control = false;
+       }
+
+       return ret;
+}
+
+static int si_fan_ctrl_start_smc_fan_control(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       PPSMC_Result ret;
+
+       ret = amdgpu_si_send_msg_to_smc(adev, PPSMC_StartFanControl);
+       if (ret == PPSMC_Result_OK) {
+               si_pi->fan_is_controlled_by_smc = true;
+               return 0;
+       } else {
+               return -EINVAL;
+       }
+}
+
+static int si_fan_ctrl_stop_smc_fan_control(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       PPSMC_Result ret;
+
+       ret = amdgpu_si_send_msg_to_smc(adev, PPSMC_StopFanControl);
+
+       if (ret == PPSMC_Result_OK) {
+               si_pi->fan_is_controlled_by_smc = false;
+               return 0;
+       } else {
+               return -EINVAL;
+       }
+}
+
+static int si_dpm_get_fan_speed_percent(struct amdgpu_device *adev,
+                                     u32 *speed)
+{
+       u32 duty, duty100;
+       u64 tmp64;
+
+       if (adev->pm.no_fan)
+               return -ENOENT;
+
+       duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+       duty = (RREG32(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT;
+
+       if (duty100 == 0)
+               return -EINVAL;
+
+       tmp64 = (u64)duty * 100;
+       do_div(tmp64, duty100);
+       *speed = (u32)tmp64;
+
+       if (*speed > 100)
+               *speed = 100;
+
+       return 0;
+}
+
+static int si_dpm_set_fan_speed_percent(struct amdgpu_device *adev,
+                                     u32 speed)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 tmp;
+       u32 duty, duty100;
+       u64 tmp64;
+
+       if (adev->pm.no_fan)
+               return -ENOENT;
+
+       if (si_pi->fan_is_controlled_by_smc)
+               return -EINVAL;
+
+       if (speed > 100)
+               return -EINVAL;
+
+       duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+
+       if (duty100 == 0)
+               return -EINVAL;
+
+       tmp64 = (u64)speed * duty100;
+       do_div(tmp64, 100);
+       duty = (u32)tmp64;
+
+       tmp = RREG32(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK;
+       tmp |= FDO_STATIC_DUTY(duty);
+       WREG32(CG_FDO_CTRL0, tmp);
+
+       return 0;
+}
+
+static void si_dpm_set_fan_control_mode(struct amdgpu_device *adev, u32 mode)
+{
+       if (mode) {
+               /* stop auto-manage */
+               if (adev->pm.dpm.fan.ucode_fan_control)
+                       si_fan_ctrl_stop_smc_fan_control(adev);
+               si_fan_ctrl_set_static_mode(adev, mode);
+       } else {
+               /* restart auto-manage */
+               if (adev->pm.dpm.fan.ucode_fan_control)
+                       si_thermal_start_smc_fan_control(adev);
+               else
+                       si_fan_ctrl_set_default_mode(adev);
+       }
+}
+
+static u32 si_dpm_get_fan_control_mode(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 tmp;
+
+       if (si_pi->fan_is_controlled_by_smc)
+               return 0;
+
+       tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
+       return (tmp >> FDO_PWM_MODE_SHIFT);
+}
+
+#if 0
+static int si_fan_ctrl_get_fan_speed_rpm(struct amdgpu_device *adev,
+                                        u32 *speed)
+{
+       u32 tach_period;
+       u32 xclk = amdgpu_asic_get_xclk(adev);
+
+       if (adev->pm.no_fan)
+               return -ENOENT;
+
+       if (adev->pm.fan_pulses_per_revolution == 0)
+               return -ENOENT;
+
+       tach_period = (RREG32(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT;
+       if (tach_period == 0)
+               return -ENOENT;
+
+       *speed = 60 * xclk * 10000 / tach_period;
+
+       return 0;
+}
+
+static int si_fan_ctrl_set_fan_speed_rpm(struct amdgpu_device *adev,
+                                        u32 speed)
+{
+       u32 tach_period, tmp;
+       u32 xclk = amdgpu_asic_get_xclk(adev);
+
+       if (adev->pm.no_fan)
+               return -ENOENT;
+
+       if (adev->pm.fan_pulses_per_revolution == 0)
+               return -ENOENT;
+
+       if ((speed < adev->pm.fan_min_rpm) ||
+           (speed > adev->pm.fan_max_rpm))
+               return -EINVAL;
+
+       if (adev->pm.dpm.fan.ucode_fan_control)
+               si_fan_ctrl_stop_smc_fan_control(adev);
+
+       tach_period = 60 * xclk * 10000 / (8 * speed);
+       tmp = RREG32(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK;
+       tmp |= TARGET_PERIOD(tach_period);
+       WREG32(CG_TACH_CTRL, tmp);
+
+       si_fan_ctrl_set_static_mode(adev, FDO_PWM_MODE_STATIC_RPM);
+
+       return 0;
+}
+#endif
+
+static void si_fan_ctrl_set_default_mode(struct amdgpu_device *adev)
+{
+       struct si_power_info *si_pi = si_get_pi(adev);
+       u32 tmp;
+
+       if (!si_pi->fan_ctrl_is_in_default_mode) {
+               tmp = RREG32(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
+               tmp |= FDO_PWM_MODE(si_pi->fan_ctrl_default_mode);
+               WREG32(CG_FDO_CTRL2, tmp);
+
+               tmp = RREG32(CG_FDO_CTRL2) & ~TMIN_MASK;
+               tmp |= TMIN(si_pi->t_min);
+               WREG32(CG_FDO_CTRL2, tmp);
+               si_pi->fan_ctrl_is_in_default_mode = true;
+       }
+}
+
+static void si_thermal_start_smc_fan_control(struct amdgpu_device *adev)
+{
+       if (adev->pm.dpm.fan.ucode_fan_control) {
+               si_fan_ctrl_start_smc_fan_control(adev);
+               si_fan_ctrl_set_static_mode(adev, FDO_PWM_MODE_STATIC);
+       }
+}
+
+static void si_thermal_initialize(struct amdgpu_device *adev)
+{
+       u32 tmp;
+
+       if (adev->pm.fan_pulses_per_revolution) {
+               tmp = RREG32(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK;
+               tmp |= EDGE_PER_REV(adev->pm.fan_pulses_per_revolution -1);
+               WREG32(CG_TACH_CTRL, tmp);
+       }
+
+       tmp = RREG32(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK;
+       tmp |= TACH_PWM_RESP_RATE(0x28);
+       WREG32(CG_FDO_CTRL2, tmp);
+}
+
+static int si_thermal_start_thermal_controller(struct amdgpu_device *adev)
+{
+       int ret;
+
+       si_thermal_initialize(adev);
+       ret = si_thermal_set_temperature_range(adev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+       if (ret)
+               return ret;
+       ret = si_thermal_enable_alert(adev, true);
+       if (ret)
+               return ret;
+       if (adev->pm.dpm.fan.ucode_fan_control) {
+               ret = si_halt_smc(adev);
+               if (ret)
+                       return ret;
+               ret = si_thermal_setup_fan_table(adev);
+               if (ret)
+                       return ret;
+               ret = si_resume_smc(adev);
+               if (ret)
+                       return ret;
+               si_thermal_start_smc_fan_control(adev);
+       }
+
+       return 0;
+}
+
+static void si_thermal_stop_thermal_controller(struct amdgpu_device *adev)
+{
+       if (!adev->pm.no_fan) {
+               si_fan_ctrl_set_default_mode(adev);
+               si_fan_ctrl_stop_smc_fan_control(adev);
+       }
+}
+
+static int si_dpm_enable(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct amdgpu_ps *boot_ps = adev->pm.dpm.boot_ps;
+       int ret;
+
+       if (amdgpu_si_is_smc_running(adev))
+               return -EINVAL;
+       if (pi->voltage_control || si_pi->voltage_control_svi2)
+               si_enable_voltage_control(adev, true);
+       if (pi->mvdd_control)
+               si_get_mvdd_configuration(adev);
+       if (pi->voltage_control || si_pi->voltage_control_svi2) {
+               ret = si_construct_voltage_tables(adev);
+               if (ret) {
+                       DRM_ERROR("si_construct_voltage_tables failed\n");
+                       return ret;
+               }
+       }
+       if (eg_pi->dynamic_ac_timing) {
+               ret = si_initialize_mc_reg_table(adev);
+               if (ret)
+                       eg_pi->dynamic_ac_timing = false;
+       }
+       if (pi->dynamic_ss)
+               si_enable_spread_spectrum(adev, true);
+       if (pi->thermal_protection)
+               si_enable_thermal_protection(adev, true);
+       si_setup_bsp(adev);
+       si_program_git(adev);
+       si_program_tp(adev);
+       si_program_tpp(adev);
+       si_program_sstp(adev);
+       si_enable_display_gap(adev);
+       si_program_vc(adev);
+       ret = si_upload_firmware(adev);
+       if (ret) {
+               DRM_ERROR("si_upload_firmware failed\n");
+               return ret;
+       }
+       ret = si_process_firmware_header(adev);
+       if (ret) {
+               DRM_ERROR("si_process_firmware_header failed\n");
+               return ret;
+       }
+       ret = si_initial_switch_from_arb_f0_to_f1(adev);
+       if (ret) {
+               DRM_ERROR("si_initial_switch_from_arb_f0_to_f1 failed\n");
+               return ret;
+       }
+       ret = si_init_smc_table(adev);
+       if (ret) {
+               DRM_ERROR("si_init_smc_table failed\n");
+               return ret;
+       }
+       ret = si_init_smc_spll_table(adev);
+       if (ret) {
+               DRM_ERROR("si_init_smc_spll_table failed\n");
+               return ret;
+       }
+       ret = si_init_arb_table_index(adev);
+       if (ret) {
+               DRM_ERROR("si_init_arb_table_index failed\n");
+               return ret;
+       }
+       if (eg_pi->dynamic_ac_timing) {
+               ret = si_populate_mc_reg_table(adev, boot_ps);
+               if (ret) {
+                       DRM_ERROR("si_populate_mc_reg_table failed\n");
+                       return ret;
+               }
+       }
+       ret = si_initialize_smc_cac_tables(adev);
+       if (ret) {
+               DRM_ERROR("si_initialize_smc_cac_tables failed\n");
+               return ret;
+       }
+       ret = si_initialize_hardware_cac_manager(adev);
+       if (ret) {
+               DRM_ERROR("si_initialize_hardware_cac_manager failed\n");
+               return ret;
+       }
+       ret = si_initialize_smc_dte_tables(adev);
+       if (ret) {
+               DRM_ERROR("si_initialize_smc_dte_tables failed\n");
+               return ret;
+       }
+       ret = si_populate_smc_tdp_limits(adev, boot_ps);
+       if (ret) {
+               DRM_ERROR("si_populate_smc_tdp_limits failed\n");
+               return ret;
+       }
+       ret = si_populate_smc_tdp_limits_2(adev, boot_ps);
+       if (ret) {
+               DRM_ERROR("si_populate_smc_tdp_limits_2 failed\n");
+               return ret;
+       }
+       si_program_response_times(adev);
+       si_program_ds_registers(adev);
+       si_dpm_start_smc(adev);
+       ret = si_notify_smc_display_change(adev, false);
+       if (ret) {
+               DRM_ERROR("si_notify_smc_display_change failed\n");
+               return ret;
+       }
+       si_enable_sclk_control(adev, true);
+       si_start_dpm(adev);
+
+       si_enable_auto_throttle_source(adev, AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+       si_thermal_start_thermal_controller(adev);
+       ni_update_current_ps(adev, boot_ps);
+
+       return 0;
+}
+
+static int si_set_temperature_range(struct amdgpu_device *adev)
+{
+       int ret;
+
+       ret = si_thermal_enable_alert(adev, false);
+       if (ret)
+               return ret;
+       ret = si_thermal_set_temperature_range(adev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+       if (ret)
+               return ret;
+       ret = si_thermal_enable_alert(adev, true);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static void si_dpm_disable(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct amdgpu_ps *boot_ps = adev->pm.dpm.boot_ps;
+
+       if (!amdgpu_si_is_smc_running(adev))
+               return;
+       si_thermal_stop_thermal_controller(adev);
+       si_disable_ulv(adev);
+       si_clear_vc(adev);
+       if (pi->thermal_protection)
+               si_enable_thermal_protection(adev, false);
+       si_enable_power_containment(adev, boot_ps, false);
+       si_enable_smc_cac(adev, boot_ps, false);
+       si_enable_spread_spectrum(adev, false);
+       si_enable_auto_throttle_source(adev, AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
+       si_stop_dpm(adev);
+       si_reset_to_default(adev);
+       si_dpm_stop_smc(adev);
+       si_force_switch_to_arb_f0(adev);
+
+       ni_update_current_ps(adev, boot_ps);
+}
+
+static int si_dpm_pre_set_power_state(struct amdgpu_device *adev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct amdgpu_ps requested_ps = *adev->pm.dpm.requested_ps;
+       struct amdgpu_ps *new_ps = &requested_ps;
+
+       ni_update_requested_ps(adev, new_ps);
+       si_apply_state_adjust_rules(adev, &eg_pi->requested_rps);
+
+       return 0;
+}
+
+static int si_power_control_set_level(struct amdgpu_device *adev)
+{
+       struct amdgpu_ps *new_ps = adev->pm.dpm.requested_ps;
+       int ret;
+
+       ret = si_restrict_performance_levels_before_switch(adev);
+       if (ret)
+               return ret;
+       ret = si_halt_smc(adev);
+       if (ret)
+               return ret;
+       ret = si_populate_smc_tdp_limits(adev, new_ps);
+       if (ret)
+               return ret;
+       ret = si_populate_smc_tdp_limits_2(adev, new_ps);
+       if (ret)
+               return ret;
+       ret = si_resume_smc(adev);
+       if (ret)
+               return ret;
+       ret = si_set_sw_state(adev);
+       if (ret)
+               return ret;
+       return 0;
+}
+
+static int si_dpm_set_power_state(struct amdgpu_device *adev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct amdgpu_ps *new_ps = &eg_pi->requested_rps;
+       struct amdgpu_ps *old_ps = &eg_pi->current_rps;
+       int ret;
+
+       ret = si_disable_ulv(adev);
+       if (ret) {
+               DRM_ERROR("si_disable_ulv failed\n");
+               return ret;
+       }
+       ret = si_restrict_performance_levels_before_switch(adev);
+       if (ret) {
+               DRM_ERROR("si_restrict_performance_levels_before_switch failed\n");
+               return ret;
+       }
+       if (eg_pi->pcie_performance_request)
+               si_request_link_speed_change_before_state_change(adev, new_ps, old_ps);
+       ni_set_uvd_clock_before_set_eng_clock(adev, new_ps, old_ps);
+       ret = si_enable_power_containment(adev, new_ps, false);
+       if (ret) {
+               DRM_ERROR("si_enable_power_containment failed\n");
+               return ret;
+       }
+       ret = si_enable_smc_cac(adev, new_ps, false);
+       if (ret) {
+               DRM_ERROR("si_enable_smc_cac failed\n");
+               return ret;
+       }
+       ret = si_halt_smc(adev);
+       if (ret) {
+               DRM_ERROR("si_halt_smc failed\n");
+               return ret;
+       }
+       ret = si_upload_sw_state(adev, new_ps);
+       if (ret) {
+               DRM_ERROR("si_upload_sw_state failed\n");
+               return ret;
+       }
+       ret = si_upload_smc_data(adev);
+       if (ret) {
+               DRM_ERROR("si_upload_smc_data failed\n");
+               return ret;
+       }
+       ret = si_upload_ulv_state(adev);
+       if (ret) {
+               DRM_ERROR("si_upload_ulv_state failed\n");
+               return ret;
+       }
+       if (eg_pi->dynamic_ac_timing) {
+               ret = si_upload_mc_reg_table(adev, new_ps);
+               if (ret) {
+                       DRM_ERROR("si_upload_mc_reg_table failed\n");
+                       return ret;
+               }
+       }
+       ret = si_program_memory_timing_parameters(adev, new_ps);
+       if (ret) {
+               DRM_ERROR("si_program_memory_timing_parameters failed\n");
+               return ret;
+       }
+       si_set_pcie_lane_width_in_smc(adev, new_ps, old_ps);
+
+       ret = si_resume_smc(adev);
+       if (ret) {
+               DRM_ERROR("si_resume_smc failed\n");
+               return ret;
+       }
+       ret = si_set_sw_state(adev);
+       if (ret) {
+               DRM_ERROR("si_set_sw_state failed\n");
+               return ret;
+       }
+       ni_set_uvd_clock_after_set_eng_clock(adev, new_ps, old_ps);
+       if (eg_pi->pcie_performance_request)
+               si_notify_link_speed_change_after_state_change(adev, new_ps, old_ps);
+       ret = si_set_power_state_conditionally_enable_ulv(adev, new_ps);
+       if (ret) {
+               DRM_ERROR("si_set_power_state_conditionally_enable_ulv failed\n");
+               return ret;
+       }
+       ret = si_enable_smc_cac(adev, new_ps, true);
+       if (ret) {
+               DRM_ERROR("si_enable_smc_cac failed\n");
+               return ret;
+       }
+       ret = si_enable_power_containment(adev, new_ps, true);
+       if (ret) {
+               DRM_ERROR("si_enable_power_containment failed\n");
+               return ret;
+       }
+
+       ret = si_power_control_set_level(adev);
+       if (ret) {
+               DRM_ERROR("si_power_control_set_level failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void si_dpm_post_set_power_state(struct amdgpu_device *adev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct amdgpu_ps *new_ps = &eg_pi->requested_rps;
+
+       ni_update_current_ps(adev, new_ps);
+}
+
+#if 0
+void si_dpm_reset_asic(struct amdgpu_device *adev)
+{
+       si_restrict_performance_levels_before_switch(adev);
+       si_disable_ulv(adev);
+       si_set_boot_state(adev);
+}
+#endif
+
+static void si_dpm_display_configuration_changed(struct amdgpu_device *adev)
+{
+       si_program_display_gap(adev);
+}
+
+
+static void si_parse_pplib_non_clock_info(struct amdgpu_device *adev,
+                                         struct amdgpu_ps *rps,
+                                         struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+                                         u8 table_rev)
+{
+       rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+       rps->class = le16_to_cpu(non_clock_info->usClassification);
+       rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+       if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
+               rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
+               rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
+       } else if (r600_is_uvd_state(rps->class, rps->class2)) {
+               rps->vclk = RV770_DEFAULT_VCLK_FREQ;
+               rps->dclk = RV770_DEFAULT_DCLK_FREQ;
+       } else {
+               rps->vclk = 0;
+               rps->dclk = 0;
+       }
+
+       if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+               adev->pm.dpm.boot_ps = rps;
+       if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+               adev->pm.dpm.uvd_ps = rps;
+}
+
+static void si_parse_pplib_clock_info(struct amdgpu_device *adev,
+                                     struct amdgpu_ps *rps, int index,
+                                     union pplib_clock_info *clock_info)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(adev);
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct si_power_info *si_pi = si_get_pi(adev);
+       struct  si_ps *ps = si_get_ps(rps);
+       u16 leakage_voltage;
+       struct rv7xx_pl *pl = &ps->performance_levels[index];
+       int ret;
+
+       ps->performance_level_count = index + 1;
+
+       pl->sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
+       pl->sclk |= clock_info->si.ucEngineClockHigh << 16;
+       pl->mclk = le16_to_cpu(clock_info->si.usMemoryClockLow);
+       pl->mclk |= clock_info->si.ucMemoryClockHigh << 16;
+
+       pl->vddc = le16_to_cpu(clock_info->si.usVDDC);
+       pl->vddci = le16_to_cpu(clock_info->si.usVDDCI);
+       pl->flags = le32_to_cpu(clock_info->si.ulFlags);
+       pl->pcie_gen = r600_get_pcie_gen_support(adev,
+                                                si_pi->sys_pcie_mask,
+                                                si_pi->boot_pcie_gen,
+                                                clock_info->si.ucPCIEGen);
+
+       /* patch up vddc if necessary */
+       ret = si_get_leakage_voltage_from_leakage_index(adev, pl->vddc,
+                                                       &leakage_voltage);
+       if (ret == 0)
+               pl->vddc = leakage_voltage;
+
+       if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
+               pi->acpi_vddc = pl->vddc;
+               eg_pi->acpi_vddci = pl->vddci;
+               si_pi->acpi_pcie_gen = pl->pcie_gen;
+       }
+
+       if ((rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) &&
+           index == 0) {
+               /* XXX disable for A0 tahiti */
+               si_pi->ulv.supported = false;
+               si_pi->ulv.pl = *pl;
+               si_pi->ulv.one_pcie_lane_in_ulv = false;
+               si_pi->ulv.volt_change_delay = SISLANDS_ULVVOLTAGECHANGEDELAY_DFLT;
+               si_pi->ulv.cg_ulv_parameter = SISLANDS_CGULVPARAMETER_DFLT;
+               si_pi->ulv.cg_ulv_control = SISLANDS_CGULVCONTROL_DFLT;
+       }
+
+       if (pi->min_vddc_in_table > pl->vddc)
+               pi->min_vddc_in_table = pl->vddc;
+
+       if (pi->max_vddc_in_table < pl->vddc)
+               pi->max_vddc_in_table = pl->vddc;
+
+       /* patch up boot state */
+       if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+               u16 vddc, vddci, mvdd;
+               amdgpu_atombios_get_default_voltages(adev, &vddc, &vddci, &mvdd);
+               pl->mclk = adev->clock.default_mclk;
+               pl->sclk = adev->clock.default_sclk;
+               pl->vddc = vddc;
+               pl->vddci = vddci;
+               si_pi->mvdd_bootup_value = mvdd;
+       }
+
+       if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
+           ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
+               adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
+               adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
+               adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
+               adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
+       }
+}
+
+union pplib_power_state {
+       struct _ATOM_PPLIB_STATE v1;
+       struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static int si_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  si_ps *ps;
+
+       if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+                                  &frev, &crev, &data_offset))
+               return -EINVAL;
+       power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+       amdgpu_add_thermal_controller(adev);
+
+       state_array = (struct _StateArray *)
+               (mode_info->atom_context->bios + data_offset +
+                le16_to_cpu(power_info->pplib.usStateArrayOffset));
+       clock_info_array = (struct _ClockInfoArray *)
+               (mode_info->atom_context->bios + data_offset +
+                le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
+       non_clock_info_array = (struct _NonClockInfoArray *)
+               (mode_info->atom_context->bios + data_offset +
+                le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
+
+       adev->pm.dpm.ps = kzalloc(sizeof(struct amdgpu_ps) *
+                                 state_array->ucNumEntries, GFP_KERNEL);
+       if (!adev->pm.dpm.ps)
+               return -ENOMEM;
+       power_state_offset = (u8 *)state_array->states;
+       for (i = 0; i < state_array->ucNumEntries; i++) {
+               u8 *idx;
+               power_state = (union pplib_power_state *)power_state_offset;
+               non_clock_array_index = power_state->v2.nonClockInfoIndex;
+               non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+                       &non_clock_info_array->nonClockInfo[non_clock_array_index];
+               ps = kzalloc(sizeof(struct  si_ps), GFP_KERNEL);
+               if (ps == NULL) {
+                       kfree(adev->pm.dpm.ps);
+                       return -ENOMEM;
+               }
+               adev->pm.dpm.ps[i].ps_priv = ps;
+               si_parse_pplib_non_clock_info(adev, &adev->pm.dpm.ps[i],
+                                             non_clock_info,
+                                             non_clock_info_array->ucEntrySize);
+               k = 0;
+               idx = (u8 *)&power_state->v2.clockInfoIndex[0];
+               for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
+                       clock_array_index = idx[j];
+                       if (clock_array_index >= clock_info_array->ucNumEntries)
+                               continue;
+                       if (k >= SISLANDS_MAX_HARDWARE_POWERLEVELS)
+                               break;
+                       clock_info = (union pplib_clock_info *)
+                               ((u8 *)&clock_info_array->clockInfo[0] +
+                                (clock_array_index * clock_info_array->ucEntrySize));
+                       si_parse_pplib_clock_info(adev,
+                                                 &adev->pm.dpm.ps[i], k,
+                                                 clock_info);
+                       k++;
+               }
+               power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+       }
+       adev->pm.dpm.num_ps = state_array->ucNumEntries;
+
+       /* fill in the vce power states */
+       for (i = 0; i < AMDGPU_MAX_VCE_LEVELS; i++) {
+               u32 sclk, mclk;
+               clock_array_index = adev->pm.dpm.vce_states[i].clk_idx;
+               clock_info = (union pplib_clock_info *)
+                       &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+               sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
+               sclk |= clock_info->si.ucEngineClockHigh << 16;
+               mclk = le16_to_cpu(clock_info->si.usMemoryClockLow);
+               mclk |= clock_info->si.ucMemoryClockHigh << 16;
+               adev->pm.dpm.vce_states[i].sclk = sclk;
+               adev->pm.dpm.vce_states[i].mclk = mclk;
+       }
+
+       return 0;
+}
+
+static int si_dpm_init(struct amdgpu_device *adev)
+{
+       struct rv7xx_power_info *pi;
+       struct evergreen_power_info *eg_pi;
+       struct ni_power_info *ni_pi;
+       struct si_power_info *si_pi;
+       struct atom_clock_dividers dividers;
+       int ret;
+       u32 mask;
+
+       si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL);
+       if (si_pi == NULL)
+               return -ENOMEM;
+       adev->pm.dpm.priv = si_pi;
+       ni_pi = &si_pi->ni;
+       eg_pi = &ni_pi->eg;
+       pi = &eg_pi->rv7xx;
+
+       ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
+       if (ret)
+               si_pi->sys_pcie_mask = 0;
+       else
+               si_pi->sys_pcie_mask = mask;
+       si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID;
+       si_pi->boot_pcie_gen = si_get_current_pcie_speed(adev);
+
+       si_set_max_cu_value(adev);
+
+       rv770_get_max_vddc(adev);
+       si_get_leakage_vddc(adev);
+       si_patch_dependency_tables_based_on_leakage(adev);
+
+       pi->acpi_vddc = 0;
+       eg_pi->acpi_vddci = 0;
+       pi->min_vddc_in_table = 0;
+       pi->max_vddc_in_table = 0;
+
+       ret = amdgpu_get_platform_caps(adev);
+       if (ret)
+               return ret;
+
+       ret = amdgpu_parse_extended_power_table(adev);
+       if (ret)
+               return ret;
+
+       ret = si_parse_power_table(adev);
+       if (ret)
+               return ret;
+
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries =
+               kzalloc(4 * sizeof(struct amdgpu_clock_voltage_dependency_entry), GFP_KERNEL);
+       if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) {
+               amdgpu_free_extended_power_table(adev);
+               return -ENOMEM;
+       }
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4;
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0;
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0;
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000;
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720;
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000;
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810;
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000;
+       adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900;
+
+       if (adev->pm.dpm.voltage_response_time == 0)
+               adev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+       if (adev->pm.dpm.backbias_response_time == 0)
+               adev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+       ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_ENGINE_PLL_PARAM,
+                                            0, false, &dividers);
+       if (ret)
+               pi->ref_div = dividers.ref_div + 1;
+       else
+               pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+       eg_pi->smu_uvd_hs = false;
+
+       pi->mclk_strobe_mode_threshold = 40000;
+       if (si_is_special_1gb_platform(adev))
+               pi->mclk_stutter_mode_threshold = 0;
+       else
+               pi->mclk_stutter_mode_threshold = pi->mclk_strobe_mode_threshold;
+       pi->mclk_edc_enable_threshold = 40000;
+       eg_pi->mclk_edc_wr_enable_threshold = 40000;
+
+       ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold;
+
+       pi->voltage_control =
+               amdgpu_atombios_is_voltage_gpio(adev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+                                           VOLTAGE_OBJ_GPIO_LUT);
+       if (!pi->voltage_control) {
+               si_pi->voltage_control_svi2 =
+                       amdgpu_atombios_is_voltage_gpio(adev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+                                                   VOLTAGE_OBJ_SVID2);
+               if (si_pi->voltage_control_svi2)
+                       amdgpu_atombios_get_svi2_info(adev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+                                                 &si_pi->svd_gpio_id, &si_pi->svc_gpio_id);
+       }
+
+       pi->mvdd_control =
+               amdgpu_atombios_is_voltage_gpio(adev, SET_VOLTAGE_TYPE_ASIC_MVDDC,
+                                           VOLTAGE_OBJ_GPIO_LUT);
+
+       eg_pi->vddci_control =
+               amdgpu_atombios_is_voltage_gpio(adev, SET_VOLTAGE_TYPE_ASIC_VDDCI,
+                                           VOLTAGE_OBJ_GPIO_LUT);
+       if (!eg_pi->vddci_control)
+               si_pi->vddci_control_svi2 =
+                       amdgpu_atombios_is_voltage_gpio(adev, SET_VOLTAGE_TYPE_ASIC_VDDCI,
+                                                   VOLTAGE_OBJ_SVID2);
+
+       si_pi->vddc_phase_shed_control =
+               amdgpu_atombios_is_voltage_gpio(adev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+                                           VOLTAGE_OBJ_PHASE_LUT);
+
+       rv770_get_engine_memory_ss(adev);
+
+       pi->asi = RV770_ASI_DFLT;
+       pi->pasi = CYPRESS_HASI_DFLT;
+       pi->vrc = SISLANDS_VRC_DFLT;
+
+       pi->gfx_clock_gating = true;
+
+       eg_pi->sclk_deep_sleep = true;
+       si_pi->sclk_deep_sleep_above_low = false;
+
+       if (adev->pm.int_thermal_type != THERMAL_TYPE_NONE)
+               pi->thermal_protection = true;
+       else
+               pi->thermal_protection = false;
+
+       eg_pi->dynamic_ac_timing = true;
+
+       eg_pi->light_sleep = true;
+#if defined(CONFIG_ACPI)
+       eg_pi->pcie_performance_request =
+               amdgpu_acpi_is_pcie_performance_request_supported(adev);
+#else
+       eg_pi->pcie_performance_request = false;
+#endif
+
+       si_pi->sram_end = SMC_RAM_END;
+
+       adev->pm.dpm.dyn_state.mclk_sclk_ratio = 4;
+       adev->pm.dpm.dyn_state.sclk_mclk_delta = 15000;
+       adev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
+       adev->pm.dpm.dyn_state.valid_sclk_values.count = 0;
+       adev->pm.dpm.dyn_state.valid_sclk_values.values = NULL;
+       adev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
+       adev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
+
+       si_initialize_powertune_defaults(adev);
+
+       /* make sure dc limits are valid */
+       if ((adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) ||
+           (adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk == 0))
+               adev->pm.dpm.dyn_state.max_clock_voltage_on_dc =
+                       adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+
+       si_pi->fan_ctrl_is_in_default_mode = true;
+
+       return 0;
+}
+
+static void si_dpm_fini(struct amdgpu_device *adev)
+{
+       int i;
+
+       if (adev->pm.dpm.ps)
+               for (i = 0; i < adev->pm.dpm.num_ps; i++)
+                       kfree(adev->pm.dpm.ps[i].ps_priv);
+       kfree(adev->pm.dpm.ps);
+       kfree(adev->pm.dpm.priv);
+       kfree(adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries);
+       amdgpu_free_extended_power_table(adev);
+}
+
+static void si_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
+                                                   struct seq_file *m)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct amdgpu_ps *rps = &eg_pi->current_rps;
+       struct  si_ps *ps = si_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               seq_printf(m, "invalid dpm profile %d\n", current_index);
+       } else {
+               pl = &ps->performance_levels[current_index];
+               seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+               seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n",
+                          current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
+       }
+}
+
+static int si_dpm_set_interrupt_state(struct amdgpu_device *adev,
+                                     struct amdgpu_irq_src *source,
+                                     unsigned type,
+                                     enum amdgpu_interrupt_state state)
+{
+       u32 cg_thermal_int;
+
+       switch (type) {
+       case AMDGPU_THERMAL_IRQ_LOW_TO_HIGH:
+               switch (state) {
+               case AMDGPU_IRQ_STATE_DISABLE:
+                       cg_thermal_int = RREG32_SMC(CG_THERMAL_INT);
+                       cg_thermal_int |= THERM_INT_MASK_HIGH;
+                       WREG32_SMC(CG_THERMAL_INT, cg_thermal_int);
+                       break;
+               case AMDGPU_IRQ_STATE_ENABLE:
+                       cg_thermal_int = RREG32_SMC(CG_THERMAL_INT);
+                       cg_thermal_int &= ~THERM_INT_MASK_HIGH;
+                       WREG32_SMC(CG_THERMAL_INT, cg_thermal_int);
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case AMDGPU_THERMAL_IRQ_HIGH_TO_LOW:
+               switch (state) {
+               case AMDGPU_IRQ_STATE_DISABLE:
+                       cg_thermal_int = RREG32_SMC(CG_THERMAL_INT);
+                       cg_thermal_int |= THERM_INT_MASK_LOW;
+                       WREG32_SMC(CG_THERMAL_INT, cg_thermal_int);
+                       break;
+               case AMDGPU_IRQ_STATE_ENABLE:
+                       cg_thermal_int = RREG32_SMC(CG_THERMAL_INT);
+                       cg_thermal_int &= ~THERM_INT_MASK_LOW;
+                       WREG32_SMC(CG_THERMAL_INT, cg_thermal_int);
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int si_dpm_process_interrupt(struct amdgpu_device *adev,
+                                   struct amdgpu_irq_src *source,
+                                   struct amdgpu_iv_entry *entry)
+{
+       bool queue_thermal = false;
+
+       if (entry == NULL)
+               return -EINVAL;
+
+       switch (entry->src_id) {
+       case 230: /* thermal low to high */
+               DRM_DEBUG("IH: thermal low to high\n");
+               adev->pm.dpm.thermal.high_to_low = false;
+               queue_thermal = true;
+               break;
+       case 231: /* thermal high to low */
+               DRM_DEBUG("IH: thermal high to low\n");
+               adev->pm.dpm.thermal.high_to_low = true;
+               queue_thermal = true;
+               break;
+       default:
+               break;
+       }
+
+       if (queue_thermal)
+               schedule_work(&adev->pm.dpm.thermal.work);
+
+       return 0;
+}
+
+static int si_dpm_late_init(void *handle)
+{
+       int ret;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!amdgpu_dpm)
+               return 0;
+
+       /* init the sysfs and debugfs files late */
+       ret = amdgpu_pm_sysfs_init(adev);
+       if (ret)
+               return ret;
+
+       ret = si_set_temperature_range(adev);
+       if (ret)
+               return ret;
+#if 0 //TODO ?
+       si_dpm_powergate_uvd(adev, true);
+#endif
+       return 0;
+}
+
+/**
+ * si_dpm_init_microcode - load ucode images from disk
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Use the firmware interface to load the ucode images into
+ * the driver (not loaded into hw).
+ * Returns 0 on success, error on failure.
+ */
+static int si_dpm_init_microcode(struct amdgpu_device *adev)
+{
+       const char *chip_name;
+       char fw_name[30];
+       int err;
+
+       DRM_DEBUG("\n");
+       switch (adev->asic_type) {
+       case CHIP_TAHITI:
+               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))
+                       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))
+                       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->device == 0x6604) ||
+                   (adev->pdev->device == 0x6605))
+                       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))
+                       chip_name = "hainan_k";
+               else
+                       chip_name = "hainan";
+               break;
+       default: BUG();
+       }
+
+       snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
+       err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
+       if (err)
+               goto out;
+       err = amdgpu_ucode_validate(adev->pm.fw);
+
+out:
+       if (err) {
+               DRM_ERROR("si_smc: Failed to load firmware. err = %d\"%s\"\n",
+                         err, fw_name);
+               release_firmware(adev->pm.fw);
+               adev->pm.fw = NULL;
+       }
+       return err;
+
+}
+
+static int si_dpm_sw_init(void *handle)
+{
+       int ret;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       ret = amdgpu_irq_add_id(adev, 230, &adev->pm.dpm.thermal.irq);
+       if (ret)
+               return ret;
+
+       ret = amdgpu_irq_add_id(adev, 231, &adev->pm.dpm.thermal.irq);
+       if (ret)
+               return ret;
+
+       /* default to balanced state */
+       adev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
+       adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+       adev->pm.dpm.forced_level = 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;
+
+       ret = si_dpm_init_microcode(adev);
+       if (ret)
+               return ret;
+
+       INIT_WORK(&adev->pm.dpm.thermal.work, amdgpu_dpm_thermal_work_handler);
+       mutex_lock(&adev->pm.mutex);
+       ret = si_dpm_init(adev);
+       if (ret)
+               goto dpm_failed;
+       adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;
+       if (amdgpu_dpm == 1)
+               amdgpu_pm_print_power_states(adev);
+       mutex_unlock(&adev->pm.mutex);
+       DRM_INFO("amdgpu: dpm initialized\n");
+
+       return 0;
+
+dpm_failed:
+       si_dpm_fini(adev);
+       mutex_unlock(&adev->pm.mutex);
+       DRM_ERROR("amdgpu: dpm initialization failed\n");
+       return ret;
+}
+
+static int si_dpm_sw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       mutex_lock(&adev->pm.mutex);
+       amdgpu_pm_sysfs_fini(adev);
+       si_dpm_fini(adev);
+       mutex_unlock(&adev->pm.mutex);
+
+       return 0;
+}
+
+static int si_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);
+       si_dpm_setup_asic(adev);
+       ret = si_dpm_enable(adev);
+       if (ret)
+               adev->pm.dpm_enabled = false;
+       else
+               adev->pm.dpm_enabled = true;
+       mutex_unlock(&adev->pm.mutex);
+
+       return ret;
+}
+
+static int si_dpm_hw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (adev->pm.dpm_enabled) {
+               mutex_lock(&adev->pm.mutex);
+               si_dpm_disable(adev);
+               mutex_unlock(&adev->pm.mutex);
+       }
+
+       return 0;
+}
+
+static int si_dpm_suspend(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (adev->pm.dpm_enabled) {
+               mutex_lock(&adev->pm.mutex);
+               /* disable dpm */
+               si_dpm_disable(adev);
+               /* reset the power state */
+               adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;
+               mutex_unlock(&adev->pm.mutex);
+       }
+       return 0;
+}
+
+static int si_dpm_resume(void *handle)
+{
+       int ret;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (adev->pm.dpm_enabled) {
+               /* asic init will reset to the boot state */
+               mutex_lock(&adev->pm.mutex);
+               si_dpm_setup_asic(adev);
+               ret = si_dpm_enable(adev);
+               if (ret)
+                       adev->pm.dpm_enabled = false;
+               else
+                       adev->pm.dpm_enabled = true;
+               mutex_unlock(&adev->pm.mutex);
+               if (adev->pm.dpm_enabled)
+                       amdgpu_pm_compute_clocks(adev);
+       }
+       return 0;
+}
+
+static bool si_dpm_is_idle(void *handle)
+{
+       /* XXX */
+       return true;
+}
+
+static int si_dpm_wait_for_idle(void *handle)
+{
+       /* XXX */
+       return 0;
+}
+
+static int si_dpm_soft_reset(void *handle)
+{
+       return 0;
+}
+
+static int si_dpm_set_clockgating_state(void *handle,
+                                       enum amd_clockgating_state state)
+{
+       return 0;
+}
+
+static int si_dpm_set_powergating_state(void *handle,
+                                       enum amd_powergating_state state)
+{
+       return 0;
+}
+
+/* get temperature in millidegrees */
+static int si_dpm_get_temp(struct amdgpu_device *adev)
+{
+       u32 temp;
+       int actual_temp = 0;
+
+       temp = (RREG32(CG_MULT_THERMAL_STATUS) & CTF_TEMP_MASK) >>
+               CTF_TEMP_SHIFT;
+
+       if (temp & 0x200)
+               actual_temp = 255;
+       else
+               actual_temp = temp & 0x1ff;
+
+       actual_temp = (actual_temp * 1000);
+
+       return actual_temp;
+}
+
+static u32 si_dpm_get_sclk(struct amdgpu_device *adev, bool low)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct  si_ps *requested_state = si_get_ps(&eg_pi->requested_rps);
+
+       if (low)
+               return requested_state->performance_levels[0].sclk;
+       else
+               return requested_state->performance_levels[requested_state->performance_level_count - 1].sclk;
+}
+
+static u32 si_dpm_get_mclk(struct amdgpu_device *adev, bool low)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
+       struct  si_ps *requested_state = si_get_ps(&eg_pi->requested_rps);
+
+       if (low)
+               return requested_state->performance_levels[0].mclk;
+       else
+               return requested_state->performance_levels[requested_state->performance_level_count - 1].mclk;
+}
+
+static void si_dpm_print_power_state(struct amdgpu_device *adev,
+                                    struct amdgpu_ps *rps)
+{
+       struct  si_ps *ps = si_get_ps(rps);
+       struct rv7xx_pl *pl;
+       int i;
+
+       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->performance_level_count; i++) {
+               pl = &ps->performance_levels[i];
+               if (adev->asic_type >= CHIP_TAHITI)
+                       DRM_INFO("\t\tpower level %d    sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n",
+                                i, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
+               else
+                       DRM_INFO("\t\tpower level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+                                i, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+       }
+       amdgpu_dpm_print_ps_status(adev, rps);
+}
+
+static int si_dpm_early_init(void *handle)
+{
+
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       si_dpm_set_dpm_funcs(adev);
+       si_dpm_set_irq_funcs(adev);
+       return 0;
+}
+
+
+const struct amd_ip_funcs si_dpm_ip_funcs = {
+       .name = "si_dpm",
+       .early_init = si_dpm_early_init,
+       .late_init = si_dpm_late_init,
+       .sw_init = si_dpm_sw_init,
+       .sw_fini = si_dpm_sw_fini,
+       .hw_init = si_dpm_hw_init,
+       .hw_fini = si_dpm_hw_fini,
+       .suspend = si_dpm_suspend,
+       .resume = si_dpm_resume,
+       .is_idle = si_dpm_is_idle,
+       .wait_for_idle = si_dpm_wait_for_idle,
+       .soft_reset = si_dpm_soft_reset,
+       .set_clockgating_state = si_dpm_set_clockgating_state,
+       .set_powergating_state = si_dpm_set_powergating_state,
+};
+
+static const struct amdgpu_dpm_funcs si_dpm_funcs = {
+       .get_temperature = &si_dpm_get_temp,
+       .pre_set_power_state = &si_dpm_pre_set_power_state,
+       .set_power_state = &si_dpm_set_power_state,
+       .post_set_power_state = &si_dpm_post_set_power_state,
+       .display_configuration_changed = &si_dpm_display_configuration_changed,
+       .get_sclk = &si_dpm_get_sclk,
+       .get_mclk = &si_dpm_get_mclk,
+       .print_power_state = &si_dpm_print_power_state,
+       .debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level,
+       .force_performance_level = &si_dpm_force_performance_level,
+       .vblank_too_short = &si_dpm_vblank_too_short,
+       .set_fan_control_mode = &si_dpm_set_fan_control_mode,
+       .get_fan_control_mode = &si_dpm_get_fan_control_mode,
+       .set_fan_speed_percent = &si_dpm_set_fan_speed_percent,
+       .get_fan_speed_percent = &si_dpm_get_fan_speed_percent,
+};
+
+static void si_dpm_set_dpm_funcs(struct amdgpu_device *adev)
+{
+       if (adev->pm.funcs == NULL)
+               adev->pm.funcs = &si_dpm_funcs;
+}
+
+static const struct amdgpu_irq_src_funcs si_dpm_irq_funcs = {
+       .set = si_dpm_set_interrupt_state,
+       .process = si_dpm_process_interrupt,
+};
+
+static void si_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 = &si_dpm_irq_funcs;
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.h b/drivers/gpu/drm/amd/amdgpu/si_dpm.h
new file mode 100644 (file)
index 0000000..51ce21c
--- /dev/null
@@ -0,0 +1,1015 @@
+/*
+ * Copyright 2012 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 __SI_DPM_H__
+#define __SI_DPM_H__
+
+#include "amdgpu_atombios.h"
+#include "sislands_smc.h"
+
+#define MC_CG_CONFIG                                    0x96f
+#define MC_ARB_CG                                       0x9fa
+#define                CG_ARB_REQ(x)                           ((x) << 0)
+#define                CG_ARB_REQ_MASK                         (0xff << 0)
+
+#define        MC_ARB_DRAM_TIMING_1                            0x9fc
+#define        MC_ARB_DRAM_TIMING_2                            0x9fd
+#define        MC_ARB_DRAM_TIMING_3                            0x9fe
+#define        MC_ARB_DRAM_TIMING2_1                           0x9ff
+#define        MC_ARB_DRAM_TIMING2_2                           0xa00
+#define        MC_ARB_DRAM_TIMING2_3                           0xa01
+
+#define MAX_NO_OF_MVDD_VALUES 2
+#define MAX_NO_VREG_STEPS 32
+#define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16
+#define SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE 32
+#define SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20
+#define RV770_ASI_DFLT                                1000
+#define CYPRESS_HASI_DFLT                               400000
+#define PCIE_PERF_REQ_PECI_GEN1         2
+#define PCIE_PERF_REQ_PECI_GEN2         3
+#define PCIE_PERF_REQ_PECI_GEN3         4
+#define RV770_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
+#define RV770_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
+
+#define SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE 16
+
+#define RV770_SMC_TABLE_ADDRESS 0xB000
+#define RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE    3
+
+#define SMC_STROBE_RATIO    0x0F
+#define SMC_STROBE_ENABLE   0x10
+
+#define SMC_MC_EDC_RD_FLAG  0x01
+#define SMC_MC_EDC_WR_FLAG  0x02
+#define SMC_MC_RTT_ENABLE   0x04
+#define SMC_MC_STUTTER_EN   0x08
+
+#define RV770_SMC_VOLTAGEMASK_VDDC 0
+#define RV770_SMC_VOLTAGEMASK_MVDD 1
+#define RV770_SMC_VOLTAGEMASK_VDDCI 2
+#define RV770_SMC_VOLTAGEMASK_MAX  4
+
+#define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16
+#define NISLANDS_SMC_STROBE_RATIO    0x0F
+#define NISLANDS_SMC_STROBE_ENABLE   0x10
+
+#define NISLANDS_SMC_MC_EDC_RD_FLAG  0x01
+#define NISLANDS_SMC_MC_EDC_WR_FLAG  0x02
+#define NISLANDS_SMC_MC_RTT_ENABLE   0x04
+#define NISLANDS_SMC_MC_STUTTER_EN   0x08
+
+#define MAX_NO_VREG_STEPS 32
+
+#define NISLANDS_SMC_VOLTAGEMASK_VDDC  0
+#define NISLANDS_SMC_VOLTAGEMASK_MVDD  1
+#define NISLANDS_SMC_VOLTAGEMASK_VDDCI 2
+#define NISLANDS_SMC_VOLTAGEMASK_MAX   4
+
+#define SISLANDS_MCREGISTERTABLE_INITIAL_SLOT               0
+#define SISLANDS_MCREGISTERTABLE_ACPI_SLOT                  1
+#define SISLANDS_MCREGISTERTABLE_ULV_SLOT                   2
+#define SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT     3
+
+#define SISLANDS_LEAKAGE_INDEX0     0xff01
+#define SISLANDS_MAX_LEAKAGE_COUNT  4
+
+#define SISLANDS_MAX_HARDWARE_POWERLEVELS 5
+#define SISLANDS_INITIAL_STATE_ARB_INDEX    0
+#define SISLANDS_ACPI_STATE_ARB_INDEX       1
+#define SISLANDS_ULV_STATE_ARB_INDEX        2
+#define SISLANDS_DRIVER_STATE_ARB_INDEX     3
+
+#define SISLANDS_DPM2_MAX_PULSE_SKIP        256
+
+#define SISLANDS_DPM2_NEAR_TDP_DEC          10
+#define SISLANDS_DPM2_ABOVE_SAFE_INC        5
+#define SISLANDS_DPM2_BELOW_SAFE_INC        20
+
+#define SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT            80
+
+#define SISLANDS_DPM2_MAXPS_PERCENT_H                   99
+#define SISLANDS_DPM2_MAXPS_PERCENT_M                   99
+
+#define SISLANDS_DPM2_SQ_RAMP_MAX_POWER                 0x3FFF
+#define SISLANDS_DPM2_SQ_RAMP_MIN_POWER                 0x12
+#define SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA           0x15
+#define SISLANDS_DPM2_SQ_RAMP_STI_SIZE                  0x1E
+#define SISLANDS_DPM2_SQ_RAMP_LTI_RATIO                 0xF
+
+#define SISLANDS_DPM2_PWREFFICIENCYRATIO_MARGIN         10
+
+#define SISLANDS_VRC_DFLT                               0xC000B3
+#define SISLANDS_ULVVOLTAGECHANGEDELAY_DFLT             1687
+#define SISLANDS_CGULVPARAMETER_DFLT                    0x00040035
+#define SISLANDS_CGULVCONTROL_DFLT                      0x1f007550
+
+#define SI_ASI_DFLT                                10000
+#define SI_BSP_DFLT                                0x41EB
+#define SI_BSU_DFLT                                0x2
+#define SI_AH_DFLT                                 5
+#define SI_RLP_DFLT                                25
+#define SI_RMP_DFLT                                65
+#define SI_LHP_DFLT                                40
+#define SI_LMP_DFLT                                15
+#define SI_TD_DFLT                                 0
+#define SI_UTC_DFLT_00                             0x24
+#define SI_UTC_DFLT_01                             0x22
+#define SI_UTC_DFLT_02                             0x22
+#define SI_UTC_DFLT_03                             0x22
+#define SI_UTC_DFLT_04                             0x22
+#define SI_UTC_DFLT_05                             0x22
+#define SI_UTC_DFLT_06                             0x22
+#define SI_UTC_DFLT_07                             0x22
+#define SI_UTC_DFLT_08                             0x22
+#define SI_UTC_DFLT_09                             0x22
+#define SI_UTC_DFLT_10                             0x22
+#define SI_UTC_DFLT_11                             0x22
+#define SI_UTC_DFLT_12                             0x22
+#define SI_UTC_DFLT_13                             0x22
+#define SI_UTC_DFLT_14                             0x22
+#define SI_DTC_DFLT_00                             0x24
+#define SI_DTC_DFLT_01                             0x22
+#define SI_DTC_DFLT_02                             0x22
+#define SI_DTC_DFLT_03                             0x22
+#define SI_DTC_DFLT_04                             0x22
+#define SI_DTC_DFLT_05                             0x22
+#define SI_DTC_DFLT_06                             0x22
+#define SI_DTC_DFLT_07                             0x22
+#define SI_DTC_DFLT_08                             0x22
+#define SI_DTC_DFLT_09                             0x22
+#define SI_DTC_DFLT_10                             0x22
+#define SI_DTC_DFLT_11                             0x22
+#define SI_DTC_DFLT_12                             0x22
+#define SI_DTC_DFLT_13                             0x22
+#define SI_DTC_DFLT_14                             0x22
+#define SI_VRC_DFLT                                0x0000C003
+#define SI_VOLTAGERESPONSETIME_DFLT                1000
+#define SI_BACKBIASRESPONSETIME_DFLT               1000
+#define SI_VRU_DFLT                                0x3
+#define SI_SPLLSTEPTIME_DFLT                       0x1000
+#define SI_SPLLSTEPUNIT_DFLT                       0x3
+#define SI_TPU_DFLT                                0
+#define SI_TPC_DFLT                                0x200
+#define SI_SSTU_DFLT                               0
+#define SI_SST_DFLT                                0x00C8
+#define SI_GICST_DFLT                              0x200
+#define SI_FCT_DFLT                                0x0400
+#define SI_FCTU_DFLT                               0
+#define SI_CTXCGTT3DRPHC_DFLT                      0x20
+#define SI_CTXCGTT3DRSDC_DFLT                      0x40
+#define SI_VDDC3DOORPHC_DFLT                       0x100
+#define SI_VDDC3DOORSDC_DFLT                       0x7
+#define SI_VDDC3DOORSU_DFLT                        0
+#define SI_MPLLLOCKTIME_DFLT                       100
+#define SI_MPLLRESETTIME_DFLT                      150
+#define SI_VCOSTEPPCT_DFLT                          20
+#define SI_ENDINGVCOSTEPPCT_DFLT                    5
+#define SI_REFERENCEDIVIDER_DFLT                    4
+
+#define SI_PM_NUMBER_OF_TC 15
+#define SI_PM_NUMBER_OF_SCLKS 20
+#define SI_PM_NUMBER_OF_MCLKS 4
+#define SI_PM_NUMBER_OF_VOLTAGE_LEVELS 4
+#define SI_PM_NUMBER_OF_ACTIVITY_LEVELS 3
+
+/* XXX are these ok? */
+#define SI_TEMP_RANGE_MIN (90 * 1000)
+#define SI_TEMP_RANGE_MAX (120 * 1000)
+
+#define FDO_PWM_MODE_STATIC  1
+#define FDO_PWM_MODE_STATIC_RPM 5
+
+enum ni_dc_cac_level
+{
+       NISLANDS_DCCAC_LEVEL_0 = 0,
+       NISLANDS_DCCAC_LEVEL_1,
+       NISLANDS_DCCAC_LEVEL_2,
+       NISLANDS_DCCAC_LEVEL_3,
+       NISLANDS_DCCAC_LEVEL_4,
+       NISLANDS_DCCAC_LEVEL_5,
+       NISLANDS_DCCAC_LEVEL_6,
+       NISLANDS_DCCAC_LEVEL_7,
+       NISLANDS_DCCAC_MAX_LEVELS
+};
+
+enum si_cac_config_reg_type
+{
+       SISLANDS_CACCONFIG_MMR = 0,
+       SISLANDS_CACCONFIG_CGIND,
+       SISLANDS_CACCONFIG_MAX
+};
+
+enum si_power_level {
+       SI_POWER_LEVEL_LOW = 0,
+       SI_POWER_LEVEL_MEDIUM = 1,
+       SI_POWER_LEVEL_HIGH = 2,
+       SI_POWER_LEVEL_CTXSW = 3,
+};
+
+enum si_td {
+       SI_TD_AUTO,
+       SI_TD_UP,
+       SI_TD_DOWN,
+};
+
+enum si_display_watermark {
+       SI_DISPLAY_WATERMARK_LOW = 0,
+       SI_DISPLAY_WATERMARK_HIGH = 1,
+};
+
+enum si_display_gap
+{
+    SI_PM_DISPLAY_GAP_VBLANK_OR_WM = 0,
+    SI_PM_DISPLAY_GAP_VBLANK       = 1,
+    SI_PM_DISPLAY_GAP_WATERMARK    = 2,
+    SI_PM_DISPLAY_GAP_IGNORE       = 3,
+};
+
+extern const struct amd_ip_funcs si_dpm_ip_funcs;
+
+struct ni_leakage_coeffients
+{
+       u32 at;
+       u32 bt;
+       u32 av;
+       u32 bv;
+       s32 t_slope;
+       s32 t_intercept;
+       u32 t_ref;
+};
+
+struct SMC_Evergreen_MCRegisterAddress
+{
+    uint16_t s0;
+    uint16_t s1;
+};
+
+typedef struct SMC_Evergreen_MCRegisterAddress SMC_Evergreen_MCRegisterAddress;
+
+struct evergreen_mc_reg_entry {
+       u32 mclk_max;
+       u32 mc_data[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct evergreen_mc_reg_table {
+       u8 last;
+       u8 num_entries;
+       u16 valid_flag;
+       struct evergreen_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+       SMC_Evergreen_MCRegisterAddress mc_reg_address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct SMC_Evergreen_MCRegisterSet
+{
+    uint32_t value[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMC_Evergreen_MCRegisterSet SMC_Evergreen_MCRegisterSet;
+
+struct SMC_Evergreen_MCRegisters
+{
+    uint8_t                             last;
+    uint8_t                             reserved[3];
+    SMC_Evergreen_MCRegisterAddress     address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+    SMC_Evergreen_MCRegisterSet         data[5];
+};
+
+typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;
+
+struct SMC_NIslands_MCRegisterSet
+{
+    uint32_t value[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMC_NIslands_MCRegisterSet SMC_NIslands_MCRegisterSet;
+
+struct ni_mc_reg_entry {
+       u32 mclk_max;
+       u32 mc_data[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct SMC_NIslands_MCRegisterAddress
+{
+    uint16_t s0;
+    uint16_t s1;
+};
+
+typedef struct SMC_NIslands_MCRegisterAddress SMC_NIslands_MCRegisterAddress;
+
+struct SMC_NIslands_MCRegisters
+{
+    uint8_t                             last;
+    uint8_t                             reserved[3];
+    SMC_NIslands_MCRegisterAddress      address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+    SMC_NIslands_MCRegisterSet          data[SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT];
+};
+
+typedef struct SMC_NIslands_MCRegisters SMC_NIslands_MCRegisters;
+
+struct evergreen_ulv_param {
+       bool supported;
+       struct rv7xx_pl *pl;
+};
+
+struct evergreen_arb_registers {
+       u32 mc_arb_dram_timing;
+       u32 mc_arb_dram_timing2;
+       u32 mc_arb_rfsh_rate;
+       u32 mc_arb_burst_time;
+};
+
+struct at {
+       u32 rlp;
+       u32 rmp;
+       u32 lhp;
+       u32 lmp;
+};
+
+struct ni_clock_registers {
+       u32 cg_spll_func_cntl;
+       u32 cg_spll_func_cntl_2;
+       u32 cg_spll_func_cntl_3;
+       u32 cg_spll_func_cntl_4;
+       u32 cg_spll_spread_spectrum;
+       u32 cg_spll_spread_spectrum_2;
+       u32 mclk_pwrmgt_cntl;
+       u32 dll_cntl;
+       u32 mpll_ad_func_cntl;
+       u32 mpll_ad_func_cntl_2;
+       u32 mpll_dq_func_cntl;
+       u32 mpll_dq_func_cntl_2;
+       u32 mpll_ss1;
+       u32 mpll_ss2;
+};
+
+struct RV770_SMC_SCLK_VALUE
+{
+    uint32_t        vCG_SPLL_FUNC_CNTL;
+    uint32_t        vCG_SPLL_FUNC_CNTL_2;
+    uint32_t        vCG_SPLL_FUNC_CNTL_3;
+    uint32_t        vCG_SPLL_SPREAD_SPECTRUM;
+    uint32_t        vCG_SPLL_SPREAD_SPECTRUM_2;
+    uint32_t        sclk_value;
+};
+
+typedef struct RV770_SMC_SCLK_VALUE RV770_SMC_SCLK_VALUE;
+
+struct RV770_SMC_MCLK_VALUE
+{
+    uint32_t        vMPLL_AD_FUNC_CNTL;
+    uint32_t        vMPLL_AD_FUNC_CNTL_2;
+    uint32_t        vMPLL_DQ_FUNC_CNTL;
+    uint32_t        vMPLL_DQ_FUNC_CNTL_2;
+    uint32_t        vMCLK_PWRMGT_CNTL;
+    uint32_t        vDLL_CNTL;
+    uint32_t        vMPLL_SS;
+    uint32_t        vMPLL_SS2;
+    uint32_t        mclk_value;
+};
+
+typedef struct RV770_SMC_MCLK_VALUE RV770_SMC_MCLK_VALUE;
+
+
+struct RV730_SMC_MCLK_VALUE
+{
+    uint32_t        vMCLK_PWRMGT_CNTL;
+    uint32_t        vDLL_CNTL;
+    uint32_t        vMPLL_FUNC_CNTL;
+    uint32_t        vMPLL_FUNC_CNTL2;
+    uint32_t        vMPLL_FUNC_CNTL3;
+    uint32_t        vMPLL_SS;
+    uint32_t        vMPLL_SS2;
+    uint32_t        mclk_value;
+};
+
+typedef struct RV730_SMC_MCLK_VALUE RV730_SMC_MCLK_VALUE;
+
+struct RV770_SMC_VOLTAGE_VALUE
+{
+    uint16_t             value;
+    uint8_t              index;
+    uint8_t              padding;
+};
+
+typedef struct RV770_SMC_VOLTAGE_VALUE RV770_SMC_VOLTAGE_VALUE;
+
+union RV7XX_SMC_MCLK_VALUE
+{
+    RV770_SMC_MCLK_VALUE    mclk770;
+    RV730_SMC_MCLK_VALUE    mclk730;
+};
+
+typedef union RV7XX_SMC_MCLK_VALUE RV7XX_SMC_MCLK_VALUE, *LPRV7XX_SMC_MCLK_VALUE;
+
+struct RV770_SMC_HW_PERFORMANCE_LEVEL
+{
+    uint8_t                 arbValue;
+    union{
+        uint8_t             seqValue;
+        uint8_t             ACIndex;
+    };
+    uint8_t                 displayWatermark;
+    uint8_t                 gen2PCIE;
+    uint8_t                 gen2XSP;
+    uint8_t                 backbias;
+    uint8_t                 strobeMode;
+    uint8_t                 mcFlags;
+    uint32_t                aT;
+    uint32_t                bSP;
+    RV770_SMC_SCLK_VALUE    sclk;
+    RV7XX_SMC_MCLK_VALUE    mclk;
+    RV770_SMC_VOLTAGE_VALUE vddc;
+    RV770_SMC_VOLTAGE_VALUE mvdd;
+    RV770_SMC_VOLTAGE_VALUE vddci;
+    uint8_t                 reserved1;
+    uint8_t                 reserved2;
+    uint8_t                 stateFlags;
+    uint8_t                 padding;
+};
+
+typedef struct RV770_SMC_HW_PERFORMANCE_LEVEL RV770_SMC_HW_PERFORMANCE_LEVEL;
+
+struct RV770_SMC_SWSTATE
+{
+    uint8_t           flags;
+    uint8_t           padding1;
+    uint8_t           padding2;
+    uint8_t           padding3;
+    RV770_SMC_HW_PERFORMANCE_LEVEL levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+};
+
+typedef struct RV770_SMC_SWSTATE RV770_SMC_SWSTATE;
+
+struct RV770_SMC_VOLTAGEMASKTABLE
+{
+    uint8_t  highMask[RV770_SMC_VOLTAGEMASK_MAX];
+    uint32_t lowMask[RV770_SMC_VOLTAGEMASK_MAX];
+};
+
+typedef struct RV770_SMC_VOLTAGEMASKTABLE RV770_SMC_VOLTAGEMASKTABLE;
+
+struct RV770_SMC_STATETABLE
+{
+    uint8_t             thermalProtectType;
+    uint8_t             systemFlags;
+    uint8_t             maxVDDCIndexInPPTable;
+    uint8_t             extraFlags;
+    uint8_t             highSMIO[MAX_NO_VREG_STEPS];
+    uint32_t            lowSMIO[MAX_NO_VREG_STEPS];
+    RV770_SMC_VOLTAGEMASKTABLE voltageMaskTable;
+    RV770_SMC_SWSTATE   initialState;
+    RV770_SMC_SWSTATE   ACPIState;
+    RV770_SMC_SWSTATE   driverState;
+    RV770_SMC_SWSTATE   ULVState;
+};
+
+typedef struct RV770_SMC_STATETABLE RV770_SMC_STATETABLE;
+
+struct vddc_table_entry {
+       u16 vddc;
+       u8 vddc_index;
+       u8 high_smio;
+       u32 low_smio;
+};
+
+struct rv770_clock_registers {
+       u32 cg_spll_func_cntl;
+       u32 cg_spll_func_cntl_2;
+       u32 cg_spll_func_cntl_3;
+       u32 cg_spll_spread_spectrum;
+       u32 cg_spll_spread_spectrum_2;
+       u32 mpll_ad_func_cntl;
+       u32 mpll_ad_func_cntl_2;
+       u32 mpll_dq_func_cntl;
+       u32 mpll_dq_func_cntl_2;
+       u32 mclk_pwrmgt_cntl;
+       u32 dll_cntl;
+       u32 mpll_ss1;
+       u32 mpll_ss2;
+};
+
+struct rv730_clock_registers {
+       u32 cg_spll_func_cntl;
+       u32 cg_spll_func_cntl_2;
+       u32 cg_spll_func_cntl_3;
+       u32 cg_spll_spread_spectrum;
+       u32 cg_spll_spread_spectrum_2;
+       u32 mclk_pwrmgt_cntl;
+       u32 dll_cntl;
+       u32 mpll_func_cntl;
+       u32 mpll_func_cntl2;
+       u32 mpll_func_cntl3;
+       u32 mpll_ss;
+       u32 mpll_ss2;
+};
+
+union r7xx_clock_registers {
+       struct rv770_clock_registers rv770;
+       struct rv730_clock_registers rv730;
+};
+
+struct rv7xx_power_info {
+       /* flags */
+       bool mem_gddr5;
+       bool pcie_gen2;
+       bool dynamic_pcie_gen2;
+       bool acpi_pcie_gen2;
+       bool boot_in_gen2;
+       bool voltage_control; /* vddc */
+       bool mvdd_control;
+       bool sclk_ss;
+       bool mclk_ss;
+       bool dynamic_ss;
+       bool gfx_clock_gating;
+       bool mg_clock_gating;
+       bool mgcgtssm;
+       bool power_gating;
+       bool thermal_protection;
+       bool display_gap;
+       bool dcodt;
+       bool ulps;
+       /* registers */
+       union r7xx_clock_registers clk_regs;
+       u32 s0_vid_lower_smio_cntl;
+       /* voltage */
+       u32 vddc_mask_low;
+       u32 mvdd_mask_low;
+       u32 mvdd_split_frequency;
+       u32 mvdd_low_smio[MAX_NO_OF_MVDD_VALUES];
+       u16 max_vddc;
+       u16 max_vddc_in_table;
+       u16 min_vddc_in_table;
+       struct vddc_table_entry vddc_table[MAX_NO_VREG_STEPS];
+       u8 valid_vddc_entries;
+       /* dc odt */
+       u32 mclk_odt_threshold;
+       u8 odt_value_0[2];
+       u8 odt_value_1[2];
+       /* stored values */
+       u32 boot_sclk;
+       u16 acpi_vddc;
+       u32 ref_div;
+       u32 active_auto_throttle_sources;
+       u32 mclk_stutter_mode_threshold;
+       u32 mclk_strobe_mode_threshold;
+       u32 mclk_edc_enable_threshold;
+       u32 bsp;
+       u32 bsu;
+       u32 pbsp;
+       u32 pbsu;
+       u32 dsp;
+       u32 psp;
+       u32 asi;
+       u32 pasi;
+       u32 vrc;
+       u32 restricted_levels;
+       u32 rlp;
+       u32 rmp;
+       u32 lhp;
+       u32 lmp;
+       /* smc offsets */
+       u16 state_table_start;
+       u16 soft_regs_start;
+       u16 sram_end;
+       /* scratch structs */
+       RV770_SMC_STATETABLE smc_statetable;
+};
+
+struct rv7xx_pl {
+       u32 sclk;
+       u32 mclk;
+       u16 vddc;
+       u16 vddci; /* eg+ only */
+       u32 flags;
+       enum amdgpu_pcie_gen pcie_gen; /* si+ only */
+};
+
+struct rv7xx_ps {
+       struct rv7xx_pl high;
+       struct rv7xx_pl medium;
+       struct rv7xx_pl low;
+       bool dc_compatible;
+};
+
+struct si_ps {
+       u16 performance_level_count;
+       bool dc_compatible;
+       struct rv7xx_pl performance_levels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+};
+
+struct ni_mc_reg_table {
+       u8 last;
+       u8 num_entries;
+       u16 valid_flag;
+       struct ni_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+       SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct ni_cac_data
+{
+       struct ni_leakage_coeffients leakage_coefficients;
+       u32 i_leakage;
+       s32 leakage_minimum_temperature;
+       u32 pwr_const;
+       u32 dc_cac_value;
+       u32 bif_cac_value;
+       u32 lkge_pwr;
+       u8 mc_wr_weight;
+       u8 mc_rd_weight;
+       u8 allow_ovrflw;
+       u8 num_win_tdp;
+       u8 l2num_win_tdp;
+       u8 lts_truncate_n;
+};
+
+struct evergreen_power_info {
+       /* must be first! */
+       struct rv7xx_power_info rv7xx;
+       /* flags */
+       bool vddci_control;
+       bool dynamic_ac_timing;
+       bool abm;
+       bool mcls;
+       bool light_sleep;
+       bool memory_transition;
+       bool pcie_performance_request;
+       bool pcie_performance_request_registered;
+       bool sclk_deep_sleep;
+       bool dll_default_on;
+       bool ls_clock_gating;
+       bool smu_uvd_hs;
+       bool uvd_enabled;
+       /* stored values */
+       u16 acpi_vddci;
+       u8 mvdd_high_index;
+       u8 mvdd_low_index;
+       u32 mclk_edc_wr_enable_threshold;
+       struct evergreen_mc_reg_table mc_reg_table;
+       struct atom_voltage_table vddc_voltage_table;
+       struct atom_voltage_table vddci_voltage_table;
+       struct evergreen_arb_registers bootup_arb_registers;
+       struct evergreen_ulv_param ulv;
+       struct at ats[2];
+       /* smc offsets */
+       u16 mc_reg_table_start;
+       struct amdgpu_ps current_rps;
+       struct rv7xx_ps current_ps;
+       struct amdgpu_ps requested_rps;
+       struct rv7xx_ps requested_ps;
+};
+
+struct PP_NIslands_Dpm2PerfLevel
+{
+    uint8_t     MaxPS;
+    uint8_t     TgtAct;
+    uint8_t     MaxPS_StepInc;
+    uint8_t     MaxPS_StepDec;
+    uint8_t     PSST;
+    uint8_t     NearTDPDec;
+    uint8_t     AboveSafeInc;
+    uint8_t     BelowSafeInc;
+    uint8_t     PSDeltaLimit;
+    uint8_t     PSDeltaWin;
+    uint8_t     Reserved[6];
+};
+
+typedef struct PP_NIslands_Dpm2PerfLevel PP_NIslands_Dpm2PerfLevel;
+
+struct PP_NIslands_DPM2Parameters
+{
+    uint32_t    TDPLimit;
+    uint32_t    NearTDPLimit;
+    uint32_t    SafePowerLimit;
+    uint32_t    PowerBoostLimit;
+};
+typedef struct PP_NIslands_DPM2Parameters PP_NIslands_DPM2Parameters;
+
+struct NISLANDS_SMC_SCLK_VALUE
+{
+    uint32_t        vCG_SPLL_FUNC_CNTL;
+    uint32_t        vCG_SPLL_FUNC_CNTL_2;
+    uint32_t        vCG_SPLL_FUNC_CNTL_3;
+    uint32_t        vCG_SPLL_FUNC_CNTL_4;
+    uint32_t        vCG_SPLL_SPREAD_SPECTRUM;
+    uint32_t        vCG_SPLL_SPREAD_SPECTRUM_2;
+    uint32_t        sclk_value;
+};
+
+typedef struct NISLANDS_SMC_SCLK_VALUE NISLANDS_SMC_SCLK_VALUE;
+
+struct NISLANDS_SMC_MCLK_VALUE
+{
+    uint32_t        vMPLL_FUNC_CNTL;
+    uint32_t        vMPLL_FUNC_CNTL_1;
+    uint32_t        vMPLL_FUNC_CNTL_2;
+    uint32_t        vMPLL_AD_FUNC_CNTL;
+    uint32_t        vMPLL_AD_FUNC_CNTL_2;
+    uint32_t        vMPLL_DQ_FUNC_CNTL;
+    uint32_t        vMPLL_DQ_FUNC_CNTL_2;
+    uint32_t        vMCLK_PWRMGT_CNTL;
+    uint32_t        vDLL_CNTL;
+    uint32_t        vMPLL_SS;
+    uint32_t        vMPLL_SS2;
+    uint32_t        mclk_value;
+};
+
+typedef struct NISLANDS_SMC_MCLK_VALUE NISLANDS_SMC_MCLK_VALUE;
+
+struct NISLANDS_SMC_VOLTAGE_VALUE
+{
+    uint16_t             value;
+    uint8_t              index;
+    uint8_t              padding;
+};
+
+typedef struct NISLANDS_SMC_VOLTAGE_VALUE NISLANDS_SMC_VOLTAGE_VALUE;
+
+struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL
+{
+    uint8_t                     arbValue;
+    uint8_t                     ACIndex;
+    uint8_t                     displayWatermark;
+    uint8_t                     gen2PCIE;
+    uint8_t                     reserved1;
+    uint8_t                     reserved2;
+    uint8_t                     strobeMode;
+    uint8_t                     mcFlags;
+    uint32_t                    aT;
+    uint32_t                    bSP;
+    NISLANDS_SMC_SCLK_VALUE     sclk;
+    NISLANDS_SMC_MCLK_VALUE     mclk;
+    NISLANDS_SMC_VOLTAGE_VALUE  vddc;
+    NISLANDS_SMC_VOLTAGE_VALUE  mvdd;
+    NISLANDS_SMC_VOLTAGE_VALUE  vddci;
+    NISLANDS_SMC_VOLTAGE_VALUE  std_vddc;
+    uint32_t                    powergate_en;
+    uint8_t                     hUp;
+    uint8_t                     hDown;
+    uint8_t                     stateFlags;
+    uint8_t                     arbRefreshState;
+    uint32_t                    SQPowerThrottle;
+    uint32_t                    SQPowerThrottle_2;
+    uint32_t                    reserved[2];
+    PP_NIslands_Dpm2PerfLevel   dpm2;
+};
+
+typedef struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL NISLANDS_SMC_HW_PERFORMANCE_LEVEL;
+
+struct NISLANDS_SMC_SWSTATE
+{
+    uint8_t                             flags;
+    uint8_t                             levelCount;
+    uint8_t                             padding2;
+    uint8_t                             padding3;
+    NISLANDS_SMC_HW_PERFORMANCE_LEVEL   levels[1];
+};
+
+typedef struct NISLANDS_SMC_SWSTATE NISLANDS_SMC_SWSTATE;
+
+struct NISLANDS_SMC_VOLTAGEMASKTABLE
+{
+    uint8_t  highMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
+    uint32_t lowMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
+};
+
+typedef struct NISLANDS_SMC_VOLTAGEMASKTABLE NISLANDS_SMC_VOLTAGEMASKTABLE;
+
+#define NISLANDS_MAX_NO_VREG_STEPS 32
+
+struct NISLANDS_SMC_STATETABLE
+{
+    uint8_t                             thermalProtectType;
+    uint8_t                             systemFlags;
+    uint8_t                             maxVDDCIndexInPPTable;
+    uint8_t                             extraFlags;
+    uint8_t                             highSMIO[NISLANDS_MAX_NO_VREG_STEPS];
+    uint32_t                            lowSMIO[NISLANDS_MAX_NO_VREG_STEPS];
+    NISLANDS_SMC_VOLTAGEMASKTABLE       voltageMaskTable;
+    PP_NIslands_DPM2Parameters          dpm2Params;
+    NISLANDS_SMC_SWSTATE                initialState;
+    NISLANDS_SMC_SWSTATE                ACPIState;
+    NISLANDS_SMC_SWSTATE                ULVState;
+    NISLANDS_SMC_SWSTATE                driverState;
+    NISLANDS_SMC_HW_PERFORMANCE_LEVEL   dpmLevels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
+};
+
+typedef struct NISLANDS_SMC_STATETABLE NISLANDS_SMC_STATETABLE;
+
+struct ni_power_info {
+       /* must be first! */
+       struct evergreen_power_info eg;
+       struct ni_clock_registers clock_registers;
+       struct ni_mc_reg_table mc_reg_table;
+       u32 mclk_rtt_mode_threshold;
+       /* flags */
+       bool use_power_boost_limit;
+       bool support_cac_long_term_average;
+       bool cac_enabled;
+       bool cac_configuration_required;
+       bool driver_calculate_cac_leakage;
+       bool pc_enabled;
+       bool enable_power_containment;
+       bool enable_cac;
+       bool enable_sq_ramping;
+       /* smc offsets */
+       u16 arb_table_start;
+       u16 fan_table_start;
+       u16 cac_table_start;
+       u16 spll_table_start;
+       /* CAC stuff */
+       struct ni_cac_data cac_data;
+       u32 dc_cac_table[NISLANDS_DCCAC_MAX_LEVELS];
+       const struct ni_cac_weights *cac_weights;
+       u8 lta_window_size;
+       u8 lts_truncate;
+       struct si_ps current_ps;
+       struct si_ps requested_ps;
+       /* scratch structs */
+       SMC_NIslands_MCRegisters smc_mc_reg_table;
+       NISLANDS_SMC_STATETABLE smc_statetable;
+};
+
+struct si_cac_config_reg
+{
+       u32 offset;
+       u32 mask;
+       u32 shift;
+       u32 value;
+       enum si_cac_config_reg_type type;
+};
+
+struct si_powertune_data
+{
+       u32 cac_window;
+       u32 l2_lta_window_size_default;
+       u8 lts_truncate_default;
+       u8 shift_n_default;
+       u8 operating_temp;
+       struct ni_leakage_coeffients leakage_coefficients;
+       u32 fixed_kt;
+       u32 lkge_lut_v0_percent;
+       u8 dc_cac[NISLANDS_DCCAC_MAX_LEVELS];
+       bool enable_powertune_by_default;
+};
+
+struct si_dyn_powertune_data
+{
+       u32 cac_leakage;
+       s32 leakage_minimum_temperature;
+       u32 wintime;
+       u32 l2_lta_window_size;
+       u8 lts_truncate;
+       u8 shift_n;
+       u8 dc_pwr_value;
+       bool disable_uvd_powertune;
+};
+
+struct si_dte_data
+{
+       u32 tau[SMC_SISLANDS_DTE_MAX_FILTER_STAGES];
+       u32 r[SMC_SISLANDS_DTE_MAX_FILTER_STAGES];
+       u32 k;
+       u32 t0;
+       u32 max_t;
+       u8 window_size;
+       u8 temp_select;
+       u8 dte_mode;
+       u8 tdep_count;
+       u8 t_limits[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+       u32 tdep_tau[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+       u32 tdep_r[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+       u32 t_threshold;
+       bool enable_dte_by_default;
+};
+
+struct si_clock_registers {
+       u32 cg_spll_func_cntl;
+       u32 cg_spll_func_cntl_2;
+       u32 cg_spll_func_cntl_3;
+       u32 cg_spll_func_cntl_4;
+       u32 cg_spll_spread_spectrum;
+       u32 cg_spll_spread_spectrum_2;
+       u32 dll_cntl;
+       u32 mclk_pwrmgt_cntl;
+       u32 mpll_ad_func_cntl;
+       u32 mpll_dq_func_cntl;
+       u32 mpll_func_cntl;
+       u32 mpll_func_cntl_1;
+       u32 mpll_func_cntl_2;
+       u32 mpll_ss1;
+       u32 mpll_ss2;
+};
+
+struct si_mc_reg_entry {
+       u32 mclk_max;
+       u32 mc_data[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct si_mc_reg_table {
+       u8 last;
+       u8 num_entries;
+       u16 valid_flag;
+       struct si_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+       SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct si_leakage_voltage_entry
+{
+       u16 voltage;
+       u16 leakage_index;
+};
+
+struct si_leakage_voltage
+{
+       u16 count;
+       struct si_leakage_voltage_entry entries[SISLANDS_MAX_LEAKAGE_COUNT];
+};
+
+
+struct si_ulv_param {
+       bool supported;
+       u32 cg_ulv_control;
+       u32 cg_ulv_parameter;
+       u32 volt_change_delay;
+       struct rv7xx_pl pl;
+       bool one_pcie_lane_in_ulv;
+};
+
+struct si_power_info {
+       /* must be first! */
+       struct ni_power_info ni;
+       struct si_clock_registers clock_registers;
+       struct si_mc_reg_table mc_reg_table;
+       struct atom_voltage_table mvdd_voltage_table;
+       struct atom_voltage_table vddc_phase_shed_table;
+       struct si_leakage_voltage leakage_voltage;
+       u16 mvdd_bootup_value;
+       struct si_ulv_param ulv;
+       u32 max_cu;
+       /* pcie gen */
+       enum amdgpu_pcie_gen force_pcie_gen;
+       enum amdgpu_pcie_gen boot_pcie_gen;
+       enum amdgpu_pcie_gen acpi_pcie_gen;
+       u32 sys_pcie_mask;
+       /* flags */
+       bool enable_dte;
+       bool enable_ppm;
+       bool vddc_phase_shed_control;
+       bool pspp_notify_required;
+       bool sclk_deep_sleep_above_low;
+       bool voltage_control_svi2;
+       bool vddci_control_svi2;
+       /* smc offsets */
+       u32 sram_end;
+       u32 state_table_start;
+       u32 soft_regs_start;
+       u32 mc_reg_table_start;
+       u32 arb_table_start;
+       u32 cac_table_start;
+       u32 dte_table_start;
+       u32 spll_table_start;
+       u32 papm_cfg_table_start;
+       u32 fan_table_start;
+       /* CAC stuff */
+       const struct si_cac_config_reg *cac_weights;
+       const struct si_cac_config_reg *lcac_config;
+       const struct si_cac_config_reg *cac_override;
+       const struct si_powertune_data *powertune_data;
+       struct si_dyn_powertune_data dyn_powertune_data;
+       /* DTE stuff */
+       struct si_dte_data dte_data;
+       /* scratch structs */
+       SMC_SIslands_MCRegisters smc_mc_reg_table;
+       SISLANDS_SMC_STATETABLE smc_statetable;
+       PP_SIslands_PAPMParameters papm_parm;
+       /* SVI2 */
+       u8 svd_gpio_id;
+       u8 svc_gpio_id;
+       /* fan control */
+       bool fan_ctrl_is_in_default_mode;
+       u32 t_min;
+       u32 fan_ctrl_default_mode;
+       bool fan_is_controlled_by_smc;
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c
new file mode 100644 (file)
index 0000000..8fae3d4
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2015 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 "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_ih.h"
+#include "si/sid.h"
+#include "si_ih.h"
+
+static void si_ih_set_interrupt_funcs(struct amdgpu_device *adev);
+
+static void si_ih_enable_interrupts(struct amdgpu_device *adev)
+{
+       u32 ih_cntl = RREG32(IH_CNTL);
+       u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+
+       ih_cntl |= ENABLE_INTR;
+       ih_rb_cntl |= IH_RB_ENABLE;
+       WREG32(IH_CNTL, ih_cntl);
+       WREG32(IH_RB_CNTL, ih_rb_cntl);
+       adev->irq.ih.enabled = true;
+}
+  
+static void si_ih_disable_interrupts(struct amdgpu_device *adev)
+{
+       u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+       u32 ih_cntl = RREG32(IH_CNTL);
+
+       ih_rb_cntl &= ~IH_RB_ENABLE;
+       ih_cntl &= ~ENABLE_INTR;
+       WREG32(IH_RB_CNTL, ih_rb_cntl);
+       WREG32(IH_CNTL, ih_cntl);
+       WREG32(IH_RB_RPTR, 0);
+       WREG32(IH_RB_WPTR, 0);
+       adev->irq.ih.enabled = false;
+       adev->irq.ih.rptr = 0;
+}
+
+static int si_ih_irq_init(struct amdgpu_device *adev)
+{
+       int rb_bufsz;
+       u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
+       u64 wptr_off;
+
+       si_ih_disable_interrupts(adev);
+       WREG32(INTERRUPT_CNTL2, adev->irq.ih.gpu_addr >> 8);
+       interrupt_cntl = RREG32(INTERRUPT_CNTL);
+       interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE;
+       interrupt_cntl &= ~IH_REQ_NONSNOOP_EN;
+       WREG32(INTERRUPT_CNTL, interrupt_cntl);
+
+       WREG32(IH_RB_BASE, adev->irq.ih.gpu_addr >> 8);
+       rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
+
+       ih_rb_cntl = IH_WPTR_OVERFLOW_ENABLE |
+                    IH_WPTR_OVERFLOW_CLEAR |
+                    (rb_bufsz << 1) |
+                    IH_WPTR_WRITEBACK_ENABLE;
+
+       wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
+       WREG32(IH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
+       WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
+       WREG32(IH_RB_CNTL, ih_rb_cntl);
+       WREG32(IH_RB_RPTR, 0);
+       WREG32(IH_RB_WPTR, 0);
+
+       ih_cntl = MC_WRREQ_CREDIT(0x10) | MC_WR_CLEAN_CNT(0x10) | MC_VMID(0);
+       if (adev->irq.msi_enabled)
+               ih_cntl |= RPTR_REARM;
+       WREG32(IH_CNTL, ih_cntl);
+
+       pci_set_master(adev->pdev);
+       si_ih_enable_interrupts(adev);
+
+       return 0;
+}
+
+static void si_ih_irq_disable(struct amdgpu_device *adev)
+{
+       si_ih_disable_interrupts(adev);
+       mdelay(1);
+}
+
+static u32 si_ih_get_wptr(struct amdgpu_device *adev)
+{
+       u32 wptr, tmp;
+
+       wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
+
+       if (wptr & IH_RB_WPTR__RB_OVERFLOW_MASK) {
+               wptr &= ~IH_RB_WPTR__RB_OVERFLOW_MASK;
+               dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
+                       wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
+               adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+               tmp = RREG32(IH_RB_CNTL);
+               tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
+               WREG32(IH_RB_CNTL, tmp);
+       }
+       return (wptr & adev->irq.ih.ptr_mask);
+}
+
+static void si_ih_decode_iv(struct amdgpu_device *adev,
+                            struct amdgpu_iv_entry *entry)
+{
+       u32 ring_index = adev->irq.ih.rptr >> 2;
+       uint32_t dw[4];
+
+       dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
+       dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
+       dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
+       dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
+
+       entry->src_id = dw[0] & 0xff;
+       entry->src_data = dw[1] & 0xfffffff;
+       entry->ring_id = dw[2] & 0xff;
+       entry->vm_id = (dw[2] >> 8) & 0xff;
+
+       adev->irq.ih.rptr += 16;
+}
+
+static void si_ih_set_rptr(struct amdgpu_device *adev)
+{
+       WREG32(IH_RB_RPTR, adev->irq.ih.rptr);
+}
+
+static int si_ih_early_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       si_ih_set_interrupt_funcs(adev);
+
+       return 0;
+}
+
+static int si_ih_sw_init(void *handle)
+{
+       int r;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       r = amdgpu_ih_ring_init(adev, 64 * 1024, false);
+       if (r)
+               return r;
+
+       return amdgpu_irq_init(adev);
+}
+
+static int si_ih_sw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       amdgpu_irq_fini(adev);
+       amdgpu_ih_ring_fini(adev);
+
+       return 0;
+}
+
+static int si_ih_hw_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return si_ih_irq_init(adev);
+}
+
+static int si_ih_hw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       si_ih_irq_disable(adev);
+
+       return 0;
+}
+
+static int si_ih_suspend(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return si_ih_hw_fini(adev);
+}
+
+static int si_ih_resume(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       return si_ih_hw_init(adev);
+}
+
+static bool si_ih_is_idle(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 tmp = RREG32(SRBM_STATUS);
+
+       if (tmp & SRBM_STATUS__IH_BUSY_MASK)
+               return false;
+
+       return true;
+}
+
+static int si_ih_wait_for_idle(void *handle)
+{
+       unsigned i;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (si_ih_is_idle(handle))
+                       return 0;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+}
+
+static int si_ih_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       u32 srbm_soft_reset = 0;
+       u32 tmp = RREG32(SRBM_STATUS);
+
+       if (tmp & SRBM_STATUS__IH_BUSY_MASK)
+               srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_IH_MASK;
+
+       if (srbm_soft_reset) {
+               tmp = RREG32(SRBM_SOFT_RESET);
+               tmp |= srbm_soft_reset;
+               dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+               WREG32(SRBM_SOFT_RESET, tmp);
+               tmp = RREG32(SRBM_SOFT_RESET);
+
+               udelay(50);
+
+               tmp &= ~srbm_soft_reset;
+               WREG32(SRBM_SOFT_RESET, tmp);
+               tmp = RREG32(SRBM_SOFT_RESET);
+
+               udelay(50);
+       }
+
+       return 0;
+}
+
+static int si_ih_set_clockgating_state(void *handle,
+                                         enum amd_clockgating_state state)
+{
+       return 0;
+}
+
+static int si_ih_set_powergating_state(void *handle,
+                                         enum amd_powergating_state state)
+{
+       return 0;
+}
+
+const struct amd_ip_funcs si_ih_ip_funcs = {
+       .name = "si_ih",
+       .early_init = si_ih_early_init,
+       .late_init = NULL,
+       .sw_init = si_ih_sw_init,
+       .sw_fini = si_ih_sw_fini,
+       .hw_init = si_ih_hw_init,
+       .hw_fini = si_ih_hw_fini,
+       .suspend = si_ih_suspend,
+       .resume = si_ih_resume,
+       .is_idle = si_ih_is_idle,
+       .wait_for_idle = si_ih_wait_for_idle,
+       .soft_reset = si_ih_soft_reset,
+       .set_clockgating_state = si_ih_set_clockgating_state,
+       .set_powergating_state = si_ih_set_powergating_state,
+};
+
+static const struct amdgpu_ih_funcs si_ih_funcs = {
+       .get_wptr = si_ih_get_wptr,
+       .decode_iv = si_ih_decode_iv,
+       .set_rptr = si_ih_set_rptr
+};
+
+static void si_ih_set_interrupt_funcs(struct amdgpu_device *adev)
+{
+       if (adev->irq.ih_funcs == NULL)
+               adev->irq.ih_funcs = &si_ih_funcs;
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.h b/drivers/gpu/drm/amd/amdgpu/si_ih.h
new file mode 100644 (file)
index 0000000..f3e3a95
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 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 __SI_IH_H__
+#define __SI_IH_H__
+
+extern const struct amd_ip_funcs si_ih_ip_funcs;
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/si_smc.c b/drivers/gpu/drm/amd/amdgpu/si_smc.c
new file mode 100644 (file)
index 0000000..668ba99
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "amdgpu.h"
+#include "si/sid.h"
+#include "ppsmc.h"
+#include "amdgpu_ucode.h"
+#include "sislands_smc.h"
+
+static int si_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(SMC_IND_INDEX_0, smc_address);
+       WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
+
+       return 0;
+}
+
+int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev,
+                               u32 smc_start_address,
+                               const u8 *src, u32 byte_count, u32 limit)
+{
+       unsigned long flags;
+       int ret = 0;
+       u32 data, original_data, addr, extra_shift;
+
+       if (smc_start_address & 3)
+               return -EINVAL;
+       if ((smc_start_address + byte_count) > limit)
+               return -EINVAL;
+
+       addr = smc_start_address;
+
+       spin_lock_irqsave(&adev->smc_idx_lock, flags);
+       while (byte_count >= 4) {
+               /* SMC address space is BE */
+               data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+
+               ret = si_set_smc_sram_address(adev, addr, limit);
+               if (ret)
+                       goto done;
+
+               WREG32(SMC_IND_DATA_0, data);
+
+               src += 4;
+               byte_count -= 4;
+               addr += 4;
+       }
+
+       /* RMW for the final bytes */
+       if (byte_count > 0) {
+               data = 0;
+
+               ret = si_set_smc_sram_address(adev, addr, limit);
+               if (ret)
+                       goto done;
+
+               original_data = RREG32(SMC_IND_DATA_0);
+               extra_shift = 8 * (4 - byte_count);
+
+               while (byte_count > 0) {
+                       /* SMC address space is BE */
+                       data = (data << 8) + *src++;
+                       byte_count--;
+               }
+
+               data <<= extra_shift;
+               data |= (original_data & ~((~0UL) << extra_shift));
+
+               ret = si_set_smc_sram_address(adev, addr, limit);
+               if (ret)
+                       goto done;
+
+               WREG32(SMC_IND_DATA_0, data);
+       }
+
+done:
+       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+       return ret;
+}
+
+void amdgpu_si_start_smc(struct amdgpu_device *adev)
+{
+       u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
+
+       tmp &= ~RST_REG;
+
+       WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
+}
+
+void amdgpu_si_reset_smc(struct amdgpu_device *adev)
+{
+       u32 tmp;
+
+       RREG32(CB_CGTT_SCLK_CTRL);
+       RREG32(CB_CGTT_SCLK_CTRL);
+       RREG32(CB_CGTT_SCLK_CTRL);
+       RREG32(CB_CGTT_SCLK_CTRL);
+
+       tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL) |
+             RST_REG;
+       WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
+}
+
+int amdgpu_si_program_jump_on_start(struct amdgpu_device *adev)
+{
+       static const u8 data[] = { 0x0E, 0x00, 0x40, 0x40 };
+
+       return amdgpu_si_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
+}
+
+void amdgpu_si_smc_clock(struct amdgpu_device *adev, bool enable)
+{
+       u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
+
+       if (enable)
+               tmp &= ~CK_DISABLE;
+       else
+               tmp |= CK_DISABLE;
+
+       WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
+}
+
+bool amdgpu_si_is_smc_running(struct amdgpu_device *adev)
+{
+       u32 rst = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
+       u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
+
+       if (!(rst & RST_REG) && !(clk & CK_DISABLE))
+               return true;
+
+       return false;
+}
+
+PPSMC_Result amdgpu_si_send_msg_to_smc(struct amdgpu_device *adev,
+                                      PPSMC_Msg msg)
+{
+       u32 tmp;
+       int i;
+
+       if (!amdgpu_si_is_smc_running(adev))
+               return PPSMC_Result_Failed;
+
+       WREG32(SMC_MESSAGE_0, msg);
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               tmp = RREG32(SMC_RESP_0);
+               if (tmp != 0)
+                       break;
+               udelay(1);
+       }
+
+       return (PPSMC_Result)RREG32(SMC_RESP_0);
+}
+
+PPSMC_Result amdgpu_si_wait_for_smc_inactive(struct amdgpu_device *adev)
+{
+       u32 tmp;
+       int i;
+
+       if (!amdgpu_si_is_smc_running(adev))
+               return PPSMC_Result_OK;
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
+               if ((tmp & CKEN) == 0)
+                       break;
+               udelay(1);
+       }
+
+       return PPSMC_Result_OK;
+}
+
+int amdgpu_si_load_smc_ucode(struct amdgpu_device *adev, u32 limit)
+{
+       const struct smc_firmware_header_v1_0 *hdr;
+       unsigned long flags;
+       u32 ucode_start_address;
+       u32 ucode_size;
+       const u8 *src;
+       u32 data;
+
+       if (!adev->pm.fw)
+               return -EINVAL;
+
+       hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
+
+       amdgpu_ucode_print_smc_hdr(&hdr->header);
+
+       adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
+       ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
+       ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
+       src = (const u8 *)
+               (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+       if (ucode_size & 3)
+               return -EINVAL;
+
+       spin_lock_irqsave(&adev->smc_idx_lock, flags);
+       WREG32(SMC_IND_INDEX_0, ucode_start_address);
+       WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
+       while (ucode_size >= 4) {
+               /* SMC address space is BE */
+               data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+
+               WREG32(SMC_IND_DATA_0, data);
+
+               src += 4;
+               ucode_size -= 4;
+       }
+       WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
+       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+       return 0;
+}
+
+int amdgpu_si_read_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
+                                 u32 *value, u32 limit)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&adev->smc_idx_lock, flags);
+       ret = si_set_smc_sram_address(adev, smc_address, limit);
+       if (ret == 0)
+               *value = RREG32(SMC_IND_DATA_0);
+       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+       return ret;
+}
+
+int amdgpu_si_write_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
+                                  u32 value, u32 limit)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&adev->smc_idx_lock, flags);
+       ret = si_set_smc_sram_address(adev, smc_address, limit);
+       if (ret == 0)
+               WREG32(SMC_IND_DATA_0, value);
+       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+       return ret;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/sislands_smc.h b/drivers/gpu/drm/amd/amdgpu/sislands_smc.h
new file mode 100644 (file)
index 0000000..d2930ec
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef PP_SISLANDS_SMC_H
+#define PP_SISLANDS_SMC_H
+
+#include "ppsmc.h"
+
+#pragma pack(push, 1)
+
+#define SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16
+
+struct PP_SIslands_Dpm2PerfLevel
+{
+    uint8_t MaxPS;
+    uint8_t TgtAct;
+    uint8_t MaxPS_StepInc;
+    uint8_t MaxPS_StepDec;
+    uint8_t PSSamplingTime;
+    uint8_t NearTDPDec;
+    uint8_t AboveSafeInc;
+    uint8_t BelowSafeInc;
+    uint8_t PSDeltaLimit;
+    uint8_t PSDeltaWin;
+    uint16_t PwrEfficiencyRatio;
+    uint8_t Reserved[4];
+};
+
+typedef struct PP_SIslands_Dpm2PerfLevel PP_SIslands_Dpm2PerfLevel;
+
+struct PP_SIslands_DPM2Status
+{
+    uint32_t    dpm2Flags;
+    uint8_t     CurrPSkip;
+    uint8_t     CurrPSkipPowerShift;
+    uint8_t     CurrPSkipTDP;
+    uint8_t     CurrPSkipOCP;
+    uint8_t     MaxSPLLIndex;
+    uint8_t     MinSPLLIndex;
+    uint8_t     CurrSPLLIndex;
+    uint8_t     InfSweepMode;
+    uint8_t     InfSweepDir;
+    uint8_t     TDPexceeded;
+    uint8_t     reserved;
+    uint8_t     SwitchDownThreshold;
+    uint32_t    SwitchDownCounter;
+    uint32_t    SysScalingFactor;
+};
+
+typedef struct PP_SIslands_DPM2Status PP_SIslands_DPM2Status;
+
+struct PP_SIslands_DPM2Parameters
+{
+    uint32_t    TDPLimit;
+    uint32_t    NearTDPLimit;
+    uint32_t    SafePowerLimit;
+    uint32_t    PowerBoostLimit;
+    uint32_t    MinLimitDelta;
+};
+typedef struct PP_SIslands_DPM2Parameters PP_SIslands_DPM2Parameters;
+
+struct PP_SIslands_PAPMStatus
+{
+    uint32_t    EstimatedDGPU_T;
+    uint32_t    EstimatedDGPU_P;
+    uint32_t    EstimatedAPU_T;
+    uint32_t    EstimatedAPU_P;
+    uint8_t     dGPU_T_Limit_Exceeded;
+    uint8_t     reserved[3];
+};
+typedef struct PP_SIslands_PAPMStatus PP_SIslands_PAPMStatus;
+
+struct PP_SIslands_PAPMParameters
+{
+    uint32_t    NearTDPLimitTherm;
+    uint32_t    NearTDPLimitPAPM;
+    uint32_t    PlatformPowerLimit;
+    uint32_t    dGPU_T_Limit;
+    uint32_t    dGPU_T_Warning;
+    uint32_t    dGPU_T_Hysteresis;
+};
+typedef struct PP_SIslands_PAPMParameters PP_SIslands_PAPMParameters;
+
+struct SISLANDS_SMC_SCLK_VALUE
+{
+    uint32_t    vCG_SPLL_FUNC_CNTL;
+    uint32_t    vCG_SPLL_FUNC_CNTL_2;
+    uint32_t    vCG_SPLL_FUNC_CNTL_3;
+    uint32_t    vCG_SPLL_FUNC_CNTL_4;
+    uint32_t    vCG_SPLL_SPREAD_SPECTRUM;
+    uint32_t    vCG_SPLL_SPREAD_SPECTRUM_2;
+    uint32_t    sclk_value;
+};
+
+typedef struct SISLANDS_SMC_SCLK_VALUE SISLANDS_SMC_SCLK_VALUE;
+
+struct SISLANDS_SMC_MCLK_VALUE
+{
+    uint32_t    vMPLL_FUNC_CNTL;
+    uint32_t    vMPLL_FUNC_CNTL_1;
+    uint32_t    vMPLL_FUNC_CNTL_2;
+    uint32_t    vMPLL_AD_FUNC_CNTL;
+    uint32_t    vMPLL_DQ_FUNC_CNTL;
+    uint32_t    vMCLK_PWRMGT_CNTL;
+    uint32_t    vDLL_CNTL;
+    uint32_t    vMPLL_SS;
+    uint32_t    vMPLL_SS2;
+    uint32_t    mclk_value;
+};
+
+typedef struct SISLANDS_SMC_MCLK_VALUE SISLANDS_SMC_MCLK_VALUE;
+
+struct SISLANDS_SMC_VOLTAGE_VALUE
+{
+    uint16_t    value;
+    uint8_t     index;
+    uint8_t     phase_settings;
+};
+
+typedef struct SISLANDS_SMC_VOLTAGE_VALUE SISLANDS_SMC_VOLTAGE_VALUE;
+
+struct SISLANDS_SMC_HW_PERFORMANCE_LEVEL
+{
+    uint8_t                     ACIndex;
+    uint8_t                     displayWatermark;
+    uint8_t                     gen2PCIE;
+    uint8_t                     UVDWatermark;
+    uint8_t                     VCEWatermark;
+    uint8_t                     strobeMode;
+    uint8_t                     mcFlags;
+    uint8_t                     padding;
+    uint32_t                    aT;
+    uint32_t                    bSP;
+    SISLANDS_SMC_SCLK_VALUE     sclk;
+    SISLANDS_SMC_MCLK_VALUE     mclk;
+    SISLANDS_SMC_VOLTAGE_VALUE  vddc;
+    SISLANDS_SMC_VOLTAGE_VALUE  mvdd;
+    SISLANDS_SMC_VOLTAGE_VALUE  vddci;
+    SISLANDS_SMC_VOLTAGE_VALUE  std_vddc;
+    uint8_t                     hysteresisUp;
+    uint8_t                     hysteresisDown;
+    uint8_t                     stateFlags;
+    uint8_t                     arbRefreshState;
+    uint32_t                    SQPowerThrottle;
+    uint32_t                    SQPowerThrottle_2;
+    uint32_t                    MaxPoweredUpCU;
+    SISLANDS_SMC_VOLTAGE_VALUE  high_temp_vddc;
+    SISLANDS_SMC_VOLTAGE_VALUE  low_temp_vddc;
+    uint32_t                    reserved[2];
+    PP_SIslands_Dpm2PerfLevel   dpm2;
+};
+
+#define SISLANDS_SMC_STROBE_RATIO    0x0F
+#define SISLANDS_SMC_STROBE_ENABLE   0x10
+
+#define SISLANDS_SMC_MC_EDC_RD_FLAG  0x01
+#define SISLANDS_SMC_MC_EDC_WR_FLAG  0x02
+#define SISLANDS_SMC_MC_RTT_ENABLE   0x04
+#define SISLANDS_SMC_MC_STUTTER_EN   0x08
+#define SISLANDS_SMC_MC_PG_EN        0x10
+
+typedef struct SISLANDS_SMC_HW_PERFORMANCE_LEVEL SISLANDS_SMC_HW_PERFORMANCE_LEVEL;
+
+struct SISLANDS_SMC_SWSTATE
+{
+    uint8_t                             flags;
+    uint8_t                             levelCount;
+    uint8_t                             padding2;
+    uint8_t                             padding3;
+    SISLANDS_SMC_HW_PERFORMANCE_LEVEL   levels[1];
+};
+
+typedef struct SISLANDS_SMC_SWSTATE SISLANDS_SMC_SWSTATE;
+
+#define SISLANDS_SMC_VOLTAGEMASK_VDDC  0
+#define SISLANDS_SMC_VOLTAGEMASK_MVDD  1
+#define SISLANDS_SMC_VOLTAGEMASK_VDDCI 2
+#define SISLANDS_SMC_VOLTAGEMASK_VDDC_PHASE_SHEDDING 3
+#define SISLANDS_SMC_VOLTAGEMASK_MAX   4
+
+struct SISLANDS_SMC_VOLTAGEMASKTABLE
+{
+    uint32_t lowMask[SISLANDS_SMC_VOLTAGEMASK_MAX];
+};
+
+typedef struct SISLANDS_SMC_VOLTAGEMASKTABLE SISLANDS_SMC_VOLTAGEMASKTABLE;
+
+#define SISLANDS_MAX_NO_VREG_STEPS 32
+
+struct SISLANDS_SMC_STATETABLE
+{
+    uint8_t                             thermalProtectType;
+    uint8_t                             systemFlags;
+    uint8_t                             maxVDDCIndexInPPTable;
+    uint8_t                             extraFlags;
+    uint32_t                            lowSMIO[SISLANDS_MAX_NO_VREG_STEPS];
+    SISLANDS_SMC_VOLTAGEMASKTABLE       voltageMaskTable;
+    SISLANDS_SMC_VOLTAGEMASKTABLE       phaseMaskTable;
+    PP_SIslands_DPM2Parameters          dpm2Params;
+    SISLANDS_SMC_SWSTATE                initialState;
+    SISLANDS_SMC_SWSTATE                ACPIState;
+    SISLANDS_SMC_SWSTATE                ULVState;
+    SISLANDS_SMC_SWSTATE                driverState;
+    SISLANDS_SMC_HW_PERFORMANCE_LEVEL   dpmLevels[SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
+};
+
+typedef struct SISLANDS_SMC_STATETABLE SISLANDS_SMC_STATETABLE;
+
+#define SI_SMC_SOFT_REGISTER_mclk_chg_timeout         0x0
+#define SI_SMC_SOFT_REGISTER_delay_vreg               0xC
+#define SI_SMC_SOFT_REGISTER_delay_acpi               0x28
+#define SI_SMC_SOFT_REGISTER_seq_index                0x5C
+#define SI_SMC_SOFT_REGISTER_mvdd_chg_time            0x60
+#define SI_SMC_SOFT_REGISTER_mclk_switch_lim          0x70
+#define SI_SMC_SOFT_REGISTER_watermark_threshold      0x78
+#define SI_SMC_SOFT_REGISTER_phase_shedding_delay     0x88
+#define SI_SMC_SOFT_REGISTER_ulv_volt_change_delay    0x8C
+#define SI_SMC_SOFT_REGISTER_mc_block_delay           0x98
+#define SI_SMC_SOFT_REGISTER_ticks_per_us             0xA8
+#define SI_SMC_SOFT_REGISTER_crtc_index               0xC4
+#define SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min 0xC8
+#define SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max 0xCC
+#define SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width  0xF4
+#define SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen   0xFC
+#define SI_SMC_SOFT_REGISTER_vr_hot_gpio              0x100
+#define SI_SMC_SOFT_REGISTER_svi_rework_plat_type     0x118
+#define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd   0x11c
+#define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc   0x120
+
+struct PP_SIslands_FanTable
+{
+       uint8_t  fdo_mode;
+       uint8_t  padding;
+       int16_t  temp_min;
+       int16_t  temp_med;
+       int16_t  temp_max;
+       int16_t  slope1;
+       int16_t  slope2;
+       int16_t  fdo_min;
+       int16_t  hys_up;
+       int16_t  hys_down;
+       int16_t  hys_slope;
+       int16_t  temp_resp_lim;
+       int16_t  temp_curr;
+       int16_t  slope_curr;
+       int16_t  pwm_curr;
+       uint32_t refresh_period;
+       int16_t  fdo_max;
+       uint8_t  temp_src;
+       int8_t  padding2;
+};
+
+typedef struct PP_SIslands_FanTable PP_SIslands_FanTable;
+
+#define SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
+#define SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 32
+
+#define SMC_SISLANDS_SCALE_I  7
+#define SMC_SISLANDS_SCALE_R 12
+
+struct PP_SIslands_CacConfig
+{
+    uint16_t   cac_lkge_lut[SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES];
+    uint32_t   lkge_lut_V0;
+    uint32_t   lkge_lut_Vstep;
+    uint32_t   WinTime;
+    uint32_t   R_LL;
+    uint32_t   calculation_repeats;
+    uint32_t   l2numWin_TDP;
+    uint32_t   dc_cac;
+    uint8_t    lts_truncate_n;
+    uint8_t    SHIFT_N;
+    uint8_t    log2_PG_LKG_SCALE;
+    uint8_t    cac_temp;
+    uint32_t   lkge_lut_T0;
+    uint32_t   lkge_lut_Tstep;
+};
+
+typedef struct PP_SIslands_CacConfig PP_SIslands_CacConfig;
+
+#define SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE 16
+#define SMC_SISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20
+
+struct SMC_SIslands_MCRegisterAddress
+{
+    uint16_t s0;
+    uint16_t s1;
+};
+
+typedef struct SMC_SIslands_MCRegisterAddress SMC_SIslands_MCRegisterAddress;
+
+struct SMC_SIslands_MCRegisterSet
+{
+    uint32_t value[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMC_SIslands_MCRegisterSet SMC_SIslands_MCRegisterSet;
+
+struct SMC_SIslands_MCRegisters
+{
+    uint8_t                             last;
+    uint8_t                             reserved[3];
+    SMC_SIslands_MCRegisterAddress      address[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE];
+    SMC_SIslands_MCRegisterSet          data[SMC_SISLANDS_MC_REGISTER_ARRAY_SET_COUNT];
+};
+
+typedef struct SMC_SIslands_MCRegisters SMC_SIslands_MCRegisters;
+
+struct SMC_SIslands_MCArbDramTimingRegisterSet
+{
+    uint32_t mc_arb_dram_timing;
+    uint32_t mc_arb_dram_timing2;
+    uint8_t  mc_arb_rfsh_rate;
+    uint8_t  mc_arb_burst_time;
+    uint8_t  padding[2];
+};
+
+typedef struct SMC_SIslands_MCArbDramTimingRegisterSet SMC_SIslands_MCArbDramTimingRegisterSet;
+
+struct SMC_SIslands_MCArbDramTimingRegisters
+{
+    uint8_t                                     arb_current;
+    uint8_t                                     reserved[3];
+    SMC_SIslands_MCArbDramTimingRegisterSet     data[16];
+};
+
+typedef struct SMC_SIslands_MCArbDramTimingRegisters SMC_SIslands_MCArbDramTimingRegisters;
+
+struct SMC_SISLANDS_SPLL_DIV_TABLE
+{
+    uint32_t    freq[256];
+    uint32_t    ss[256];
+};
+
+#define SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK  0x01ffffff
+#define SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT 0
+#define SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK   0xfe000000
+#define SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT  25
+#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK   0x000fffff
+#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT  0
+#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK   0xfff00000
+#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT  20
+
+typedef struct SMC_SISLANDS_SPLL_DIV_TABLE SMC_SISLANDS_SPLL_DIV_TABLE;
+
+#define SMC_SISLANDS_DTE_MAX_FILTER_STAGES 5
+
+#define SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE 16
+
+struct Smc_SIslands_DTE_Configuration
+{
+    uint32_t tau[SMC_SISLANDS_DTE_MAX_FILTER_STAGES];
+    uint32_t R[SMC_SISLANDS_DTE_MAX_FILTER_STAGES];
+    uint32_t K;
+    uint32_t T0;
+    uint32_t MaxT;
+    uint8_t  WindowSize;
+    uint8_t  Tdep_count;
+    uint8_t  temp_select;
+    uint8_t  DTE_mode;
+    uint8_t  T_limits[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+    uint32_t Tdep_tau[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+    uint32_t Tdep_R[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+    uint32_t Tthreshold;
+};
+
+typedef struct Smc_SIslands_DTE_Configuration Smc_SIslands_DTE_Configuration;
+
+#define SMC_SISLANDS_DTE_STATUS_FLAG_DTE_ON 1
+
+#define SISLANDS_SMC_FIRMWARE_HEADER_LOCATION 0x10000
+
+#define SISLANDS_SMC_FIRMWARE_HEADER_version                   0x0
+#define SISLANDS_SMC_FIRMWARE_HEADER_flags                     0x4
+#define SISLANDS_SMC_FIRMWARE_HEADER_softRegisters             0xC
+#define SISLANDS_SMC_FIRMWARE_HEADER_stateTable                0x10
+#define SISLANDS_SMC_FIRMWARE_HEADER_fanTable                  0x14
+#define SISLANDS_SMC_FIRMWARE_HEADER_CacConfigTable            0x18
+#define SISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable           0x24
+#define SISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable 0x30
+#define SISLANDS_SMC_FIRMWARE_HEADER_spllTable                 0x38
+#define SISLANDS_SMC_FIRMWARE_HEADER_DteConfiguration          0x40
+#define SISLANDS_SMC_FIRMWARE_HEADER_PAPMParameters            0x48
+
+#pragma pack(pop)
+
+int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev,
+                               u32 smc_start_address,
+                               const u8 *src, u32 byte_count, u32 limit);
+void amdgpu_si_start_smc(struct amdgpu_device *adev);
+void amdgpu_si_reset_smc(struct amdgpu_device *adev);
+int amdgpu_si_program_jump_on_start(struct amdgpu_device *adev);
+void amdgpu_si_smc_clock(struct amdgpu_device *adev, bool enable);
+bool amdgpu_si_is_smc_running(struct amdgpu_device *adev);
+PPSMC_Result amdgpu_si_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg);
+PPSMC_Result amdgpu_si_wait_for_smc_inactive(struct amdgpu_device *adev);
+int amdgpu_si_load_smc_ucode(struct amdgpu_device *adev, u32 limit);
+int amdgpu_si_read_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
+                                 u32 *value, u32 limit);
+int amdgpu_si_write_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
+                                  u32 value, u32 limit);
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c b/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c
deleted file mode 100644 (file)
index f06f6f4..0000000
+++ /dev/null
@@ -1,186 +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 "tonga_smum.h"
-
-MODULE_FIRMWARE("amdgpu/tonga_smc.bin");
-
-static void tonga_dpm_set_funcs(struct amdgpu_device *adev);
-
-static int tonga_dpm_early_init(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       tonga_dpm_set_funcs(adev);
-
-       return 0;
-}
-
-static int tonga_dpm_init_microcode(struct amdgpu_device *adev)
-{
-       char fw_name[30] = "amdgpu/tonga_smc.bin";
-       int err;
-       err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
-       if (err)
-               goto out;
-       err = amdgpu_ucode_validate(adev->pm.fw);
-
-out:
-       if (err) {
-               DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
-               release_firmware(adev->pm.fw);
-               adev->pm.fw = NULL;
-       }
-       return err;
-}
-
-static int tonga_dpm_sw_init(void *handle)
-{
-       int ret;
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       ret = tonga_dpm_init_microcode(adev);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int tonga_dpm_sw_fini(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       release_firmware(adev->pm.fw);
-       adev->pm.fw = NULL;
-
-       return 0;
-}
-
-static int tonga_dpm_hw_init(void *handle)
-{
-       int ret;
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       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 = tonga_smu_init(adev);
-       if (ret) {
-               DRM_ERROR("SMU initialization failed\n");
-               goto fail;
-       }
-
-       ret = tonga_smu_start(adev);
-       if (ret) {
-               DRM_ERROR("SMU start failed\n");
-               goto fail;
-       }
-
-       mutex_unlock(&adev->pm.mutex);
-       return 0;
-
-fail:
-       adev->firmware.smu_load = false;
-       mutex_unlock(&adev->pm.mutex);
-       return -EINVAL;
-}
-
-static int tonga_dpm_hw_fini(void *handle)
-{
-       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.
-        */
-       tonga_smu_fini(adev);
-       mutex_unlock(&adev->pm.mutex);
-       return 0;
-}
-
-static int tonga_dpm_suspend(void *handle)
-{
-       return tonga_dpm_hw_fini(handle);
-}
-
-static int tonga_dpm_resume(void *handle)
-{
-       return tonga_dpm_hw_init(handle);
-}
-
-static int tonga_dpm_set_clockgating_state(void *handle,
-                       enum amd_clockgating_state state)
-{
-       return 0;
-}
-
-static int tonga_dpm_set_powergating_state(void *handle,
-                       enum amd_powergating_state state)
-{
-       return 0;
-}
-
-const struct amd_ip_funcs tonga_dpm_ip_funcs = {
-       .name = "tonga_dpm",
-       .early_init = tonga_dpm_early_init,
-       .late_init = NULL,
-       .sw_init = tonga_dpm_sw_init,
-       .sw_fini = tonga_dpm_sw_fini,
-       .hw_init = tonga_dpm_hw_init,
-       .hw_fini = tonga_dpm_hw_fini,
-       .suspend = tonga_dpm_suspend,
-       .resume = tonga_dpm_resume,
-       .is_idle = NULL,
-       .wait_for_idle = NULL,
-       .soft_reset = NULL,
-       .set_clockgating_state = tonga_dpm_set_clockgating_state,
-       .set_powergating_state = tonga_dpm_set_powergating_state,
-};
-
-static const struct amdgpu_dpm_funcs tonga_dpm_funcs = {
-       .get_temperature = NULL,
-       .pre_set_power_state = NULL,
-       .set_power_state = NULL,
-       .post_set_power_state = NULL,
-       .display_configuration_changed = NULL,
-       .get_sclk = NULL,
-       .get_mclk = NULL,
-       .print_power_state = NULL,
-       .debugfs_print_current_performance_level = NULL,
-       .force_performance_level = NULL,
-       .vblank_too_short = NULL,
-       .powergate_uvd = NULL,
-};
-
-static void tonga_dpm_set_funcs(struct amdgpu_device *adev)
-{
-       if (NULL == adev->pm.funcs)
-               adev->pm.funcs = &tonga_dpm_funcs;
-}
index c920558..d127d59 100644 (file)
@@ -373,10 +373,10 @@ static int tonga_ih_wait_for_idle(void *handle)
        return -ETIMEDOUT;
 }
 
-static int tonga_ih_soft_reset(void *handle)
+static int tonga_ih_check_soft_reset(void *handle)
 {
-       u32 srbm_soft_reset = 0;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset = 0;
        u32 tmp = RREG32(mmSRBM_STATUS);
 
        if (tmp & SRBM_STATUS__IH_BUSY_MASK)
@@ -384,6 +384,48 @@ static int tonga_ih_soft_reset(void *handle)
                                                SOFT_RESET_IH, 1);
 
        if (srbm_soft_reset) {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang = true;
+               adev->irq.srbm_soft_reset = srbm_soft_reset;
+       } else {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang = false;
+               adev->irq.srbm_soft_reset = 0;
+       }
+
+       return 0;
+}
+
+static int tonga_ih_pre_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang)
+               return 0;
+
+       return tonga_ih_hw_fini(adev);
+}
+
+static int tonga_ih_post_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang)
+               return 0;
+
+       return tonga_ih_hw_init(adev);
+}
+
+static int tonga_ih_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang)
+               return 0;
+       srbm_soft_reset = adev->irq.srbm_soft_reset;
+
+       if (srbm_soft_reset) {
+               u32 tmp;
+
                tmp = RREG32(mmSRBM_SOFT_RESET);
                tmp |= srbm_soft_reset;
                dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
@@ -427,7 +469,10 @@ const struct amd_ip_funcs tonga_ih_ip_funcs = {
        .resume = tonga_ih_resume,
        .is_idle = tonga_ih_is_idle,
        .wait_for_idle = tonga_ih_wait_for_idle,
+       .check_soft_reset = tonga_ih_check_soft_reset,
+       .pre_soft_reset = tonga_ih_pre_soft_reset,
        .soft_reset = tonga_ih_soft_reset,
+       .post_soft_reset = tonga_ih_post_soft_reset,
        .set_clockgating_state = tonga_ih_set_clockgating_state,
        .set_powergating_state = tonga_ih_set_powergating_state,
 };
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c
deleted file mode 100644 (file)
index 940de18..0000000
+++ /dev/null
@@ -1,862 +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 "tonga_ppsmc.h"
-#include "tonga_smum.h"
-#include "smu_ucode_xfer_vi.h"
-#include "amdgpu_ucode.h"
-
-#include "smu/smu_7_1_2_d.h"
-#include "smu/smu_7_1_2_sh_mask.h"
-
-#define TONGA_SMC_SIZE 0x20000
-
-static int tonga_set_smc_sram_address(struct amdgpu_device *adev, uint32_t smc_address, uint32_t limit)
-{
-       uint32_t val;
-
-       if (smc_address & 3)
-               return -EINVAL;
-
-       if ((smc_address + 3) > limit)
-               return -EINVAL;
-
-       WREG32(mmSMC_IND_INDEX_0, smc_address);
-
-       val = RREG32(mmSMC_IND_ACCESS_CNTL);
-       val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
-       WREG32(mmSMC_IND_ACCESS_CNTL, val);
-
-       return 0;
-}
-
-static int tonga_copy_bytes_to_smc(struct amdgpu_device *adev, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit)
-{
-       uint32_t addr;
-       uint32_t data, orig_data;
-       int result = 0;
-       uint32_t extra_shift;
-       unsigned long flags;
-
-       if (smc_start_address & 3)
-               return -EINVAL;
-
-       if ((smc_start_address + byte_count) > limit)
-               return -EINVAL;
-
-       addr = smc_start_address;
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       while (byte_count >= 4) {
-               /* Bytes are written into the SMC addres space with the MSB first */
-               data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
-
-               result = tonga_set_smc_sram_address(adev, addr, limit);
-
-               if (result)
-                       goto out;
-
-               WREG32(mmSMC_IND_DATA_0, data);
-
-               src += 4;
-               byte_count -= 4;
-               addr += 4;
-       }
-
-       if (0 != byte_count) {
-               /* Now write odd bytes left, do a read modify write cycle */
-               data = 0;
-
-               result = tonga_set_smc_sram_address(adev, addr, limit);
-               if (result)
-                       goto out;
-
-               orig_data = RREG32(mmSMC_IND_DATA_0);
-               extra_shift = 8 * (4 - byte_count);
-
-               while (byte_count > 0) {
-                       data = (data << 8) + *src++;
-                       byte_count--;
-               }
-
-               data <<= extra_shift;
-               data |= (orig_data & ~((~0UL) << extra_shift));
-
-               result = tonga_set_smc_sram_address(adev, addr, limit);
-               if (result)
-                       goto out;
-
-               WREG32(mmSMC_IND_DATA_0, data);
-       }
-
-out:
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-       return result;
-}
-
-static int tonga_program_jump_on_start(struct amdgpu_device *adev)
-{
-       static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40};
-       tonga_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
-
-       return 0;
-}
-
-static bool tonga_is_smc_ram_running(struct amdgpu_device *adev)
-{
-       uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-       val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable);
-
-       return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C)));
-}
-
-static int wait_smu_response(struct amdgpu_device *adev)
-{
-       int i;
-       uint32_t val;
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32(mmSMC_RESP_0);
-               if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int tonga_send_msg_to_smc_offset(struct amdgpu_device *adev)
-{
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MSG_ARG_0, 0x20000);
-       WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_Test);
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send message\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int tonga_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg)
-{
-       if (!tonga_is_smc_ram_running(adev))
-       {
-               return -EINVAL;
-       }
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MESSAGE_0, msg);
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send message\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int tonga_send_msg_to_smc_without_waiting(struct amdgpu_device *adev,
-                                               PPSMC_Msg msg)
-{
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MESSAGE_0, msg);
-
-       return 0;
-}
-
-static int tonga_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
-                                               PPSMC_Msg msg,
-                                               uint32_t parameter)
-{
-       if (!tonga_is_smc_ram_running(adev))
-               return -EINVAL;
-
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MSG_ARG_0, parameter);
-
-       return tonga_send_msg_to_smc(adev, msg);
-}
-
-static int tonga_send_msg_to_smc_with_parameter_without_waiting(
-                                       struct amdgpu_device *adev,
-                                       PPSMC_Msg msg, uint32_t parameter)
-{
-       if (wait_smu_response(adev)) {
-               DRM_ERROR("Failed to send previous message\n");
-               return -EINVAL;
-       }
-
-       WREG32(mmSMC_MSG_ARG_0, parameter);
-
-       return tonga_send_msg_to_smc_without_waiting(adev, msg);
-}
-
-#if 0 /* not used yet */
-static int tonga_wait_for_smc_inactive(struct amdgpu_device *adev)
-{
-       int i;
-       uint32_t val;
-
-       if (!tonga_is_smc_ram_running(adev))
-               return -EINVAL;
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-               if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0)
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout)
-               return -EINVAL;
-
-       return 0;
-}
-#endif
-
-static int tonga_smu_upload_firmware_image(struct amdgpu_device *adev)
-{
-       const struct smc_firmware_header_v1_0 *hdr;
-       uint32_t ucode_size;
-       uint32_t ucode_start_address;
-       const uint8_t *src;
-       uint32_t val;
-       uint32_t byte_count;
-       uint32_t *data;
-       unsigned long flags;
-
-       if (!adev->pm.fw)
-               return -EINVAL;
-
-       /* Skip SMC ucode loading on SR-IOV capable boards.
-        * vbios does this for us in asic_init in that case.
-        */
-       if (adev->virtualization.supports_sr_iov)
-               return 0;
-
-       hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
-       amdgpu_ucode_print_smc_hdr(&hdr->header);
-
-       adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
-       ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
-       ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
-       src = (const uint8_t *)
-               (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-
-       if (ucode_size & 3) {
-               DRM_ERROR("SMC ucode is not 4 bytes aligned\n");
-               return -EINVAL;
-       }
-
-       if (ucode_size > TONGA_SMC_SIZE) {
-               DRM_ERROR("SMC address is beyond the SMC RAM area\n");
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
-
-       val = RREG32(mmSMC_IND_ACCESS_CNTL);
-       val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
-       WREG32(mmSMC_IND_ACCESS_CNTL, val);
-
-       byte_count = ucode_size;
-       data = (uint32_t *)src;
-       for (; byte_count >= 4; data++, byte_count -= 4)
-               WREG32(mmSMC_IND_DATA_0, data[0]);
-
-       val = RREG32(mmSMC_IND_ACCESS_CNTL);
-       val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
-       WREG32(mmSMC_IND_ACCESS_CNTL, val);
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-
-       return 0;
-}
-
-#if 0 /* not used yet */
-static int tonga_read_smc_sram_dword(struct amdgpu_device *adev,
-                               uint32_t smc_address,
-                               uint32_t *value,
-                               uint32_t limit)
-{
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       result = tonga_set_smc_sram_address(adev, smc_address, limit);
-       if (result == 0)
-               *value = RREG32(mmSMC_IND_DATA_0);
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-       return result;
-}
-
-static int tonga_write_smc_sram_dword(struct amdgpu_device *adev,
-                               uint32_t smc_address,
-                               uint32_t value,
-                               uint32_t limit)
-{
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&adev->smc_idx_lock, flags);
-       result = tonga_set_smc_sram_address(adev, smc_address, limit);
-       if (result == 0)
-               WREG32(mmSMC_IND_DATA_0, value);
-       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
-       return result;
-}
-
-static int tonga_smu_stop_smc(struct amdgpu_device *adev)
-{
-       uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-       val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1);
-       WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
-
-       return 0;
-}
-#endif
-
-static enum AMDGPU_UCODE_ID tonga_convert_fw_type(uint32_t fw_type)
-{
-       switch (fw_type) {
-               case UCODE_ID_SDMA0:
-                       return AMDGPU_UCODE_ID_SDMA0;
-               case UCODE_ID_SDMA1:
-                       return AMDGPU_UCODE_ID_SDMA1;
-               case UCODE_ID_CP_CE:
-                       return AMDGPU_UCODE_ID_CP_CE;
-               case UCODE_ID_CP_PFP:
-                       return AMDGPU_UCODE_ID_CP_PFP;
-               case UCODE_ID_CP_ME:
-                       return AMDGPU_UCODE_ID_CP_ME;
-               case UCODE_ID_CP_MEC:
-               case UCODE_ID_CP_MEC_JT1:
-                       return AMDGPU_UCODE_ID_CP_MEC1;
-               case UCODE_ID_CP_MEC_JT2:
-                       return AMDGPU_UCODE_ID_CP_MEC2;
-               case UCODE_ID_RLC_G:
-                       return AMDGPU_UCODE_ID_RLC_G;
-               default:
-                       DRM_ERROR("ucode type is out of range!\n");
-                       return AMDGPU_UCODE_ID_MAXIMUM;
-       }
-}
-
-static int tonga_smu_populate_single_firmware_entry(struct amdgpu_device *adev,
-                                               uint32_t fw_type,
-                                               struct SMU_Entry *entry)
-{
-       enum AMDGPU_UCODE_ID id = tonga_convert_fw_type(fw_type);
-       struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id];
-       const struct gfx_firmware_header_v1_0 *header = NULL;
-       uint64_t gpu_addr;
-       uint32_t data_size;
-
-       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 ((fw_type == UCODE_ID_CP_MEC_JT1) ||
-               (fw_type == UCODE_ID_CP_MEC_JT2)) {
-               gpu_addr += le32_to_cpu(header->jt_offset) << 2;
-               data_size = le32_to_cpu(header->jt_size) << 2;
-       }
-
-       entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version);
-       entry->id = (uint16_t)fw_type;
-       entry->image_addr_high = upper_32_bits(gpu_addr);
-       entry->image_addr_low = lower_32_bits(gpu_addr);
-       entry->meta_data_addr_high = 0;
-       entry->meta_data_addr_low = 0;
-       entry->data_size_byte = data_size;
-       entry->num_register_entries = 0;
-
-       if (fw_type == UCODE_ID_RLC_G)
-               entry->flags = 1;
-       else
-               entry->flags = 0;
-
-       return 0;
-}
-
-static int tonga_smu_request_load_fw(struct amdgpu_device *adev)
-{
-       struct tonga_smu_private_data *private = (struct tonga_smu_private_data *)adev->smu.priv;
-       struct SMU_DRAMData_TOC *toc;
-       uint32_t fw_to_load;
-
-       WREG32_SMC(ixSOFT_REGISTERS_TABLE_28, 0);
-
-       tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_HI, private->smu_buffer_addr_high);
-       tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_LO, private->smu_buffer_addr_low);
-
-       toc = (struct SMU_DRAMData_TOC *)private->header;
-       toc->num_entries = 0;
-       toc->structure_version = 1;
-
-       if (!adev->firmware.smu_load)
-               return 0;
-
-       if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for RLC\n");
-               return -EINVAL;
-       }
-
-       if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for CE\n");
-               return -EINVAL;
-       }
-
-       if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for PFP\n");
-               return -EINVAL;
-       }
-
-       if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for ME\n");
-               return -EINVAL;
-       }
-
-       if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for MEC\n");
-               return -EINVAL;
-       }
-
-       if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for MEC_JT1\n");
-               return -EINVAL;
-       }
-
-       if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for MEC_JT2\n");
-               return -EINVAL;
-       }
-
-       if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for SDMA0\n");
-               return -EINVAL;
-       }
-
-       if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for SDMA1\n");
-               return -EINVAL;
-       }
-
-       tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high);
-       tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low);
-
-       fw_to_load = 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_MASK;
-
-       if (tonga_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) {
-               DRM_ERROR("Fail to request SMU load ucode\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static uint32_t tonga_smu_get_mask_for_fw_type(uint32_t fw_type)
-{
-       switch (fw_type) {
-               case AMDGPU_UCODE_ID_SDMA0:
-                       return UCODE_ID_SDMA0_MASK;
-               case AMDGPU_UCODE_ID_SDMA1:
-                       return UCODE_ID_SDMA1_MASK;
-               case AMDGPU_UCODE_ID_CP_CE:
-                       return UCODE_ID_CP_CE_MASK;
-               case AMDGPU_UCODE_ID_CP_PFP:
-                       return UCODE_ID_CP_PFP_MASK;
-               case AMDGPU_UCODE_ID_CP_ME:
-                       return UCODE_ID_CP_ME_MASK;
-               case AMDGPU_UCODE_ID_CP_MEC1:
-                       return UCODE_ID_CP_MEC_MASK;
-               case AMDGPU_UCODE_ID_CP_MEC2:
-                       return UCODE_ID_CP_MEC_MASK;
-               case AMDGPU_UCODE_ID_RLC_G:
-                       return UCODE_ID_RLC_G_MASK;
-               default:
-                       DRM_ERROR("ucode type is out of range!\n");
-                       return 0;
-       }
-}
-
-static int tonga_smu_check_fw_load_finish(struct amdgpu_device *adev,
-                                       uint32_t fw_type)
-{
-       uint32_t fw_mask = tonga_smu_get_mask_for_fw_type(fw_type);
-       int i;
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_28) & fw_mask))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("check firmware loading failed\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int tonga_smu_start_in_protection_mode(struct amdgpu_device *adev)
-{
-       int result;
-       uint32_t val;
-       int i;
-
-       /* Assert reset */
-       val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       result = tonga_smu_upload_firmware_image(adev);
-       if (result)
-               return result;
-
-       /* Clear status */
-       WREG32_SMC(ixSMU_STATUS, 0);
-
-       /* Enable clock */
-       val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-       val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
-       WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
-
-       /* De-assert reset */
-       val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       /* Set SMU Auto Start */
-       val = RREG32_SMC(ixSMU_INPUT_DATA);
-       val = REG_SET_FIELD(val, SMU_INPUT_DATA, AUTO_START, 1);
-       WREG32_SMC(ixSMU_INPUT_DATA, val);
-
-       /* Clear firmware interrupt enable flag */
-       WREG32_SMC(ixFIRMWARE_FLAGS, 0);
-
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixRCU_UC_EVENTS);
-               if (REG_GET_FIELD(val, RCU_UC_EVENTS, INTERRUPTS_ENABLED))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("Interrupt is not enabled by firmware\n");
-               return -EINVAL;
-       }
-
-       /* Call Test SMU message with 0x20000 offset
-        * to trigger SMU start
-        */
-       tonga_send_msg_to_smc_offset(adev);
-
-       /* Wait for done bit to be set */
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixSMU_STATUS);
-               if (REG_GET_FIELD(val, SMU_STATUS, SMU_DONE))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("Timeout for SMU start\n");
-               return -EINVAL;
-       }
-
-       /* Check pass/failed indicator */
-       val = RREG32_SMC(ixSMU_STATUS);
-       if (!REG_GET_FIELD(val, SMU_STATUS, SMU_PASS)) {
-               DRM_ERROR("SMU Firmware start failed\n");
-               return -EINVAL;
-       }
-
-       /* Wait for firmware to initialize */
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixFIRMWARE_FLAGS);
-               if(REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("SMU firmware initialization failed\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int tonga_smu_start_in_non_protection_mode(struct amdgpu_device *adev)
-{
-       int i, result;
-       uint32_t val;
-
-       /* wait for smc boot up */
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixRCU_UC_EVENTS);
-               val = REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done);
-               if (val)
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("SMC boot sequence is not completed\n");
-               return -EINVAL;
-       }
-
-       /* Clear firmware interrupt enable flag */
-       WREG32_SMC(ixFIRMWARE_FLAGS, 0);
-
-       /* Assert reset */
-       val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       result = tonga_smu_upload_firmware_image(adev);
-       if (result)
-               return result;
-
-       /* Set smc instruct start point at 0x0 */
-       tonga_program_jump_on_start(adev);
-
-       /* Enable clock */
-       val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
-       val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
-       WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val);
-
-       /* De-assert reset */
-       val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
-       val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0);
-       WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val);
-
-       /* Wait for firmware to initialize */
-       for (i = 0; i < adev->usec_timeout; i++) {
-               val = RREG32_SMC(ixFIRMWARE_FLAGS);
-               if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED))
-                       break;
-               udelay(1);
-       }
-
-       if (i == adev->usec_timeout) {
-               DRM_ERROR("Timeout for SMC firmware initialization\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int tonga_smu_start(struct amdgpu_device *adev)
-{
-       int result;
-       uint32_t val;
-
-       if (!tonga_is_smc_ram_running(adev)) {
-               val = RREG32_SMC(ixSMU_FIRMWARE);
-               if (!REG_GET_FIELD(val, SMU_FIRMWARE, SMU_MODE)) {
-                       result = tonga_smu_start_in_non_protection_mode(adev);
-                       if (result)
-                               return result;
-               } else {
-                       result = tonga_smu_start_in_protection_mode(adev);
-                       if (result)
-                               return result;
-               }
-       }
-
-       return tonga_smu_request_load_fw(adev);
-}
-
-static const struct amdgpu_smumgr_funcs tonga_smumgr_funcs = {
-       .check_fw_load_finish = tonga_smu_check_fw_load_finish,
-       .request_smu_load_fw = NULL,
-       .request_smu_specific_fw = NULL,
-};
-
-int tonga_smu_init(struct amdgpu_device *adev)
-{
-       struct tonga_smu_private_data *private;
-       uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
-       uint32_t smu_internal_buffer_size = 200*4096;
-       struct amdgpu_bo **toc_buf = &adev->smu.toc_buf;
-       struct amdgpu_bo **smu_buf = &adev->smu.smu_buf;
-       uint64_t mc_addr;
-       void *toc_buf_ptr;
-       void *smu_buf_ptr;
-       int ret;
-
-       private = kzalloc(sizeof(struct tonga_smu_private_data), GFP_KERNEL);
-       if (NULL == private)
-               return -ENOMEM;
-
-       /* allocate firmware buffers */
-       if (adev->firmware.smu_load)
-               amdgpu_ucode_init_bo(adev);
-
-       adev->smu.priv = private;
-       adev->smu.fw_flags = 0;
-
-       /* Allocate FW image data structure and header buffer */
-       ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE,
-                              true, AMDGPU_GEM_DOMAIN_VRAM,
-                              AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
-                              NULL, NULL, toc_buf);
-       if (ret) {
-               DRM_ERROR("Failed to allocate memory for TOC buffer\n");
-               return -ENOMEM;
-       }
-
-       /* Allocate buffer for SMU internal buffer */
-       ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE,
-                              true, AMDGPU_GEM_DOMAIN_VRAM,
-                              AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
-                              NULL, NULL, smu_buf);
-       if (ret) {
-               DRM_ERROR("Failed to allocate memory for SMU internal buffer\n");
-               return -ENOMEM;
-       }
-
-       /* Retrieve GPU address for header buffer and internal buffer */
-       ret = amdgpu_bo_reserve(adev->smu.toc_buf, false);
-       if (ret) {
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to reserve the TOC buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.toc_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to pin the TOC buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.toc_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to map the TOC buffer\n");
-               return -EINVAL;
-       }
-
-       amdgpu_bo_unreserve(adev->smu.toc_buf);
-       private->header_addr_low = lower_32_bits(mc_addr);
-       private->header_addr_high = upper_32_bits(mc_addr);
-       private->header = toc_buf_ptr;
-
-       ret = amdgpu_bo_reserve(adev->smu.smu_buf, false);
-       if (ret) {
-               amdgpu_bo_unref(&adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to reserve the SMU internal buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to pin the SMU internal buffer\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr);
-       if (ret) {
-               amdgpu_bo_unreserve(adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.smu_buf);
-               amdgpu_bo_unref(&adev->smu.toc_buf);
-               DRM_ERROR("Failed to map the SMU internal buffer\n");
-               return -EINVAL;
-       }
-
-       amdgpu_bo_unreserve(adev->smu.smu_buf);
-       private->smu_buffer_addr_low = lower_32_bits(mc_addr);
-       private->smu_buffer_addr_high = upper_32_bits(mc_addr);
-
-       adev->smu.smumgr_funcs = &tonga_smumgr_funcs;
-
-       return 0;
-}
-
-int tonga_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.fw_buf)
-               amdgpu_ucode_fini_bo(adev);
-
-       return 0;
-}
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_smum.h b/drivers/gpu/drm/amd/amdgpu/tonga_smum.h
deleted file mode 100644 (file)
index c031ff9..0000000
+++ /dev/null
@@ -1,42 +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 TONGA_SMUMGR_H
-#define TONGA_SMUMGR_H
-
-#include "tonga_ppsmc.h"
-
-int tonga_smu_init(struct amdgpu_device *adev);
-int tonga_smu_fini(struct amdgpu_device *adev);
-int tonga_smu_start(struct amdgpu_device *adev);
-
-struct tonga_smu_private_data
-{
-       uint8_t *header;
-       uint32_t smu_buffer_addr_high;
-       uint32_t smu_buffer_addr_low;
-       uint32_t header_addr_high;
-       uint32_t header_addr_low;
-};
-
-#endif
index 132e613..f6c9415 100644 (file)
@@ -116,7 +116,7 @@ static int uvd_v4_2_sw_init(void *handle)
 
        ring = &adev->uvd.ring;
        sprintf(ring->name, "uvd");
-       r = amdgpu_ring_init(adev, ring, 512, CP_PACKET2, 0xf,
+       r = amdgpu_ring_init(adev, ring, 512, PACKET0(mmUVD_NO_OP, 0), 0xf,
                             &adev->uvd.irq, 0, AMDGPU_RING_TYPE_UVD);
 
        return r;
@@ -526,6 +526,20 @@ static void uvd_v4_2_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, ib->length_dw);
 }
 
+static unsigned uvd_v4_2_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               4; /* uvd_v4_2_ring_emit_ib */
+}
+
+static unsigned uvd_v4_2_ring_get_dma_frame_size(struct amdgpu_ring *ring)
+{
+       return
+               2 + /* uvd_v4_2_ring_emit_hdp_flush */
+               2 + /* uvd_v4_2_ring_emit_hdp_invalidate */
+               14; /* uvd_v4_2_ring_emit_fence  x1 no user fence */
+}
+
 /**
  * uvd_v4_2_mc_resume - memory controller programming
  *
@@ -756,6 +770,8 @@ static const struct amdgpu_ring_funcs uvd_v4_2_ring_funcs = {
        .pad_ib = amdgpu_ring_generic_pad_ib,
        .begin_use = amdgpu_uvd_ring_begin_use,
        .end_use = amdgpu_uvd_ring_end_use,
+       .get_emit_ib_size = uvd_v4_2_ring_get_emit_ib_size,
+       .get_dma_frame_size = uvd_v4_2_ring_get_dma_frame_size,
 };
 
 static void uvd_v4_2_set_ring_funcs(struct amdgpu_device *adev)
index 101de13..400c16f 100644 (file)
@@ -112,7 +112,7 @@ static int uvd_v5_0_sw_init(void *handle)
 
        ring = &adev->uvd.ring;
        sprintf(ring->name, "uvd");
-       r = amdgpu_ring_init(adev, ring, 512, CP_PACKET2, 0xf,
+       r = amdgpu_ring_init(adev, ring, 512, PACKET0(mmUVD_NO_OP, 0), 0xf,
                             &adev->uvd.irq, 0, AMDGPU_RING_TYPE_UVD);
 
        return r;
@@ -577,6 +577,20 @@ static void uvd_v5_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, ib->length_dw);
 }
 
+static unsigned uvd_v5_0_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               6; /* uvd_v5_0_ring_emit_ib */
+}
+
+static unsigned uvd_v5_0_ring_get_dma_frame_size(struct amdgpu_ring *ring)
+{
+       return
+               2 + /* uvd_v5_0_ring_emit_hdp_flush */
+               2 + /* uvd_v5_0_ring_emit_hdp_invalidate */
+               14; /* uvd_v5_0_ring_emit_fence  x1 no user fence */
+}
+
 static bool uvd_v5_0_is_idle(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -807,6 +821,8 @@ static const struct amdgpu_ring_funcs uvd_v5_0_ring_funcs = {
        .pad_ib = amdgpu_ring_generic_pad_ib,
        .begin_use = amdgpu_uvd_ring_begin_use,
        .end_use = amdgpu_uvd_ring_end_use,
+       .get_emit_ib_size = uvd_v5_0_ring_get_emit_ib_size,
+       .get_dma_frame_size = uvd_v5_0_ring_get_dma_frame_size,
 };
 
 static void uvd_v5_0_set_ring_funcs(struct amdgpu_device *adev)
index 7f21102..e0fd9f2 100644 (file)
@@ -116,7 +116,7 @@ static int uvd_v6_0_sw_init(void *handle)
 
        ring = &adev->uvd.ring;
        sprintf(ring->name, "uvd");
-       r = amdgpu_ring_init(adev, ring, 512, CP_PACKET2, 0xf,
+       r = amdgpu_ring_init(adev, ring, 512, PACKET0(mmUVD_NO_OP, 0), 0xf,
                             &adev->uvd.irq, 0, AMDGPU_RING_TYPE_UVD);
 
        return r;
@@ -396,21 +396,14 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
 
        uvd_v6_0_mc_resume(adev);
 
-       /* Set dynamic clock gating in S/W control mode */
-       if (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG) {
-               uvd_v6_0_set_sw_clock_gating(adev);
-       } else {
-               /* disable clock gating */
-               uint32_t data = RREG32(mmUVD_CGC_CTRL);
-               data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
-               WREG32(mmUVD_CGC_CTRL, data);
-       }
+       /* disable clock gating */
+       WREG32_FIELD(UVD_CGC_CTRL, DYN_CLOCK_MODE, 0);
 
        /* disable interupt */
-       WREG32_P(mmUVD_MASTINT_EN, 0, ~UVD_MASTINT_EN__VCPU_EN_MASK);
+       WREG32_FIELD(UVD_MASTINT_EN, VCPU_EN, 0);
 
        /* stall UMC and register bus before resetting VCPU */
-       WREG32_P(mmUVD_LMI_CTRL2, UVD_LMI_CTRL2__STALL_ARB_UMC_MASK, ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
+       WREG32_FIELD(UVD_LMI_CTRL2, STALL_ARB_UMC, 1);
        mdelay(1);
 
        /* put LMI, VCPU, RBC etc... into reset */
@@ -426,7 +419,7 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
        mdelay(5);
 
        /* take UVD block out of reset */
-       WREG32_P(mmSRBM_SOFT_RESET, 0, ~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK);
+       WREG32_FIELD(SRBM_SOFT_RESET, SOFT_RESET_UVD, 0);
        mdelay(5);
 
        /* initialize UVD memory controller */
@@ -461,7 +454,7 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
        WREG32(mmUVD_VCPU_CNTL, UVD_VCPU_CNTL__CLK_EN_MASK);
 
        /* enable UMC */
-       WREG32_P(mmUVD_LMI_CTRL2, 0, ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
+       WREG32_FIELD(UVD_LMI_CTRL2, STALL_ARB_UMC, 0);
 
        /* boot up the VCPU */
        WREG32(mmUVD_SOFT_RESET, 0);
@@ -481,11 +474,9 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
                        break;
 
                DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");
-               WREG32_P(mmUVD_SOFT_RESET, UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK,
-                               ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);
+               WREG32_FIELD(UVD_SOFT_RESET, VCPU_SOFT_RESET, 1);
                mdelay(10);
-               WREG32_P(mmUVD_SOFT_RESET, 0,
-                        ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);
+               WREG32_FIELD(UVD_SOFT_RESET, VCPU_SOFT_RESET, 0);
                mdelay(10);
                r = -1;
        }
@@ -502,15 +493,14 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
        /* clear the bit 4 of UVD_STATUS */
        WREG32_P(mmUVD_STATUS, 0, ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
 
+       /* force RBC into idle state */
        rb_bufsz = order_base_2(ring->ring_size);
-       tmp = 0;
-       tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
+       tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_WPTR_POLL_EN, 0);
        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
-       /* force RBC into idle state */
        WREG32(mmUVD_RBC_RB_CNTL, tmp);
 
        /* set the write pointer delay */
@@ -531,7 +521,7 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
        ring->wptr = RREG32(mmUVD_RBC_RB_RPTR);
        WREG32(mmUVD_RBC_RB_WPTR, ring->wptr);
 
-       WREG32_P(mmUVD_RBC_RB_CNTL, 0, ~UVD_RBC_RB_CNTL__RB_NO_FETCH_MASK);
+       WREG32_FIELD(UVD_RBC_RB_CNTL, RB_NO_FETCH, 0);
 
        return 0;
 }
@@ -735,6 +725,31 @@ static void uvd_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
        amdgpu_ring_write(ring, 0xE);
 }
 
+static unsigned uvd_v6_0_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               8; /* uvd_v6_0_ring_emit_ib */
+}
+
+static unsigned uvd_v6_0_ring_get_dma_frame_size(struct amdgpu_ring *ring)
+{
+       return
+               2 + /* uvd_v6_0_ring_emit_hdp_flush */
+               2 + /* uvd_v6_0_ring_emit_hdp_invalidate */
+               10 + /* uvd_v6_0_ring_emit_pipeline_sync */
+               14; /* uvd_v6_0_ring_emit_fence x1 no user fence */
+}
+
+static unsigned uvd_v6_0_ring_get_dma_frame_size_vm(struct amdgpu_ring *ring)
+{
+       return
+               2 + /* uvd_v6_0_ring_emit_hdp_flush */
+               2 + /* uvd_v6_0_ring_emit_hdp_invalidate */
+               10 + /* uvd_v6_0_ring_emit_pipeline_sync */
+               20 + /* uvd_v6_0_ring_emit_vm_flush */
+               14 + 14; /* uvd_v6_0_ring_emit_fence x2 vm fence */
+}
+
 static bool uvd_v6_0_is_idle(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -748,20 +763,82 @@ static int uvd_v6_0_wait_for_idle(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        for (i = 0; i < adev->usec_timeout; i++) {
-               if (!(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK))
+               if (uvd_v6_0_is_idle(handle))
                        return 0;
        }
        return -ETIMEDOUT;
 }
 
-static int uvd_v6_0_soft_reset(void *handle)
+#define AMDGPU_UVD_STATUS_BUSY_MASK    0xfd
+static int uvd_v6_0_check_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset = 0;
+       u32 tmp = RREG32(mmSRBM_STATUS);
+
+       if (REG_GET_FIELD(tmp, SRBM_STATUS, UVD_RQ_PENDING) ||
+           REG_GET_FIELD(tmp, SRBM_STATUS, UVD_BUSY) ||
+           (RREG32(mmUVD_STATUS) & AMDGPU_UVD_STATUS_BUSY_MASK))
+               srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_UVD, 1);
+
+       if (srbm_soft_reset) {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = true;
+               adev->uvd.srbm_soft_reset = srbm_soft_reset;
+       } else {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = false;
+               adev->uvd.srbm_soft_reset = 0;
+       }
+       return 0;
+}
+static int uvd_v6_0_pre_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang)
+               return 0;
 
        uvd_v6_0_stop(adev);
+       return 0;
+}
+
+static int uvd_v6_0_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang)
+               return 0;
+       srbm_soft_reset = adev->uvd.srbm_soft_reset;
+
+       if (srbm_soft_reset) {
+               u32 tmp;
+
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+               tmp |= srbm_soft_reset;
+               dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+               WREG32(mmSRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+
+               udelay(50);
+
+               tmp &= ~srbm_soft_reset;
+               WREG32(mmSRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+
+               /* Wait a little for things to settle down */
+               udelay(50);
+       }
+
+       return 0;
+}
+
+static int uvd_v6_0_post_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang)
+               return 0;
 
-       WREG32_P(mmSRBM_SOFT_RESET, SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK,
-                       ~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK);
        mdelay(5);
 
        return uvd_v6_0_start(adev);
@@ -902,21 +979,15 @@ static int uvd_v6_0_set_clockgating_state(void *handle,
                                          enum amd_clockgating_state state)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-       bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
-       static int curstate = -1;
 
        if (adev->asic_type == CHIP_FIJI ||
-                       adev->asic_type == CHIP_POLARIS10)
-               uvd_v6_set_bypass_mode(adev, enable);
+           adev->asic_type == CHIP_POLARIS10)
+               uvd_v6_set_bypass_mode(adev, state == AMD_CG_STATE_GATE ? true : false);
 
        if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
                return 0;
 
-       if (curstate == state)
-               return 0;
-
-       curstate = state;
-       if (enable) {
+       if (state == AMD_CG_STATE_GATE) {
                /* disable HW gating and enable Sw gating */
                uvd_v6_0_set_sw_clock_gating(adev);
        } else {
@@ -946,6 +1017,8 @@ static int uvd_v6_0_set_powergating_state(void *handle,
        if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
                return 0;
 
+       WREG32(mmUVD_POWER_STATUS, UVD_POWER_STATUS__UVD_PG_EN_MASK);
+
        if (state == AMD_PG_STATE_GATE) {
                uvd_v6_0_stop(adev);
                return 0;
@@ -966,7 +1039,10 @@ const struct amd_ip_funcs uvd_v6_0_ip_funcs = {
        .resume = uvd_v6_0_resume,
        .is_idle = uvd_v6_0_is_idle,
        .wait_for_idle = uvd_v6_0_wait_for_idle,
+       .check_soft_reset = uvd_v6_0_check_soft_reset,
+       .pre_soft_reset = uvd_v6_0_pre_soft_reset,
        .soft_reset = uvd_v6_0_soft_reset,
+       .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,
 };
@@ -986,6 +1062,8 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_phys_funcs = {
        .pad_ib = amdgpu_ring_generic_pad_ib,
        .begin_use = amdgpu_uvd_ring_begin_use,
        .end_use = amdgpu_uvd_ring_end_use,
+       .get_emit_ib_size = uvd_v6_0_ring_get_emit_ib_size,
+       .get_dma_frame_size = uvd_v6_0_ring_get_dma_frame_size,
 };
 
 static const struct amdgpu_ring_funcs uvd_v6_0_ring_vm_funcs = {
@@ -1005,6 +1083,8 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_vm_funcs = {
        .pad_ib = amdgpu_ring_generic_pad_ib,
        .begin_use = amdgpu_uvd_ring_begin_use,
        .end_use = amdgpu_uvd_ring_end_use,
+       .get_emit_ib_size = uvd_v6_0_ring_get_emit_ib_size,
+       .get_dma_frame_size = uvd_v6_0_ring_get_dma_frame_size_vm,
 };
 
 static void uvd_v6_0_set_ring_funcs(struct amdgpu_device *adev)
index 80a37a6..76e64ad 100644 (file)
 #include "amdgpu.h"
 #include "amdgpu_vce.h"
 #include "cikd.h"
-
 #include "vce/vce_2_0_d.h"
 #include "vce/vce_2_0_sh_mask.h"
-
+#include "smu/smu_7_0_1_d.h"
+#include "smu/smu_7_0_1_sh_mask.h"
 #include "oss/oss_2_0_d.h"
 #include "oss/oss_2_0_sh_mask.h"
 
 #define VCE_V2_0_FW_SIZE       (256 * 1024)
 #define VCE_V2_0_STACK_SIZE    (64 * 1024)
 #define VCE_V2_0_DATA_SIZE     (23552 * AMDGPU_MAX_VCE_HANDLES)
+#define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK  0x02
 
 static void vce_v2_0_mc_resume(struct amdgpu_device *adev);
 static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev);
@@ -96,6 +97,49 @@ static void vce_v2_0_ring_set_wptr(struct amdgpu_ring *ring)
                WREG32(mmVCE_RB_WPTR2, ring->wptr);
 }
 
+static int vce_v2_0_lmi_clean(struct amdgpu_device *adev)
+{
+       int i, j;
+
+       for (i = 0; i < 10; ++i) {
+               for (j = 0; j < 100; ++j) {
+                       uint32_t status = RREG32(mmVCE_LMI_STATUS);
+
+                       if (status & 0x337f)
+                               return 0;
+                       mdelay(10);
+               }
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int vce_v2_0_firmware_loaded(struct amdgpu_device *adev)
+{
+       int i, j;
+
+       for (i = 0; i < 10; ++i) {
+               for (j = 0; j < 100; ++j) {
+                       uint32_t status = RREG32(mmVCE_STATUS);
+
+                       if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK)
+                               return 0;
+                       mdelay(10);
+               }
+
+               DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
+               WREG32_P(mmVCE_SOFT_RESET,
+                       VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
+                       ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
+               mdelay(10);
+               WREG32_P(mmVCE_SOFT_RESET, 0,
+                       ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
+               mdelay(10);
+       }
+
+       return -ETIMEDOUT;
+}
+
 /**
  * vce_v2_0_start - start VCE block
  *
@@ -106,7 +150,7 @@ static void vce_v2_0_ring_set_wptr(struct amdgpu_ring *ring)
 static int vce_v2_0_start(struct amdgpu_device *adev)
 {
        struct amdgpu_ring *ring;
-       int i, j, r;
+       int r;
 
        vce_v2_0_mc_resume(adev);
 
@@ -127,36 +171,12 @@ static int vce_v2_0_start(struct amdgpu_device *adev)
        WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
        WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
 
-       WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, ~VCE_VCPU_CNTL__CLK_EN_MASK);
-
-       WREG32_P(mmVCE_SOFT_RESET,
-                VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
-                ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
-
+       WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1);
+       WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
        mdelay(100);
+       WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
 
-       WREG32_P(mmVCE_SOFT_RESET, 0, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
-
-       for (i = 0; i < 10; ++i) {
-               uint32_t status;
-               for (j = 0; j < 100; ++j) {
-                       status = RREG32(mmVCE_STATUS);
-                       if (status & 2)
-                               break;
-                       mdelay(10);
-               }
-               r = 0;
-               if (status & 2)
-                       break;
-
-               DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
-               WREG32_P(mmVCE_SOFT_RESET, VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
-                               ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
-               mdelay(10);
-               WREG32_P(mmVCE_SOFT_RESET, 0, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
-               mdelay(10);
-               r = -1;
-       }
+       r = vce_v2_0_firmware_loaded(adev);
 
        /* clear BUSY flag */
        WREG32_P(mmVCE_STATUS, 0, ~1);
@@ -173,6 +193,8 @@ static int vce_v2_0_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       adev->vce.num_rings = 2;
+
        vce_v2_0_set_ring_funcs(adev);
        vce_v2_0_set_irq_funcs(adev);
 
@@ -182,7 +204,7 @@ static int vce_v2_0_early_init(void *handle)
 static int vce_v2_0_sw_init(void *handle)
 {
        struct amdgpu_ring *ring;
-       int r;
+       int r, i;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        /* VCE */
@@ -199,19 +221,14 @@ static int vce_v2_0_sw_init(void *handle)
        if (r)
                return r;
 
-       ring = &adev->vce.ring[0];
-       sprintf(ring->name, "vce0");
-       r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
-                            &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
-       if (r)
-               return r;
-
-       ring = &adev->vce.ring[1];
-       sprintf(ring->name, "vce1");
-       r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
-                            &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
-       if (r)
-               return r;
+       for (i = 0; i < adev->vce.num_rings; i++) {
+               ring = &adev->vce.ring[i];
+               sprintf(ring->name, "vce%d", i);
+               r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
+                                    &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
+               if (r)
+                       return r;
+       }
 
        return r;
 }
@@ -234,29 +251,23 @@ static int vce_v2_0_sw_fini(void *handle)
 
 static int vce_v2_0_hw_init(void *handle)
 {
-       struct amdgpu_ring *ring;
-       int r;
+       int r, i;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        r = vce_v2_0_start(adev);
+       /* this error mean vcpu not in running state, so just skip ring test, not stop driver initialize */
        if (r)
-/* this error mean vcpu not in running state, so just skip ring test, not stop driver initialize */
                return 0;
 
-       ring = &adev->vce.ring[0];
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
-               return r;
-       }
+       for (i = 0; i < adev->vce.num_rings; i++)
+               adev->vce.ring[i].ready = false;
 
-       ring = &adev->vce.ring[1];
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
-               return r;
+       for (i = 0; i < adev->vce.num_rings; i++) {
+               r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
+               if (r)
+                       return r;
+               else
+                       adev->vce.ring[i].ready = true;
        }
 
        DRM_INFO("VCE initialized successfully.\n");
@@ -338,47 +349,50 @@ static void vce_v2_0_set_sw_cg(struct amdgpu_device *adev, bool gated)
 
 static void vce_v2_0_set_dyn_cg(struct amdgpu_device *adev, bool gated)
 {
-       u32 orig, tmp;
+       if (vce_v2_0_wait_for_idle(adev)) {
+               DRM_INFO("VCE is busy, Can't set clock gateing");
+               return;
+       }
 
-       if (gated) {
-               if (vce_v2_0_wait_for_idle(adev)) {
-                       DRM_INFO("VCE is busy, Can't set clock gateing");
-                       return;
-               }
-               WREG32_P(mmVCE_VCPU_CNTL, 0, ~VCE_VCPU_CNTL__CLK_EN_MASK);
-               WREG32_P(mmVCE_SOFT_RESET, VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
-               mdelay(100);
-               WREG32(mmVCE_STATUS, 0);
-       } else {
-               WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, ~VCE_VCPU_CNTL__CLK_EN_MASK);
-               WREG32_P(mmVCE_SOFT_RESET, VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
-               mdelay(100);
+       WREG32_P(mmVCE_LMI_CTRL2, 0x100, ~0x100);
+
+       if (vce_v2_0_lmi_clean(adev)) {
+               DRM_INFO("LMI is busy, Can't set clock gateing");
+               return;
        }
 
-       tmp = RREG32(mmVCE_CLOCK_GATING_B);
-       tmp &= ~0x00060006;
+       WREG32_P(mmVCE_VCPU_CNTL, 0, ~VCE_VCPU_CNTL__CLK_EN_MASK);
+       WREG32_P(mmVCE_SOFT_RESET,
+                VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
+                ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
+       WREG32(mmVCE_STATUS, 0);
+
+       if (gated)
+               WREG32(mmVCE_CGTT_CLK_OVERRIDE, 0);
+       /* LMI_MC/LMI_UMC always set in dynamic, set {CGC_*_GATE_MODE, CGC_*_SW_GATE} = {0, 0} */
        if (gated) {
-               tmp |= 0xe10000;
+               /* Force CLOCK OFF , set {CGC_*_GATE_MODE, CGC_*_SW_GATE} = {*, 1} */
+               WREG32(mmVCE_CLOCK_GATING_B, 0xe90010);
        } else {
-               tmp |= 0xe1;
-               tmp &= ~0xe10000;
+               /* Force CLOCK ON, set {CGC_*_GATE_MODE, CGC_*_SW_GATE} = {1, 0} */
+               WREG32(mmVCE_CLOCK_GATING_B, 0x800f1);
        }
-       WREG32(mmVCE_CLOCK_GATING_B, tmp);
 
-       orig = tmp = RREG32(mmVCE_UENC_CLOCK_GATING);
-       tmp &= ~0x1fe000;
-       tmp &= ~0xff000000;
-       if (tmp != orig)
-               WREG32(mmVCE_UENC_CLOCK_GATING, tmp);
+       /* Set VCE_UENC_CLOCK_GATING always in dynamic mode {*_FORCE_ON, *_FORCE_OFF} = {0, 0}*/;
+       WREG32(mmVCE_UENC_CLOCK_GATING, 0x40);
 
-       orig = tmp = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
-       tmp &= ~0x3fc;
-       if (tmp != orig)
-               WREG32(mmVCE_UENC_REG_CLOCK_GATING, tmp);
+       /* set VCE_UENC_REG_CLOCK_GATING always in dynamic mode */
+       WREG32(mmVCE_UENC_REG_CLOCK_GATING, 0x00);
 
-       if (gated)
-               WREG32(mmVCE_CGTT_CLK_OVERRIDE, 0);
-       WREG32_P(mmVCE_SOFT_RESET, 0, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
+       WREG32_P(mmVCE_LMI_CTRL2, 0, ~0x100);
+       if(!gated) {
+               WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, ~VCE_VCPU_CNTL__CLK_EN_MASK);
+               mdelay(100);
+               WREG32_P(mmVCE_SOFT_RESET, 0, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
+
+               vce_v2_0_firmware_loaded(adev);
+               WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
+       }
 }
 
 static void vce_v2_0_disable_cg(struct amdgpu_device *adev)
@@ -458,9 +472,7 @@ static void vce_v2_0_mc_resume(struct amdgpu_device *adev)
        WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
 
        WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
-
-       WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK,
-                ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
+       WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1);
 
        vce_v2_0_init_cg(adev);
 }
@@ -474,11 +486,11 @@ static bool vce_v2_0_is_idle(void *handle)
 
 static int vce_v2_0_wait_for_idle(void *handle)
 {
-       unsigned i;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       unsigned i;
 
        for (i = 0; i < adev->usec_timeout; i++) {
-               if (!(RREG32(mmSRBM_STATUS2) & SRBM_STATUS2__VCE_BUSY_MASK))
+               if (vce_v2_0_is_idle(handle))
                        return 0;
        }
        return -ETIMEDOUT;
@@ -488,8 +500,7 @@ static int vce_v2_0_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       WREG32_P(mmSRBM_SOFT_RESET, SRBM_SOFT_RESET__SOFT_RESET_VCE_MASK,
-                       ~SRBM_SOFT_RESET__SOFT_RESET_VCE_MASK);
+       WREG32_FIELD(SRBM_SOFT_RESET, SOFT_RESET_VCE, 1);
        mdelay(5);
 
        return vce_v2_0_start(adev);
@@ -516,10 +527,8 @@ static int vce_v2_0_process_interrupt(struct amdgpu_device *adev,
        DRM_DEBUG("IH: VCE\n");
        switch (entry->src_data) {
        case 0:
-               amdgpu_fence_process(&adev->vce.ring[0]);
-               break;
        case 1:
-               amdgpu_fence_process(&adev->vce.ring[1]);
+               amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
                break;
        default:
                DRM_ERROR("Unhandled interrupt: %d %d\n",
@@ -530,11 +539,28 @@ static int vce_v2_0_process_interrupt(struct amdgpu_device *adev,
        return 0;
 }
 
+static void vce_v2_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_v2_0_set_clockgating_state(void *handle,
                                          enum amd_clockgating_state state)
 {
        bool gate = false;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
+
+
+       vce_v2_0_set_bypass_mode(adev, enable);
 
        if (state == AMD_CG_STATE_GATE)
                gate = true;
@@ -596,12 +622,16 @@ static const struct amdgpu_ring_funcs vce_v2_0_ring_funcs = {
        .pad_ib = amdgpu_ring_generic_pad_ib,
        .begin_use = amdgpu_vce_ring_begin_use,
        .end_use = amdgpu_vce_ring_end_use,
+       .get_emit_ib_size = amdgpu_vce_ring_get_emit_ib_size,
+       .get_dma_frame_size = amdgpu_vce_ring_get_dma_frame_size,
 };
 
 static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev)
 {
-       adev->vce.ring[0].funcs = &vce_v2_0_ring_funcs;
-       adev->vce.ring[1].funcs = &vce_v2_0_ring_funcs;
+       int i;
+
+       for (i = 0; i < adev->vce.num_rings; i++)
+               adev->vce.ring[i].funcs = &vce_v2_0_ring_funcs;
 }
 
 static const struct amdgpu_irq_src_funcs vce_v2_0_irq_funcs = {
index c271abf..3f6db4e 100644 (file)
@@ -37,6 +37,9 @@
 #include "gca/gfx_8_0_d.h"
 #include "smu/smu_7_1_2_d.h"
 #include "smu/smu_7_1_2_sh_mask.h"
+#include "gca/gfx_8_0_d.h"
+#include "gca/gfx_8_0_sh_mask.h"
+
 
 #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT    0x04
 #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK      0x10
@@ -67,8 +70,10 @@ static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring)
 
        if (ring == &adev->vce.ring[0])
                return RREG32(mmVCE_RB_RPTR);
-       else
+       else if (ring == &adev->vce.ring[1])
                return RREG32(mmVCE_RB_RPTR2);
+       else
+               return RREG32(mmVCE_RB_RPTR3);
 }
 
 /**
@@ -84,8 +89,10 @@ static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring)
 
        if (ring == &adev->vce.ring[0])
                return RREG32(mmVCE_RB_WPTR);
-       else
+       else if (ring == &adev->vce.ring[1])
                return RREG32(mmVCE_RB_WPTR2);
+       else
+               return RREG32(mmVCE_RB_WPTR3);
 }
 
 /**
@@ -101,108 +108,80 @@ static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
 
        if (ring == &adev->vce.ring[0])
                WREG32(mmVCE_RB_WPTR, ring->wptr);
-       else
+       else if (ring == &adev->vce.ring[1])
                WREG32(mmVCE_RB_WPTR2, ring->wptr);
+       else
+               WREG32(mmVCE_RB_WPTR3, ring->wptr);
 }
 
 static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override)
 {
-       u32 tmp, data;
-
-       tmp = data = RREG32(mmVCE_RB_ARB_CTRL);
-       if (override)
-               data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
-       else
-               data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
-
-       if (tmp != data)
-               WREG32(mmVCE_RB_ARB_CTRL, data);
+       WREG32_FIELD(VCE_RB_ARB_CTRL, VCE_CGTT_OVERRIDE, override ? 1 : 0);
 }
 
 static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
                                             bool gated)
 {
-       u32 tmp, data;
+       u32 data;
+
        /* Set Override to disable Clock Gating */
        vce_v3_0_override_vce_clock_gating(adev, true);
 
-       if (!gated) {
-               /* Force CLOCK ON for VCE_CLOCK_GATING_B,
-                * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
-                * VREG can be FORCE ON or set to Dynamic, but can't be OFF
-                */
-               tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
+       /* This function enables MGCG which is controlled by firmware.
+          With the clocks in the gated state the core is still
+          accessible but the firmware will throttle the clocks on the
+          fly as necessary.
+       */
+       if (gated) {
+               data = RREG32(mmVCE_CLOCK_GATING_B);
                data |= 0x1ff;
                data &= ~0xef0000;
-               if (tmp != data)
-                       WREG32(mmVCE_CLOCK_GATING_B, data);
+               WREG32(mmVCE_CLOCK_GATING_B, data);
 
-               /* Force CLOCK ON for VCE_UENC_CLOCK_GATING,
-                * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
-                */
-               tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
+               data = RREG32(mmVCE_UENC_CLOCK_GATING);
                data |= 0x3ff000;
                data &= ~0xffc00000;
-               if (tmp != data)
-                       WREG32(mmVCE_UENC_CLOCK_GATING, data);
+               WREG32(mmVCE_UENC_CLOCK_GATING, data);
 
-               /* set VCE_UENC_CLOCK_GATING_2 */
-               tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
+               data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
                data |= 0x2;
-               data &= ~0x2;
-               if (tmp != data)
-                       WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
+               data &= ~0x00010000;
+               WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
 
-               /* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */
-               tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
+               data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
                data |= 0x37f;
-               if (tmp != data)
-                       WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
+               WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
 
-               /* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */
-               tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
+               data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
                data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
-                               VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
-                               VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
-                               0x8;
-               if (tmp != data)
-                       WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
+                       VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
+                       VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
+                       0x8;
+               WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
        } else {
-               /* Force CLOCK OFF for VCE_CLOCK_GATING_B,
-                * {*, *_FORCE_OFF} = {*, 1}
-                * set VREG to Dynamic, as it can't be OFF
-                */
-               tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
+               data = RREG32(mmVCE_CLOCK_GATING_B);
                data &= ~0x80010;
                data |= 0xe70008;
-               if (tmp != data)
-                       WREG32(mmVCE_CLOCK_GATING_B, data);
-               /* Force CLOCK OFF for VCE_UENC_CLOCK_GATING,
-                * Force ClOCK OFF takes precedent over Force CLOCK ON setting.
-                * {*_FORCE_ON, *_FORCE_OFF} = {*, 1}
-                */
-               tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
+               WREG32(mmVCE_CLOCK_GATING_B, data);
+
+               data = RREG32(mmVCE_UENC_CLOCK_GATING);
                data |= 0xffc00000;
-               if (tmp != data)
-                       WREG32(mmVCE_UENC_CLOCK_GATING, data);
-               /* Set VCE_UENC_CLOCK_GATING_2 */
-               tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
+               WREG32(mmVCE_UENC_CLOCK_GATING, data);
+
+               data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
                data |= 0x10000;
-               if (tmp != data)
-                       WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
-               /* Set VCE_UENC_REG_CLOCK_GATING to dynamic */
-               tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
+               WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
+
+               data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
                data &= ~0xffc00000;
-               if (tmp != data)
-                       WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
-               /* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */
-               tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
+               WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
+
+               data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
                data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
-                               VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
-                               VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
-                               0x8);
-               if (tmp != data)
-                       WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
+                         VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
+                         VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
+                         0x8);
+               WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
        }
        vce_v3_0_override_vce_clock_gating(adev, false);
 }
@@ -221,12 +200,9 @@ static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev)
                }
 
                DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
-               WREG32_P(mmVCE_SOFT_RESET,
-                       VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
-                       ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
+               WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
                mdelay(10);
-               WREG32_P(mmVCE_SOFT_RESET, 0,
-                       ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
+               WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
                mdelay(10);
        }
 
@@ -259,43 +235,34 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
        WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
        WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
 
+       ring = &adev->vce.ring[2];
+       WREG32(mmVCE_RB_RPTR3, ring->wptr);
+       WREG32(mmVCE_RB_WPTR3, ring->wptr);
+       WREG32(mmVCE_RB_BASE_LO3, ring->gpu_addr);
+       WREG32(mmVCE_RB_BASE_HI3, upper_32_bits(ring->gpu_addr));
+       WREG32(mmVCE_RB_SIZE3, ring->ring_size / 4);
+
        mutex_lock(&adev->grbm_idx_mutex);
        for (idx = 0; idx < 2; ++idx) {
                if (adev->vce.harvest_config & (1 << idx))
                        continue;
 
-               if (idx == 0)
-                       WREG32_P(mmGRBM_GFX_INDEX, 0,
-                               ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
-               else
-                       WREG32_P(mmGRBM_GFX_INDEX,
-                               GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
-                               ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
-
+               WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
                vce_v3_0_mc_resume(adev, idx);
-
-               WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK,
-                        ~VCE_STATUS__JOB_BUSY_MASK);
+               WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1);
 
                if (adev->asic_type >= CHIP_STONEY)
                        WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001);
                else
-                       WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK,
-                               ~VCE_VCPU_CNTL__CLK_EN_MASK);
-
-               WREG32_P(mmVCE_SOFT_RESET, 0,
-                       ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
+                       WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1);
 
+               WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
                mdelay(100);
 
                r = vce_v3_0_firmware_loaded(adev);
 
                /* clear BUSY flag */
-               WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
-
-               /* Set Clock-Gating off */
-               if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
-                       vce_v3_0_set_vce_sw_clock_gating(adev, false);
+               WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0);
 
                if (r) {
                        DRM_ERROR("VCE not responding, giving up!!!\n");
@@ -304,7 +271,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
                }
        }
 
-       WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+       WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
        mutex_unlock(&adev->grbm_idx_mutex);
 
        return 0;
@@ -319,33 +286,25 @@ static int vce_v3_0_stop(struct amdgpu_device *adev)
                if (adev->vce.harvest_config & (1 << idx))
                        continue;
 
-               if (idx == 0)
-                       WREG32_P(mmGRBM_GFX_INDEX, 0,
-                               ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
-               else
-                       WREG32_P(mmGRBM_GFX_INDEX,
-                               GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
-                               ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+               WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
 
                if (adev->asic_type >= CHIP_STONEY)
                        WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
                else
-                       WREG32_P(mmVCE_VCPU_CNTL, 0,
-                               ~VCE_VCPU_CNTL__CLK_EN_MASK);
+                       WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 0);
+
                /* hold on ECPU */
-               WREG32_P(mmVCE_SOFT_RESET,
-                        VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
-                        ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
+               WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
 
                /* clear BUSY flag */
-               WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
+               WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0);
 
                /* Set Clock-Gating off */
                if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
                        vce_v3_0_set_vce_sw_clock_gating(adev, false);
        }
 
-       WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+       WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
        mutex_unlock(&adev->grbm_idx_mutex);
 
        return 0;
@@ -399,6 +358,8 @@ static int vce_v3_0_early_init(void *handle)
            (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
                return -ENOENT;
 
+       adev->vce.num_rings = 3;
+
        vce_v3_0_set_ring_funcs(adev);
        vce_v3_0_set_irq_funcs(adev);
 
@@ -409,7 +370,7 @@ static int vce_v3_0_sw_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        struct amdgpu_ring *ring;
-       int r;
+       int r, i;
 
        /* VCE */
        r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq);
@@ -425,19 +386,14 @@ static int vce_v3_0_sw_init(void *handle)
        if (r)
                return r;
 
-       ring = &adev->vce.ring[0];
-       sprintf(ring->name, "vce0");
-       r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
-                            &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
-       if (r)
-               return r;
-
-       ring = &adev->vce.ring[1];
-       sprintf(ring->name, "vce1");
-       r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
-                            &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
-       if (r)
-               return r;
+       for (i = 0; i < adev->vce.num_rings; i++) {
+               ring = &adev->vce.ring[i];
+               sprintf(ring->name, "vce%d", i);
+               r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
+                                    &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
+               if (r)
+                       return r;
+       }
 
        return r;
 }
@@ -467,10 +423,10 @@ static int vce_v3_0_hw_init(void *handle)
        if (r)
                return r;
 
-       adev->vce.ring[0].ready = false;
-       adev->vce.ring[1].ready = false;
+       for (i = 0; i < adev->vce.num_rings; i++)
+               adev->vce.ring[i].ready = false;
 
-       for (i = 0; i < 2; i++) {
+       for (i = 0; i < adev->vce.num_rings; i++) {
                r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
                if (r)
                        return r;
@@ -534,7 +490,7 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
        WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
        WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
        WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
-       WREG32(mmVCE_CLOCK_GATING_B, 0xf7);
+       WREG32(mmVCE_CLOCK_GATING_B, 0x1FF);
 
        WREG32(mmVCE_LMI_CTRL, 0x00398000);
        WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
@@ -573,9 +529,7 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
        }
 
        WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
-
-       WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK,
-                ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
+       WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1);
 }
 
 static bool vce_v3_0_is_idle(void *handle)
@@ -601,20 +555,108 @@ static int vce_v3_0_wait_for_idle(void *handle)
        return -ETIMEDOUT;
 }
 
+#define  VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK  0x00000008L   /* AUTO_BUSY */
+#define  VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK   0x00000010L   /* RB0_BUSY */
+#define  VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK   0x00000020L   /* RB1_BUSY */
+#define  AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \
+                                     VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK)
+
+static int vce_v3_0_check_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset = 0;
+
+       /* According to VCE team , we should use VCE_STATUS instead
+        * SRBM_STATUS.VCE_BUSY bit for busy status checking.
+        * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE
+        * instance's registers are accessed
+        * (0 for 1st instance, 10 for 2nd instance).
+        *
+        *VCE_STATUS
+        *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 |          |FW_LOADED|JOB |
+        *|----+----+-----------+----+----+----+----------+---------+----|
+        *|bit8|bit7|    bit6   |bit5|bit4|bit3|   bit2   |  bit1   |bit0|
+        *
+        * 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);
+       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);
+       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);
+
+       if (srbm_soft_reset) {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true;
+               adev->vce.srbm_soft_reset = srbm_soft_reset;
+       } else {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false;
+               adev->vce.srbm_soft_reset = 0;
+       }
+       mutex_unlock(&adev->grbm_idx_mutex);
+       return 0;
+}
+
 static int vce_v3_0_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-       u32 mask = 0;
+       u32 srbm_soft_reset;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
+               return 0;
+       srbm_soft_reset = adev->vce.srbm_soft_reset;
+
+       if (srbm_soft_reset) {
+               u32 tmp;
 
-       mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK;
-       mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK;
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+               tmp |= srbm_soft_reset;
+               dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+               WREG32(mmSRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+
+               udelay(50);
+
+               tmp &= ~srbm_soft_reset;
+               WREG32(mmSRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+
+               /* Wait a little for things to settle down */
+               udelay(50);
+       }
+
+       return 0;
+}
+
+static int vce_v3_0_pre_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
+               return 0;
 
-       WREG32_P(mmSRBM_SOFT_RESET, mask,
-                ~(SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK |
-                  SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK));
        mdelay(5);
 
-       return vce_v3_0_start(adev);
+       return vce_v3_0_suspend(adev);
+}
+
+
+static int vce_v3_0_post_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
+               return 0;
+
+       mdelay(5);
+
+       return vce_v3_0_resume(adev);
 }
 
 static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev,
@@ -637,13 +679,12 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
 {
        DRM_DEBUG("IH: VCE\n");
 
-       WREG32_P(mmVCE_SYS_INT_STATUS,
-               VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK,
-               ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK);
+       WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1);
 
        switch (entry->src_data) {
        case 0:
        case 1:
+       case 2:
                amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
                break;
        default:
@@ -655,7 +696,7 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
        return 0;
 }
 
-static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable)
+static void vce_v3_0_set_bypass_mode(struct amdgpu_device *adev, bool enable)
 {
        u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL);
 
@@ -674,8 +715,10 @@ 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)
-               vce_v3_set_bypass_mode(adev, enable);
+       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;
@@ -686,13 +729,7 @@ static int vce_v3_0_set_clockgating_state(void *handle,
                if (adev->vce.harvest_config & (1 << i))
                        continue;
 
-               if (i == 0)
-                       WREG32_P(mmGRBM_GFX_INDEX, 0,
-                                       ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
-               else
-                       WREG32_P(mmGRBM_GFX_INDEX,
-                                       GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
-                                       ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+               WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i);
 
                if (enable) {
                        /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
@@ -711,7 +748,7 @@ static int vce_v3_0_set_clockgating_state(void *handle,
                vce_v3_0_set_vce_sw_clock_gating(adev, enable);
        }
 
-       WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+       WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
        mutex_unlock(&adev->grbm_idx_mutex);
 
        return 0;
@@ -739,6 +776,60 @@ static int vce_v3_0_set_powergating_state(void *handle,
                return vce_v3_0_start(adev);
 }
 
+static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
+               struct amdgpu_ib *ib, unsigned int vm_id, bool ctx_switch)
+{
+       amdgpu_ring_write(ring, VCE_CMD_IB_VM);
+       amdgpu_ring_write(ring, vm_id);
+       amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
+       amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
+       amdgpu_ring_write(ring, ib->length_dw);
+}
+
+static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring,
+                        unsigned int vm_id, uint64_t pd_addr)
+{
+       amdgpu_ring_write(ring, VCE_CMD_UPDATE_PTB);
+       amdgpu_ring_write(ring, vm_id);
+       amdgpu_ring_write(ring, pd_addr >> 12);
+
+       amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB);
+       amdgpu_ring_write(ring, vm_id);
+       amdgpu_ring_write(ring, VCE_CMD_END);
+}
+
+static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring)
+{
+       uint32_t seq = ring->fence_drv.sync_seq;
+       uint64_t addr = ring->fence_drv.gpu_addr;
+
+       amdgpu_ring_write(ring, VCE_CMD_WAIT_GE);
+       amdgpu_ring_write(ring, lower_32_bits(addr));
+       amdgpu_ring_write(ring, upper_32_bits(addr));
+       amdgpu_ring_write(ring, seq);
+}
+
+static unsigned vce_v3_0_ring_get_emit_ib_size(struct amdgpu_ring *ring)
+{
+       return
+               5; /* vce_v3_0_ring_emit_ib */
+}
+
+static unsigned vce_v3_0_ring_get_dma_frame_size(struct amdgpu_ring *ring)
+{
+       return
+               4 + /* vce_v3_0_emit_pipeline_sync */
+               6; /* amdgpu_vce_ring_emit_fence x1 no user fence */
+}
+
+static unsigned vce_v3_0_ring_get_dma_frame_size_vm(struct amdgpu_ring *ring)
+{
+       return
+               6 + /* vce_v3_0_emit_vm_flush */
+               4 + /* vce_v3_0_emit_pipeline_sync */
+               6 + 6; /* amdgpu_vce_ring_emit_fence x2 vm fence */
+}
+
 const struct amd_ip_funcs vce_v3_0_ip_funcs = {
        .name = "vce_v3_0",
        .early_init = vce_v3_0_early_init,
@@ -751,12 +842,15 @@ const struct amd_ip_funcs vce_v3_0_ip_funcs = {
        .resume = vce_v3_0_resume,
        .is_idle = vce_v3_0_is_idle,
        .wait_for_idle = vce_v3_0_wait_for_idle,
+       .check_soft_reset = vce_v3_0_check_soft_reset,
+       .pre_soft_reset = vce_v3_0_pre_soft_reset,
        .soft_reset = vce_v3_0_soft_reset,
+       .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,
 };
 
-static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = {
+static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = {
        .get_rptr = vce_v3_0_ring_get_rptr,
        .get_wptr = vce_v3_0_ring_get_wptr,
        .set_wptr = vce_v3_0_ring_set_wptr,
@@ -769,12 +863,42 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = {
        .pad_ib = amdgpu_ring_generic_pad_ib,
        .begin_use = amdgpu_vce_ring_begin_use,
        .end_use = amdgpu_vce_ring_end_use,
+       .get_emit_ib_size = vce_v3_0_ring_get_emit_ib_size,
+       .get_dma_frame_size = vce_v3_0_ring_get_dma_frame_size,
+};
+
+static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = {
+       .get_rptr = vce_v3_0_ring_get_rptr,
+       .get_wptr = vce_v3_0_ring_get_wptr,
+       .set_wptr = vce_v3_0_ring_set_wptr,
+       .parse_cs = NULL,
+       .emit_ib = vce_v3_0_ring_emit_ib,
+       .emit_vm_flush = vce_v3_0_emit_vm_flush,
+       .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync,
+       .emit_fence = amdgpu_vce_ring_emit_fence,
+       .test_ring = amdgpu_vce_ring_test_ring,
+       .test_ib = amdgpu_vce_ring_test_ib,
+       .insert_nop = amdgpu_ring_insert_nop,
+       .pad_ib = amdgpu_ring_generic_pad_ib,
+       .begin_use = amdgpu_vce_ring_begin_use,
+       .end_use = amdgpu_vce_ring_end_use,
+       .get_emit_ib_size = vce_v3_0_ring_get_emit_ib_size,
+       .get_dma_frame_size = vce_v3_0_ring_get_dma_frame_size_vm,
 };
 
 static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev)
 {
-       adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs;
-       adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs;
+       int i;
+
+       if (adev->asic_type >= CHIP_STONEY) {
+               for (i = 0; i < adev->vce.num_rings; i++)
+                       adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs;
+               DRM_INFO("VCE enabled in VM mode\n");
+       } else {
+               for (i = 0; i < adev->vce.num_rings; i++)
+                       adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs;
+               DRM_INFO("VCE enabled in physical mode\n");
+       }
 }
 
 static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = {
index 03a31c5..c0d9aad 100644 (file)
 #if defined(CONFIG_DRM_AMD_ACP)
 #include "amdgpu_acp.h"
 #endif
+#include "dce_virtual.h"
 
+MODULE_FIRMWARE("amdgpu/topaz_smc.bin");
+MODULE_FIRMWARE("amdgpu/tonga_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");
@@ -444,18 +448,21 @@ static bool vi_read_bios_from_rom(struct amdgpu_device *adev,
        return true;
 }
 
-static u32 vi_get_virtual_caps(struct amdgpu_device *adev)
+static void vi_detect_hw_virtualization(struct amdgpu_device *adev)
 {
-       u32 caps = 0;
-       u32 reg = RREG32(mmBIF_IOV_FUNC_IDENTIFIER);
-
-       if (REG_GET_FIELD(reg, BIF_IOV_FUNC_IDENTIFIER, IOV_ENABLE))
-               caps |= AMDGPU_VIRT_CAPS_SRIOV_EN;
-
-       if (REG_GET_FIELD(reg, BIF_IOV_FUNC_IDENTIFIER, FUNC_IDENTIFIER))
-               caps |= AMDGPU_VIRT_CAPS_IS_VF;
-
-       return caps;
+       uint32_t reg = RREG32(mmBIF_IOV_FUNC_IDENTIFIER);
+       /* 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;
+
+       if (reg & 0x80000000)
+               adev->virtualization.virtual_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;
+       }
 }
 
 static const struct amdgpu_allowed_register_entry tonga_allowed_read_registers[] = {
@@ -822,6 +829,60 @@ static const struct amdgpu_ip_block_version topaz_ip_blocks[] =
        },
 };
 
+static const struct amdgpu_ip_block_version topaz_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vi_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 7,
+               .minor = 4,
+               .rev = 0,
+               .funcs = &gmc_v7_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 2,
+               .minor = 4,
+               .rev = 0,
+               .funcs = &iceland_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 7,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 1,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 8,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gfx_v8_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 2,
+               .minor = 4,
+               .rev = 0,
+               .funcs = &sdma_v2_4_ip_funcs,
+       },
+};
+
 static const struct amdgpu_ip_block_version tonga_ip_blocks[] =
 {
        /* ORDER MATTERS! */
@@ -890,6 +951,74 @@ static const struct amdgpu_ip_block_version tonga_ip_blocks[] =
        },
 };
 
+static const struct amdgpu_ip_block_version tonga_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vi_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 8,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gmc_v8_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 3,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &tonga_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 7,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 10,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 8,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gfx_v8_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 3,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &sdma_v3_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 5,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &uvd_v5_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 3,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vce_v3_0_ip_funcs,
+       },
+};
+
 static const struct amdgpu_ip_block_version fiji_ip_blocks[] =
 {
        /* ORDER MATTERS! */
@@ -958,6 +1087,74 @@ static const struct amdgpu_ip_block_version fiji_ip_blocks[] =
        },
 };
 
+static const struct amdgpu_ip_block_version fiji_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vi_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 8,
+               .minor = 5,
+               .rev = 0,
+               .funcs = &gmc_v8_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 3,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &tonga_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 7,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 10,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 8,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gfx_v8_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 3,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &sdma_v3_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 6,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &uvd_v6_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 3,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vce_v3_0_ip_funcs,
+       },
+};
+
 static const struct amdgpu_ip_block_version polaris11_ip_blocks[] =
 {
        /* ORDER MATTERS! */
@@ -1026,6 +1223,74 @@ static const struct amdgpu_ip_block_version polaris11_ip_blocks[] =
        },
 };
 
+static const struct amdgpu_ip_block_version polaris11_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vi_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 8,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &gmc_v8_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 3,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &tonga_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 7,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 11,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 8,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gfx_v8_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 3,
+               .minor = 1,
+               .rev = 0,
+               .funcs = &sdma_v3_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 6,
+               .minor = 3,
+               .rev = 0,
+               .funcs = &uvd_v6_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 3,
+               .minor = 4,
+               .rev = 0,
+               .funcs = &vce_v3_0_ip_funcs,
+       },
+};
+
 static const struct amdgpu_ip_block_version cz_ip_blocks[] =
 {
        /* ORDER MATTERS! */
@@ -1103,34 +1368,142 @@ static const struct amdgpu_ip_block_version cz_ip_blocks[] =
 #endif
 };
 
+static const struct amdgpu_ip_block_version cz_ip_blocks_vd[] =
+{
+       /* ORDER MATTERS! */
+       {
+               .type = AMD_IP_BLOCK_TYPE_COMMON,
+               .major = 2,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vi_common_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GMC,
+               .major = 8,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gmc_v8_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_IH,
+               .major = 3,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &cz_ih_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SMC,
+               .major = 8,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &amdgpu_pp_ip_funcs
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_DCE,
+               .major = 11,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &dce_virtual_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_GFX,
+               .major = 8,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &gfx_v8_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_SDMA,
+               .major = 3,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &sdma_v3_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_UVD,
+               .major = 6,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &uvd_v6_0_ip_funcs,
+       },
+       {
+               .type = AMD_IP_BLOCK_TYPE_VCE,
+               .major = 3,
+               .minor = 0,
+               .rev = 0,
+               .funcs = &vce_v3_0_ip_funcs,
+       },
+#if defined(CONFIG_DRM_AMD_ACP)
+       {
+               .type = AMD_IP_BLOCK_TYPE_ACP,
+               .major = 2,
+               .minor = 2,
+               .rev = 0,
+               .funcs = &acp_ip_funcs,
+       },
+#endif
+};
+
 int vi_set_ip_blocks(struct amdgpu_device *adev)
 {
-       switch (adev->asic_type) {
-       case CHIP_TOPAZ:
-               adev->ip_blocks = topaz_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(topaz_ip_blocks);
-               break;
-       case CHIP_FIJI:
-               adev->ip_blocks = fiji_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(fiji_ip_blocks);
-               break;
-       case CHIP_TONGA:
-               adev->ip_blocks = tonga_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(tonga_ip_blocks);
-               break;
-       case CHIP_POLARIS11:
-       case CHIP_POLARIS10:
-               adev->ip_blocks = polaris11_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(polaris11_ip_blocks);
-               break;
-       case CHIP_CARRIZO:
-       case CHIP_STONEY:
-               adev->ip_blocks = cz_ip_blocks;
-               adev->num_ip_blocks = ARRAY_SIZE(cz_ip_blocks);
-               break;
-       default:
-               /* FIXME: not supported yet */
-               return -EINVAL;
+       if (adev->enable_virtual_display) {
+               switch (adev->asic_type) {
+               case CHIP_TOPAZ:
+                       adev->ip_blocks = topaz_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(topaz_ip_blocks_vd);
+                       break;
+               case CHIP_FIJI:
+                       adev->ip_blocks = fiji_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(fiji_ip_blocks_vd);
+                       break;
+               case CHIP_TONGA:
+                       adev->ip_blocks = tonga_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(tonga_ip_blocks_vd);
+                       break;
+               case CHIP_POLARIS11:
+               case CHIP_POLARIS10:
+                       adev->ip_blocks = polaris11_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(polaris11_ip_blocks_vd);
+                       break;
+
+               case CHIP_CARRIZO:
+               case CHIP_STONEY:
+                       adev->ip_blocks = cz_ip_blocks_vd;
+                       adev->num_ip_blocks = ARRAY_SIZE(cz_ip_blocks_vd);
+                       break;
+               default:
+                       /* FIXME: not supported yet */
+                       return -EINVAL;
+               }
+       } else {
+               switch (adev->asic_type) {
+               case CHIP_TOPAZ:
+                       adev->ip_blocks = topaz_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(topaz_ip_blocks);
+                       break;
+               case CHIP_FIJI:
+                       adev->ip_blocks = fiji_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(fiji_ip_blocks);
+                       break;
+               case CHIP_TONGA:
+                       adev->ip_blocks = tonga_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(tonga_ip_blocks);
+                       break;
+               case CHIP_POLARIS11:
+               case CHIP_POLARIS10:
+                       adev->ip_blocks = polaris11_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(polaris11_ip_blocks);
+                       break;
+               case CHIP_CARRIZO:
+               case CHIP_STONEY:
+                       adev->ip_blocks = cz_ip_blocks;
+                       adev->num_ip_blocks = ARRAY_SIZE(cz_ip_blocks);
+                       break;
+               default:
+                       /* FIXME: not supported yet */
+                       return -EINVAL;
+               }
        }
 
        return 0;
@@ -1154,13 +1527,13 @@ 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,
        .get_xclk = &vi_get_xclk,
        .set_uvd_clocks = &vi_set_uvd_clocks,
        .set_vce_clocks = &vi_set_vce_clocks,
-       .get_virtual_caps = &vi_get_virtual_caps,
 };
 
 static int vi_common_early_init(void *handle)
@@ -1248,8 +1621,17 @@ static int vi_common_early_init(void *handle)
                        AMD_CG_SUPPORT_HDP_MGCG |
                        AMD_CG_SUPPORT_HDP_LS |
                        AMD_CG_SUPPORT_SDMA_MGCG |
-                       AMD_CG_SUPPORT_SDMA_LS;
+                       AMD_CG_SUPPORT_SDMA_LS |
+                       AMD_CG_SUPPORT_VCE_MGCG;
+               /* rev0 hardware requires workarounds to support PG */
                adev->pg_flags = 0;
+               if (adev->rev_id != 0x00) {
+                       adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
+                               AMD_PG_SUPPORT_GFX_SMG |
+                               AMD_PG_SUPPORT_GFX_PIPELINE |
+                               AMD_PG_SUPPORT_UVD |
+                               AMD_PG_SUPPORT_VCE;
+               }
                adev->external_rev_id = adev->rev_id + 0x1;
                break;
        case CHIP_STONEY:
@@ -1267,14 +1649,24 @@ static int vi_common_early_init(void *handle)
                        AMD_CG_SUPPORT_HDP_MGCG |
                        AMD_CG_SUPPORT_HDP_LS |
                        AMD_CG_SUPPORT_SDMA_MGCG |
-                       AMD_CG_SUPPORT_SDMA_LS;
-               adev->external_rev_id = adev->rev_id + 0x1;
+                       AMD_CG_SUPPORT_SDMA_LS |
+                       AMD_CG_SUPPORT_VCE_MGCG;
+               adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
+                       AMD_PG_SUPPORT_GFX_SMG |
+                       AMD_PG_SUPPORT_GFX_PIPELINE |
+                       AMD_PG_SUPPORT_UVD |
+                       AMD_PG_SUPPORT_VCE;
+               adev->external_rev_id = adev->rev_id + 0x61;
                break;
        default:
                /* FIXME: not supported yet */
                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;
 
@@ -1418,6 +1810,63 @@ static void vi_update_rom_medium_grain_clock_gating(struct amdgpu_device *adev,
                WREG32_SMC(ixCGTT_ROM_CLK_CTRL0, data);
 }
 
+static int vi_common_set_clockgating_state_by_smu(void *handle,
+                                          enum amd_clockgating_state state)
+{
+       uint32_t msg_id, pp_state;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       void *pp_handle = adev->powerplay.pp_handle;
+
+       if (state == AMD_CG_STATE_UNGATE)
+               pp_state = 0;
+       else
+               pp_state = PP_STATE_CG | PP_STATE_LS;
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
+                      PP_BLOCK_SYS_MC,
+                      PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                      pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
+                      PP_BLOCK_SYS_SDMA,
+                      PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                      pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
+                      PP_BLOCK_SYS_HDP,
+                      PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
+                      pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
+                      PP_BLOCK_SYS_BIF,
+                      PP_STATE_SUPPORT_LS,
+                      pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
+                      PP_BLOCK_SYS_BIF,
+                      PP_STATE_SUPPORT_CG,
+                      pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
+                      PP_BLOCK_SYS_DRM,
+                      PP_STATE_SUPPORT_LS,
+                      pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
+                      PP_BLOCK_SYS_ROM,
+                      PP_STATE_SUPPORT_CG,
+                      pp_state);
+       amd_set_clockgating_by_smu(pp_handle, msg_id);
+
+       return 0;
+}
+
 static int vi_common_set_clockgating_state(void *handle,
                                           enum amd_clockgating_state state)
 {
@@ -1443,6 +1892,10 @@ static int vi_common_set_clockgating_state(void *handle,
                vi_update_hdp_light_sleep(adev,
                                state == AMD_CG_STATE_GATE ? true : false);
                break;
+       case CHIP_TONGA:
+       case CHIP_POLARIS10:
+       case CHIP_POLARIS11:
+               vi_common_set_clockgating_state_by_smu(adev, state);
        default:
                break;
        }
index 062ee16..11746f2 100644 (file)
 #define VCE_CMD_IB_AUTO        0x00000005
 #define VCE_CMD_SEMAPHORE      0x00000006
 
+#define VCE_CMD_IB_VM           0x00000102
+#define VCE_CMD_WAIT_GE         0x00000106
+#define VCE_CMD_UPDATE_PTB      0x00000107
+#define VCE_CMD_FLUSH_TLB       0x00000108
+
+/* mmPA_SC_RASTER_CONFIG mask */
+#define RB_MAP_PKR0(x)                         ((x) << 0)
+#define RB_MAP_PKR0_MASK                       (0x3 << 0)
+#define RB_MAP_PKR1(x)                         ((x) << 2)
+#define RB_MAP_PKR1_MASK                       (0x3 << 2)
+#define RB_XSEL2(x)                            ((x) << 4)
+#define RB_XSEL2_MASK                          (0x3 << 4)
+#define RB_XSEL                                        (1 << 6)
+#define RB_YSEL                                        (1 << 7)
+#define PKR_MAP(x)                             ((x) << 8)
+#define PKR_MAP_MASK                           (0x3 << 8)
+#define PKR_XSEL(x)                            ((x) << 10)
+#define PKR_XSEL_MASK                          (0x3 << 10)
+#define PKR_YSEL(x)                            ((x) << 12)
+#define PKR_YSEL_MASK                          (0x3 << 12)
+#define SC_MAP(x)                              ((x) << 16)
+#define SC_MAP_MASK                            (0x3 << 16)
+#define SC_XSEL(x)                             ((x) << 18)
+#define SC_XSEL_MASK                           (0x3 << 18)
+#define SC_YSEL(x)                             ((x) << 20)
+#define SC_YSEL_MASK                           (0x3 << 20)
+#define SE_MAP(x)                              ((x) << 24)
+#define SE_MAP_MASK                            (0x3 << 24)
+#define SE_XSEL(x)                             ((x) << 26)
+#define SE_XSEL_MASK                           (0x3 << 26)
+#define SE_YSEL(x)                             ((x) << 28)
+#define SE_YSEL_MASK                           (0x3 << 28)
+
+/* mmPA_SC_RASTER_CONFIG_1 mask */
+#define SE_PAIR_MAP(x)                         ((x) << 0)
+#define SE_PAIR_MAP_MASK                       (0x3 << 0)
+#define SE_PAIR_XSEL(x)                                ((x) << 2)
+#define SE_PAIR_XSEL_MASK                      (0x3 << 2)
+#define SE_PAIR_YSEL(x)                                ((x) << 4)
+#define SE_PAIR_YSEL_MASK                      (0x3 << 4)
+
 #endif
index a7d3cb3..453c5d6 100644 (file)
@@ -142,13 +142,15 @@ int kfd_doorbell_mmap(struct kfd_process *process, struct vm_area_struct *vma)
 
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-       pr_debug("mapping doorbell page:\n");
-       pr_debug("     target user address == 0x%08llX\n",
-                       (unsigned long long) vma->vm_start);
-       pr_debug("     physical address    == 0x%08llX\n", address);
-       pr_debug("     vm_flags            == 0x%04lX\n", vma->vm_flags);
-       pr_debug("     size                == 0x%04lX\n",
-                        doorbell_process_allocation());
+       pr_debug("kfd: mapping doorbell page in %s\n"
+                "     target user address == 0x%08llX\n"
+                "     physical address    == 0x%08llX\n"
+                "     vm_flags            == 0x%04lX\n"
+                "     size                == 0x%04lX\n",
+                __func__,
+                (unsigned long long) vma->vm_start, address, vma->vm_flags,
+                doorbell_process_allocation());
+
 
        return io_remap_pfn_range(vma,
                                vma->vm_start,
index 9beae87..d135cd0 100644 (file)
@@ -47,6 +47,9 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
        pr_debug("amdkfd: In func %s initializing queue type %d size %d\n",
                        __func__, KFD_QUEUE_TYPE_HIQ, queue_size);
 
+       memset(&prop, 0, sizeof(prop));
+       memset(&nop, 0, sizeof(nop));
+
        nop.opcode = IT_NOP;
        nop.type = PM4_TYPE_3;
        nop.u32all |= PM4_COUNT_ZERO;
@@ -121,7 +124,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
        prop.eop_ring_buffer_address = kq->eop_gpu_addr;
        prop.eop_ring_buffer_size = PAGE_SIZE;
 
-       if (init_queue(&kq->queue, prop) != 0)
+       if (init_queue(&kq->queue, &prop) != 0)
                goto err_init_queue;
 
        kq->queue->device = dev;
index 80113c3..4750cab 100644 (file)
@@ -619,7 +619,7 @@ int kfd_init_apertures(struct kfd_process *process);
 /* Queue Context Management */
 struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd);
 
-int init_queue(struct queue **q, struct queue_properties properties);
+int init_queue(struct queue **q, const struct queue_properties *properties);
 void uninit_queue(struct queue *q);
 void print_queue_properties(struct queue_properties *q);
 void print_queue(struct queue *q);
index 4f3849a..ef7c8de 100644 (file)
@@ -404,58 +404,47 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid)
 {
        struct kfd_process *p;
        struct kfd_process_device *pdd;
-       int idx, i;
 
        BUG_ON(dev == NULL);
 
-       idx = srcu_read_lock(&kfd_processes_srcu);
-
        /*
         * Look for the process that matches the pasid. If there is no such
         * process, we either released it in amdkfd's own notifier, or there
         * is a bug. Unfortunately, there is no way to tell...
         */
-       hash_for_each_rcu(kfd_processes_table, i, p, kfd_processes)
-               if (p->pasid == pasid) {
-
-                       srcu_read_unlock(&kfd_processes_srcu, idx);
-
-                       pr_debug("Unbinding process %d from IOMMU\n", pasid);
+       p = kfd_lookup_process_by_pasid(pasid);
+       if (!p)
+               return;
 
-                       mutex_lock(&p->mutex);
-
-                       if ((dev->dbgmgr) && (dev->dbgmgr->pasid == p->pasid))
-                               kfd_dbgmgr_destroy(dev->dbgmgr);
-
-                       pqm_uninit(&p->pqm);
+       pr_debug("Unbinding process %d from IOMMU\n", pasid);
 
-                       pdd = kfd_get_process_device_data(dev, p);
+       if ((dev->dbgmgr) && (dev->dbgmgr->pasid == p->pasid))
+               kfd_dbgmgr_destroy(dev->dbgmgr);
 
-                       if (!pdd) {
-                               mutex_unlock(&p->mutex);
-                               return;
-                       }
+       pqm_uninit(&p->pqm);
 
-                       if (pdd->reset_wavefronts) {
-                               dbgdev_wave_reset_wavefronts(pdd->dev, p);
-                               pdd->reset_wavefronts = false;
-                       }
+       pdd = kfd_get_process_device_data(dev, p);
 
-                       /*
-                        * Just mark pdd as unbound, because we still need it
-                        * to call amd_iommu_unbind_pasid() in when the
-                        * process exits.
-                        * We don't call amd_iommu_unbind_pasid() here
-                        * because the IOMMU called us.
-                        */
-                       pdd->bound = false;
+       if (!pdd) {
+               mutex_unlock(&p->mutex);
+               return;
+       }
 
-                       mutex_unlock(&p->mutex);
+       if (pdd->reset_wavefronts) {
+               dbgdev_wave_reset_wavefronts(pdd->dev, p);
+               pdd->reset_wavefronts = false;
+       }
 
-                       return;
-               }
+       /*
+        * Just mark pdd as unbound, because we still need it
+        * to call amd_iommu_unbind_pasid() in when the
+        * process exits.
+        * We don't call amd_iommu_unbind_pasid() here
+        * because the IOMMU called us.
+        */
+       pdd->bound = false;
 
-       srcu_read_unlock(&kfd_processes_srcu, idx);
+       mutex_unlock(&p->mutex);
 }
 
 struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p)
index 7b69070..e1fb40b 100644 (file)
@@ -129,7 +129,7 @@ static int create_cp_queue(struct process_queue_manager *pqm,
        q_properties->vmid = 0;
        q_properties->queue_id = qid;
 
-       retval = init_queue(q, *q_properties);
+       retval = init_queue(q, q_properties);
        if (retval != 0)
                goto err_init_queue;
 
index 9a0c90b..0ab1970 100644 (file)
@@ -63,7 +63,7 @@ void print_queue(struct queue *q)
        pr_debug("Queue Device Address: 0x%p\n", q->device);
 }
 
-int init_queue(struct queue **q, struct queue_properties properties)
+int init_queue(struct queue **q, const struct queue_properties *properties)
 {
        struct queue *tmp;
 
@@ -73,7 +73,7 @@ int init_queue(struct queue **q, struct queue_properties properties)
        if (!tmp)
                return -ENOMEM;
 
-       memcpy(&tmp->properties, &properties, sizeof(struct queue_properties));
+       memcpy(&tmp->properties, properties, sizeof(struct queue_properties));
 
        *q = tmp;
        return 0;
index 884c96f..1e50647 100644 (file)
@@ -1090,19 +1090,21 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
 {
        uint32_t hashout;
        uint32_t buf[7];
+       uint64_t local_mem_size;
        int i;
 
        if (!gpu)
                return 0;
 
+       local_mem_size = gpu->kfd2kgd->get_vmem_size(gpu->kgd);
+
        buf[0] = gpu->pdev->devfn;
        buf[1] = gpu->pdev->subsystem_vendor;
        buf[2] = gpu->pdev->subsystem_device;
        buf[3] = gpu->pdev->device;
        buf[4] = gpu->pdev->bus->number;
-       buf[5] = (uint32_t)(gpu->kfd2kgd->get_vmem_size(gpu->kgd)
-                       & 0xffffffff);
-       buf[6] = (uint32_t)(gpu->kfd2kgd->get_vmem_size(gpu->kgd) >> 32);
+       buf[5] = lower_32_bits(local_mem_size);
+       buf[6] = upper_32_bits(local_mem_size);
 
        for (i = 0, hashout = 0; i < 7; i++)
                hashout ^= hash_32(buf[i], KFD_GPU_ID_HASH_WIDTH);
index a74a0d2..c934b78 100644 (file)
  * Supported ASIC types
  */
 enum amd_asic_type {
-       CHIP_BONAIRE = 0,
+       CHIP_TAHITI = 0,
+       CHIP_PITCAIRN,
+       CHIP_VERDE,
+       CHIP_OLAND,
+       CHIP_HAINAN,
+       CHIP_BONAIRE,
        CHIP_KAVERI,
        CHIP_KABINI,
        CHIP_HAWAII,
@@ -159,8 +164,14 @@ struct amd_ip_funcs {
        bool (*is_idle)(void *handle);
        /* poll for idle */
        int (*wait_for_idle)(void *handle);
+       /* check soft reset the IP block */
+       int (*check_soft_reset)(void *handle);
+       /* pre soft reset the IP block */
+       int (*pre_soft_reset)(void *handle);
        /* soft reset the IP block */
        int (*soft_reset)(void *handle);
+       /* post soft reset the IP block */
+       int (*post_soft_reset)(void *handle);
        /* enable/disable cg for the IP block */
        int (*set_clockgating_state)(void *handle,
                                     enum amd_clockgating_state state);
diff --git a/drivers/gpu/drm/amd/include/asic_reg/si/clearstate_si.h b/drivers/gpu/drm/amd/include/asic_reg/si/clearstate_si.h
new file mode 100644 (file)
index 0000000..66e39cd
--- /dev/null
@@ -0,0 +1,941 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+static const u32 si_SECT_CONTEXT_def_1[] =
+{
+    0x00000000, // DB_RENDER_CONTROL
+    0x00000000, // DB_COUNT_CONTROL
+    0x00000000, // DB_DEPTH_VIEW
+    0x00000000, // DB_RENDER_OVERRIDE
+    0x00000000, // DB_RENDER_OVERRIDE2
+    0x00000000, // DB_HTILE_DATA_BASE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // DB_DEPTH_BOUNDS_MIN
+    0x00000000, // DB_DEPTH_BOUNDS_MAX
+    0x00000000, // DB_STENCIL_CLEAR
+    0x00000000, // DB_DEPTH_CLEAR
+    0x00000000, // PA_SC_SCREEN_SCISSOR_TL
+    0x40004000, // PA_SC_SCREEN_SCISSOR_BR
+    0, // HOLE
+    0x00000000, // DB_DEPTH_INFO
+    0x00000000, // DB_Z_INFO
+    0x00000000, // DB_STENCIL_INFO
+    0x00000000, // DB_Z_READ_BASE
+    0x00000000, // DB_STENCIL_READ_BASE
+    0x00000000, // DB_Z_WRITE_BASE
+    0x00000000, // DB_STENCIL_WRITE_BASE
+    0x00000000, // DB_DEPTH_SIZE
+    0x00000000, // DB_DEPTH_SLICE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // TA_BC_BASE_ADDR
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // COHER_DEST_BASE_2
+    0x00000000, // COHER_DEST_BASE_3
+    0x00000000, // PA_SC_WINDOW_OFFSET
+    0x80000000, // PA_SC_WINDOW_SCISSOR_TL
+    0x40004000, // PA_SC_WINDOW_SCISSOR_BR
+    0x0000ffff, // PA_SC_CLIPRECT_RULE
+    0x00000000, // PA_SC_CLIPRECT_0_TL
+    0x40004000, // PA_SC_CLIPRECT_0_BR
+    0x00000000, // PA_SC_CLIPRECT_1_TL
+    0x40004000, // PA_SC_CLIPRECT_1_BR
+    0x00000000, // PA_SC_CLIPRECT_2_TL
+    0x40004000, // PA_SC_CLIPRECT_2_BR
+    0x00000000, // PA_SC_CLIPRECT_3_TL
+    0x40004000, // PA_SC_CLIPRECT_3_BR
+    0xaa99aaaa, // PA_SC_EDGERULE
+    0x00000000, // PA_SU_HARDWARE_SCREEN_OFFSET
+    0xffffffff, // CB_TARGET_MASK
+    0xffffffff, // CB_SHADER_MASK
+    0x80000000, // PA_SC_GENERIC_SCISSOR_TL
+    0x40004000, // PA_SC_GENERIC_SCISSOR_BR
+    0x00000000, // COHER_DEST_BASE_0
+    0x00000000, // COHER_DEST_BASE_1
+    0x80000000, // PA_SC_VPORT_SCISSOR_0_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_0_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_1_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_1_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_2_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_2_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_3_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_3_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_4_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_4_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_5_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_5_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_6_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_6_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_7_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_7_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_8_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_8_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_9_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_9_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_10_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_10_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_11_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_11_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_12_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_12_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_13_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_13_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_14_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_14_BR
+    0x80000000, // PA_SC_VPORT_SCISSOR_15_TL
+    0x40004000, // PA_SC_VPORT_SCISSOR_15_BR
+    0x00000000, // PA_SC_VPORT_ZMIN_0
+    0x3f800000, // PA_SC_VPORT_ZMAX_0
+    0x00000000, // PA_SC_VPORT_ZMIN_1
+    0x3f800000, // PA_SC_VPORT_ZMAX_1
+    0x00000000, // PA_SC_VPORT_ZMIN_2
+    0x3f800000, // PA_SC_VPORT_ZMAX_2
+    0x00000000, // PA_SC_VPORT_ZMIN_3
+    0x3f800000, // PA_SC_VPORT_ZMAX_3
+    0x00000000, // PA_SC_VPORT_ZMIN_4
+    0x3f800000, // PA_SC_VPORT_ZMAX_4
+    0x00000000, // PA_SC_VPORT_ZMIN_5
+    0x3f800000, // PA_SC_VPORT_ZMAX_5
+    0x00000000, // PA_SC_VPORT_ZMIN_6
+    0x3f800000, // PA_SC_VPORT_ZMAX_6
+    0x00000000, // PA_SC_VPORT_ZMIN_7
+    0x3f800000, // PA_SC_VPORT_ZMAX_7
+    0x00000000, // PA_SC_VPORT_ZMIN_8
+    0x3f800000, // PA_SC_VPORT_ZMAX_8
+    0x00000000, // PA_SC_VPORT_ZMIN_9
+    0x3f800000, // PA_SC_VPORT_ZMAX_9
+    0x00000000, // PA_SC_VPORT_ZMIN_10
+    0x3f800000, // PA_SC_VPORT_ZMAX_10
+    0x00000000, // PA_SC_VPORT_ZMIN_11
+    0x3f800000, // PA_SC_VPORT_ZMAX_11
+    0x00000000, // PA_SC_VPORT_ZMIN_12
+    0x3f800000, // PA_SC_VPORT_ZMAX_12
+    0x00000000, // PA_SC_VPORT_ZMIN_13
+    0x3f800000, // PA_SC_VPORT_ZMAX_13
+    0x00000000, // PA_SC_VPORT_ZMIN_14
+    0x3f800000, // PA_SC_VPORT_ZMAX_14
+    0x00000000, // PA_SC_VPORT_ZMIN_15
+    0x3f800000, // PA_SC_VPORT_ZMAX_15
+};
+static const u32 si_SECT_CONTEXT_def_2[] =
+{
+    0x00000000, // CP_PERFMON_CNTX_CNTL
+    0x00000000, // CP_RINGID
+    0x00000000, // CP_VMID
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0xffffffff, // VGT_MAX_VTX_INDX
+    0x00000000, // VGT_MIN_VTX_INDX
+    0x00000000, // VGT_INDX_OFFSET
+    0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX
+    0, // HOLE
+    0x00000000, // CB_BLEND_RED
+    0x00000000, // CB_BLEND_GREEN
+    0x00000000, // CB_BLEND_BLUE
+    0x00000000, // CB_BLEND_ALPHA
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // DB_STENCIL_CONTROL
+    0x00000000, // DB_STENCILREFMASK
+    0x00000000, // DB_STENCILREFMASK_BF
+    0, // HOLE
+    0x00000000, // PA_CL_VPORT_XSCALE
+    0x00000000, // PA_CL_VPORT_XOFFSET
+    0x00000000, // PA_CL_VPORT_YSCALE
+    0x00000000, // PA_CL_VPORT_YOFFSET
+    0x00000000, // PA_CL_VPORT_ZSCALE
+    0x00000000, // PA_CL_VPORT_ZOFFSET
+    0x00000000, // PA_CL_VPORT_XSCALE_1
+    0x00000000, // PA_CL_VPORT_XOFFSET_1
+    0x00000000, // PA_CL_VPORT_YSCALE_1
+    0x00000000, // PA_CL_VPORT_YOFFSET_1
+    0x00000000, // PA_CL_VPORT_ZSCALE_1
+    0x00000000, // PA_CL_VPORT_ZOFFSET_1
+    0x00000000, // PA_CL_VPORT_XSCALE_2
+    0x00000000, // PA_CL_VPORT_XOFFSET_2
+    0x00000000, // PA_CL_VPORT_YSCALE_2
+    0x00000000, // PA_CL_VPORT_YOFFSET_2
+    0x00000000, // PA_CL_VPORT_ZSCALE_2
+    0x00000000, // PA_CL_VPORT_ZOFFSET_2
+    0x00000000, // PA_CL_VPORT_XSCALE_3
+    0x00000000, // PA_CL_VPORT_XOFFSET_3
+    0x00000000, // PA_CL_VPORT_YSCALE_3
+    0x00000000, // PA_CL_VPORT_YOFFSET_3
+    0x00000000, // PA_CL_VPORT_ZSCALE_3
+    0x00000000, // PA_CL_VPORT_ZOFFSET_3
+    0x00000000, // PA_CL_VPORT_XSCALE_4
+    0x00000000, // PA_CL_VPORT_XOFFSET_4
+    0x00000000, // PA_CL_VPORT_YSCALE_4
+    0x00000000, // PA_CL_VPORT_YOFFSET_4
+    0x00000000, // PA_CL_VPORT_ZSCALE_4
+    0x00000000, // PA_CL_VPORT_ZOFFSET_4
+    0x00000000, // PA_CL_VPORT_XSCALE_5
+    0x00000000, // PA_CL_VPORT_XOFFSET_5
+    0x00000000, // PA_CL_VPORT_YSCALE_5
+    0x00000000, // PA_CL_VPORT_YOFFSET_5
+    0x00000000, // PA_CL_VPORT_ZSCALE_5
+    0x00000000, // PA_CL_VPORT_ZOFFSET_5
+    0x00000000, // PA_CL_VPORT_XSCALE_6
+    0x00000000, // PA_CL_VPORT_XOFFSET_6
+    0x00000000, // PA_CL_VPORT_YSCALE_6
+    0x00000000, // PA_CL_VPORT_YOFFSET_6
+    0x00000000, // PA_CL_VPORT_ZSCALE_6
+    0x00000000, // PA_CL_VPORT_ZOFFSET_6
+    0x00000000, // PA_CL_VPORT_XSCALE_7
+    0x00000000, // PA_CL_VPORT_XOFFSET_7
+    0x00000000, // PA_CL_VPORT_YSCALE_7
+    0x00000000, // PA_CL_VPORT_YOFFSET_7
+    0x00000000, // PA_CL_VPORT_ZSCALE_7
+    0x00000000, // PA_CL_VPORT_ZOFFSET_7
+    0x00000000, // PA_CL_VPORT_XSCALE_8
+    0x00000000, // PA_CL_VPORT_XOFFSET_8
+    0x00000000, // PA_CL_VPORT_YSCALE_8
+    0x00000000, // PA_CL_VPORT_YOFFSET_8
+    0x00000000, // PA_CL_VPORT_ZSCALE_8
+    0x00000000, // PA_CL_VPORT_ZOFFSET_8
+    0x00000000, // PA_CL_VPORT_XSCALE_9
+    0x00000000, // PA_CL_VPORT_XOFFSET_9
+    0x00000000, // PA_CL_VPORT_YSCALE_9
+    0x00000000, // PA_CL_VPORT_YOFFSET_9
+    0x00000000, // PA_CL_VPORT_ZSCALE_9
+    0x00000000, // PA_CL_VPORT_ZOFFSET_9
+    0x00000000, // PA_CL_VPORT_XSCALE_10
+    0x00000000, // PA_CL_VPORT_XOFFSET_10
+    0x00000000, // PA_CL_VPORT_YSCALE_10
+    0x00000000, // PA_CL_VPORT_YOFFSET_10
+    0x00000000, // PA_CL_VPORT_ZSCALE_10
+    0x00000000, // PA_CL_VPORT_ZOFFSET_10
+    0x00000000, // PA_CL_VPORT_XSCALE_11
+    0x00000000, // PA_CL_VPORT_XOFFSET_11
+    0x00000000, // PA_CL_VPORT_YSCALE_11
+    0x00000000, // PA_CL_VPORT_YOFFSET_11
+    0x00000000, // PA_CL_VPORT_ZSCALE_11
+    0x00000000, // PA_CL_VPORT_ZOFFSET_11
+    0x00000000, // PA_CL_VPORT_XSCALE_12
+    0x00000000, // PA_CL_VPORT_XOFFSET_12
+    0x00000000, // PA_CL_VPORT_YSCALE_12
+    0x00000000, // PA_CL_VPORT_YOFFSET_12
+    0x00000000, // PA_CL_VPORT_ZSCALE_12
+    0x00000000, // PA_CL_VPORT_ZOFFSET_12
+    0x00000000, // PA_CL_VPORT_XSCALE_13
+    0x00000000, // PA_CL_VPORT_XOFFSET_13
+    0x00000000, // PA_CL_VPORT_YSCALE_13
+    0x00000000, // PA_CL_VPORT_YOFFSET_13
+    0x00000000, // PA_CL_VPORT_ZSCALE_13
+    0x00000000, // PA_CL_VPORT_ZOFFSET_13
+    0x00000000, // PA_CL_VPORT_XSCALE_14
+    0x00000000, // PA_CL_VPORT_XOFFSET_14
+    0x00000000, // PA_CL_VPORT_YSCALE_14
+    0x00000000, // PA_CL_VPORT_YOFFSET_14
+    0x00000000, // PA_CL_VPORT_ZSCALE_14
+    0x00000000, // PA_CL_VPORT_ZOFFSET_14
+    0x00000000, // PA_CL_VPORT_XSCALE_15
+    0x00000000, // PA_CL_VPORT_XOFFSET_15
+    0x00000000, // PA_CL_VPORT_YSCALE_15
+    0x00000000, // PA_CL_VPORT_YOFFSET_15
+    0x00000000, // PA_CL_VPORT_ZSCALE_15
+    0x00000000, // PA_CL_VPORT_ZOFFSET_15
+    0x00000000, // PA_CL_UCP_0_X
+    0x00000000, // PA_CL_UCP_0_Y
+    0x00000000, // PA_CL_UCP_0_Z
+    0x00000000, // PA_CL_UCP_0_W
+    0x00000000, // PA_CL_UCP_1_X
+    0x00000000, // PA_CL_UCP_1_Y
+    0x00000000, // PA_CL_UCP_1_Z
+    0x00000000, // PA_CL_UCP_1_W
+    0x00000000, // PA_CL_UCP_2_X
+    0x00000000, // PA_CL_UCP_2_Y
+    0x00000000, // PA_CL_UCP_2_Z
+    0x00000000, // PA_CL_UCP_2_W
+    0x00000000, // PA_CL_UCP_3_X
+    0x00000000, // PA_CL_UCP_3_Y
+    0x00000000, // PA_CL_UCP_3_Z
+    0x00000000, // PA_CL_UCP_3_W
+    0x00000000, // PA_CL_UCP_4_X
+    0x00000000, // PA_CL_UCP_4_Y
+    0x00000000, // PA_CL_UCP_4_Z
+    0x00000000, // PA_CL_UCP_4_W
+    0x00000000, // PA_CL_UCP_5_X
+    0x00000000, // PA_CL_UCP_5_Y
+    0x00000000, // PA_CL_UCP_5_Z
+    0x00000000, // PA_CL_UCP_5_W
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SPI_PS_INPUT_CNTL_0
+    0x00000000, // SPI_PS_INPUT_CNTL_1
+    0x00000000, // SPI_PS_INPUT_CNTL_2
+    0x00000000, // SPI_PS_INPUT_CNTL_3
+    0x00000000, // SPI_PS_INPUT_CNTL_4
+    0x00000000, // SPI_PS_INPUT_CNTL_5
+    0x00000000, // SPI_PS_INPUT_CNTL_6
+    0x00000000, // SPI_PS_INPUT_CNTL_7
+    0x00000000, // SPI_PS_INPUT_CNTL_8
+    0x00000000, // SPI_PS_INPUT_CNTL_9
+    0x00000000, // SPI_PS_INPUT_CNTL_10
+    0x00000000, // SPI_PS_INPUT_CNTL_11
+    0x00000000, // SPI_PS_INPUT_CNTL_12
+    0x00000000, // SPI_PS_INPUT_CNTL_13
+    0x00000000, // SPI_PS_INPUT_CNTL_14
+    0x00000000, // SPI_PS_INPUT_CNTL_15
+    0x00000000, // SPI_PS_INPUT_CNTL_16
+    0x00000000, // SPI_PS_INPUT_CNTL_17
+    0x00000000, // SPI_PS_INPUT_CNTL_18
+    0x00000000, // SPI_PS_INPUT_CNTL_19
+    0x00000000, // SPI_PS_INPUT_CNTL_20
+    0x00000000, // SPI_PS_INPUT_CNTL_21
+    0x00000000, // SPI_PS_INPUT_CNTL_22
+    0x00000000, // SPI_PS_INPUT_CNTL_23
+    0x00000000, // SPI_PS_INPUT_CNTL_24
+    0x00000000, // SPI_PS_INPUT_CNTL_25
+    0x00000000, // SPI_PS_INPUT_CNTL_26
+    0x00000000, // SPI_PS_INPUT_CNTL_27
+    0x00000000, // SPI_PS_INPUT_CNTL_28
+    0x00000000, // SPI_PS_INPUT_CNTL_29
+    0x00000000, // SPI_PS_INPUT_CNTL_30
+    0x00000000, // SPI_PS_INPUT_CNTL_31
+    0x00000000, // SPI_VS_OUT_CONFIG
+    0, // HOLE
+    0x00000000, // SPI_PS_INPUT_ENA
+    0x00000000, // SPI_PS_INPUT_ADDR
+    0x00000000, // SPI_INTERP_CONTROL_0
+    0x00000002, // SPI_PS_IN_CONTROL
+    0, // HOLE
+    0x00000000, // SPI_BARYC_CNTL
+    0, // HOLE
+    0x00000000, // SPI_TMPRING_SIZE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // SPI_WAVE_MGMT_1
+    0x00000000, // SPI_WAVE_MGMT_2
+    0x00000000, // SPI_SHADER_POS_FORMAT
+    0x00000000, // SPI_SHADER_Z_FORMAT
+    0x00000000, // SPI_SHADER_COL_FORMAT
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_BLEND0_CONTROL
+    0x00000000, // CB_BLEND1_CONTROL
+    0x00000000, // CB_BLEND2_CONTROL
+    0x00000000, // CB_BLEND3_CONTROL
+    0x00000000, // CB_BLEND4_CONTROL
+    0x00000000, // CB_BLEND5_CONTROL
+    0x00000000, // CB_BLEND6_CONTROL
+    0x00000000, // CB_BLEND7_CONTROL
+};
+static const u32 si_SECT_CONTEXT_def_3[] =
+{
+    0x00000000, // PA_CL_POINT_X_RAD
+    0x00000000, // PA_CL_POINT_Y_RAD
+    0x00000000, // PA_CL_POINT_SIZE
+    0x00000000, // PA_CL_POINT_CULL_RAD
+    0x00000000, // VGT_DMA_BASE_HI
+    0x00000000, // VGT_DMA_BASE
+};
+static const u32 si_SECT_CONTEXT_def_4[] =
+{
+    0x00000000, // DB_DEPTH_CONTROL
+    0x00000000, // DB_EQAA
+    0x00000000, // CB_COLOR_CONTROL
+    0x00000000, // DB_SHADER_CONTROL
+    0x00090000, // PA_CL_CLIP_CNTL
+    0x00000004, // PA_SU_SC_MODE_CNTL
+    0x00000000, // PA_CL_VTE_CNTL
+    0x00000000, // PA_CL_VS_OUT_CNTL
+    0x00000000, // PA_CL_NANINF_CNTL
+    0x00000000, // PA_SU_LINE_STIPPLE_CNTL
+    0x00000000, // PA_SU_LINE_STIPPLE_SCALE
+    0x00000000, // PA_SU_PRIM_FILTER_CNTL
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // PA_SU_POINT_SIZE
+    0x00000000, // PA_SU_POINT_MINMAX
+    0x00000000, // PA_SU_LINE_CNTL
+    0x00000000, // PA_SC_LINE_STIPPLE
+    0x00000000, // VGT_OUTPUT_PATH_CNTL
+    0x00000000, // VGT_HOS_CNTL
+    0x00000000, // VGT_HOS_MAX_TESS_LEVEL
+    0x00000000, // VGT_HOS_MIN_TESS_LEVEL
+    0x00000000, // VGT_HOS_REUSE_DEPTH
+    0x00000000, // VGT_GROUP_PRIM_TYPE
+    0x00000000, // VGT_GROUP_FIRST_DECR
+    0x00000000, // VGT_GROUP_DECR
+    0x00000000, // VGT_GROUP_VECT_0_CNTL
+    0x00000000, // VGT_GROUP_VECT_1_CNTL
+    0x00000000, // VGT_GROUP_VECT_0_FMT_CNTL
+    0x00000000, // VGT_GROUP_VECT_1_FMT_CNTL
+    0x00000000, // VGT_GS_MODE
+    0, // HOLE
+    0x00000000, // PA_SC_MODE_CNTL_0
+    0x00000000, // PA_SC_MODE_CNTL_1
+    0x00000000, // VGT_ENHANCE
+    0x00000100, // VGT_GS_PER_ES
+    0x00000080, // VGT_ES_PER_GS
+    0x00000002, // VGT_GS_PER_VS
+    0x00000000, // VGT_GSVS_RING_OFFSET_1
+    0x00000000, // VGT_GSVS_RING_OFFSET_2
+    0x00000000, // VGT_GSVS_RING_OFFSET_3
+    0x00000000, // VGT_GS_OUT_PRIM_TYPE
+    0x00000000, // IA_ENHANCE
+};
+static const u32 si_SECT_CONTEXT_def_5[] =
+{
+    0x00000000, // VGT_PRIMITIVEID_EN
+};
+static const u32 si_SECT_CONTEXT_def_6[] =
+{
+    0x00000000, // VGT_PRIMITIVEID_RESET
+};
+static const u32 si_SECT_CONTEXT_def_7[] =
+{
+    0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_INSTANCE_STEP_RATE_0
+    0x00000000, // VGT_INSTANCE_STEP_RATE_1
+    0x000000ff, // IA_MULTI_VGT_PARAM
+    0x00000000, // VGT_ESGS_RING_ITEMSIZE
+    0x00000000, // VGT_GSVS_RING_ITEMSIZE
+    0x00000000, // VGT_REUSE_OFF
+    0x00000000, // VGT_VTX_CNT_EN
+    0x00000000, // DB_HTILE_SURFACE
+    0x00000000, // DB_SRESULTS_COMPARE_STATE0
+    0x00000000, // DB_SRESULTS_COMPARE_STATE1
+    0x00000000, // DB_PRELOAD_CONTROL
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_0
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_0
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_1
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_2
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2
+    0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3
+    0x00000000, // VGT_STRMOUT_VTX_STRIDE_3
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+    0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+    0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
+    0, // HOLE
+    0x00000000, // VGT_GS_MAX_VERT_OUT
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // VGT_SHADER_STAGES_EN
+    0x00000000, // VGT_LS_HS_CONFIG
+    0x00000000, // VGT_GS_VERT_ITEMSIZE
+    0x00000000, // VGT_GS_VERT_ITEMSIZE_1
+    0x00000000, // VGT_GS_VERT_ITEMSIZE_2
+    0x00000000, // VGT_GS_VERT_ITEMSIZE_3
+    0x00000000, // VGT_TF_PARAM
+    0x00000000, // DB_ALPHA_TO_MASK
+    0, // HOLE
+    0x00000000, // PA_SU_POLY_OFFSET_DB_FMT_CNTL
+    0x00000000, // PA_SU_POLY_OFFSET_CLAMP
+    0x00000000, // PA_SU_POLY_OFFSET_FRONT_SCALE
+    0x00000000, // PA_SU_POLY_OFFSET_FRONT_OFFSET
+    0x00000000, // PA_SU_POLY_OFFSET_BACK_SCALE
+    0x00000000, // PA_SU_POLY_OFFSET_BACK_OFFSET
+    0x00000000, // VGT_GS_INSTANCE_CNT
+    0x00000000, // VGT_STRMOUT_CONFIG
+    0x00000000, // VGT_STRMOUT_BUFFER_CONFIG
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // PA_SC_CENTROID_PRIORITY_0
+    0x00000000, // PA_SC_CENTROID_PRIORITY_1
+    0x00001000, // PA_SC_LINE_CNTL
+    0x00000000, // PA_SC_AA_CONFIG
+    0x00000005, // PA_SU_VTX_CNTL
+    0x3f800000, // PA_CL_GB_VERT_CLIP_ADJ
+    0x3f800000, // PA_CL_GB_VERT_DISC_ADJ
+    0x3f800000, // PA_CL_GB_HORZ_CLIP_ADJ
+    0x3f800000, // PA_CL_GB_HORZ_DISC_ADJ
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_1
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_2
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_3
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_1
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_2
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_3
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_1
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_2
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_3
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_1
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_2
+    0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_3
+    0xffffffff, // PA_SC_AA_MASK_X0Y0_X1Y0
+    0xffffffff, // PA_SC_AA_MASK_X0Y1_X1Y1
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0, // HOLE
+    0x0000000e, // VGT_VERTEX_REUSE_BLOCK_CNTL
+    0x00000010, // VGT_OUT_DEALLOC_CNTL
+    0x00000000, // CB_COLOR0_BASE
+    0x00000000, // CB_COLOR0_PITCH
+    0x00000000, // CB_COLOR0_SLICE
+    0x00000000, // CB_COLOR0_VIEW
+    0x00000000, // CB_COLOR0_INFO
+    0x00000000, // CB_COLOR0_ATTRIB
+    0, // HOLE
+    0x00000000, // CB_COLOR0_CMASK
+    0x00000000, // CB_COLOR0_CMASK_SLICE
+    0x00000000, // CB_COLOR0_FMASK
+    0x00000000, // CB_COLOR0_FMASK_SLICE
+    0x00000000, // CB_COLOR0_CLEAR_WORD0
+    0x00000000, // CB_COLOR0_CLEAR_WORD1
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_COLOR1_BASE
+    0x00000000, // CB_COLOR1_PITCH
+    0x00000000, // CB_COLOR1_SLICE
+    0x00000000, // CB_COLOR1_VIEW
+    0x00000000, // CB_COLOR1_INFO
+    0x00000000, // CB_COLOR1_ATTRIB
+    0, // HOLE
+    0x00000000, // CB_COLOR1_CMASK
+    0x00000000, // CB_COLOR1_CMASK_SLICE
+    0x00000000, // CB_COLOR1_FMASK
+    0x00000000, // CB_COLOR1_FMASK_SLICE
+    0x00000000, // CB_COLOR1_CLEAR_WORD0
+    0x00000000, // CB_COLOR1_CLEAR_WORD1
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_COLOR2_BASE
+    0x00000000, // CB_COLOR2_PITCH
+    0x00000000, // CB_COLOR2_SLICE
+    0x00000000, // CB_COLOR2_VIEW
+    0x00000000, // CB_COLOR2_INFO
+    0x00000000, // CB_COLOR2_ATTRIB
+    0, // HOLE
+    0x00000000, // CB_COLOR2_CMASK
+    0x00000000, // CB_COLOR2_CMASK_SLICE
+    0x00000000, // CB_COLOR2_FMASK
+    0x00000000, // CB_COLOR2_FMASK_SLICE
+    0x00000000, // CB_COLOR2_CLEAR_WORD0
+    0x00000000, // CB_COLOR2_CLEAR_WORD1
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_COLOR3_BASE
+    0x00000000, // CB_COLOR3_PITCH
+    0x00000000, // CB_COLOR3_SLICE
+    0x00000000, // CB_COLOR3_VIEW
+    0x00000000, // CB_COLOR3_INFO
+    0x00000000, // CB_COLOR3_ATTRIB
+    0, // HOLE
+    0x00000000, // CB_COLOR3_CMASK
+    0x00000000, // CB_COLOR3_CMASK_SLICE
+    0x00000000, // CB_COLOR3_FMASK
+    0x00000000, // CB_COLOR3_FMASK_SLICE
+    0x00000000, // CB_COLOR3_CLEAR_WORD0
+    0x00000000, // CB_COLOR3_CLEAR_WORD1
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_COLOR4_BASE
+    0x00000000, // CB_COLOR4_PITCH
+    0x00000000, // CB_COLOR4_SLICE
+    0x00000000, // CB_COLOR4_VIEW
+    0x00000000, // CB_COLOR4_INFO
+    0x00000000, // CB_COLOR4_ATTRIB
+    0, // HOLE
+    0x00000000, // CB_COLOR4_CMASK
+    0x00000000, // CB_COLOR4_CMASK_SLICE
+    0x00000000, // CB_COLOR4_FMASK
+    0x00000000, // CB_COLOR4_FMASK_SLICE
+    0x00000000, // CB_COLOR4_CLEAR_WORD0
+    0x00000000, // CB_COLOR4_CLEAR_WORD1
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_COLOR5_BASE
+    0x00000000, // CB_COLOR5_PITCH
+    0x00000000, // CB_COLOR5_SLICE
+    0x00000000, // CB_COLOR5_VIEW
+    0x00000000, // CB_COLOR5_INFO
+    0x00000000, // CB_COLOR5_ATTRIB
+    0, // HOLE
+    0x00000000, // CB_COLOR5_CMASK
+    0x00000000, // CB_COLOR5_CMASK_SLICE
+    0x00000000, // CB_COLOR5_FMASK
+    0x00000000, // CB_COLOR5_FMASK_SLICE
+    0x00000000, // CB_COLOR5_CLEAR_WORD0
+    0x00000000, // CB_COLOR5_CLEAR_WORD1
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_COLOR6_BASE
+    0x00000000, // CB_COLOR6_PITCH
+    0x00000000, // CB_COLOR6_SLICE
+    0x00000000, // CB_COLOR6_VIEW
+    0x00000000, // CB_COLOR6_INFO
+    0x00000000, // CB_COLOR6_ATTRIB
+    0, // HOLE
+    0x00000000, // CB_COLOR6_CMASK
+    0x00000000, // CB_COLOR6_CMASK_SLICE
+    0x00000000, // CB_COLOR6_FMASK
+    0x00000000, // CB_COLOR6_FMASK_SLICE
+    0x00000000, // CB_COLOR6_CLEAR_WORD0
+    0x00000000, // CB_COLOR6_CLEAR_WORD1
+    0, // HOLE
+    0, // HOLE
+    0x00000000, // CB_COLOR7_BASE
+    0x00000000, // CB_COLOR7_PITCH
+    0x00000000, // CB_COLOR7_SLICE
+    0x00000000, // CB_COLOR7_VIEW
+    0x00000000, // CB_COLOR7_INFO
+    0x00000000, // CB_COLOR7_ATTRIB
+    0, // HOLE
+    0x00000000, // CB_COLOR7_CMASK
+    0x00000000, // CB_COLOR7_CMASK_SLICE
+    0x00000000, // CB_COLOR7_FMASK
+    0x00000000, // CB_COLOR7_FMASK_SLICE
+    0x00000000, // CB_COLOR7_CLEAR_WORD0
+    0x00000000, // CB_COLOR7_CLEAR_WORD1
+};
+static const struct cs_extent_def si_SECT_CONTEXT_defs[] =
+{
+    {si_SECT_CONTEXT_def_1, 0x0000a000, 212 },
+    {si_SECT_CONTEXT_def_2, 0x0000a0d8, 272 },
+    {si_SECT_CONTEXT_def_3, 0x0000a1f5, 6 },
+    {si_SECT_CONTEXT_def_4, 0x0000a200, 157 },
+    {si_SECT_CONTEXT_def_5, 0x0000a2a1, 1 },
+    {si_SECT_CONTEXT_def_6, 0x0000a2a3, 1 },
+    {si_SECT_CONTEXT_def_7, 0x0000a2a5, 233 },
+    { NULL, 0, 0 }
+};
+static const struct cs_section_def si_cs_data[] = {
+    { si_SECT_CONTEXT_defs, SECT_CONTEXT },
+    { NULL, SECT_NONE }
+};
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
new file mode 100644 (file)
index 0000000..895c8e2
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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/asic_reg/si/sid.h b/drivers/gpu/drm/amd/include/asic_reg/si/sid.h
new file mode 100644 (file)
index 0000000..c57eff1
--- /dev/null
@@ -0,0 +1,2461 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef SI_H
+#define SI_H
+
+#define TAHITI_RB_BITMAP_WIDTH_PER_SH  2
+
+#define TAHITI_GB_ADDR_CONFIG_GOLDEN        0x12011003
+#define VERDE_GB_ADDR_CONFIG_GOLDEN         0x12010002
+#define HAINAN_GB_ADDR_CONFIG_GOLDEN        0x02010001
+
+#define SI_MAX_SH_GPRS                 256
+#define SI_MAX_TEMP_GPRS               16
+#define SI_MAX_SH_THREADS              256
+#define SI_MAX_SH_STACK_ENTRIES        4096
+#define SI_MAX_FRC_EOV_CNT             16384
+#define SI_MAX_BACKENDS                8
+#define SI_MAX_BACKENDS_MASK           0xFF
+#define SI_MAX_BACKENDS_PER_SE_MASK     0x0F
+#define SI_MAX_SIMDS                   12
+#define SI_MAX_SIMDS_MASK              0x0FFF
+#define SI_MAX_SIMDS_PER_SE_MASK        0x00FF
+#define SI_MAX_PIPES                   8
+#define SI_MAX_PIPES_MASK              0xFF
+#define SI_MAX_PIPES_PER_SIMD_MASK      0x3F
+#define SI_MAX_LDS_NUM                 0xFFFF
+#define SI_MAX_TCC                     16
+#define SI_MAX_TCC_MASK                0xFFFF
+
+#define AMDGPU_NUM_OF_VMIDS            8
+
+/* SMC IND accessor regs */
+#define SMC_IND_INDEX_0                              0x80
+#define SMC_IND_DATA_0                               0x81
+
+#define SMC_IND_ACCESS_CNTL                          0x8A
+#       define AUTO_INCREMENT_IND_0                  (1 << 0)
+#define SMC_MESSAGE_0                                0x8B
+#define SMC_RESP_0                                   0x8C
+
+/* CG IND registers are accessed via SMC indirect space + SMC_CG_IND_START */
+#define SMC_CG_IND_START                    0xc0030000
+#define SMC_CG_IND_END                      0xc0040000
+
+#define        CG_CGTT_LOCAL_0                         0x400
+#define        CG_CGTT_LOCAL_1                         0x401
+
+/* SMC IND registers */
+#define        SMC_SYSCON_RESET_CNTL                           0x80000000
+#       define RST_REG                                  (1 << 0)
+#define        SMC_SYSCON_CLOCK_CNTL_0                         0x80000004
+#       define CK_DISABLE                               (1 << 0)
+#       define CKEN                                     (1 << 24)
+
+#define VGA_HDP_CONTROL                                0xCA
+#define                VGA_MEMORY_DISABLE                              (1 << 4)
+
+#define DCCG_DISP_SLOW_SELECT_REG                       0x13F
+#define                DCCG_DISP1_SLOW_SELECT(x)               ((x) << 0)
+#define                DCCG_DISP1_SLOW_SELECT_MASK             (7 << 0)
+#define                DCCG_DISP1_SLOW_SELECT_SHIFT            0
+#define                DCCG_DISP2_SLOW_SELECT(x)               ((x) << 4)
+#define                DCCG_DISP2_SLOW_SELECT_MASK             (7 << 4)
+#define                DCCG_DISP2_SLOW_SELECT_SHIFT            4
+
+#define        CG_SPLL_FUNC_CNTL                               0x180
+#define                SPLL_RESET                              (1 << 0)
+#define                SPLL_SLEEP                              (1 << 1)
+#define                SPLL_BYPASS_EN                          (1 << 3)
+#define                SPLL_REF_DIV(x)                         ((x) << 4)
+#define                SPLL_REF_DIV_MASK                       (0x3f << 4)
+#define                SPLL_PDIV_A(x)                          ((x) << 20)
+#define                SPLL_PDIV_A_MASK                        (0x7f << 20)
+#define                SPLL_PDIV_A_SHIFT                       20
+#define        CG_SPLL_FUNC_CNTL_2                             0x181
+#define                SCLK_MUX_SEL(x)                         ((x) << 0)
+#define                SCLK_MUX_SEL_MASK                       (0x1ff << 0)
+#define                SPLL_CTLREQ_CHG                         (1 << 23)
+#define                SCLK_MUX_UPDATE                         (1 << 26)
+#define        CG_SPLL_FUNC_CNTL_3                             0x182
+#define                SPLL_FB_DIV(x)                          ((x) << 0)
+#define                SPLL_FB_DIV_MASK                        (0x3ffffff << 0)
+#define                SPLL_FB_DIV_SHIFT                       0
+#define                SPLL_DITHEN                             (1 << 28)
+#define        CG_SPLL_FUNC_CNTL_4                             0x183
+
+#define        SPLL_STATUS                                     0x185
+#define                SPLL_CHG_STATUS                         (1 << 1)
+#define        SPLL_CNTL_MODE                                  0x186
+#define                SPLL_SW_DIR_CONTROL                     (1 << 0)
+#      define SPLL_REFCLK_SEL(x)                       ((x) << 26)
+#      define SPLL_REFCLK_SEL_MASK                     (3 << 26)
+
+#define        CG_SPLL_SPREAD_SPECTRUM                         0x188
+#define                SSEN                                    (1 << 0)
+#define                CLK_S(x)                                ((x) << 4)
+#define                CLK_S_MASK                              (0xfff << 4)
+#define                CLK_S_SHIFT                             4
+#define        CG_SPLL_SPREAD_SPECTRUM_2                       0x189
+#define                CLK_V(x)                                ((x) << 0)
+#define                CLK_V_MASK                              (0x3ffffff << 0)
+#define                CLK_V_SHIFT                             0
+
+#define        CG_SPLL_AUTOSCALE_CNTL                          0x18b
+#       define AUTOSCALE_ON_SS_CLEAR                    (1 << 9)
+
+/* discrete uvd clocks */
+#define        CG_UPLL_FUNC_CNTL                               0x18d
+#      define UPLL_RESET_MASK                          0x00000001
+#      define UPLL_SLEEP_MASK                          0x00000002
+#      define UPLL_BYPASS_EN_MASK                      0x00000004
+#      define UPLL_CTLREQ_MASK                         0x00000008
+#      define UPLL_VCO_MODE_MASK                       0x00000600
+#      define UPLL_REF_DIV_MASK                        0x003F0000
+#      define UPLL_CTLACK_MASK                         0x40000000
+#      define UPLL_CTLACK2_MASK                        0x80000000
+#define        CG_UPLL_FUNC_CNTL_2                             0x18e
+#      define UPLL_PDIV_A(x)                           ((x) << 0)
+#      define UPLL_PDIV_A_MASK                         0x0000007F
+#      define UPLL_PDIV_B(x)                           ((x) << 8)
+#      define UPLL_PDIV_B_MASK                         0x00007F00
+#      define VCLK_SRC_SEL(x)                          ((x) << 20)
+#      define VCLK_SRC_SEL_MASK                        0x01F00000
+#      define DCLK_SRC_SEL(x)                          ((x) << 25)
+#      define DCLK_SRC_SEL_MASK                        0x3E000000
+#define        CG_UPLL_FUNC_CNTL_3                             0x18f
+#      define UPLL_FB_DIV(x)                           ((x) << 0)
+#      define UPLL_FB_DIV_MASK                         0x01FFFFFF
+#define        CG_UPLL_FUNC_CNTL_4                             0x191
+#      define UPLL_SPARE_ISPARE9                       0x00020000
+#define        CG_UPLL_FUNC_CNTL_5                             0x192
+#      define RESET_ANTI_MUX_MASK                      0x00000200
+#define        CG_UPLL_SPREAD_SPECTRUM                         0x194
+#      define SSEN_MASK                                0x00000001
+
+#define        MPLL_BYPASSCLK_SEL                              0x197
+#      define MPLL_CLKOUT_SEL(x)                       ((x) << 8)
+#      define MPLL_CLKOUT_SEL_MASK                     0xFF00
+
+#define CG_CLKPIN_CNTL                                    0x198
+#       define XTALIN_DIVIDE                              (1 << 1)
+#       define BCLK_AS_XCLK                               (1 << 2)
+#define CG_CLKPIN_CNTL_2                                  0x199
+#       define FORCE_BIF_REFCLK_EN                        (1 << 3)
+#       define MUX_TCLK_TO_XCLK                           (1 << 8)
+
+#define        THM_CLK_CNTL                                    0x19b
+#      define CMON_CLK_SEL(x)                          ((x) << 0)
+#      define CMON_CLK_SEL_MASK                        0xFF
+#      define TMON_CLK_SEL(x)                          ((x) << 8)
+#      define TMON_CLK_SEL_MASK                        0xFF00
+#define        MISC_CLK_CNTL                                   0x19c
+#      define DEEP_SLEEP_CLK_SEL(x)                    ((x) << 0)
+#      define DEEP_SLEEP_CLK_SEL_MASK                  0xFF
+#      define ZCLK_SEL(x)                              ((x) << 8)
+#      define ZCLK_SEL_MASK                            0xFF00
+
+#define        CG_THERMAL_CTRL                                 0x1c0
+#define        DPM_EVENT_SRC(x)                        ((x) << 0)
+#define        DPM_EVENT_SRC_MASK                      (7 << 0)
+#define                DIG_THERM_DPM(x)                        ((x) << 14)
+#define                DIG_THERM_DPM_MASK                      0x003FC000
+#define                DIG_THERM_DPM_SHIFT                     14
+#define        CG_THERMAL_STATUS                               0x1c1
+#define                FDO_PWM_DUTY(x)                         ((x) << 9)
+#define                FDO_PWM_DUTY_MASK                       (0xff << 9)
+#define                FDO_PWM_DUTY_SHIFT                      9
+#define        CG_THERMAL_INT                                  0x1c2
+#define                DIG_THERM_INTH(x)                       ((x) << 8)
+#define                DIG_THERM_INTH_MASK                     0x0000FF00
+#define                DIG_THERM_INTH_SHIFT                    8
+#define                DIG_THERM_INTL(x)                       ((x) << 16)
+#define                DIG_THERM_INTL_MASK                     0x00FF0000
+#define                DIG_THERM_INTL_SHIFT                    16
+#define        THERM_INT_MASK_HIGH                     (1 << 24)
+#define        THERM_INT_MASK_LOW                      (1 << 25)
+
+#define        CG_MULT_THERMAL_CTRL                                    0x1c4
+#define                TEMP_SEL(x)                                     ((x) << 20)
+#define                TEMP_SEL_MASK                                   (0xff << 20)
+#define                TEMP_SEL_SHIFT                                  20
+#define        CG_MULT_THERMAL_STATUS                                  0x1c5
+#define                ASIC_MAX_TEMP(x)                                ((x) << 0)
+#define                ASIC_MAX_TEMP_MASK                              0x000001ff
+#define                ASIC_MAX_TEMP_SHIFT                             0
+#define                CTF_TEMP(x)                                     ((x) << 9)
+#define                CTF_TEMP_MASK                                   0x0003fe00
+#define                CTF_TEMP_SHIFT                                  9
+
+#define        CG_FDO_CTRL0                                    0x1d5
+#define                FDO_STATIC_DUTY(x)                      ((x) << 0)
+#define                FDO_STATIC_DUTY_MASK                    0x000000FF
+#define                FDO_STATIC_DUTY_SHIFT                   0
+#define        CG_FDO_CTRL1                                    0x1d6
+#define                FMAX_DUTY100(x)                         ((x) << 0)
+#define                FMAX_DUTY100_MASK                       0x000000FF
+#define                FMAX_DUTY100_SHIFT                      0
+#define        CG_FDO_CTRL2                                    0x1d7
+#define                TMIN(x)                                 ((x) << 0)
+#define                TMIN_MASK                               0x000000FF
+#define                TMIN_SHIFT                              0
+#define                FDO_PWM_MODE(x)                         ((x) << 11)
+#define                FDO_PWM_MODE_MASK                       (7 << 11)
+#define                FDO_PWM_MODE_SHIFT                      11
+#define                TACH_PWM_RESP_RATE(x)                   ((x) << 25)
+#define                TACH_PWM_RESP_RATE_MASK                 (0x7f << 25)
+#define                TACH_PWM_RESP_RATE_SHIFT                25
+
+#define CG_TACH_CTRL                                    0x1dc
+#       define EDGE_PER_REV(x)                          ((x) << 0)
+#       define EDGE_PER_REV_MASK                        (0x7 << 0)
+#       define EDGE_PER_REV_SHIFT                       0
+#       define TARGET_PERIOD(x)                         ((x) << 3)
+#       define TARGET_PERIOD_MASK                       0xfffffff8
+#       define TARGET_PERIOD_SHIFT                      3
+#define CG_TACH_STATUS                                  0x1dd
+#       define TACH_PERIOD(x)                           ((x) << 0)
+#       define TACH_PERIOD_MASK                         0xffffffff
+#       define TACH_PERIOD_SHIFT                        0
+
+#define GENERAL_PWRMGT                                  0x1e0
+#       define GLOBAL_PWRMGT_EN                         (1 << 0)
+#       define STATIC_PM_EN                             (1 << 1)
+#       define THERMAL_PROTECTION_DIS                   (1 << 2)
+#       define THERMAL_PROTECTION_TYPE                  (1 << 3)
+#       define SW_SMIO_INDEX(x)                         ((x) << 6)
+#       define SW_SMIO_INDEX_MASK                       (1 << 6)
+#       define SW_SMIO_INDEX_SHIFT                      6
+#       define VOLT_PWRMGT_EN                           (1 << 10)
+#       define DYN_SPREAD_SPECTRUM_EN                   (1 << 23)
+#define CG_TPC                                            0x1e1
+#define SCLK_PWRMGT_CNTL                                  0x1e2
+#       define SCLK_PWRMGT_OFF                            (1 << 0)
+#       define SCLK_LOW_D1                                (1 << 1)
+#       define FIR_RESET                                  (1 << 4)
+#       define FIR_FORCE_TREND_SEL                        (1 << 5)
+#       define FIR_TREND_MODE                             (1 << 6)
+#       define DYN_GFX_CLK_OFF_EN                         (1 << 7)
+#       define GFX_CLK_FORCE_ON                           (1 << 8)
+#       define GFX_CLK_REQUEST_OFF                        (1 << 9)
+#       define GFX_CLK_FORCE_OFF                          (1 << 10)
+#       define GFX_CLK_OFF_ACPI_D1                        (1 << 11)
+#       define GFX_CLK_OFF_ACPI_D2                        (1 << 12)
+#       define GFX_CLK_OFF_ACPI_D3                        (1 << 13)
+#       define DYN_LIGHT_SLEEP_EN                         (1 << 14)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX                  0x1e6
+#       define CURRENT_STATE_INDEX_MASK                   (0xf << 4)
+#       define CURRENT_STATE_INDEX_SHIFT                  4
+
+#define CG_FTV                                            0x1ef
+
+#define CG_FFCT_0                                         0x1f0
+#       define UTC_0(x)                                   ((x) << 0)
+#       define UTC_0_MASK                                 (0x3ff << 0)
+#       define DTC_0(x)                                   ((x) << 10)
+#       define DTC_0_MASK                                 (0x3ff << 10)
+
+#define CG_BSP                                          0x1ff
+#       define BSP(x)                                  ((x) << 0)
+#       define BSP_MASK                                        (0xffff << 0)
+#       define BSU(x)                                  ((x) << 16)
+#       define BSU_MASK                                        (0xf << 16)
+#define CG_AT                                           0x200
+#       define CG_R(x)                                 ((x) << 0)
+#       define CG_R_MASK                               (0xffff << 0)
+#       define CG_L(x)                                 ((x) << 16)
+#       define CG_L_MASK                               (0xffff << 16)
+
+#define CG_GIT                                          0x201
+#       define CG_GICST(x)                              ((x) << 0)
+#       define CG_GICST_MASK                            (0xffff << 0)
+#       define CG_GIPOT(x)                              ((x) << 16)
+#       define CG_GIPOT_MASK                            (0xffff << 16)
+
+#define CG_SSP                                            0x203
+#       define SST(x)                                     ((x) << 0)
+#       define SST_MASK                                   (0xffff << 0)
+#       define SSTU(x)                                    ((x) << 16)
+#       define SSTU_MASK                                  (0xf << 16)
+
+#define CG_DISPLAY_GAP_CNTL                               0x20a
+#       define DISP1_GAP(x)                               ((x) << 0)
+#       define DISP1_GAP_MASK                             (3 << 0)
+#       define DISP2_GAP(x)                               ((x) << 2)
+#       define DISP2_GAP_MASK                             (3 << 2)
+#       define VBI_TIMER_COUNT(x)                         ((x) << 4)
+#       define VBI_TIMER_COUNT_MASK                       (0x3fff << 4)
+#       define VBI_TIMER_UNIT(x)                          ((x) << 20)
+#       define VBI_TIMER_UNIT_MASK                        (7 << 20)
+#       define DISP1_GAP_MCHG(x)                          ((x) << 24)
+#       define DISP1_GAP_MCHG_MASK                        (3 << 24)
+#       define DISP2_GAP_MCHG(x)                          ((x) << 26)
+#       define DISP2_GAP_MCHG_MASK                        (3 << 26)
+
+#define        CG_ULV_CONTROL                                  0x21e
+#define        CG_ULV_PARAMETER                                0x21f
+
+#define        SMC_SCRATCH0                                    0x221
+
+#define        CG_CAC_CTRL                                     0x22e
+#      define CAC_WINDOW(x)                            ((x) << 0)
+#      define CAC_WINDOW_MASK                          0x00ffffff
+
+#define DMIF_ADDR_CONFIG                               0x2F5
+
+#define DMIF_ADDR_CALC                                 0x300
+
+#define        PIPE0_DMIF_BUFFER_CONTROL                         0x0328
+#       define DMIF_BUFFERS_ALLOCATED(x)                  ((x) << 0)
+#       define DMIF_BUFFERS_ALLOCATED_COMPLETED           (1 << 4)
+
+#define        SRBM_STATUS                                     0x394
+#define                GRBM_RQ_PENDING                         (1 << 5)
+#define                VMC_BUSY                                (1 << 8)
+#define                MCB_BUSY                                (1 << 9)
+#define                MCB_NON_DISPLAY_BUSY                    (1 << 10)
+#define                MCC_BUSY                                (1 << 11)
+#define                MCD_BUSY                                (1 << 12)
+#define                SEM_BUSY                                (1 << 14)
+#define                IH_BUSY                                 (1 << 17)
+
+#define        SRBM_SOFT_RESET                                 0x398
+#define                SOFT_RESET_BIF                          (1 << 1)
+#define                SOFT_RESET_DC                           (1 << 5)
+#define                SOFT_RESET_DMA1                         (1 << 6)
+#define                SOFT_RESET_GRBM                         (1 << 8)
+#define                SOFT_RESET_HDP                          (1 << 9)
+#define                SOFT_RESET_IH                           (1 << 10)
+#define                SOFT_RESET_MC                           (1 << 11)
+#define                SOFT_RESET_ROM                          (1 << 14)
+#define                SOFT_RESET_SEM                          (1 << 15)
+#define                SOFT_RESET_VMC                          (1 << 17)
+#define                SOFT_RESET_DMA                          (1 << 20)
+#define                SOFT_RESET_TST                          (1 << 21)
+#define                SOFT_RESET_REGBB                        (1 << 22)
+#define                SOFT_RESET_ORB                          (1 << 23)
+
+#define        CC_SYS_RB_BACKEND_DISABLE                       0x3A0
+#define        GC_USER_SYS_RB_BACKEND_DISABLE                  0x3A1
+
+#define SRBM_READ_ERROR                                        0x3A6
+#define SRBM_INT_CNTL                                  0x3A8
+#define SRBM_INT_ACK                                   0x3AA
+
+#define        SRBM_STATUS2                                    0x3B1
+#define                DMA_BUSY                                (1 << 5)
+#define                DMA1_BUSY                               (1 << 6)
+
+#define VM_L2_CNTL                                     0x500
+#define                ENABLE_L2_CACHE                                 (1 << 0)
+#define                ENABLE_L2_FRAGMENT_PROCESSING                   (1 << 1)
+#define                L2_CACHE_PTE_ENDIAN_SWAP_MODE(x)                ((x) << 2)
+#define                L2_CACHE_PDE_ENDIAN_SWAP_MODE(x)                ((x) << 4)
+#define                ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE         (1 << 9)
+#define                ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE        (1 << 10)
+#define                EFFECTIVE_L2_QUEUE_SIZE(x)                      (((x) & 7) << 15)
+#define                CONTEXT1_IDENTITY_ACCESS_MODE(x)                (((x) & 3) << 19)
+#define VM_L2_CNTL2                                    0x501
+#define                INVALIDATE_ALL_L1_TLBS                          (1 << 0)
+#define                INVALIDATE_L2_CACHE                             (1 << 1)
+#define                INVALIDATE_CACHE_MODE(x)                        ((x) << 26)
+#define                        INVALIDATE_PTE_AND_PDE_CACHES           0
+#define                        INVALIDATE_ONLY_PTE_CACHES              1
+#define                        INVALIDATE_ONLY_PDE_CACHES              2
+#define VM_L2_CNTL3                                    0x502
+#define                BANK_SELECT(x)                                  ((x) << 0)
+#define                L2_CACHE_UPDATE_MODE(x)                         ((x) << 6)
+#define                L2_CACHE_BIGK_FRAGMENT_SIZE(x)                  ((x) << 15)
+#define                L2_CACHE_BIGK_ASSOCIATIVITY                     (1 << 20)
+#define        VM_L2_STATUS                                    0x503
+#define                L2_BUSY                                         (1 << 0)
+#define VM_CONTEXT0_CNTL                               0x504
+#define                ENABLE_CONTEXT                                  (1 << 0)
+#define                PAGE_TABLE_DEPTH(x)                             (((x) & 3) << 1)
+#define                RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT         (1 << 3)
+#define                RANGE_PROTECTION_FAULT_ENABLE_DEFAULT           (1 << 4)
+#define                DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT    (1 << 6)
+#define                DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT      (1 << 7)
+#define                PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT          (1 << 9)
+#define                PDE0_PROTECTION_FAULT_ENABLE_DEFAULT            (1 << 10)
+#define                VALID_PROTECTION_FAULT_ENABLE_INTERRUPT         (1 << 12)
+#define                VALID_PROTECTION_FAULT_ENABLE_DEFAULT           (1 << 13)
+#define                READ_PROTECTION_FAULT_ENABLE_INTERRUPT          (1 << 15)
+#define                READ_PROTECTION_FAULT_ENABLE_DEFAULT            (1 << 16)
+#define                WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT         (1 << 18)
+#define                WRITE_PROTECTION_FAULT_ENABLE_DEFAULT           (1 << 19)
+#define                PAGE_TABLE_BLOCK_SIZE(x)                        (((x) & 0xF) << 24)
+#define VM_CONTEXT1_CNTL                               0x505
+#define VM_CONTEXT0_CNTL2                              0x50C
+#define VM_CONTEXT1_CNTL2                              0x50D
+#define        VM_CONTEXT8_PAGE_TABLE_BASE_ADDR                0x50E
+#define        VM_CONTEXT9_PAGE_TABLE_BASE_ADDR                0x50F
+#define        VM_CONTEXT10_PAGE_TABLE_BASE_ADDR               0x510
+#define        VM_CONTEXT11_PAGE_TABLE_BASE_ADDR               0x511
+#define        VM_CONTEXT12_PAGE_TABLE_BASE_ADDR               0x512
+#define        VM_CONTEXT13_PAGE_TABLE_BASE_ADDR               0x513
+#define        VM_CONTEXT14_PAGE_TABLE_BASE_ADDR               0x514
+#define        VM_CONTEXT15_PAGE_TABLE_BASE_ADDR               0x515
+
+#define        VM_CONTEXT1_PROTECTION_FAULT_ADDR               0x53f
+#define        VM_CONTEXT1_PROTECTION_FAULT_STATUS             0x537
+#define                PROTECTIONS_MASK                        (0xf << 0)
+#define                PROTECTIONS_SHIFT                       0
+               /* bit 0: range
+                * bit 1: pde0
+                * bit 2: valid
+                * bit 3: read
+                * bit 4: write
+                */
+#define                MEMORY_CLIENT_ID_MASK                   (0xff << 12)
+#define                MEMORY_CLIENT_ID_SHIFT                  12
+#define                MEMORY_CLIENT_RW_MASK                   (1 << 24)
+#define                MEMORY_CLIENT_RW_SHIFT                  24
+#define                FAULT_VMID_MASK                         (0xf << 25)
+#define                FAULT_VMID_SHIFT                        25
+
+#define VM_INVALIDATE_REQUEST                          0x51E
+#define VM_INVALIDATE_RESPONSE                         0x51F
+
+#define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR      0x546
+#define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR      0x547
+
+#define        VM_CONTEXT0_PAGE_TABLE_BASE_ADDR                0x54F
+#define        VM_CONTEXT1_PAGE_TABLE_BASE_ADDR                0x550
+#define        VM_CONTEXT2_PAGE_TABLE_BASE_ADDR                0x551
+#define        VM_CONTEXT3_PAGE_TABLE_BASE_ADDR                0x552
+#define        VM_CONTEXT4_PAGE_TABLE_BASE_ADDR                0x553
+#define        VM_CONTEXT5_PAGE_TABLE_BASE_ADDR                0x554
+#define        VM_CONTEXT6_PAGE_TABLE_BASE_ADDR                0x555
+#define        VM_CONTEXT7_PAGE_TABLE_BASE_ADDR                0x556
+#define        VM_CONTEXT0_PAGE_TABLE_START_ADDR               0x557
+#define        VM_CONTEXT1_PAGE_TABLE_START_ADDR               0x558
+
+#define        VM_CONTEXT0_PAGE_TABLE_END_ADDR                 0x55F
+#define        VM_CONTEXT1_PAGE_TABLE_END_ADDR                 0x560
+
+#define VM_L2_CG                                       0x570
+#define                MC_CG_ENABLE                            (1 << 18)
+#define                MC_LS_ENABLE                            (1 << 19)
+
+#define MC_SHARED_CHMAP                                                0x801
+#define                NOOFCHAN_SHIFT                                  12
+#define                NOOFCHAN_MASK                                   0x0000f000
+#define MC_SHARED_CHREMAP                                      0x802
+
+#define        MC_VM_FB_LOCATION                               0x809
+#define        MC_VM_AGP_TOP                                   0x80A
+#define        MC_VM_AGP_BOT                                   0x80B
+#define        MC_VM_AGP_BASE                                  0x80C
+#define        MC_VM_SYSTEM_APERTURE_LOW_ADDR                  0x80D
+#define        MC_VM_SYSTEM_APERTURE_HIGH_ADDR                 0x80E
+#define        MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR              0x80F
+
+#define        MC_VM_MX_L1_TLB_CNTL                            0x819
+#define                ENABLE_L1_TLB                                   (1 << 0)
+#define                ENABLE_L1_FRAGMENT_PROCESSING                   (1 << 1)
+#define                SYSTEM_ACCESS_MODE_PA_ONLY                      (0 << 3)
+#define                SYSTEM_ACCESS_MODE_USE_SYS_MAP                  (1 << 3)
+#define                SYSTEM_ACCESS_MODE_IN_SYS                       (2 << 3)
+#define                SYSTEM_ACCESS_MODE_NOT_IN_SYS                   (3 << 3)
+#define                SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU       (0 << 5)
+#define                ENABLE_ADVANCED_DRIVER_MODEL                    (1 << 6)
+
+#define MC_SHARED_BLACKOUT_CNTL                        0x82B
+
+#define MC_HUB_MISC_HUB_CG                             0x82E
+#define MC_HUB_MISC_VM_CG                              0x82F
+
+#define MC_HUB_MISC_SIP_CG                             0x830
+
+#define MC_XPB_CLK_GAT                                 0x91E
+
+#define MC_CITF_MISC_RD_CG                             0x992
+#define MC_CITF_MISC_WR_CG                             0x993
+#define MC_CITF_MISC_VM_CG                             0x994
+
+#define        MC_ARB_RAMCFG                                   0x9D8
+#define                NOOFBANK_SHIFT                                  0
+#define                NOOFBANK_MASK                                   0x00000003
+#define                NOOFRANK_SHIFT                                  2
+#define                NOOFRANK_MASK                                   0x00000004
+#define                NOOFROWS_SHIFT                                  3
+#define                NOOFROWS_MASK                                   0x00000038
+#define                NOOFCOLS_SHIFT                                  6
+#define                NOOFCOLS_MASK                                   0x000000C0
+#define                CHANSIZE_SHIFT                                  8
+#define                CHANSIZE_MASK                                   0x00000100
+#define                CHANSIZE_OVERRIDE                               (1 << 11)
+#define                NOOFGROUPS_SHIFT                                12
+#define                NOOFGROUPS_MASK                                 0x00001000
+
+#define        MC_ARB_DRAM_TIMING                              0x9DD
+#define        MC_ARB_DRAM_TIMING2                             0x9DE
+
+#define MC_ARB_BURST_TIME                               0xA02
+#define                STATE0(x)                               ((x) << 0)
+#define                STATE0_MASK                             (0x1f << 0)
+#define                STATE0_SHIFT                            0
+#define                STATE1(x)                               ((x) << 5)
+#define                STATE1_MASK                             (0x1f << 5)
+#define                STATE1_SHIFT                            5
+#define                STATE2(x)                               ((x) << 10)
+#define                STATE2_MASK                             (0x1f << 10)
+#define                STATE2_SHIFT                            10
+#define                STATE3(x)                               ((x) << 15)
+#define                STATE3_MASK                             (0x1f << 15)
+#define                STATE3_SHIFT                            15
+
+#define        MC_SEQ_TRAIN_WAKEUP_CNTL                        0xA3A
+#define                TRAIN_DONE_D0                           (1 << 30)
+#define                TRAIN_DONE_D1                           (1 << 31)
+
+#define MC_SEQ_SUP_CNTL                                0xA32
+#define                RUN_MASK                                (1 << 0)
+#define MC_SEQ_SUP_PGM                                 0xA33
+#define MC_PMG_AUTO_CMD                                0xA34
+
+#define MC_IO_PAD_CNTL_D0                              0xA74
+#define                MEM_FALL_OUT_CMD                        (1 << 8)
+
+#define MC_SEQ_RAS_TIMING                               0xA28
+#define MC_SEQ_CAS_TIMING                               0xA29
+#define MC_SEQ_MISC_TIMING                              0xA2A
+#define MC_SEQ_MISC_TIMING2                             0xA2B
+#define MC_SEQ_PMG_TIMING                               0xA2C
+#define MC_SEQ_RD_CTL_D0                                0xA2D
+#define MC_SEQ_RD_CTL_D1                                0xA2E
+#define MC_SEQ_WR_CTL_D0                                0xA2F
+#define MC_SEQ_WR_CTL_D1                                0xA30
+
+#define MC_SEQ_MISC0                                           0xA80
+#define        MC_SEQ_MISC0_VEN_ID_SHIFT               8
+#define        MC_SEQ_MISC0_VEN_ID_MASK                0x00000f00
+#define        MC_SEQ_MISC0_VEN_ID_VALUE               3
+#define        MC_SEQ_MISC0_REV_ID_SHIFT               12
+#define        MC_SEQ_MISC0_REV_ID_MASK                0x0000f000
+#define        MC_SEQ_MISC0_REV_ID_VALUE               1
+#define        MC_SEQ_MISC0_GDDR5_SHIFT                28
+#define        MC_SEQ_MISC0_GDDR5_MASK                 0xf0000000
+#define        MC_SEQ_MISC0_GDDR5_VALUE                5
+#define MC_SEQ_MISC1                                    0xA81
+#define MC_SEQ_RESERVE_M                                0xA82
+#define MC_PMG_CMD_EMRS                                 0xA83
+
+#define MC_SEQ_IO_DEBUG_INDEX                          0xA91
+#define MC_SEQ_IO_DEBUG_DATA                                   0xA92
+
+#define MC_SEQ_MISC5                                    0xA95
+#define MC_SEQ_MISC6                                    0xA96
+
+#define MC_SEQ_MISC7                                    0xA99
+
+#define MC_SEQ_RAS_TIMING_LP                            0xA9B
+#define MC_SEQ_CAS_TIMING_LP                            0xA9C
+#define MC_SEQ_MISC_TIMING_LP                           0xA9D
+#define MC_SEQ_MISC_TIMING2_LP                          0xA9E
+#define MC_SEQ_WR_CTL_D0_LP                             0xA9F
+#define MC_SEQ_WR_CTL_D1_LP                             0xAA0
+#define MC_SEQ_PMG_CMD_EMRS_LP                          0xAA1
+#define MC_SEQ_PMG_CMD_MRS_LP                           0xAA2
+
+#define MC_PMG_CMD_MRS                                  0xAAB
+
+#define MC_SEQ_RD_CTL_D0_LP                             0xAC7
+#define MC_SEQ_RD_CTL_D1_LP                             0xAC8
+
+#define MC_PMG_CMD_MRS1                                 0xAD1
+#define MC_SEQ_PMG_CMD_MRS1_LP                          0xAD2
+#define MC_SEQ_PMG_TIMING_LP                            0xAD3
+
+#define MC_SEQ_WR_CTL_2                                 0xAD5
+#define MC_SEQ_WR_CTL_2_LP                              0xAD6
+#define MC_PMG_CMD_MRS2                                 0xAD7
+#define MC_SEQ_PMG_CMD_MRS2_LP                          0xAD8
+
+#define        MCLK_PWRMGT_CNTL                                0xAE8
+#       define DLL_SPEED(x)                            ((x) << 0)
+#       define DLL_SPEED_MASK                          (0x1f << 0)
+#       define DLL_READY                                (1 << 6)
+#       define MC_INT_CNTL                              (1 << 7)
+#       define MRDCK0_PDNB                              (1 << 8)
+#       define MRDCK1_PDNB                              (1 << 9)
+#       define MRDCK0_RESET                             (1 << 16)
+#       define MRDCK1_RESET                             (1 << 17)
+#       define DLL_READY_READ                           (1 << 24)
+#define        DLL_CNTL                                        0xAE9
+#       define MRDCK0_BYPASS                            (1 << 24)
+#       define MRDCK1_BYPASS                            (1 << 25)
+
+#define        MPLL_CNTL_MODE                                  0xAEC
+#       define MPLL_MCLK_SEL                            (1 << 11)
+#define        MPLL_FUNC_CNTL                                  0xAED
+#define                BWCTRL(x)                               ((x) << 20)
+#define                BWCTRL_MASK                             (0xff << 20)
+#define        MPLL_FUNC_CNTL_1                                0xAEE
+#define                VCO_MODE(x)                             ((x) << 0)
+#define                VCO_MODE_MASK                           (3 << 0)
+#define                CLKFRAC(x)                              ((x) << 4)
+#define                CLKFRAC_MASK                            (0xfff << 4)
+#define                CLKF(x)                                 ((x) << 16)
+#define                CLKF_MASK                               (0xfff << 16)
+#define        MPLL_FUNC_CNTL_2                                0xAEF
+#define        MPLL_AD_FUNC_CNTL                               0xAF0
+#define                YCLK_POST_DIV(x)                        ((x) << 0)
+#define                YCLK_POST_DIV_MASK                      (7 << 0)
+#define        MPLL_DQ_FUNC_CNTL                               0xAF1
+#define                YCLK_SEL(x)                             ((x) << 4)
+#define                YCLK_SEL_MASK                           (1 << 4)
+
+#define        MPLL_SS1                                        0xAF3
+#define                CLKV(x)                                 ((x) << 0)
+#define                CLKV_MASK                               (0x3ffffff << 0)
+#define        MPLL_SS2                                        0xAF4
+#define                CLKS(x)                                 ((x) << 0)
+#define                CLKS_MASK                               (0xfff << 0)
+
+#define        HDP_HOST_PATH_CNTL                              0xB00
+#define        CLOCK_GATING_DIS                        (1 << 23)
+#define        HDP_NONSURFACE_BASE                             0xB01
+#define        HDP_NONSURFACE_INFO                             0xB02
+#define        HDP_NONSURFACE_SIZE                             0xB03
+
+#define HDP_DEBUG0                                     0xBCC
+
+#define HDP_ADDR_CONFIG                                0xBD2
+#define HDP_MISC_CNTL                                  0xBD3
+#define        HDP_FLUSH_INVALIDATE_CACHE                      (1 << 0)
+#define HDP_MEM_POWER_LS                               0xBD4
+#define        HDP_LS_ENABLE                           (1 << 0)
+
+#define ATC_MISC_CG                                    0xCD4
+
+#define IH_RB_CNTL                                        0xF80
+#       define IH_RB_ENABLE                               (1 << 0)
+#       define IH_IB_SIZE(x)                              ((x) << 1) /* log2 */
+#       define IH_RB_FULL_DRAIN_ENABLE                    (1 << 6)
+#       define IH_WPTR_WRITEBACK_ENABLE                   (1 << 8)
+#       define IH_WPTR_WRITEBACK_TIMER(x)                 ((x) << 9) /* log2 */
+#       define IH_WPTR_OVERFLOW_ENABLE                    (1 << 16)
+#       define IH_WPTR_OVERFLOW_CLEAR                     (1 << 31)
+#define IH_RB_BASE                                        0xF81
+#define IH_RB_RPTR                                        0xF82
+#define IH_RB_WPTR                                        0xF83
+#       define RB_OVERFLOW                                (1 << 0)
+#       define WPTR_OFFSET_MASK                           0x3fffc
+#define IH_RB_WPTR_ADDR_HI                                0xF84
+#define IH_RB_WPTR_ADDR_LO                                0xF85
+#define IH_CNTL                                           0xF86
+#       define ENABLE_INTR                                (1 << 0)
+#       define IH_MC_SWAP(x)                              ((x) << 1)
+#       define IH_MC_SWAP_NONE                            0
+#       define IH_MC_SWAP_16BIT                           1
+#       define IH_MC_SWAP_32BIT                           2
+#       define IH_MC_SWAP_64BIT                           3
+#       define RPTR_REARM                                 (1 << 4)
+#       define MC_WRREQ_CREDIT(x)                         ((x) << 15)
+#       define MC_WR_CLEAN_CNT(x)                         ((x) << 20)
+#       define MC_VMID(x)                                 ((x) << 25)
+
+#define        CONFIG_MEMSIZE                                  0x150A
+
+#define INTERRUPT_CNTL                                    0x151A
+#       define IH_DUMMY_RD_OVERRIDE                       (1 << 0)
+#       define IH_DUMMY_RD_EN                             (1 << 1)
+#       define IH_REQ_NONSNOOP_EN                         (1 << 3)
+#       define GEN_IH_INT_EN                              (1 << 8)
+#define INTERRUPT_CNTL2                                   0x151B
+
+#define HDP_MEM_COHERENCY_FLUSH_CNTL                   0x1520
+
+#define        BIF_FB_EN                                               0x1524
+#define                FB_READ_EN                                      (1 << 0)
+#define                FB_WRITE_EN                                     (1 << 1)
+
+#define HDP_REG_COHERENCY_FLUSH_CNTL                   0x1528
+
+/* DCE6 ELD audio interface */
+#define AZ_F0_CODEC_ENDPOINT_INDEX                       0x1780
+#       define AZ_ENDPOINT_REG_INDEX(x)                  (((x) & 0xff) << 0)
+#       define AZ_ENDPOINT_REG_WRITE_EN                  (1 << 8)
+#define AZ_F0_CODEC_ENDPOINT_DATA                        0x1781
+
+#define AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER          0x25
+#define                SPEAKER_ALLOCATION(x)                   (((x) & 0x7f) << 0)
+#define                SPEAKER_ALLOCATION_MASK                 (0x7f << 0)
+#define                SPEAKER_ALLOCATION_SHIFT                0
+#define                HDMI_CONNECTION                         (1 << 16)
+#define                DP_CONNECTION                           (1 << 17)
+
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0        0x28 /* LPCM */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1        0x29 /* AC3 */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2        0x2A /* MPEG1 */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3        0x2B /* MP3 */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4        0x2C /* MPEG2 */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5        0x2D /* AAC */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6        0x2E /* DTS */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7        0x2F /* ATRAC */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR8        0x30 /* one bit audio - leave at 0 (default) */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9        0x31 /* Dolby Digital */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10       0x32 /* DTS-HD */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11       0x33 /* MAT-MLP */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR12       0x34 /* DTS */
+#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13       0x35 /* WMA Pro */
+#       define MAX_CHANNELS(x)                            (((x) & 0x7) << 0)
+/* max channels minus one.  7 = 8 channels */
+#       define SUPPORTED_FREQUENCIES(x)                   (((x) & 0xff) << 8)
+#       define DESCRIPTOR_BYTE_2(x)                       (((x) & 0xff) << 16)
+#       define SUPPORTED_FREQUENCIES_STEREO(x)            (((x) & 0xff) << 24) /* LPCM only */
+/* SUPPORTED_FREQUENCIES, SUPPORTED_FREQUENCIES_STEREO
+ * bit0 = 32 kHz
+ * bit1 = 44.1 kHz
+ * bit2 = 48 kHz
+ * bit3 = 88.2 kHz
+ * bit4 = 96 kHz
+ * bit5 = 176.4 kHz
+ * bit6 = 192 kHz
+ */
+
+#define AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC         0x37
+#       define VIDEO_LIPSYNC(x)                           (((x) & 0xff) << 0)
+#       define AUDIO_LIPSYNC(x)                           (((x) & 0xff) << 8)
+/* VIDEO_LIPSYNC, AUDIO_LIPSYNC
+ * 0   = invalid
+ * x   = legal delay value
+ * 255 = sync not supported
+ */
+#define AZ_F0_CODEC_PIN_CONTROL_RESPONSE_HBR             0x38
+#       define HBR_CAPABLE                                (1 << 0) /* enabled by default */
+
+#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO0               0x3a
+#       define MANUFACTURER_ID(x)                        (((x) & 0xffff) << 0)
+#       define PRODUCT_ID(x)                             (((x) & 0xffff) << 16)
+#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO1               0x3b
+#       define SINK_DESCRIPTION_LEN(x)                   (((x) & 0xff) << 0)
+#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO2               0x3c
+#       define PORT_ID0(x)                               (((x) & 0xffffffff) << 0)
+#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO3               0x3d
+#       define PORT_ID1(x)                               (((x) & 0xffffffff) << 0)
+#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO4               0x3e
+#       define DESCRIPTION0(x)                           (((x) & 0xff) << 0)
+#       define DESCRIPTION1(x)                           (((x) & 0xff) << 8)
+#       define DESCRIPTION2(x)                           (((x) & 0xff) << 16)
+#       define DESCRIPTION3(x)                           (((x) & 0xff) << 24)
+#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO5               0x3f
+#       define DESCRIPTION4(x)                           (((x) & 0xff) << 0)
+#       define DESCRIPTION5(x)                           (((x) & 0xff) << 8)
+#       define DESCRIPTION6(x)                           (((x) & 0xff) << 16)
+#       define DESCRIPTION7(x)                           (((x) & 0xff) << 24)
+#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO6               0x40
+#       define DESCRIPTION8(x)                           (((x) & 0xff) << 0)
+#       define DESCRIPTION9(x)                           (((x) & 0xff) << 8)
+#       define DESCRIPTION10(x)                          (((x) & 0xff) << 16)
+#       define DESCRIPTION11(x)                          (((x) & 0xff) << 24)
+#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO7               0x41
+#       define DESCRIPTION12(x)                          (((x) & 0xff) << 0)
+#       define DESCRIPTION13(x)                          (((x) & 0xff) << 8)
+#       define DESCRIPTION14(x)                          (((x) & 0xff) << 16)
+#       define DESCRIPTION15(x)                          (((x) & 0xff) << 24)
+#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO8               0x42
+#       define DESCRIPTION16(x)                          (((x) & 0xff) << 0)
+#       define DESCRIPTION17(x)                          (((x) & 0xff) << 8)
+
+#define AZ_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL         0x54
+#       define AUDIO_ENABLED                             (1 << 31)
+
+#define AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT  0x56
+#define                PORT_CONNECTIVITY_MASK                          (3 << 30)
+#define                PORT_CONNECTIVITY_SHIFT                         30
+
+#define        DC_LB_MEMORY_SPLIT                                      0x1AC3
+#define                DC_LB_MEMORY_CONFIG(x)                          ((x) << 20)
+
+#define        PRIORITY_A_CNT                                          0x1AC6
+#define                PRIORITY_MARK_MASK                              0x7fff
+#define                PRIORITY_OFF                                    (1 << 16)
+#define                PRIORITY_ALWAYS_ON                              (1 << 20)
+#define        PRIORITY_B_CNT                                          0x1AC7
+
+#define        DPG_PIPE_ARBITRATION_CONTROL3                           0x1B32
+#       define LATENCY_WATERMARK_MASK(x)                       ((x) << 16)
+#define        DPG_PIPE_LATENCY_CONTROL                                0x1B33
+#       define LATENCY_LOW_WATERMARK(x)                                ((x) << 0)
+#       define LATENCY_HIGH_WATERMARK(x)                       ((x) << 16)
+
+/* 0x6bb8, 0x77b8, 0x103b8, 0x10fb8, 0x11bb8, 0x127b8 */
+#define VLINE_STATUS                                    0x1AEE
+#       define VLINE_OCCURRED                           (1 << 0)
+#       define VLINE_ACK                                (1 << 4)
+#       define VLINE_STAT                               (1 << 12)
+#       define VLINE_INTERRUPT                          (1 << 16)
+#       define VLINE_INTERRUPT_TYPE                     (1 << 17)
+/* 0x6bbc, 0x77bc, 0x103bc, 0x10fbc, 0x11bbc, 0x127bc */
+#define VBLANK_STATUS                                   0x1AEF
+#       define VBLANK_OCCURRED                          (1 << 0)
+#       define VBLANK_ACK                               (1 << 4)
+#       define VBLANK_STAT                              (1 << 12)
+#       define VBLANK_INTERRUPT                         (1 << 16)
+#       define VBLANK_INTERRUPT_TYPE                    (1 << 17)
+
+/* 0x6b40, 0x7740, 0x10340, 0x10f40, 0x11b40, 0x12740 */
+#define INT_MASK                                        0x1AD0
+#       define VBLANK_INT_MASK                          (1 << 0)
+#       define VLINE_INT_MASK                           (1 << 4)
+
+#define DISP_INTERRUPT_STATUS                           0x183D
+#       define LB_D1_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D1_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD1_INTERRUPT                        (1 << 17)
+#       define DC_HPD1_RX_INTERRUPT                     (1 << 18)
+#       define DACA_AUTODETECT_INTERRUPT                (1 << 22)
+#       define DACB_AUTODETECT_INTERRUPT                (1 << 23)
+#       define DC_I2C_SW_DONE_INTERRUPT                 (1 << 24)
+#       define DC_I2C_HW_DONE_INTERRUPT                 (1 << 25)
+#define DISP_INTERRUPT_STATUS_CONTINUE                  0x183E
+#       define LB_D2_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D2_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD2_INTERRUPT                        (1 << 17)
+#       define DC_HPD2_RX_INTERRUPT                     (1 << 18)
+#       define DISP_TIMER_INTERRUPT                     (1 << 24)
+#define DISP_INTERRUPT_STATUS_CONTINUE2                 0x183F
+#       define LB_D3_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D3_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD3_INTERRUPT                        (1 << 17)
+#       define DC_HPD3_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE3                 0x1840
+#       define LB_D4_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D4_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD4_INTERRUPT                        (1 << 17)
+#       define DC_HPD4_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE4                 0x1853
+#       define LB_D5_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D5_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD5_INTERRUPT                        (1 << 17)
+#       define DC_HPD5_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE5                 0x1854
+#       define LB_D6_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D6_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD6_INTERRUPT                        (1 << 17)
+#       define DC_HPD6_RX_INTERRUPT                     (1 << 18)
+
+/* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */
+#define GRPH_INT_STATUS                                 0x1A16
+#       define GRPH_PFLIP_INT_OCCURRED                  (1 << 0)
+#       define GRPH_PFLIP_INT_CLEAR                     (1 << 8)
+/* 0x685c, 0x745c, 0x1005c, 0x10c5c, 0x1185c, 0x1245c */
+#define        GRPH_INT_CONTROL                                0x1A17
+#       define GRPH_PFLIP_INT_MASK                      (1 << 0)
+#       define GRPH_PFLIP_INT_TYPE                      (1 << 8)
+
+#define        DAC_AUTODETECT_INT_CONTROL                      0x19F2
+
+#define DC_HPD1_INT_STATUS                              0x1807
+#define DC_HPD2_INT_STATUS                              0x180A
+#define DC_HPD3_INT_STATUS                              0x180D
+#define DC_HPD4_INT_STATUS                              0x1810
+#define DC_HPD5_INT_STATUS                              0x1813
+#define DC_HPD6_INT_STATUS                              0x1816
+#       define DC_HPDx_INT_STATUS                       (1 << 0)
+#       define DC_HPDx_SENSE                            (1 << 1)
+#       define DC_HPDx_RX_INT_STATUS                    (1 << 8)
+
+#define DC_HPD1_INT_CONTROL                             0x1808
+#define DC_HPD2_INT_CONTROL                             0x180B
+#define DC_HPD3_INT_CONTROL                             0x180E
+#define DC_HPD4_INT_CONTROL                             0x1811
+#define DC_HPD5_INT_CONTROL                             0x1814
+#define DC_HPD6_INT_CONTROL                             0x1817
+#       define DC_HPDx_INT_ACK                          (1 << 0)
+#       define DC_HPDx_INT_POLARITY                     (1 << 8)
+#       define DC_HPDx_INT_EN                           (1 << 16)
+#       define DC_HPDx_RX_INT_ACK                       (1 << 20)
+#       define DC_HPDx_RX_INT_EN                        (1 << 24)
+
+#define DC_HPD1_CONTROL                                   0x1809
+#define DC_HPD2_CONTROL                                   0x180C
+#define DC_HPD3_CONTROL                                   0x180F
+#define DC_HPD4_CONTROL                                   0x1812
+#define DC_HPD5_CONTROL                                   0x1815
+#define DC_HPD6_CONTROL                                   0x1818
+#       define DC_HPDx_CONNECTION_TIMER(x)                ((x) << 0)
+#       define DC_HPDx_RX_INT_TIMER(x)                    ((x) << 16)
+#       define DC_HPDx_EN                                 (1 << 28)
+
+#define DPG_PIPE_STUTTER_CONTROL                          0x1B35
+#       define STUTTER_ENABLE                             (1 << 0)
+
+/* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */
+#define CRTC_STATUS_FRAME_COUNT                         0x1BA6
+
+/* Audio clocks */
+#define DCCG_AUDIO_DTO_SOURCE                           0x05ac
+#       define DCCG_AUDIO_DTO0_SOURCE_SEL(x) ((x) << 0) /* crtc0 - crtc5 */
+#       define DCCG_AUDIO_DTO_SEL            (1 << 4)   /* 0=dto0 1=dto1 */
+
+#define DCCG_AUDIO_DTO0_PHASE                           0x05b0
+#define DCCG_AUDIO_DTO0_MODULE                          0x05b4
+#define DCCG_AUDIO_DTO1_PHASE                           0x05c0
+#define DCCG_AUDIO_DTO1_MODULE                          0x05c4
+
+#define AFMT_AUDIO_SRC_CONTROL                          0x1c4f
+#define                AFMT_AUDIO_SRC_SELECT(x)                (((x) & 7) << 0)
+/* AFMT_AUDIO_SRC_SELECT
+ * 0 = stream0
+ * 1 = stream1
+ * 2 = stream2
+ * 3 = stream3
+ * 4 = stream4
+ * 5 = stream5
+ */
+
+#define        GRBM_CNTL                                       0x2000
+#define                GRBM_READ_TIMEOUT(x)                            ((x) << 0)
+
+#define        GRBM_STATUS2                                    0x2002
+#define                RLC_RQ_PENDING                                  (1 << 0)
+#define                RLC_BUSY                                        (1 << 8)
+#define                TC_BUSY                                         (1 << 9)
+
+#define        GRBM_STATUS                                     0x2004
+#define                CMDFIFO_AVAIL_MASK                              0x0000000F
+#define                RING2_RQ_PENDING                                (1 << 4)
+#define                SRBM_RQ_PENDING                                 (1 << 5)
+#define                RING1_RQ_PENDING                                (1 << 6)
+#define                CF_RQ_PENDING                                   (1 << 7)
+#define                PF_RQ_PENDING                                   (1 << 8)
+#define                GDS_DMA_RQ_PENDING                              (1 << 9)
+#define                GRBM_EE_BUSY                                    (1 << 10)
+#define                DB_CLEAN                                        (1 << 12)
+#define                CB_CLEAN                                        (1 << 13)
+#define                TA_BUSY                                         (1 << 14)
+#define                GDS_BUSY                                        (1 << 15)
+#define                VGT_BUSY                                        (1 << 17)
+#define                IA_BUSY_NO_DMA                                  (1 << 18)
+#define                IA_BUSY                                         (1 << 19)
+#define                SX_BUSY                                         (1 << 20)
+#define                SPI_BUSY                                        (1 << 22)
+#define                BCI_BUSY                                        (1 << 23)
+#define                SC_BUSY                                         (1 << 24)
+#define                PA_BUSY                                         (1 << 25)
+#define                DB_BUSY                                         (1 << 26)
+#define                CP_COHERENCY_BUSY                               (1 << 28)
+#define                CP_BUSY                                         (1 << 29)
+#define                CB_BUSY                                         (1 << 30)
+#define                GUI_ACTIVE                                      (1 << 31)
+#define        GRBM_STATUS_SE0                                 0x2005
+#define        GRBM_STATUS_SE1                                 0x2006
+#define                SE_DB_CLEAN                                     (1 << 1)
+#define                SE_CB_CLEAN                                     (1 << 2)
+#define                SE_BCI_BUSY                                     (1 << 22)
+#define                SE_VGT_BUSY                                     (1 << 23)
+#define                SE_PA_BUSY                                      (1 << 24)
+#define                SE_TA_BUSY                                      (1 << 25)
+#define                SE_SX_BUSY                                      (1 << 26)
+#define                SE_SPI_BUSY                                     (1 << 27)
+#define                SE_SC_BUSY                                      (1 << 29)
+#define                SE_DB_BUSY                                      (1 << 30)
+#define                SE_CB_BUSY                                      (1 << 31)
+
+#define        GRBM_SOFT_RESET                                 0x2008
+#define                SOFT_RESET_CP                                   (1 << 0)
+#define                SOFT_RESET_CB                                   (1 << 1)
+#define                SOFT_RESET_RLC                                  (1 << 2)
+#define                SOFT_RESET_DB                                   (1 << 3)
+#define                SOFT_RESET_GDS                                  (1 << 4)
+#define                SOFT_RESET_PA                                   (1 << 5)
+#define                SOFT_RESET_SC                                   (1 << 6)
+#define                SOFT_RESET_BCI                                  (1 << 7)
+#define                SOFT_RESET_SPI                                  (1 << 8)
+#define                SOFT_RESET_SX                                   (1 << 10)
+#define                SOFT_RESET_TC                                   (1 << 11)
+#define                SOFT_RESET_TA                                   (1 << 12)
+#define                SOFT_RESET_VGT                                  (1 << 14)
+#define                SOFT_RESET_IA                                   (1 << 15)
+
+#define GRBM_GFX_INDEX                                 0x200B
+#define                INSTANCE_INDEX(x)                       ((x) << 0)
+#define                SH_INDEX(x)                             ((x) << 8)
+#define                SE_INDEX(x)                             ((x) << 16)
+#define                SH_BROADCAST_WRITES                     (1 << 29)
+#define                INSTANCE_BROADCAST_WRITES               (1 << 30)
+#define                SE_BROADCAST_WRITES                     (1 << 31)
+
+#define GRBM_INT_CNTL                                   0x2018
+#       define RDERR_INT_ENABLE                         (1 << 0)
+#       define GUI_IDLE_INT_ENABLE                      (1 << 19)
+
+#define        CP_STRMOUT_CNTL                                 0x213F
+#define        SCRATCH_REG0                                    0x2140
+#define        SCRATCH_REG1                                    0x2141
+#define        SCRATCH_REG2                                    0x2142
+#define        SCRATCH_REG3                                    0x2143
+#define        SCRATCH_REG4                                    0x2144
+#define        SCRATCH_REG5                                    0x2145
+#define        SCRATCH_REG6                                    0x2146
+#define        SCRATCH_REG7                                    0x2147
+
+#define        SCRATCH_UMSK                                    0x2150
+#define        SCRATCH_ADDR                                    0x2151
+
+#define        CP_SEM_WAIT_TIMER                               0x216F
+
+#define        CP_SEM_INCOMPLETE_TIMER_CNTL                    0x2172
+
+#define CP_ME_CNTL                                     0x21B6
+#define                CP_CE_HALT                                      (1 << 24)
+#define                CP_PFP_HALT                                     (1 << 26)
+#define                CP_ME_HALT                                      (1 << 28)
+
+#define        CP_COHER_CNTL2                                  0x217A
+
+#define        CP_RB2_RPTR                                     0x21BE
+#define        CP_RB1_RPTR                                     0x21BF
+#define        CP_RB0_RPTR                                     0x21C0
+#define        CP_RB_WPTR_DELAY                                0x21C1
+
+#define        CP_QUEUE_THRESHOLDS                             0x21D8
+#define                ROQ_IB1_START(x)                                ((x) << 0)
+#define                ROQ_IB2_START(x)                                ((x) << 8)
+#define CP_MEQ_THRESHOLDS                              0x21D9
+#define                MEQ1_START(x)                           ((x) << 0)
+#define                MEQ2_START(x)                           ((x) << 8)
+
+#define        CP_PERFMON_CNTL                                 0x21FF
+
+#define        VGT_VTX_VECT_EJECT_REG                          0x222C
+
+#define        VGT_CACHE_INVALIDATION                          0x2231
+#define                CACHE_INVALIDATION(x)                           ((x) << 0)
+#define                        VC_ONLY                                         0
+#define                        TC_ONLY                                         1
+#define                        VC_AND_TC                                       2
+#define                AUTO_INVLD_EN(x)                                ((x) << 6)
+#define                        NO_AUTO                                         0
+#define                        ES_AUTO                                         1
+#define                        GS_AUTO                                         2
+#define                        ES_AND_GS_AUTO                                  3
+#define        VGT_ESGS_RING_SIZE                              0x2232
+#define        VGT_GSVS_RING_SIZE                              0x2233
+
+#define        VGT_GS_VERTEX_REUSE                             0x2235
+
+#define        VGT_PRIMITIVE_TYPE                              0x2256
+#define        VGT_INDEX_TYPE                                  0x2257
+
+#define        VGT_NUM_INDICES                                 0x225C
+#define        VGT_NUM_INSTANCES                               0x225D
+
+#define        VGT_TF_RING_SIZE                                0x2262
+
+#define        VGT_HS_OFFCHIP_PARAM                            0x226C
+
+#define        VGT_TF_MEMORY_BASE                              0x226E
+
+#define CC_GC_SHADER_ARRAY_CONFIG                      0x226F
+#define                INACTIVE_CUS_MASK                       0xFFFF0000
+#define                INACTIVE_CUS_SHIFT                      16
+#define GC_USER_SHADER_ARRAY_CONFIG                    0x2270
+
+#define        PA_CL_ENHANCE                                   0x2285
+#define                CLIP_VTX_REORDER_ENA                            (1 << 0)
+#define                NUM_CLIP_SEQ(x)                                 ((x) << 1)
+
+#define        PA_SU_LINE_STIPPLE_VALUE                        0x2298
+
+#define        PA_SC_LINE_STIPPLE_STATE                        0x22C4
+
+#define        PA_SC_FORCE_EOV_MAX_CNTS                        0x22C9
+#define                FORCE_EOV_MAX_CLK_CNT(x)                        ((x) << 0)
+#define                FORCE_EOV_MAX_REZ_CNT(x)                        ((x) << 16)
+
+#define        PA_SC_FIFO_SIZE                                 0x22F3
+#define                SC_FRONTEND_PRIM_FIFO_SIZE(x)                   ((x) << 0)
+#define                SC_BACKEND_PRIM_FIFO_SIZE(x)                    ((x) << 6)
+#define                SC_HIZ_TILE_FIFO_SIZE(x)                        ((x) << 15)
+#define                SC_EARLYZ_TILE_FIFO_SIZE(x)                     ((x) << 23)
+
+#define        PA_SC_ENHANCE                                   0x22FC
+
+#define        SQ_CONFIG                                       0x2300
+
+#define        SQC_CACHES                                      0x2302
+
+#define SQ_POWER_THROTTLE                               0x2396
+#define                MIN_POWER(x)                            ((x) << 0)
+#define                MIN_POWER_MASK                          (0x3fff << 0)
+#define                MIN_POWER_SHIFT                         0
+#define                MAX_POWER(x)                            ((x) << 16)
+#define                MAX_POWER_MASK                          (0x3fff << 16)
+#define                MAX_POWER_SHIFT                         0
+#define SQ_POWER_THROTTLE2                              0x2397
+#define                MAX_POWER_DELTA(x)                      ((x) << 0)
+#define                MAX_POWER_DELTA_MASK                    (0x3fff << 0)
+#define                MAX_POWER_DELTA_SHIFT                   0
+#define                STI_SIZE(x)                             ((x) << 16)
+#define                STI_SIZE_MASK                           (0x3ff << 16)
+#define                STI_SIZE_SHIFT                          16
+#define                LTI_RATIO(x)                            ((x) << 27)
+#define                LTI_RATIO_MASK                          (0xf << 27)
+#define                LTI_RATIO_SHIFT                         27
+
+#define        SX_DEBUG_1                                      0x2418
+
+#define        SPI_STATIC_THREAD_MGMT_1                        0x2438
+#define        SPI_STATIC_THREAD_MGMT_2                        0x2439
+#define        SPI_STATIC_THREAD_MGMT_3                        0x243A
+#define        SPI_PS_MAX_WAVE_ID                              0x243B
+
+#define        SPI_CONFIG_CNTL                                 0x2440
+
+#define        SPI_CONFIG_CNTL_1                               0x244F
+#define                VTX_DONE_DELAY(x)                               ((x) << 0)
+#define                INTERP_ONE_PRIM_PER_ROW                         (1 << 4)
+
+#define        CGTS_TCC_DISABLE                                0x2452
+#define        CGTS_USER_TCC_DISABLE                           0x2453
+#define                TCC_DISABLE_MASK                                0xFFFF0000
+#define                TCC_DISABLE_SHIFT                               16
+#define        CGTS_SM_CTRL_REG                                0x2454
+#define                OVERRIDE                                (1 << 21)
+#define                LS_OVERRIDE                             (1 << 22)
+
+#define        SPI_LB_CU_MASK                                  0x24D5
+
+#define        TA_CNTL_AUX                                     0x2542
+
+#define CC_RB_BACKEND_DISABLE                          0x263D
+#define                BACKEND_DISABLE(x)                      ((x) << 16)
+#define GB_ADDR_CONFIG                                 0x263E
+#define                NUM_PIPES(x)                            ((x) << 0)
+#define                NUM_PIPES_MASK                          0x00000007
+#define                NUM_PIPES_SHIFT                         0
+#define                PIPE_INTERLEAVE_SIZE(x)                 ((x) << 4)
+#define                PIPE_INTERLEAVE_SIZE_MASK               0x00000070
+#define                PIPE_INTERLEAVE_SIZE_SHIFT              4
+#define                NUM_SHADER_ENGINES(x)                   ((x) << 12)
+#define                NUM_SHADER_ENGINES_MASK                 0x00003000
+#define                NUM_SHADER_ENGINES_SHIFT                12
+#define                SHADER_ENGINE_TILE_SIZE(x)              ((x) << 16)
+#define                SHADER_ENGINE_TILE_SIZE_MASK            0x00070000
+#define                SHADER_ENGINE_TILE_SIZE_SHIFT           16
+#define                NUM_GPUS(x)                             ((x) << 20)
+#define                NUM_GPUS_MASK                           0x00700000
+#define                NUM_GPUS_SHIFT                          20
+#define                MULTI_GPU_TILE_SIZE(x)                  ((x) << 24)
+#define                MULTI_GPU_TILE_SIZE_MASK                0x03000000
+#define                MULTI_GPU_TILE_SIZE_SHIFT               24
+#define                ROW_SIZE(x)                             ((x) << 28)
+#define                ROW_SIZE_MASK                           0x30000000
+#define                ROW_SIZE_SHIFT                          28
+
+#define        GB_TILE_MODE0                                   0x2644
+#       define MICRO_TILE_MODE(x)                              ((x) << 0)
+#              define  ADDR_SURF_DISPLAY_MICRO_TILING          0
+#              define  ADDR_SURF_THIN_MICRO_TILING             1
+#              define  ADDR_SURF_DEPTH_MICRO_TILING            2
+#       define ARRAY_MODE(x)                                   ((x) << 2)
+#              define  ARRAY_LINEAR_GENERAL                    0
+#              define  ARRAY_LINEAR_ALIGNED                    1
+#              define  ARRAY_1D_TILED_THIN1                    2
+#              define  ARRAY_2D_TILED_THIN1                    4
+#       define PIPE_CONFIG(x)                                  ((x) << 6)
+#              define  ADDR_SURF_P2                            0
+#              define  ADDR_SURF_P4_8x16                       4
+#              define  ADDR_SURF_P4_16x16                      5
+#              define  ADDR_SURF_P4_16x32                      6
+#              define  ADDR_SURF_P4_32x32                      7
+#              define  ADDR_SURF_P8_16x16_8x16                 8
+#              define  ADDR_SURF_P8_16x32_8x16                 9
+#              define  ADDR_SURF_P8_32x32_8x16                 10
+#              define  ADDR_SURF_P8_16x32_16x16                11
+#              define  ADDR_SURF_P8_32x32_16x16                12
+#              define  ADDR_SURF_P8_32x32_16x32                13
+#              define  ADDR_SURF_P8_32x64_32x32                14
+#       define TILE_SPLIT(x)                                   ((x) << 11)
+#              define  ADDR_SURF_TILE_SPLIT_64B                0
+#              define  ADDR_SURF_TILE_SPLIT_128B               1
+#              define  ADDR_SURF_TILE_SPLIT_256B               2
+#              define  ADDR_SURF_TILE_SPLIT_512B               3
+#              define  ADDR_SURF_TILE_SPLIT_1KB                4
+#              define  ADDR_SURF_TILE_SPLIT_2KB                5
+#              define  ADDR_SURF_TILE_SPLIT_4KB                6
+#       define BANK_WIDTH(x)                                   ((x) << 14)
+#              define  ADDR_SURF_BANK_WIDTH_1                  0
+#              define  ADDR_SURF_BANK_WIDTH_2                  1
+#              define  ADDR_SURF_BANK_WIDTH_4                  2
+#              define  ADDR_SURF_BANK_WIDTH_8                  3
+#       define BANK_HEIGHT(x)                                  ((x) << 16)
+#              define  ADDR_SURF_BANK_HEIGHT_1                 0
+#              define  ADDR_SURF_BANK_HEIGHT_2                 1
+#              define  ADDR_SURF_BANK_HEIGHT_4                 2
+#              define  ADDR_SURF_BANK_HEIGHT_8                 3
+#       define MACRO_TILE_ASPECT(x)                            ((x) << 18)
+#              define  ADDR_SURF_MACRO_ASPECT_1                0
+#              define  ADDR_SURF_MACRO_ASPECT_2                1
+#              define  ADDR_SURF_MACRO_ASPECT_4                2
+#              define  ADDR_SURF_MACRO_ASPECT_8                3
+#       define NUM_BANKS(x)                                    ((x) << 20)
+#              define  ADDR_SURF_2_BANK                        0
+#              define  ADDR_SURF_4_BANK                        1
+#              define  ADDR_SURF_8_BANK                        2
+#              define  ADDR_SURF_16_BANK                       3
+#define        GB_TILE_MODE1                                   0x2645
+#define        GB_TILE_MODE2                                   0x2646
+#define        GB_TILE_MODE3                                   0x2647
+#define        GB_TILE_MODE4                                   0x2648
+#define        GB_TILE_MODE5                                   0x2649
+#define        GB_TILE_MODE6                                   0x264a
+#define        GB_TILE_MODE7                                   0x264b
+#define        GB_TILE_MODE8                                   0x264c
+#define        GB_TILE_MODE9                                   0x264d
+#define        GB_TILE_MODE10                                  0x264e
+#define        GB_TILE_MODE11                                  0x264f
+#define        GB_TILE_MODE12                                  0x2650
+#define        GB_TILE_MODE13                                  0x2651
+#define        GB_TILE_MODE14                                  0x2652
+#define        GB_TILE_MODE15                                  0x2653
+#define        GB_TILE_MODE16                                  0x2654
+#define        GB_TILE_MODE17                                  0x2655
+#define        GB_TILE_MODE18                                  0x2656
+#define        GB_TILE_MODE19                                  0x2657
+#define        GB_TILE_MODE20                                  0x2658
+#define        GB_TILE_MODE21                                  0x2659
+#define        GB_TILE_MODE22                                  0x265a
+#define        GB_TILE_MODE23                                  0x265b
+#define        GB_TILE_MODE24                                  0x265c
+#define        GB_TILE_MODE25                                  0x265d
+#define        GB_TILE_MODE26                                  0x265e
+#define        GB_TILE_MODE27                                  0x265f
+#define        GB_TILE_MODE28                                  0x2660
+#define        GB_TILE_MODE29                                  0x2661
+#define        GB_TILE_MODE30                                  0x2662
+#define        GB_TILE_MODE31                                  0x2663
+
+#define        CB_PERFCOUNTER0_SELECT0                         0x2688
+#define        CB_PERFCOUNTER0_SELECT1                         0x2689
+#define        CB_PERFCOUNTER1_SELECT0                         0x268A
+#define        CB_PERFCOUNTER1_SELECT1                         0x268B
+#define        CB_PERFCOUNTER2_SELECT0                         0x268C
+#define        CB_PERFCOUNTER2_SELECT1                         0x268D
+#define        CB_PERFCOUNTER3_SELECT0                         0x268E
+#define        CB_PERFCOUNTER3_SELECT1                         0x268F
+
+#define        CB_CGTT_SCLK_CTRL                               0x2698
+
+#define        GC_USER_RB_BACKEND_DISABLE                      0x26DF
+#define                BACKEND_DISABLE_MASK                    0x00FF0000
+#define                BACKEND_DISABLE_SHIFT                   16
+
+#define        TCP_CHAN_STEER_LO                               0x2B03
+#define        TCP_CHAN_STEER_HI                               0x2B94
+
+#define        CP_RB0_BASE                                     0x3040
+#define        CP_RB0_CNTL                                     0x3041
+#define                RB_BUFSZ(x)                                     ((x) << 0)
+#define                RB_BLKSZ(x)                                     ((x) << 8)
+#define                BUF_SWAP_32BIT                                  (2 << 16)
+#define                RB_NO_UPDATE                                    (1 << 27)
+#define                RB_RPTR_WR_ENA                                  (1 << 31)
+
+#define        CP_RB0_RPTR_ADDR                                0x3043
+#define        CP_RB0_RPTR_ADDR_HI                             0x3044
+#define        CP_RB0_WPTR                                     0x3045
+
+#define        CP_PFP_UCODE_ADDR                               0x3054
+#define        CP_PFP_UCODE_DATA                               0x3055
+#define        CP_ME_RAM_RADDR                                 0x3056
+#define        CP_ME_RAM_WADDR                                 0x3057
+#define        CP_ME_RAM_DATA                                  0x3058
+
+#define        CP_CE_UCODE_ADDR                                0x305A
+#define        CP_CE_UCODE_DATA                                0x305B
+
+#define        CP_RB1_BASE                                     0x3060
+#define        CP_RB1_CNTL                                     0x3061
+#define        CP_RB1_RPTR_ADDR                                0x3062
+#define        CP_RB1_RPTR_ADDR_HI                             0x3063
+#define        CP_RB1_WPTR                                     0x3064
+#define        CP_RB2_BASE                                     0x3065
+#define        CP_RB2_CNTL                                     0x3066
+#define        CP_RB2_RPTR_ADDR                                0x3067
+#define        CP_RB2_RPTR_ADDR_HI                             0x3068
+#define        CP_RB2_WPTR                                     0x3069
+#define CP_INT_CNTL_RING0                               0x306A
+#define CP_INT_CNTL_RING1                               0x306B
+#define CP_INT_CNTL_RING2                               0x306C
+#       define CNTX_BUSY_INT_ENABLE                     (1 << 19)
+#       define CNTX_EMPTY_INT_ENABLE                    (1 << 20)
+#       define WAIT_MEM_SEM_INT_ENABLE                  (1 << 21)
+#       define TIME_STAMP_INT_ENABLE                    (1 << 26)
+#       define CP_RINGID2_INT_ENABLE                    (1 << 29)
+#       define CP_RINGID1_INT_ENABLE                    (1 << 30)
+#       define CP_RINGID0_INT_ENABLE                    (1 << 31)
+#define CP_INT_STATUS_RING0                             0x306D
+#define CP_INT_STATUS_RING1                             0x306E
+#define CP_INT_STATUS_RING2                             0x306F
+#       define WAIT_MEM_SEM_INT_STAT                    (1 << 21)
+#       define TIME_STAMP_INT_STAT                      (1 << 26)
+#       define CP_RINGID2_INT_STAT                      (1 << 29)
+#       define CP_RINGID1_INT_STAT                      (1 << 30)
+#       define CP_RINGID0_INT_STAT                      (1 << 31)
+
+#define        CP_MEM_SLP_CNTL                                 0x3079
+#       define CP_MEM_LS_EN                             (1 << 0)
+
+#define        CP_DEBUG                                        0x307F
+
+#define RLC_CNTL                                          0x30C0
+#       define RLC_ENABLE                                 (1 << 0)
+#define RLC_RL_BASE                                       0x30C1
+#define RLC_RL_SIZE                                       0x30C2
+#define RLC_LB_CNTL                                       0x30C3
+#       define LOAD_BALANCE_ENABLE                        (1 << 0)
+#define RLC_SAVE_AND_RESTORE_BASE                         0x30C4
+#define RLC_LB_CNTR_MAX                                   0x30C5
+#define RLC_LB_CNTR_INIT                                  0x30C6
+
+#define RLC_CLEAR_STATE_RESTORE_BASE                      0x30C8
+
+#define RLC_UCODE_ADDR                                    0x30CB
+#define RLC_UCODE_DATA                                    0x30CC
+
+#define RLC_GPU_CLOCK_COUNT_LSB                           0x30CE
+#define RLC_GPU_CLOCK_COUNT_MSB                           0x30CF
+#define RLC_CAPTURE_GPU_CLOCK_COUNT                       0x30D0
+#define RLC_MC_CNTL                                       0x30D1
+#define RLC_UCODE_CNTL                                    0x30D2
+#define RLC_STAT                                          0x30D3
+#       define RLC_BUSY_STATUS                            (1 << 0)
+#       define GFX_POWER_STATUS                           (1 << 1)
+#       define GFX_CLOCK_STATUS                           (1 << 2)
+#       define GFX_LS_STATUS                              (1 << 3)
+
+#define        RLC_PG_CNTL                                     0x30D7
+#      define GFX_PG_ENABLE                            (1 << 0)
+#      define GFX_PG_SRC                               (1 << 1)
+
+#define        RLC_CGTT_MGCG_OVERRIDE                          0x3100
+#define        RLC_CGCG_CGLS_CTRL                              0x3101
+#      define CGCG_EN                                  (1 << 0)
+#      define CGLS_EN                                  (1 << 1)
+
+#define        RLC_TTOP_D                                      0x3105
+#      define RLC_PUD(x)                               ((x) << 0)
+#      define RLC_PUD_MASK                             (0xff << 0)
+#      define RLC_PDD(x)                               ((x) << 8)
+#      define RLC_PDD_MASK                             (0xff << 8)
+#      define RLC_TTPD(x)                              ((x) << 16)
+#      define RLC_TTPD_MASK                            (0xff << 16)
+#      define RLC_MSD(x)                               ((x) << 24)
+#      define RLC_MSD_MASK                             (0xff << 24)
+
+#define RLC_LB_INIT_CU_MASK                               0x3107
+
+#define        RLC_PG_AO_CU_MASK                               0x310B
+#define        RLC_MAX_PG_CU                                   0x310C
+#      define MAX_PU_CU(x)                             ((x) << 0)
+#      define MAX_PU_CU_MASK                           (0xff << 0)
+#define        RLC_AUTO_PG_CTRL                                0x310C
+#      define AUTO_PG_EN                               (1 << 0)
+#      define GRBM_REG_SGIT(x)                         ((x) << 3)
+#      define GRBM_REG_SGIT_MASK                       (0xffff << 3)
+#      define PG_AFTER_GRBM_REG_ST(x)                  ((x) << 19)
+#      define PG_AFTER_GRBM_REG_ST_MASK                (0x1fff << 19)
+
+#define RLC_SERDES_WR_MASTER_MASK_0                       0x3115
+#define RLC_SERDES_WR_MASTER_MASK_1                       0x3116
+#define RLC_SERDES_WR_CTRL                                0x3117
+
+#define RLC_SERDES_MASTER_BUSY_0                          0x3119
+#define RLC_SERDES_MASTER_BUSY_1                          0x311A
+
+#define RLC_GCPM_GENERAL_3                                0x311E
+
+#define        DB_RENDER_CONTROL                               0xA000
+
+#define DB_DEPTH_INFO                                   0xA00F
+
+#define PA_SC_RASTER_CONFIG                             0xA0D4
+#      define RB_MAP_PKR0(x)                           ((x) << 0)
+#      define RB_MAP_PKR0_MASK                         (0x3 << 0)
+#      define RB_MAP_PKR1(x)                           ((x) << 2)
+#      define RB_MAP_PKR1_MASK                         (0x3 << 2)
+#       define RASTER_CONFIG_RB_MAP_0                   0
+#       define RASTER_CONFIG_RB_MAP_1                   1
+#       define RASTER_CONFIG_RB_MAP_2                   2
+#       define RASTER_CONFIG_RB_MAP_3                   3
+#      define RB_XSEL2(x)                              ((x) << 4)
+#      define RB_XSEL2_MASK                            (0x3 << 4)
+#      define RB_XSEL                                  (1 << 6)
+#      define RB_YSEL                                  (1 << 7)
+#      define PKR_MAP(x)                               ((x) << 8)
+#      define PKR_MAP_MASK                             (0x3 << 8)
+#       define RASTER_CONFIG_PKR_MAP_0                 0
+#       define RASTER_CONFIG_PKR_MAP_1                 1
+#       define RASTER_CONFIG_PKR_MAP_2                 2
+#       define RASTER_CONFIG_PKR_MAP_3                 3
+#      define PKR_XSEL(x)                              ((x) << 10)
+#      define PKR_XSEL_MASK                            (0x3 << 10)
+#      define PKR_YSEL(x)                              ((x) << 12)
+#      define PKR_YSEL_MASK                            (0x3 << 12)
+#      define SC_MAP(x)                                ((x) << 16)
+#      define SC_MAP_MASK                              (0x3 << 16)
+#      define SC_XSEL(x)                               ((x) << 18)
+#      define SC_XSEL_MASK                             (0x3 << 18)
+#      define SC_YSEL(x)                               ((x) << 20)
+#      define SC_YSEL_MASK                             (0x3 << 20)
+#      define SE_MAP(x)                                ((x) << 24)
+#      define SE_MAP_MASK                              (0x3 << 24)
+#       define RASTER_CONFIG_SE_MAP_0                  0
+#       define RASTER_CONFIG_SE_MAP_1                  1
+#       define RASTER_CONFIG_SE_MAP_2                  2
+#       define RASTER_CONFIG_SE_MAP_3                  3
+#      define SE_XSEL(x)                               ((x) << 26)
+#      define SE_XSEL_MASK                             (0x3 << 26)
+#      define SE_YSEL(x)                               ((x) << 28)
+#      define SE_YSEL_MASK                             (0x3 << 28)
+
+
+#define VGT_EVENT_INITIATOR                             0xA2A4
+#       define SAMPLE_STREAMOUTSTATS1                   (1 << 0)
+#       define SAMPLE_STREAMOUTSTATS2                   (2 << 0)
+#       define SAMPLE_STREAMOUTSTATS3                   (3 << 0)
+#       define CACHE_FLUSH_TS                           (4 << 0)
+#       define CACHE_FLUSH                              (6 << 0)
+#       define CS_PARTIAL_FLUSH                         (7 << 0)
+#       define VGT_STREAMOUT_RESET                      (10 << 0)
+#       define END_OF_PIPE_INCR_DE                      (11 << 0)
+#       define END_OF_PIPE_IB_END                       (12 << 0)
+#       define RST_PIX_CNT                              (13 << 0)
+#       define VS_PARTIAL_FLUSH                         (15 << 0)
+#       define PS_PARTIAL_FLUSH                         (16 << 0)
+#       define CACHE_FLUSH_AND_INV_TS_EVENT             (20 << 0)
+#       define ZPASS_DONE                               (21 << 0)
+#       define CACHE_FLUSH_AND_INV_EVENT                (22 << 0)
+#       define PERFCOUNTER_START                        (23 << 0)
+#       define PERFCOUNTER_STOP                         (24 << 0)
+#       define PIPELINESTAT_START                       (25 << 0)
+#       define PIPELINESTAT_STOP                        (26 << 0)
+#       define PERFCOUNTER_SAMPLE                       (27 << 0)
+#       define SAMPLE_PIPELINESTAT                      (30 << 0)
+#       define SAMPLE_STREAMOUTSTATS                    (32 << 0)
+#       define RESET_VTX_CNT                            (33 << 0)
+#       define VGT_FLUSH                                (36 << 0)
+#       define BOTTOM_OF_PIPE_TS                        (40 << 0)
+#       define DB_CACHE_FLUSH_AND_INV                   (42 << 0)
+#       define FLUSH_AND_INV_DB_DATA_TS                 (43 << 0)
+#       define FLUSH_AND_INV_DB_META                    (44 << 0)
+#       define FLUSH_AND_INV_CB_DATA_TS                 (45 << 0)
+#       define FLUSH_AND_INV_CB_META                    (46 << 0)
+#       define CS_DONE                                  (47 << 0)
+#       define PS_DONE                                  (48 << 0)
+#       define FLUSH_AND_INV_CB_PIXEL_DATA              (49 << 0)
+#       define THREAD_TRACE_START                       (51 << 0)
+#       define THREAD_TRACE_STOP                        (52 << 0)
+#       define THREAD_TRACE_FLUSH                       (54 << 0)
+#       define THREAD_TRACE_FINISH                      (55 << 0)
+
+/* PIF PHY0 registers idx/data 0x8/0xc */
+#define PB0_PIF_CNTL                                      0x10
+#       define LS2_EXIT_TIME(x)                           ((x) << 17)
+#       define LS2_EXIT_TIME_MASK                         (0x7 << 17)
+#       define LS2_EXIT_TIME_SHIFT                        17
+#define PB0_PIF_PAIRING                                   0x11
+#       define MULTI_PIF                                  (1 << 25)
+#define PB0_PIF_PWRDOWN_0                                 0x12
+#       define PLL_POWER_STATE_IN_TXS2_0(x)               ((x) << 7)
+#       define PLL_POWER_STATE_IN_TXS2_0_MASK             (0x7 << 7)
+#       define PLL_POWER_STATE_IN_TXS2_0_SHIFT            7
+#       define PLL_POWER_STATE_IN_OFF_0(x)                ((x) << 10)
+#       define PLL_POWER_STATE_IN_OFF_0_MASK              (0x7 << 10)
+#       define PLL_POWER_STATE_IN_OFF_0_SHIFT             10
+#       define PLL_RAMP_UP_TIME_0(x)                      ((x) << 24)
+#       define PLL_RAMP_UP_TIME_0_MASK                    (0x7 << 24)
+#       define PLL_RAMP_UP_TIME_0_SHIFT                   24
+#define PB0_PIF_PWRDOWN_1                                 0x13
+#       define PLL_POWER_STATE_IN_TXS2_1(x)               ((x) << 7)
+#       define PLL_POWER_STATE_IN_TXS2_1_MASK             (0x7 << 7)
+#       define PLL_POWER_STATE_IN_TXS2_1_SHIFT            7
+#       define PLL_POWER_STATE_IN_OFF_1(x)                ((x) << 10)
+#       define PLL_POWER_STATE_IN_OFF_1_MASK              (0x7 << 10)
+#       define PLL_POWER_STATE_IN_OFF_1_SHIFT             10
+#       define PLL_RAMP_UP_TIME_1(x)                      ((x) << 24)
+#       define PLL_RAMP_UP_TIME_1_MASK                    (0x7 << 24)
+#       define PLL_RAMP_UP_TIME_1_SHIFT                   24
+
+#define PB0_PIF_PWRDOWN_2                                 0x17
+#       define PLL_POWER_STATE_IN_TXS2_2(x)               ((x) << 7)
+#       define PLL_POWER_STATE_IN_TXS2_2_MASK             (0x7 << 7)
+#       define PLL_POWER_STATE_IN_TXS2_2_SHIFT            7
+#       define PLL_POWER_STATE_IN_OFF_2(x)                ((x) << 10)
+#       define PLL_POWER_STATE_IN_OFF_2_MASK              (0x7 << 10)
+#       define PLL_POWER_STATE_IN_OFF_2_SHIFT             10
+#       define PLL_RAMP_UP_TIME_2(x)                      ((x) << 24)
+#       define PLL_RAMP_UP_TIME_2_MASK                    (0x7 << 24)
+#       define PLL_RAMP_UP_TIME_2_SHIFT                   24
+#define PB0_PIF_PWRDOWN_3                                 0x18
+#       define PLL_POWER_STATE_IN_TXS2_3(x)               ((x) << 7)
+#       define PLL_POWER_STATE_IN_TXS2_3_MASK             (0x7 << 7)
+#       define PLL_POWER_STATE_IN_TXS2_3_SHIFT            7
+#       define PLL_POWER_STATE_IN_OFF_3(x)                ((x) << 10)
+#       define PLL_POWER_STATE_IN_OFF_3_MASK              (0x7 << 10)
+#       define PLL_POWER_STATE_IN_OFF_3_SHIFT             10
+#       define PLL_RAMP_UP_TIME_3(x)                      ((x) << 24)
+#       define PLL_RAMP_UP_TIME_3_MASK                    (0x7 << 24)
+#       define PLL_RAMP_UP_TIME_3_SHIFT                   24
+/* PIF PHY1 registers idx/data 0x10/0x14 */
+#define PB1_PIF_CNTL                                      0x10
+#define PB1_PIF_PAIRING                                   0x11
+#define PB1_PIF_PWRDOWN_0                                 0x12
+#define PB1_PIF_PWRDOWN_1                                 0x13
+
+#define PB1_PIF_PWRDOWN_2                                 0x17
+#define PB1_PIF_PWRDOWN_3                                 0x18
+/* PCIE registers idx/data 0x30/0x34 */
+#define PCIE_CNTL2                                        0x1c /* PCIE */
+#       define SLV_MEM_LS_EN                              (1 << 16)
+#       define SLV_MEM_AGGRESSIVE_LS_EN                   (1 << 17)
+#       define MST_MEM_LS_EN                              (1 << 18)
+#       define REPLAY_MEM_LS_EN                           (1 << 19)
+#define PCIE_LC_STATUS1                                   0x28 /* PCIE */
+#       define LC_REVERSE_RCVR                            (1 << 0)
+#       define LC_REVERSE_XMIT                            (1 << 1)
+#       define LC_OPERATING_LINK_WIDTH_MASK               (0x7 << 2)
+#       define LC_OPERATING_LINK_WIDTH_SHIFT              2
+#       define LC_DETECTED_LINK_WIDTH_MASK                (0x7 << 5)
+#       define LC_DETECTED_LINK_WIDTH_SHIFT               5
+
+#define PCIE_P_CNTL                                       0x40 /* PCIE */
+#       define P_IGNORE_EDB_ERR                           (1 << 6)
+
+/* PCIE PORT registers idx/data 0x38/0x3c */
+#define PCIE_LC_CNTL                                      0xa0
+#       define LC_L0S_INACTIVITY(x)                       ((x) << 8)
+#       define LC_L0S_INACTIVITY_MASK                     (0xf << 8)
+#       define LC_L0S_INACTIVITY_SHIFT                    8
+#       define LC_L1_INACTIVITY(x)                        ((x) << 12)
+#       define LC_L1_INACTIVITY_MASK                      (0xf << 12)
+#       define LC_L1_INACTIVITY_SHIFT                     12
+#       define LC_PMI_TO_L1_DIS                           (1 << 16)
+#       define LC_ASPM_TO_L1_DIS                          (1 << 24)
+#define PCIE_LC_LINK_WIDTH_CNTL                           0xa2 /* PCIE_P */
+#       define LC_LINK_WIDTH_SHIFT                        0
+#       define LC_LINK_WIDTH_MASK                         0x7
+#       define LC_LINK_WIDTH_X0                           0
+#       define LC_LINK_WIDTH_X1                           1
+#       define LC_LINK_WIDTH_X2                           2
+#       define LC_LINK_WIDTH_X4                           3
+#       define LC_LINK_WIDTH_X8                           4
+#       define LC_LINK_WIDTH_X16                          6
+#       define LC_LINK_WIDTH_RD_SHIFT                     4
+#       define LC_LINK_WIDTH_RD_MASK                      0x70
+#       define LC_RECONFIG_ARC_MISSING_ESCAPE             (1 << 7)
+#       define LC_RECONFIG_NOW                            (1 << 8)
+#       define LC_RENEGOTIATION_SUPPORT                   (1 << 9)
+#       define LC_RENEGOTIATE_EN                          (1 << 10)
+#       define LC_SHORT_RECONFIG_EN                       (1 << 11)
+#       define LC_UPCONFIGURE_SUPPORT                     (1 << 12)
+#       define LC_UPCONFIGURE_DIS                         (1 << 13)
+#       define LC_DYN_LANES_PWR_STATE(x)                  ((x) << 21)
+#       define LC_DYN_LANES_PWR_STATE_MASK                (0x3 << 21)
+#       define LC_DYN_LANES_PWR_STATE_SHIFT               21
+#define PCIE_LC_N_FTS_CNTL                                0xa3 /* PCIE_P */
+#       define LC_XMIT_N_FTS(x)                           ((x) << 0)
+#       define LC_XMIT_N_FTS_MASK                         (0xff << 0)
+#       define LC_XMIT_N_FTS_SHIFT                        0
+#       define LC_XMIT_N_FTS_OVERRIDE_EN                  (1 << 8)
+#       define LC_N_FTS_MASK                              (0xff << 24)
+#define PCIE_LC_SPEED_CNTL                                0xa4 /* PCIE_P */
+#       define LC_GEN2_EN_STRAP                           (1 << 0)
+#       define LC_GEN3_EN_STRAP                           (1 << 1)
+#       define LC_TARGET_LINK_SPEED_OVERRIDE_EN           (1 << 2)
+#       define LC_TARGET_LINK_SPEED_OVERRIDE_MASK         (0x3 << 3)
+#       define LC_TARGET_LINK_SPEED_OVERRIDE_SHIFT        3
+#       define LC_FORCE_EN_SW_SPEED_CHANGE                (1 << 5)
+#       define LC_FORCE_DIS_SW_SPEED_CHANGE               (1 << 6)
+#       define LC_FORCE_EN_HW_SPEED_CHANGE                (1 << 7)
+#       define LC_FORCE_DIS_HW_SPEED_CHANGE               (1 << 8)
+#       define LC_INITIATE_LINK_SPEED_CHANGE              (1 << 9)
+#       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK      (0x3 << 10)
+#       define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT     10
+#       define LC_CURRENT_DATA_RATE_MASK                  (0x3 << 13) /* 0/1/2 = gen1/2/3 */
+#       define LC_CURRENT_DATA_RATE_SHIFT                 13
+#       define LC_CLR_FAILED_SPD_CHANGE_CNT               (1 << 16)
+#       define LC_OTHER_SIDE_EVER_SENT_GEN2               (1 << 18)
+#       define LC_OTHER_SIDE_SUPPORTS_GEN2                (1 << 19)
+#       define LC_OTHER_SIDE_EVER_SENT_GEN3               (1 << 20)
+#       define LC_OTHER_SIDE_SUPPORTS_GEN3                (1 << 21)
+
+#define PCIE_LC_CNTL2                                     0xb1
+#       define LC_ALLOW_PDWN_IN_L1                        (1 << 17)
+#       define LC_ALLOW_PDWN_IN_L23                       (1 << 18)
+
+#define PCIE_LC_CNTL3                                     0xb5 /* PCIE_P */
+#       define LC_GO_TO_RECOVERY                          (1 << 30)
+#define PCIE_LC_CNTL4                                     0xb6 /* PCIE_P */
+#       define LC_REDO_EQ                                 (1 << 5)
+#       define LC_SET_QUIESCE                             (1 << 13)
+
+/*
+ * UVD
+ */
+#define UVD_UDEC_ADDR_CONFIG                           0x3bd3
+#define UVD_UDEC_DB_ADDR_CONFIG                                0x3bd4
+#define UVD_UDEC_DBW_ADDR_CONFIG                       0x3bd5
+#define UVD_RBC_RB_RPTR                                        0x3da4
+#define UVD_RBC_RB_WPTR                                        0x3da5
+#define UVD_STATUS                                     0x3daf
+
+#define        UVD_CGC_CTRL                                    0x3dc2
+#      define DCM                                      (1 << 0)
+#      define CG_DT(x)                                 ((x) << 2)
+#      define CG_DT_MASK                               (0xf << 2)
+#      define CLK_OD(x)                                ((x) << 6)
+#      define CLK_OD_MASK                              (0x1f << 6)
+
+ /* UVD CTX indirect */
+#define        UVD_CGC_MEM_CTRL                                0xC0
+#define        UVD_CGC_CTRL2                                   0xC1
+#      define DYN_OR_EN                                (1 << 0)
+#      define DYN_RR_EN                                (1 << 1)
+#      define G_DIV_ID(x)                              ((x) << 2)
+#      define G_DIV_ID_MASK                            (0x7 << 2)
+
+/*
+ * PM4
+ */
+#define PACKET0(reg, n)        ((RADEON_PACKET_TYPE0 << 30) |                  \
+                        (((reg) >> 2) & 0xFFFF) |                      \
+                        ((n) & 0x3FFF) << 16)
+#define CP_PACKET2                     0x80000000
+#define                PACKET2_PAD_SHIFT               0
+#define                PACKET2_PAD_MASK                (0x3fffffff << 0)
+
+#define PACKET2(v)     (CP_PACKET2 | REG_SET(PACKET2_PAD, (v)))
+#define RADEON_PACKET_TYPE3 3
+#define PACKET3(op, n) ((RADEON_PACKET_TYPE3 << 30) |                  \
+                        (((op) & 0xFF) << 8) |                         \
+                        ((n) & 0x3FFF) << 16)
+
+#define PACKET3_COMPUTE(op, n) (PACKET3(op, n) | 1 << 1)
+
+/* Packet 3 types */
+#define        PACKET3_NOP                                     0x10
+#define        PACKET3_SET_BASE                                0x11
+#define                PACKET3_BASE_INDEX(x)                  ((x) << 0)
+#define                        GDS_PARTITION_BASE              2
+#define                        CE_PARTITION_BASE               3
+#define        PACKET3_CLEAR_STATE                             0x12
+#define        PACKET3_INDEX_BUFFER_SIZE                       0x13
+#define        PACKET3_DISPATCH_DIRECT                         0x15
+#define        PACKET3_DISPATCH_INDIRECT                       0x16
+#define        PACKET3_ALLOC_GDS                               0x1B
+#define        PACKET3_WRITE_GDS_RAM                           0x1C
+#define        PACKET3_ATOMIC_GDS                              0x1D
+#define        PACKET3_ATOMIC                                  0x1E
+#define        PACKET3_OCCLUSION_QUERY                         0x1F
+#define        PACKET3_SET_PREDICATION                         0x20
+#define        PACKET3_REG_RMW                                 0x21
+#define        PACKET3_COND_EXEC                               0x22
+#define        PACKET3_PRED_EXEC                               0x23
+#define        PACKET3_DRAW_INDIRECT                           0x24
+#define        PACKET3_DRAW_INDEX_INDIRECT                     0x25
+#define        PACKET3_INDEX_BASE                              0x26
+#define        PACKET3_DRAW_INDEX_2                            0x27
+#define        PACKET3_CONTEXT_CONTROL                         0x28
+#define        PACKET3_INDEX_TYPE                              0x2A
+#define        PACKET3_DRAW_INDIRECT_MULTI                     0x2C
+#define        PACKET3_DRAW_INDEX_AUTO                         0x2D
+#define        PACKET3_DRAW_INDEX_IMMD                         0x2E
+#define        PACKET3_NUM_INSTANCES                           0x2F
+#define        PACKET3_DRAW_INDEX_MULTI_AUTO                   0x30
+#define        PACKET3_INDIRECT_BUFFER_CONST                   0x31
+#define        PACKET3_INDIRECT_BUFFER                         0x3F
+#define        PACKET3_STRMOUT_BUFFER_UPDATE                   0x34
+#define        PACKET3_DRAW_INDEX_OFFSET_2                     0x35
+#define        PACKET3_DRAW_INDEX_MULTI_ELEMENT                0x36
+#define        PACKET3_WRITE_DATA                              0x37
+#define                WRITE_DATA_DST_SEL(x)                   ((x) << 8)
+                /* 0 - register
+                * 1 - memory (sync - via GRBM)
+                * 2 - tc/l2
+                * 3 - gds
+                * 4 - reserved
+                * 5 - memory (async - direct)
+                */
+#define                WR_ONE_ADDR                             (1 << 16)
+#define                WR_CONFIRM                              (1 << 20)
+#define                WRITE_DATA_ENGINE_SEL(x)                ((x) << 30)
+                /* 0 - me
+                * 1 - pfp
+                * 2 - ce
+                */
+#define        PACKET3_DRAW_INDEX_INDIRECT_MULTI               0x38
+#define        PACKET3_MEM_SEMAPHORE                           0x39
+#define        PACKET3_MPEG_INDEX                              0x3A
+#define        PACKET3_COPY_DW                                 0x3B
+#define        PACKET3_WAIT_REG_MEM                            0x3C
+#define                WAIT_REG_MEM_FUNCTION(x)                ((x) << 0)
+                /* 0 - always
+                * 1 - <
+                * 2 - <=
+                * 3 - ==
+                * 4 - !=
+                * 5 - >=
+                * 6 - >
+                */
+#define                WAIT_REG_MEM_MEM_SPACE(x)               ((x) << 4)
+                /* 0 - reg
+                * 1 - mem
+                */
+#define                WAIT_REG_MEM_ENGINE(x)                  ((x) << 8)
+                /* 0 - me
+                * 1 - pfp
+                */
+#define        PACKET3_MEM_WRITE                               0x3D
+#define        PACKET3_COPY_DATA                               0x40
+#define        PACKET3_CP_DMA                                  0x41
+/* 1. header
+ * 2. SRC_ADDR_LO or DATA [31:0]
+ * 3. CP_SYNC [31] | SRC_SEL [30:29] | ENGINE [27] | DST_SEL [21:20] |
+ *    SRC_ADDR_HI [7:0]
+ * 4. DST_ADDR_LO [31:0]
+ * 5. DST_ADDR_HI [7:0]
+ * 6. COMMAND [30:21] | BYTE_COUNT [20:0]
+ */
+#              define PACKET3_CP_DMA_DST_SEL(x)    ((x) << 20)
+                /* 0 - DST_ADDR
+                * 1 - GDS
+                */
+#              define PACKET3_CP_DMA_ENGINE(x)     ((x) << 27)
+                /* 0 - ME
+                * 1 - PFP
+                */
+#              define PACKET3_CP_DMA_SRC_SEL(x)    ((x) << 29)
+                /* 0 - SRC_ADDR
+                * 1 - GDS
+                * 2 - DATA
+                */
+#              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)
+/* COMMAND */
+#              define PACKET3_CP_DMA_DIS_WC        (1 << 21)
+#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)
+                /* 0 - none
+                * 1 - 8 in 16
+                * 2 - 8 in 32
+                * 3 - 8 in 64
+                */
+#              define PACKET3_CP_DMA_CMD_DST_SWAP(x) ((x) << 24)
+                /* 0 - none
+                * 1 - 8 in 16
+                * 2 - 8 in 32
+                * 3 - 8 in 64
+                */
+#              define PACKET3_CP_DMA_CMD_SAS       (1 << 26)
+                /* 0 - memory
+                * 1 - register
+                */
+#              define PACKET3_CP_DMA_CMD_DAS       (1 << 27)
+                /* 0 - memory
+                * 1 - register
+                */
+#              define PACKET3_CP_DMA_CMD_SAIC      (1 << 28)
+#              define PACKET3_CP_DMA_CMD_DAIC      (1 << 29)
+#              define PACKET3_CP_DMA_CMD_RAW_WAIT  (1 << 30)
+#define        PACKET3_PFP_SYNC_ME                             0x42
+#define        PACKET3_SURFACE_SYNC                            0x43
+#              define PACKET3_DEST_BASE_0_ENA      (1 << 0)
+#              define PACKET3_DEST_BASE_1_ENA      (1 << 1)
+#              define PACKET3_CB0_DEST_BASE_ENA    (1 << 6)
+#              define PACKET3_CB1_DEST_BASE_ENA    (1 << 7)
+#              define PACKET3_CB2_DEST_BASE_ENA    (1 << 8)
+#              define PACKET3_CB3_DEST_BASE_ENA    (1 << 9)
+#              define PACKET3_CB4_DEST_BASE_ENA    (1 << 10)
+#              define PACKET3_CB5_DEST_BASE_ENA    (1 << 11)
+#              define PACKET3_CB6_DEST_BASE_ENA    (1 << 12)
+#              define PACKET3_CB7_DEST_BASE_ENA    (1 << 13)
+#              define PACKET3_DB_DEST_BASE_ENA     (1 << 14)
+#              define PACKET3_DEST_BASE_2_ENA      (1 << 19)
+#              define PACKET3_DEST_BASE_3_ENA      (1 << 21)
+#              define PACKET3_TCL1_ACTION_ENA      (1 << 22)
+#              define PACKET3_TC_ACTION_ENA        (1 << 23)
+#              define PACKET3_CB_ACTION_ENA        (1 << 25)
+#              define PACKET3_DB_ACTION_ENA        (1 << 26)
+#              define PACKET3_SH_KCACHE_ACTION_ENA (1 << 27)
+#              define PACKET3_SH_ICACHE_ACTION_ENA (1 << 29)
+#define        PACKET3_ME_INITIALIZE                           0x44
+#define                PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
+#define        PACKET3_COND_WRITE                              0x45
+#define        PACKET3_EVENT_WRITE                             0x46
+#define                EVENT_TYPE(x)                           ((x) << 0)
+#define                EVENT_INDEX(x)                          ((x) << 8)
+                /* 0 - any non-TS event
+                * 1 - ZPASS_DONE
+                * 2 - SAMPLE_PIPELINESTAT
+                * 3 - SAMPLE_STREAMOUTSTAT*
+                * 4 - *S_PARTIAL_FLUSH
+                * 5 - EOP events
+                * 6 - EOS events
+                * 7 - CACHE_FLUSH, CACHE_FLUSH_AND_INV_EVENT
+                */
+#define                INV_L2                                  (1 << 20)
+                /* INV TC L2 cache when EVENT_INDEX = 7 */
+#define        PACKET3_EVENT_WRITE_EOP                         0x47
+#define                DATA_SEL(x)                             ((x) << 29)
+                /* 0 - discard
+                * 1 - send low 32bit data
+                * 2 - send 64bit data
+                * 3 - send 64bit counter value
+                */
+#define                INT_SEL(x)                              ((x) << 24)
+                /* 0 - none
+                * 1 - interrupt only (DATA_SEL = 0)
+                * 2 - interrupt when data write is confirmed
+                */
+#define        PACKET3_EVENT_WRITE_EOS                         0x48
+#define        PACKET3_PREAMBLE_CNTL                           0x4A
+#              define PACKET3_PREAMBLE_BEGIN_CLEAR_STATE     (2 << 28)
+#              define PACKET3_PREAMBLE_END_CLEAR_STATE       (3 << 28)
+#define        PACKET3_ONE_REG_WRITE                           0x57
+#define        PACKET3_LOAD_CONFIG_REG                         0x5F
+#define        PACKET3_LOAD_CONTEXT_REG                        0x60
+#define        PACKET3_LOAD_SH_REG                             0x61
+#define        PACKET3_SET_CONFIG_REG                          0x68
+#define                PACKET3_SET_CONFIG_REG_START                    0x00002000
+#define                PACKET3_SET_CONFIG_REG_END                      0x00002c00
+#define        PACKET3_SET_CONTEXT_REG                         0x69
+#define                PACKET3_SET_CONTEXT_REG_START                   0x000a000
+#define                PACKET3_SET_CONTEXT_REG_END                     0x000a400
+#define        PACKET3_SET_CONTEXT_REG_INDIRECT                0x73
+#define        PACKET3_SET_RESOURCE_INDIRECT                   0x74
+#define        PACKET3_SET_SH_REG                              0x76
+#define                PACKET3_SET_SH_REG_START                        0x00002c00
+#define                PACKET3_SET_SH_REG_END                          0x00003000
+#define        PACKET3_SET_SH_REG_OFFSET                       0x77
+#define        PACKET3_ME_WRITE                                0x7A
+#define        PACKET3_SCRATCH_RAM_WRITE                       0x7D
+#define        PACKET3_SCRATCH_RAM_READ                        0x7E
+#define        PACKET3_CE_WRITE                                0x7F
+#define        PACKET3_LOAD_CONST_RAM                          0x80
+#define        PACKET3_WRITE_CONST_RAM                         0x81
+#define        PACKET3_WRITE_CONST_RAM_OFFSET                  0x82
+#define        PACKET3_DUMP_CONST_RAM                          0x83
+#define        PACKET3_INCREMENT_CE_COUNTER                    0x84
+#define        PACKET3_INCREMENT_DE_COUNTER                    0x85
+#define        PACKET3_WAIT_ON_CE_COUNTER                      0x86
+#define        PACKET3_WAIT_ON_DE_COUNTER                      0x87
+#define        PACKET3_WAIT_ON_DE_COUNTER_DIFF                 0x88
+#define        PACKET3_SET_CE_DE_COUNTERS                      0x89
+#define        PACKET3_WAIT_ON_AVAIL_BUFFER                    0x8A
+#define        PACKET3_SWITCH_BUFFER                           0x8B
+
+/* ASYNC DMA - first instance at 0xd000, second at 0xd800 */
+#define DMA0_REGISTER_OFFSET                              0x0 /* not a register */
+#define DMA1_REGISTER_OFFSET                              0x200 /* not a register */
+
+#define DMA_RB_CNTL                                       0x3400
+#       define DMA_RB_ENABLE                              (1 << 0)
+#       define DMA_RB_SIZE(x)                             ((x) << 1) /* log2 */
+#       define DMA_RB_SWAP_ENABLE                         (1 << 9) /* 8IN32 */
+#       define DMA_RPTR_WRITEBACK_ENABLE                  (1 << 12)
+#       define DMA_RPTR_WRITEBACK_SWAP_ENABLE             (1 << 13)  /* 8IN32 */
+#       define DMA_RPTR_WRITEBACK_TIMER(x)                ((x) << 16) /* log2 */
+#define DMA_RB_BASE                                       0x3401
+#define DMA_RB_RPTR                                       0x3402
+#define DMA_RB_WPTR                                       0x3403
+
+#define DMA_RB_RPTR_ADDR_HI                               0x3407
+#define DMA_RB_RPTR_ADDR_LO                               0x3408
+
+#define DMA_IB_CNTL                                       0x3409
+#       define DMA_IB_ENABLE                              (1 << 0)
+#       define DMA_IB_SWAP_ENABLE                         (1 << 4)
+#       define CMD_VMID_FORCE                             (1 << 31)
+#define DMA_IB_RPTR                                       0x340a
+#define DMA_CNTL                                          0x340b
+#       define TRAP_ENABLE                                (1 << 0)
+#       define SEM_INCOMPLETE_INT_ENABLE                  (1 << 1)
+#       define SEM_WAIT_INT_ENABLE                        (1 << 2)
+#       define DATA_SWAP_ENABLE                           (1 << 3)
+#       define FENCE_SWAP_ENABLE                          (1 << 4)
+#       define CTXEMPTY_INT_ENABLE                        (1 << 28)
+#define DMA_STATUS_REG                                    0x340d
+#       define DMA_IDLE                                   (1 << 0)
+#define DMA_TILING_CONFIG                                0x342e
+
+#define        DMA_POWER_CNTL                                  0x342f
+#       define MEM_POWER_OVERRIDE                       (1 << 8)
+#define        DMA_CLK_CTRL                                    0x3430
+
+#define        DMA_PG                                          0x3435
+#      define PG_CNTL_ENABLE                           (1 << 0)
+#define        DMA_PGFSM_CONFIG                                0x3436
+#define        DMA_PGFSM_WRITE                                 0x3437
+
+#define DMA_PACKET(cmd, b, t, s, n)    ((((cmd) & 0xF) << 28) |        \
+                                        (((b) & 0x1) << 26) |          \
+                                        (((t) & 0x1) << 23) |          \
+                                        (((s) & 0x1) << 22) |          \
+                                        (((n) & 0xFFFFF) << 0))
+
+#define DMA_IB_PACKET(cmd, vmid, n)    ((((cmd) & 0xF) << 28) |        \
+                                        (((vmid) & 0xF) << 20) |       \
+                                        (((n) & 0xFFFFF) << 0))
+
+#define DMA_PTE_PDE_PACKET(n)          ((2 << 28) |                    \
+                                        (1 << 26) |                    \
+                                        (1 << 21) |                    \
+                                        (((n) & 0xFFFFF) << 0))
+
+/* async DMA Packet types */
+#define        DMA_PACKET_WRITE                                  0x2
+#define        DMA_PACKET_COPY                                   0x3
+#define        DMA_PACKET_INDIRECT_BUFFER                        0x4
+#define        DMA_PACKET_SEMAPHORE                              0x5
+#define        DMA_PACKET_FENCE                                  0x6
+#define        DMA_PACKET_TRAP                                   0x7
+#define        DMA_PACKET_SRBM_WRITE                             0x9
+#define        DMA_PACKET_CONSTANT_FILL                          0xd
+#define        DMA_PACKET_POLL_REG_MEM                           0xe
+#define        DMA_PACKET_NOP                                    0xf
+
+#define VCE_STATUS                                     0x20004
+#define VCE_VCPU_CNTL                                  0x20014
+#define                VCE_CLK_EN                              (1 << 0)
+#define VCE_VCPU_CACHE_OFFSET0                         0x20024
+#define VCE_VCPU_CACHE_SIZE0                           0x20028
+#define VCE_VCPU_CACHE_OFFSET1                         0x2002c
+#define VCE_VCPU_CACHE_SIZE1                           0x20030
+#define VCE_VCPU_CACHE_OFFSET2                         0x20034
+#define VCE_VCPU_CACHE_SIZE2                           0x20038
+#define VCE_SOFT_RESET                                 0x20120
+#define        VCE_ECPU_SOFT_RESET                     (1 << 0)
+#define        VCE_FME_SOFT_RESET                      (1 << 2)
+#define VCE_RB_BASE_LO2                                        0x2016c
+#define VCE_RB_BASE_HI2                                        0x20170
+#define VCE_RB_SIZE2                                   0x20174
+#define VCE_RB_RPTR2                                   0x20178
+#define VCE_RB_WPTR2                                   0x2017c
+#define VCE_RB_BASE_LO                                 0x20180
+#define VCE_RB_BASE_HI                                 0x20184
+#define VCE_RB_SIZE                                    0x20188
+#define VCE_RB_RPTR                                    0x2018c
+#define VCE_RB_WPTR                                    0x20190
+#define VCE_CLOCK_GATING_A                             0x202f8
+#define VCE_CLOCK_GATING_B                             0x202fc
+#define VCE_UENC_CLOCK_GATING                          0x205bc
+#define VCE_UENC_REG_CLOCK_GATING                      0x205c0
+#define VCE_FW_REG_STATUS                              0x20e10
+#      define VCE_FW_REG_STATUS_BUSY                   (1 << 0)
+#      define VCE_FW_REG_STATUS_PASS                   (1 << 3)
+#      define VCE_FW_REG_STATUS_DONE                   (1 << 11)
+#define VCE_LMI_FW_START_KEYSEL                                0x20e18
+#define VCE_LMI_FW_PERIODIC_CTRL                       0x20e20
+#define VCE_LMI_CTRL2                                  0x20e74
+#define VCE_LMI_CTRL                                   0x20e98
+#define VCE_LMI_VM_CTRL                                        0x20ea0
+#define VCE_LMI_SWAP_CNTL                              0x20eb4
+#define VCE_LMI_SWAP_CNTL1                             0x20eb8
+#define VCE_LMI_CACHE_CTRL                             0x20ef4
+
+#define VCE_CMD_NO_OP                                  0x00000000
+#define VCE_CMD_END                                    0x00000001
+#define VCE_CMD_IB                                     0x00000002
+#define VCE_CMD_FENCE                                  0x00000003
+#define VCE_CMD_TRAP                                   0x00000004
+#define VCE_CMD_IB_AUTO                                        0x00000005
+#define VCE_CMD_SEMAPHORE                              0x00000006
+
+
+//#dce stupp
+/* display controller offsets used for crtc/cur/lut/grph/viewport/etc. */
+#define SI_CRTC0_REGISTER_OFFSET                0 //(0x6df0 - 0x6df0)/4
+#define SI_CRTC1_REGISTER_OFFSET                0x300 //(0x79f0 - 0x6df0)/4
+#define SI_CRTC2_REGISTER_OFFSET                0x2600 //(0x105f0 - 0x6df0)/4
+#define SI_CRTC3_REGISTER_OFFSET                0x2900 //(0x111f0 - 0x6df0)/4
+#define SI_CRTC4_REGISTER_OFFSET                0x2c00 //(0x11df0 - 0x6df0)/4
+#define SI_CRTC5_REGISTER_OFFSET                0x2f00 //(0x129f0 - 0x6df0)/4
+
+#define CURSOR_WIDTH 64
+#define CURSOR_HEIGHT 64
+#define AMDGPU_MM_INDEX                        0x0000
+#define AMDGPU_MM_DATA                 0x0001
+
+#define VERDE_NUM_CRTC 6
+#define        BLACKOUT_MODE_MASK                      0x00000007
+#define        VGA_RENDER_CONTROL                      0xC0
+#define R_000300_VGA_RENDER_CONTROL             0xC0
+#define C_000300_VGA_VSTATUS_CNTL               0xFFFCFFFF
+#define EVERGREEN_CRTC_STATUS                   0x1BA3
+#define EVERGREEN_CRTC_V_BLANK                  (1 << 0)
+#define EVERGREEN_CRTC_STATUS_POSITION          0x1BA4
+/* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */
+#define EVERGREEN_CRTC_V_BLANK_START_END                0x1b8d
+#define EVERGREEN_CRTC_CONTROL                          0x1b9c
+#define EVERGREEN_CRTC_MASTER_EN                 (1 << 0)
+#define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24)
+#define EVERGREEN_CRTC_BLANK_CONTROL                    0x1b9d
+#define EVERGREEN_CRTC_BLANK_DATA_EN             (1 << 8)
+#define EVERGREEN_CRTC_V_BLANK                   (1 << 0)
+#define EVERGREEN_CRTC_STATUS_HV_COUNT                  0x1ba8
+#define EVERGREEN_CRTC_UPDATE_LOCK                      0x1bb5
+#define EVERGREEN_MASTER_UPDATE_LOCK                    0x1bbd
+#define EVERGREEN_MASTER_UPDATE_MODE                    0x1bbe
+#define EVERGREEN_GRPH_UPDATE_LOCK               (1 << 16)
+#define EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH     0x1a07
+#define EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH   0x1a08
+#define EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS          0x1a04
+#define EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS        0x1a05
+#define EVERGREEN_GRPH_UPDATE                           0x1a11
+#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS               0xc4
+#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH          0xc9
+#define EVERGREEN_GRPH_SURFACE_UPDATE_PENDING    (1 << 2)
+
+#define EVERGREEN_DATA_FORMAT                           0x1ac0
+#       define EVERGREEN_INTERLEAVE_EN                  (1 << 0)
+
+#define MC_SHARED_CHMAP__NOOFCHAN_MASK 0xf000
+#define MC_SHARED_CHMAP__NOOFCHAN__SHIFT 0xc
+
+#define R600_D1GRPH_ARRAY_MODE_LINEAR_GENERAL            (0 << 20)
+#define R600_D1GRPH_ARRAY_MODE_LINEAR_ALIGNED            (1 << 20)
+#define R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1            (2 << 20)
+#define R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1            (4 << 20)
+
+#define R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH                0x1a45
+#define R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH                0x1845
+
+#define R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH              0x1847
+#define R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH              0x1a47
+
+#define DISP_INTERRUPT_STATUS__LB_D1_VBLANK_INTERRUPT_MASK 0x8
+#define DISP_INTERRUPT_STATUS_CONTINUE__LB_D2_VBLANK_INTERRUPT_MASK 0x8
+#define DISP_INTERRUPT_STATUS_CONTINUE2__LB_D3_VBLANK_INTERRUPT_MASK 0x8
+#define DISP_INTERRUPT_STATUS_CONTINUE3__LB_D4_VBLANK_INTERRUPT_MASK 0x8
+#define DISP_INTERRUPT_STATUS_CONTINUE4__LB_D5_VBLANK_INTERRUPT_MASK 0x8
+#define DISP_INTERRUPT_STATUS_CONTINUE5__LB_D6_VBLANK_INTERRUPT_MASK 0x8
+
+#define DISP_INTERRUPT_STATUS__LB_D1_VLINE_INTERRUPT_MASK 0x4
+#define DISP_INTERRUPT_STATUS_CONTINUE__LB_D2_VLINE_INTERRUPT_MASK 0x4
+#define DISP_INTERRUPT_STATUS_CONTINUE2__LB_D3_VLINE_INTERRUPT_MASK 0x4
+#define DISP_INTERRUPT_STATUS_CONTINUE3__LB_D4_VLINE_INTERRUPT_MASK 0x4
+#define DISP_INTERRUPT_STATUS_CONTINUE4__LB_D5_VLINE_INTERRUPT_MASK 0x4
+#define DISP_INTERRUPT_STATUS_CONTINUE5__LB_D6_VLINE_INTERRUPT_MASK 0x4
+
+#define DISP_INTERRUPT_STATUS__DC_HPD1_INTERRUPT_MASK 0x20000
+#define DISP_INTERRUPT_STATUS_CONTINUE__DC_HPD2_INTERRUPT_MASK 0x20000
+#define DISP_INTERRUPT_STATUS_CONTINUE2__DC_HPD3_INTERRUPT_MASK 0x20000
+#define DISP_INTERRUPT_STATUS_CONTINUE3__DC_HPD4_INTERRUPT_MASK 0x20000
+#define DISP_INTERRUPT_STATUS_CONTINUE4__DC_HPD5_INTERRUPT_MASK 0x20000
+#define DISP_INTERRUPT_STATUS_CONTINUE5__DC_HPD6_INTERRUPT_MASK 0x20000
+
+#define GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_OCCURRED_MASK 0x1
+#define GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK 0x100
+
+#define DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK 0x1
+
+#define R600_D1GRPH_SWAP_CONTROL                               0x1843
+#define R600_D1GRPH_SWAP_ENDIAN_NONE                    (0 << 0)
+#define R600_D1GRPH_SWAP_ENDIAN_16BIT                   (1 << 0)
+#define R600_D1GRPH_SWAP_ENDIAN_32BIT                   (2 << 0)
+#define R600_D1GRPH_SWAP_ENDIAN_64BIT                   (3 << 0)
+
+#define AVIVO_D1VGA_CONTROL                                    0x00cc
+#       define AVIVO_DVGA_CONTROL_MODE_ENABLE            (1 << 0)
+#       define AVIVO_DVGA_CONTROL_TIMING_SELECT          (1 << 8)
+#       define AVIVO_DVGA_CONTROL_SYNC_POLARITY_SELECT   (1 << 9)
+#       define AVIVO_DVGA_CONTROL_OVERSCAN_TIMING_SELECT (1 << 10)
+#       define AVIVO_DVGA_CONTROL_OVERSCAN_COLOR_EN      (1 << 16)
+#       define AVIVO_DVGA_CONTROL_ROTATE                 (1 << 24)
+#define AVIVO_D2VGA_CONTROL                                    0x00ce
+
+#define R600_BUS_CNTL                                           0x1508
+#       define R600_BIOS_ROM_DIS                                (1 << 1)
+
+#define R600_ROM_CNTL                              0x580
+#       define R600_SCK_OVERWRITE                  (1 << 1)
+#       define R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT 28
+#       define R600_SCK_PRESCALE_CRYSTAL_CLK_MASK  (0xf << 28)
+
+#define GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK 0x1
+
+#define FMT_BIT_DEPTH_CONTROL                0x1bf2
+#define FMT_TRUNCATE_EN               (1 << 0)
+#define FMT_TRUNCATE_DEPTH            (1 << 4)
+#define FMT_SPATIAL_DITHER_EN         (1 << 8)
+#define FMT_SPATIAL_DITHER_MODE(x)    ((x) << 9)
+#define FMT_SPATIAL_DITHER_DEPTH      (1 << 12)
+#define FMT_FRAME_RANDOM_ENABLE       (1 << 13)
+#define FMT_RGB_RANDOM_ENABLE         (1 << 14)
+#define FMT_HIGHPASS_RANDOM_ENABLE    (1 << 15)
+#define FMT_TEMPORAL_DITHER_EN        (1 << 16)
+#define FMT_TEMPORAL_DITHER_DEPTH     (1 << 20)
+#define FMT_TEMPORAL_DITHER_OFFSET(x) ((x) << 21)
+#define FMT_TEMPORAL_LEVEL            (1 << 24)
+#define FMT_TEMPORAL_DITHER_RESET     (1 << 25)
+#define FMT_25FRC_SEL(x)              ((x) << 26)
+#define FMT_50FRC_SEL(x)              ((x) << 28)
+#define FMT_75FRC_SEL(x)              ((x) << 30)
+
+#define EVERGREEN_DC_LUT_CONTROL                        0x1a80
+#define EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE              0x1a81
+#define EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN             0x1a82
+#define EVERGREEN_DC_LUT_BLACK_OFFSET_RED               0x1a83
+#define EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE              0x1a84
+#define EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN             0x1a85
+#define EVERGREEN_DC_LUT_WHITE_OFFSET_RED               0x1a86
+#define EVERGREEN_DC_LUT_30_COLOR                       0x1a7c
+#define EVERGREEN_DC_LUT_RW_INDEX                       0x1a79
+#define EVERGREEN_DC_LUT_WRITE_EN_MASK                  0x1a7e
+#define EVERGREEN_DC_LUT_RW_MODE                        0x1a78
+
+#define EVERGREEN_GRPH_ENABLE                           0x1a00
+#define EVERGREEN_GRPH_CONTROL                          0x1a01
+#define EVERGREEN_GRPH_DEPTH(x)                  (((x) & 0x3) << 0)
+#define EVERGREEN_GRPH_DEPTH_8BPP                0
+#define EVERGREEN_GRPH_DEPTH_16BPP               1
+#define EVERGREEN_GRPH_DEPTH_32BPP               2
+#define EVERGREEN_GRPH_NUM_BANKS(x)              (((x) & 0x3) << 2)
+#define EVERGREEN_ADDR_SURF_2_BANK               0
+#define EVERGREEN_ADDR_SURF_4_BANK               1
+#define EVERGREEN_ADDR_SURF_8_BANK               2
+#define EVERGREEN_ADDR_SURF_16_BANK              3
+#define EVERGREEN_GRPH_Z(x)                      (((x) & 0x3) << 4)
+#define EVERGREEN_GRPH_BANK_WIDTH(x)             (((x) & 0x3) << 6)
+#define EVERGREEN_ADDR_SURF_BANK_WIDTH_1         0
+#define EVERGREEN_ADDR_SURF_BANK_WIDTH_2         1
+#define EVERGREEN_ADDR_SURF_BANK_WIDTH_4         2
+#define EVERGREEN_ADDR_SURF_BANK_WIDTH_8         3
+#define EVERGREEN_GRPH_FORMAT(x)                 (((x) & 0x7) << 8)
+
+#define EVERGREEN_GRPH_FORMAT_INDEXED            0
+#define EVERGREEN_GRPH_FORMAT_ARGB1555           0
+#define EVERGREEN_GRPH_FORMAT_ARGB565            1
+#define EVERGREEN_GRPH_FORMAT_ARGB4444           2
+#define EVERGREEN_GRPH_FORMAT_AI88               3
+#define EVERGREEN_GRPH_FORMAT_MONO16             4
+#define EVERGREEN_GRPH_FORMAT_BGRA5551           5
+
+/* 32 BPP */
+#define EVERGREEN_GRPH_FORMAT_ARGB8888           0
+#define EVERGREEN_GRPH_FORMAT_ARGB2101010        1
+#define EVERGREEN_GRPH_FORMAT_32BPP_DIG          2
+#define EVERGREEN_GRPH_FORMAT_8B_ARGB2101010     3
+#define EVERGREEN_GRPH_FORMAT_BGRA1010102        4
+#define EVERGREEN_GRPH_FORMAT_8B_BGRA1010102     5
+#define EVERGREEN_GRPH_FORMAT_RGB111110          6
+#define EVERGREEN_GRPH_FORMAT_BGR101111          7
+#define EVERGREEN_GRPH_BANK_HEIGHT(x)            (((x) & 0x3) << 11)
+#define EVERGREEN_ADDR_SURF_BANK_HEIGHT_1        0
+#define EVERGREEN_ADDR_SURF_BANK_HEIGHT_2        1
+#define EVERGREEN_ADDR_SURF_BANK_HEIGHT_4        2
+#define EVERGREEN_ADDR_SURF_BANK_HEIGHT_8        3
+#define EVERGREEN_GRPH_TILE_SPLIT(x)             (((x) & 0x7) << 13)
+#define EVERGREEN_ADDR_SURF_TILE_SPLIT_64B       0
+#define EVERGREEN_ADDR_SURF_TILE_SPLIT_128B      1
+#define EVERGREEN_ADDR_SURF_TILE_SPLIT_256B      2
+#define EVERGREEN_ADDR_SURF_TILE_SPLIT_512B      3
+#define EVERGREEN_ADDR_SURF_TILE_SPLIT_1KB       4
+#define EVERGREEN_ADDR_SURF_TILE_SPLIT_2KB       5
+#define EVERGREEN_ADDR_SURF_TILE_SPLIT_4KB       6
+#define EVERGREEN_GRPH_MACRO_TILE_ASPECT(x)      (((x) & 0x3) << 18)
+#define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_1  0
+#define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_2  1
+#define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_4  2
+#define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_8  3
+#define EVERGREEN_GRPH_ARRAY_MODE(x)             (((x) & 0x7) << 20)
+#define EVERGREEN_GRPH_ARRAY_LINEAR_GENERAL      0
+#define EVERGREEN_GRPH_ARRAY_LINEAR_ALIGNED      1
+#define EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1      2
+#define EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1      4
+#define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_1  0
+#define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_2  1
+#define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_4  2
+#define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_8  3
+
+#define EVERGREEN_GRPH_SWAP_CONTROL                     0x1a03
+#define EVERGREEN_GRPH_ENDIAN_SWAP(x)            (((x) & 0x3) << 0)
+#       define EVERGREEN_GRPH_ENDIAN_NONE               0
+#       define EVERGREEN_GRPH_ENDIAN_8IN16              1
+#       define EVERGREEN_GRPH_ENDIAN_8IN32              2
+#       define EVERGREEN_GRPH_ENDIAN_8IN64              3
+
+#define EVERGREEN_D3VGA_CONTROL                         0xf8
+#define EVERGREEN_D4VGA_CONTROL                         0xf9
+#define EVERGREEN_D5VGA_CONTROL                         0xfa
+#define EVERGREEN_D6VGA_CONTROL                         0xfb
+
+#define EVERGREEN_GRPH_SURFACE_ADDRESS_MASK      0xffffff00
+
+#define EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL         0x1a02
+#define EVERGREEN_LUT_10BIT_BYPASS_EN            (1 << 8)
+
+#define EVERGREEN_GRPH_PITCH                            0x1a06
+#define EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH     0x1a07
+#define EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH   0x1a08
+#define EVERGREEN_GRPH_SURFACE_OFFSET_X                 0x1a09
+#define EVERGREEN_GRPH_SURFACE_OFFSET_Y                 0x1a0a
+#define EVERGREEN_GRPH_X_START                          0x1a0b
+#define EVERGREEN_GRPH_Y_START                          0x1a0c
+#define EVERGREEN_GRPH_X_END                            0x1a0d
+#define EVERGREEN_GRPH_Y_END                            0x1a0e
+#define EVERGREEN_GRPH_UPDATE                           0x1a11
+#define EVERGREEN_GRPH_SURFACE_UPDATE_PENDING    (1 << 2)
+#define EVERGREEN_GRPH_UPDATE_LOCK               (1 << 16)
+#define EVERGREEN_GRPH_FLIP_CONTROL                     0x1a12
+#define EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN (1 << 0)
+
+#define EVERGREEN_VIEWPORT_START                        0x1b5c
+#define EVERGREEN_VIEWPORT_SIZE                         0x1b5d
+#define EVERGREEN_DESKTOP_HEIGHT                        0x1ac1
+
+/* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */
+#define EVERGREEN_CUR_CONTROL                           0x1a66
+#       define EVERGREEN_CURSOR_EN                      (1 << 0)
+#       define EVERGREEN_CURSOR_MODE(x)                 (((x) & 0x3) << 8)
+#       define EVERGREEN_CURSOR_MONO                    0
+#       define EVERGREEN_CURSOR_24_1                    1
+#       define EVERGREEN_CURSOR_24_8_PRE_MULT           2
+#       define EVERGREEN_CURSOR_24_8_UNPRE_MULT         3
+#       define EVERGREEN_CURSOR_2X_MAGNIFY              (1 << 16)
+#       define EVERGREEN_CURSOR_FORCE_MC_ON             (1 << 20)
+#       define EVERGREEN_CURSOR_URGENT_CONTROL(x)       (((x) & 0x7) << 24)
+#       define EVERGREEN_CURSOR_URGENT_ALWAYS           0
+#       define EVERGREEN_CURSOR_URGENT_1_8              1
+#       define EVERGREEN_CURSOR_URGENT_1_4              2
+#       define EVERGREEN_CURSOR_URGENT_3_8              3
+#       define EVERGREEN_CURSOR_URGENT_1_2              4
+#define EVERGREEN_CUR_SURFACE_ADDRESS                   0x1a67
+#       define EVERGREEN_CUR_SURFACE_ADDRESS_MASK       0xfffff000
+#define EVERGREEN_CUR_SIZE                              0x1a68
+#define EVERGREEN_CUR_SURFACE_ADDRESS_HIGH              0x1a69
+#define EVERGREEN_CUR_POSITION                          0x1a6a
+#define EVERGREEN_CUR_HOT_SPOT                          0x1a6b
+#define EVERGREEN_CUR_COLOR1                            0x1a6c
+#define EVERGREEN_CUR_COLOR2                            0x1a6d
+#define EVERGREEN_CUR_UPDATE                            0x1a6e
+#       define EVERGREEN_CURSOR_UPDATE_PENDING          (1 << 0)
+#       define EVERGREEN_CURSOR_UPDATE_TAKEN            (1 << 1)
+#       define EVERGREEN_CURSOR_UPDATE_LOCK             (1 << 16)
+#       define EVERGREEN_CURSOR_DISABLE_MULTIPLE_UPDATE (1 << 24)
+
+
+#define NI_INPUT_CSC_CONTROL                           0x1a35
+#       define NI_INPUT_CSC_GRPH_MODE(x)               (((x) & 0x3) << 0)
+#       define NI_INPUT_CSC_BYPASS                     0
+#       define NI_INPUT_CSC_PROG_COEFF                 1
+#       define NI_INPUT_CSC_PROG_SHARED_MATRIXA        2
+#       define NI_INPUT_CSC_OVL_MODE(x)                (((x) & 0x3) << 4)
+
+#define NI_OUTPUT_CSC_CONTROL                          0x1a3c
+#       define NI_OUTPUT_CSC_GRPH_MODE(x)              (((x) & 0x7) << 0)
+#       define NI_OUTPUT_CSC_BYPASS                    0
+#       define NI_OUTPUT_CSC_TV_RGB                    1
+#       define NI_OUTPUT_CSC_YCBCR_601                 2
+#       define NI_OUTPUT_CSC_YCBCR_709                 3
+#       define NI_OUTPUT_CSC_PROG_COEFF                4
+#       define NI_OUTPUT_CSC_PROG_SHARED_MATRIXB       5
+#       define NI_OUTPUT_CSC_OVL_MODE(x)               (((x) & 0x7) << 4)
+
+#define NI_DEGAMMA_CONTROL                             0x1a58
+#       define NI_GRPH_DEGAMMA_MODE(x)                 (((x) & 0x3) << 0)
+#       define NI_DEGAMMA_BYPASS                       0
+#       define NI_DEGAMMA_SRGB_24                      1
+#       define NI_DEGAMMA_XVYCC_222                    2
+#       define NI_OVL_DEGAMMA_MODE(x)                  (((x) & 0x3) << 4)
+#       define NI_ICON_DEGAMMA_MODE(x)                 (((x) & 0x3) << 8)
+#       define NI_CURSOR_DEGAMMA_MODE(x)               (((x) & 0x3) << 12)
+
+#define NI_GAMUT_REMAP_CONTROL                         0x1a59
+#       define NI_GRPH_GAMUT_REMAP_MODE(x)             (((x) & 0x3) << 0)
+#       define NI_GAMUT_REMAP_BYPASS                   0
+#       define NI_GAMUT_REMAP_PROG_COEFF               1
+#       define NI_GAMUT_REMAP_PROG_SHARED_MATRIXA      2
+#       define NI_GAMUT_REMAP_PROG_SHARED_MATRIXB      3
+#       define NI_OVL_GAMUT_REMAP_MODE(x)              (((x) & 0x3) << 4)
+
+#define NI_REGAMMA_CONTROL                             0x1aa0
+#       define NI_GRPH_REGAMMA_MODE(x)                 (((x) & 0x7) << 0)
+#       define NI_REGAMMA_BYPASS                       0
+#       define NI_REGAMMA_SRGB_24                      1
+#       define NI_REGAMMA_XVYCC_222                    2
+#       define NI_REGAMMA_PROG_A                       3
+#       define NI_REGAMMA_PROG_B                       4
+#       define NI_OVL_REGAMMA_MODE(x)                  (((x) & 0x7) << 4)
+
+
+#define NI_PRESCALE_GRPH_CONTROL                       0x1a2d
+#       define NI_GRPH_PRESCALE_BYPASS                 (1 << 4)
+
+#define NI_PRESCALE_OVL_CONTROL                        0x1a31
+#       define NI_OVL_PRESCALE_BYPASS                  (1 << 4)
+
+#define NI_INPUT_GAMMA_CONTROL                         0x1a10
+#       define NI_GRPH_INPUT_GAMMA_MODE(x)             (((x) & 0x3) << 0)
+#       define NI_INPUT_GAMMA_USE_LUT                  0
+#       define NI_INPUT_GAMMA_BYPASS                   1
+#       define NI_INPUT_GAMMA_SRGB_24                  2
+#       define NI_INPUT_GAMMA_XVYCC_222                3
+#       define NI_OVL_INPUT_GAMMA_MODE(x)              (((x) & 0x3) << 4)
+
+#define IH_RB_WPTR__RB_OVERFLOW_MASK   0x1
+#define IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK 0x80000000
+#define SRBM_STATUS__IH_BUSY_MASK      0x20000
+#define SRBM_SOFT_RESET__SOFT_RESET_IH_MASK    0x400
+
+#define        BLACKOUT_MODE_MASK                      0x00000007
+#define        VGA_RENDER_CONTROL                      0xC0
+#define R_000300_VGA_RENDER_CONTROL             0xC0
+#define C_000300_VGA_VSTATUS_CNTL               0xFFFCFFFF
+#define EVERGREEN_CRTC_STATUS                   0x1BA3
+#define EVERGREEN_CRTC_V_BLANK                  (1 << 0)
+#define EVERGREEN_CRTC_STATUS_POSITION          0x1BA4
+/* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */
+#define EVERGREEN_CRTC_V_BLANK_START_END                0x1b8d
+#define EVERGREEN_CRTC_CONTROL                          0x1b9c
+#       define EVERGREEN_CRTC_MASTER_EN                 (1 << 0)
+#       define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24)
+#define EVERGREEN_CRTC_BLANK_CONTROL                    0x1b9d
+#       define EVERGREEN_CRTC_BLANK_DATA_EN             (1 << 8)
+#       define EVERGREEN_CRTC_V_BLANK                   (1 << 0)
+#define EVERGREEN_CRTC_STATUS_HV_COUNT                  0x1ba8
+#define EVERGREEN_CRTC_UPDATE_LOCK                      0x1bb5
+#define EVERGREEN_MASTER_UPDATE_LOCK                    0x1bbd
+#define EVERGREEN_MASTER_UPDATE_MODE                    0x1bbe
+#define EVERGREEN_GRPH_UPDATE_LOCK               (1 << 16)
+#define EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH     0x1a07
+#define EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH   0x1a08
+#define EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS          0x1a04
+#define EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS        0x1a05
+#define EVERGREEN_GRPH_UPDATE                           0x1a11
+#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS               0xc4
+#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH          0xc9
+#define EVERGREEN_GRPH_SURFACE_UPDATE_PENDING    (1 << 2)
+
+#define mmVM_CONTEXT1_CNTL__xxRANGE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK 0x10
+#define mmVM_CONTEXT1_CNTL__xxRANGE_PROTECTION_FAULT_ENABLE_DEFAULT__SHIFT 0x4
+#define mmVM_CONTEXT1_CNTL__xxDUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK 0x80
+#define mmVM_CONTEXT1_CNTL__xxDUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT__SHIFT 0x7
+#define mmVM_CONTEXT1_CNTL__xxPDE0_PROTECTION_FAULT_ENABLE_DEFAULT_MASK 0x400
+#define mmVM_CONTEXT1_CNTL__xxPDE0_PROTECTION_FAULT_ENABLE_DEFAULT__SHIFT 0xa
+#define mmVM_CONTEXT1_CNTL__xxVALID_PROTECTION_FAULT_ENABLE_DEFAULT_MASK 0x2000
+#define mmVM_CONTEXT1_CNTL__xxVALID_PROTECTION_FAULT_ENABLE_DEFAULT__SHIFT 0xd
+#define mmVM_CONTEXT1_CNTL__xxREAD_PROTECTION_FAULT_ENABLE_DEFAULT_MASK 0x10000
+#define mmVM_CONTEXT1_CNTL__xxREAD_PROTECTION_FAULT_ENABLE_DEFAULT__SHIFT 0x10
+#define mmVM_CONTEXT1_CNTL__xxWRITE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK 0x80000
+#define mmVM_CONTEXT1_CNTL__xxWRITE_PROTECTION_FAULT_ENABLE_DEFAULT__SHIFT 0x13
+
+#define mmVM_CONTEXT1_PROTECTION_FAULT_STATUS__xxVMID_MASK 0x1e000000
+#define mmVM_CONTEXT1_PROTECTION_FAULT_STATUS__xxVMID__SHIFT 0x19
+#define mmVM_CONTEXT1_PROTECTION_FAULT_STATUS__xxPROTECTIONS_MASK 0xff
+#define mmVM_CONTEXT1_PROTECTION_FAULT_STATUS__xxPROTECTIONS__SHIFT 0x0
+#define mmVM_CONTEXT1_PROTECTION_FAULT_STATUS__xxMEMORY_CLIENT_ID_MASK 0xff000
+#define mmVM_CONTEXT1_PROTECTION_FAULT_STATUS__xxMEMORY_CLIENT_ID__SHIFT 0xc
+#define mmVM_CONTEXT1_PROTECTION_FAULT_STATUS__xxMEMORY_CLIENT_RW_MASK 0x1000000
+#define mmVM_CONTEXT1_PROTECTION_FAULT_STATUS__xxMEMORY_CLIENT_RW__SHIFT 0x18
+
+#define mmMC_SHARED_BLACKOUT_CNTL__xxBLACKOUT_MODE_MASK 0x7
+#define mmMC_SHARED_BLACKOUT_CNTL__xxBLACKOUT_MODE__SHIFT 0x0
+
+#define mmBIF_FB_EN__xxFB_READ_EN_MASK 0x1
+#define mmBIF_FB_EN__xxFB_READ_EN__SHIFT 0x0
+#define mmBIF_FB_EN__xxFB_WRITE_EN_MASK 0x2
+#define mmBIF_FB_EN__xxFB_WRITE_EN__SHIFT 0x1
+
+#define mmSRBM_SOFT_RESET__xxSOFT_RESET_VMC_MASK 0x20000
+#define mmSRBM_SOFT_RESET__xxSOFT_RESET_VMC__SHIFT 0x11
+#define mmSRBM_SOFT_RESET__xxSOFT_RESET_MC_MASK 0x800
+#define mmSRBM_SOFT_RESET__xxSOFT_RESET_MC__SHIFT 0xb
+
+#define VM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK 0x8
+#define VM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT__SHIFT 0x3
+#define VM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK 0x40
+#define VM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT__SHIFT 0x6
+#define VM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK 0x200
+#define VM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT__SHIFT 0x9
+#define VM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK 0x1000
+#define VM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT__SHIFT 0xc
+#define VM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK 0x8000
+#define VM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT__SHIFT 0xf
+#define VM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK 0x40000
+#define VM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT__SHIFT 0x12
+
+#define MC_SEQ_MISC0__MT__MASK 0xf0000000
+#define MC_SEQ_MISC0__MT__GDDR1  0x10000000
+#define MC_SEQ_MISC0__MT__DDR2   0x20000000
+#define MC_SEQ_MISC0__MT__GDDR3  0x30000000
+#define MC_SEQ_MISC0__MT__GDDR4  0x40000000
+#define MC_SEQ_MISC0__MT__GDDR5  0x50000000
+#define MC_SEQ_MISC0__MT__HBM    0x60000000
+#define MC_SEQ_MISC0__MT__DDR3   0xB0000000
+
+#define SRBM_STATUS__MCB_BUSY_MASK 0x200
+#define SRBM_STATUS__MCB_BUSY__SHIFT 0x9
+#define SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK 0x400
+#define SRBM_STATUS__MCB_NON_DISPLAY_BUSY__SHIFT 0xa
+#define SRBM_STATUS__MCC_BUSY_MASK 0x800
+#define SRBM_STATUS__MCC_BUSY__SHIFT 0xb
+#define SRBM_STATUS__MCD_BUSY_MASK 0x1000
+#define SRBM_STATUS__MCD_BUSY__SHIFT 0xc
+#define SRBM_STATUS__VMC_BUSY_MASK 0x100
+#define SRBM_STATUS__VMC_BUSY__SHIFT 0x8
+
+
+#define GRBM_STATUS__GUI_ACTIVE_MASK 0x80000000
+#define CP_INT_CNTL_RING__TIME_STAMP_INT_ENABLE_MASK 0x4000000
+#define CP_INT_CNTL_RING0__PRIV_REG_INT_ENABLE_MASK 0x800000
+#define CP_INT_CNTL_RING0__PRIV_INSTR_INT_ENABLE_MASK 0x400000
+#define PACKET3_SEM_WAIT_ON_SIGNAL    (0x1 << 12)
+#define PACKET3_SEM_SEL_SIGNAL     (0x6 << 29)
+#define PACKET3_SEM_SEL_WAIT       (0x7 << 29)
+
+#define CONFIG_CNTL    0x1509
+#define CC_DRM_ID_STRAPS       0X1559
+#define AMDGPU_PCIE_INDEX      0xc
+#define AMDGPU_PCIE_DATA       0xd
+
+#define DMA_SEM_INCOMPLETE_TIMER_CNTL                     0x3411
+#define DMA_SEM_WAIT_FAIL_TIMER_CNTL                      0x3412
+#define DMA_MODE                                          0x342f
+#define DMA_RB_RPTR_ADDR_HI                               0x3407
+#define DMA_RB_RPTR_ADDR_LO                               0x3408
+#define DMA_BUSY_MASK 0x20
+#define DMA1_BUSY_MASK 0X40
+#define SDMA_MAX_INSTANCE 2
+
+#define PCIE_BUS_CLK    10000
+#define TCLK            (PCIE_BUS_CLK / 10)
+#define CC_DRM_ID_STRAPS__ATI_REV_ID_MASK              0xf0000000
+#define CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT 0x1c
+#define        PCIE_PORT_INDEX                                 0xe
+#define        PCIE_PORT_DATA                                  0xf
+#define EVERGREEN_PIF_PHY0_INDEX                        0x8
+#define EVERGREEN_PIF_PHY0_DATA                         0xc
+#define EVERGREEN_PIF_PHY1_INDEX                        0x10
+#define EVERGREEN_PIF_PHY1_DATA                                0x14
+
+#define        MC_VM_FB_OFFSET                                 0x81a
+
+#endif
index f3e53b1..19802e9 100644 (file)
@@ -34,6 +34,7 @@
 #define mmUVD_UDEC_ADDR_CONFIG                                                  0x3bd3
 #define mmUVD_UDEC_DB_ADDR_CONFIG                                               0x3bd4
 #define mmUVD_UDEC_DBW_ADDR_CONFIG                                              0x3bd5
+#define mmUVD_NO_OP                                                             0x3bff
 #define mmUVD_SEMA_CNTL                                                         0x3d00
 #define mmUVD_LMI_EXT40_ADDR                                                    0x3d26
 #define mmUVD_CTX_INDEX                                                         0x3d28
index eb4cf53..cc972d2 100644 (file)
@@ -34,6 +34,7 @@
 #define mmUVD_UDEC_ADDR_CONFIG                                                  0x3bd3
 #define mmUVD_UDEC_DB_ADDR_CONFIG                                               0x3bd4
 #define mmUVD_UDEC_DBW_ADDR_CONFIG                                              0x3bd5
+#define mmUVD_NO_OP                                                             0x3bff
 #define mmUVD_LMI_RBC_RB_64BIT_BAR_LOW                                          0x3c69
 #define mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH                                         0x3c68
 #define mmUVD_LMI_RBC_IB_64BIT_BAR_LOW                                          0x3c67
index ec69869..378f4b6 100644 (file)
@@ -35,6 +35,7 @@
 #define mmUVD_UDEC_DB_ADDR_CONFIG                                               0x3bd4
 #define mmUVD_UDEC_DBW_ADDR_CONFIG                                              0x3bd5
 #define mmUVD_POWER_STATUS_U                                                    0x3bfd
+#define mmUVD_NO_OP                                                             0x3bff
 #define mmUVD_LMI_RBC_RB_64BIT_BAR_LOW                                          0x3c69
 #define mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH                                         0x3c68
 #define mmUVD_LMI_RBC_IB_64BIT_BAR_LOW                                          0x3c67
index 3493da5..4a4d379 100644 (file)
@@ -494,6 +494,7 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3
   union
   {
     ATOM_COMPUTE_CLOCK_FREQ  ulClock;         //Input Parameter
+    ULONG ulClockParams;                      //ULONG access for BE
     ATOM_S_MPLL_FB_DIVIDER   ulFbDiv;         //Output Parameter
   };
   UCHAR   ucRefDiv;                           //Output Parameter
@@ -526,6 +527,7 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5
   union
   {
     ATOM_COMPUTE_CLOCK_FREQ  ulClock;         //Input Parameter
+    ULONG ulClockParams;                      //ULONG access for BE
     ATOM_S_MPLL_FB_DIVIDER   ulFbDiv;         //Output Parameter
   };
   UCHAR   ucRefDiv;                           //Output Parameter
old mode 100644 (file)
new mode 100755 (executable)
index b86aba9..df7c18b
@@ -119,6 +119,8 @@ enum cgs_system_info_id {
        CGS_SYSTEM_INFO_PG_FLAGS,
        CGS_SYSTEM_INFO_GFX_CU_INFO,
        CGS_SYSTEM_INFO_GFX_SE_INFO,
+       CGS_SYSTEM_INFO_PCIE_SUB_SYS_ID,
+       CGS_SYSTEM_INFO_PCIE_SUB_SYS_VENDOR_ID,
        CGS_SYSTEM_INFO_ID_MAXIMUM,
 };
 
@@ -159,6 +161,7 @@ struct cgs_clock_limits {
  */
 struct cgs_firmware_info {
        uint16_t                version;
+       uint16_t                fw_version;
        uint16_t                feature_version;
        uint32_t                image_size;
        uint64_t                mc_addr;
diff --git a/drivers/gpu/drm/amd/powerplay/Kconfig b/drivers/gpu/drm/amd/powerplay/Kconfig
deleted file mode 100644 (file)
index af38033..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-config DRM_AMD_POWERPLAY
-       bool  "Enable AMD powerplay component"
-       depends on DRM_AMDGPU
-       default n
-       help
-         select this option will enable AMD powerplay component.
index abbb658..7174f7a 100644 (file)
@@ -31,6 +31,7 @@
 #include "eventmanager.h"
 #include "pp_debug.h"
 
+
 #define PP_CHECK(handle)                                               \
        do {                                                            \
                if ((handle) == NULL || (handle)->pp_valid != PP_VALID) \
@@ -162,12 +163,12 @@ static int pp_hw_fini(void *handle)
        pp_handle = (struct pp_instance *)handle;
        eventmgr = pp_handle->eventmgr;
 
-       if (eventmgr != NULL || eventmgr->pp_eventmgr_fini != NULL)
+       if (eventmgr != NULL && eventmgr->pp_eventmgr_fini != NULL)
                eventmgr->pp_eventmgr_fini(eventmgr);
 
        smumgr = pp_handle->smu_mgr;
 
-       if (smumgr != NULL || smumgr->smumgr_funcs != NULL ||
+       if (smumgr != NULL && smumgr->smumgr_funcs != NULL &&
                smumgr->smumgr_funcs->smu_fini != NULL)
                smumgr->smumgr_funcs->smu_fini(smumgr);
 
@@ -190,11 +191,9 @@ static int pp_sw_reset(void *handle)
 }
 
 
-static int pp_set_clockgating_state(void *handle,
-                                   enum amd_clockgating_state state)
+int amd_set_clockgating_by_smu(void *handle, uint32_t msg_id)
 {
        struct pp_hwmgr  *hwmgr;
-       uint32_t msg_id, pp_state;
 
        if (handle == NULL)
                return -EINVAL;
@@ -208,76 +207,7 @@ static int pp_set_clockgating_state(void *handle,
                return 0;
        }
 
-       if (state == AMD_CG_STATE_UNGATE)
-               pp_state = 0;
-       else
-               pp_state = PP_STATE_CG | PP_STATE_LS;
-
-       /* Enable/disable GFX blocks clock gating through SMU */
-       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
-                       PP_BLOCK_GFX_CG,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
-                       PP_BLOCK_GFX_3D,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
-                       PP_BLOCK_GFX_RLC,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
-                       PP_BLOCK_GFX_CP,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
-                       PP_BLOCK_GFX_MG,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-
-       /* Enable/disable System blocks clock gating through SMU */
-       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
-                       PP_BLOCK_SYS_BIF,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
-                       PP_BLOCK_SYS_BIF,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
-                       PP_BLOCK_SYS_MC,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
-                       PP_BLOCK_SYS_ROM,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
-                       PP_BLOCK_SYS_DRM,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
-                       PP_BLOCK_SYS_HDP,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-       msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
-                       PP_BLOCK_SYS_SDMA,
-                       PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
-                       pp_state);
-       hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
-
-       return 0;
+       return hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
 }
 
 static int pp_set_powergating_state(void *handle,
@@ -361,7 +291,7 @@ const struct amd_ip_funcs pp_ip_funcs = {
        .is_idle = pp_is_idle,
        .wait_for_idle = pp_wait_for_idle,
        .soft_reset = pp_sw_reset,
-       .set_clockgating_state = pp_set_clockgating_state,
+       .set_clockgating_state = NULL,
        .set_powergating_state = pp_set_powergating_state,
 };
 
@@ -537,7 +467,6 @@ int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, void *input,
                ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
                break;
        case AMD_PP_EVENT_READJUST_POWER_STATE:
-               pp_handle->hwmgr->current_ps = pp_handle->hwmgr->boot_ps;
                ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
                break;
        default:
@@ -576,28 +505,6 @@ enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
        }
 }
 
-static void
-pp_debugfs_print_current_performance_level(void *handle,
-                                              struct seq_file *m)
-{
-       struct pp_hwmgr  *hwmgr;
-
-       if (handle == NULL)
-               return;
-
-       hwmgr = ((struct pp_instance *)handle)->hwmgr;
-
-       if (hwmgr == NULL || hwmgr->hwmgr_func == NULL)
-               return;
-
-       if (hwmgr->hwmgr_func->print_current_perforce_level == NULL) {
-               printk(KERN_INFO "%s was not implemented.\n", __func__);
-               return;
-       }
-
-       hwmgr->hwmgr_func->print_current_perforce_level(hwmgr, m);
-}
-
 static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
 {
        struct pp_hwmgr  *hwmgr;
@@ -764,15 +671,12 @@ static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
        PP_CHECK_HW(hwmgr);
 
        if (!hwmgr->hardcode_pp_table) {
-               hwmgr->hardcode_pp_table =
-                               kzalloc(hwmgr->soft_pp_table_size, GFP_KERNEL);
+               hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
+                                                  hwmgr->soft_pp_table_size,
+                                                  GFP_KERNEL);
 
                if (!hwmgr->hardcode_pp_table)
                        return -ENOMEM;
-
-               /* to avoid powerplay crash when hardcode pptable is empty */
-               memcpy(hwmgr->hardcode_pp_table, hwmgr->soft_pp_table,
-                               hwmgr->soft_pp_table_size);
        }
 
        memcpy(hwmgr->hardcode_pp_table, buf, size);
@@ -897,6 +801,25 @@ static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
        return hwmgr->hwmgr_func->set_mclk_od(hwmgr, value);
 }
 
+static int pp_dpm_read_sensor(void *handle, int idx, int32_t *value)
+{
+       struct pp_hwmgr *hwmgr;
+
+       if (!handle)
+               return -EINVAL;
+
+       hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+       PP_CHECK_HW(hwmgr);
+
+       if (hwmgr->hwmgr_func->read_sensor == NULL) {
+               printk(KERN_INFO "%s was not implemented.\n", __func__);
+               return 0;
+       }
+
+       return hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value);
+}
+
 const struct amd_powerplay_funcs pp_dpm_funcs = {
        .get_temperature = pp_dpm_get_temperature,
        .load_firmware = pp_dpm_load_fw,
@@ -909,7 +832,6 @@ const struct amd_powerplay_funcs pp_dpm_funcs = {
        .powergate_vce = pp_dpm_powergate_vce,
        .powergate_uvd = pp_dpm_powergate_uvd,
        .dispatch_tasks = pp_dpm_dispatch_tasks,
-       .print_current_performance_level = pp_debugfs_print_current_performance_level,
        .set_fan_control_mode = pp_dpm_set_fan_control_mode,
        .get_fan_control_mode = pp_dpm_get_fan_control_mode,
        .set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
@@ -923,6 +845,7 @@ const struct amd_powerplay_funcs pp_dpm_funcs = {
        .set_sclk_od = pp_dpm_set_sclk_od,
        .get_mclk_od = pp_dpm_get_mclk_od,
        .set_mclk_od = pp_dpm_set_mclk_od,
+       .read_sensor = pp_dpm_read_sensor,
 };
 
 static int amd_pp_instance_init(struct amd_pp_init *pp_init,
index 635fc4b..92b1178 100644 (file)
@@ -262,6 +262,8 @@ static const pem_event_action * const display_config_change_event[] = {
        unblock_adjust_power_state_tasks,
        set_cpu_power_state,
        notify_hw_power_source_tasks,
+       get_2d_performance_state_tasks,
+       set_performance_state_tasks,
        /* updateDALConfigurationTasks,
        variBrightDisplayConfigurationChangeTasks, */
        adjust_power_state_tasks,
index a46225c..4899088 100644 (file)
@@ -70,11 +70,12 @@ int psm_set_states(struct pp_eventmgr *eventmgr, unsigned long *state_id)
        int i;
 
        table_entries = hwmgr->num_ps;
+
        state = hwmgr->ps;
 
        for (i = 0; i < table_entries; i++) {
                if (state->id == *state_id) {
-                       hwmgr->request_ps = state;
+                       memcpy(hwmgr->request_ps, state, hwmgr->ps_size);
                        return 0;
                }
                state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
@@ -100,13 +101,14 @@ int psm_adjust_power_state_dynamic(struct pp_eventmgr *eventmgr, bool skip)
        if (requested == NULL)
                return 0;
 
+       phm_apply_state_adjust_rules(hwmgr, requested, pcurrent);
+
        if (pcurrent == NULL || (0 != phm_check_states_equal(hwmgr, &pcurrent->hardware, &requested->hardware, &equal)))
                equal = false;
 
        if (!equal || phm_check_smc_update_required_for_display_configuration(hwmgr)) {
-               phm_apply_state_adjust_rules(hwmgr, requested, pcurrent);
                phm_set_power_state(hwmgr, &pcurrent->hardware, &requested->hardware);
-               hwmgr->current_ps = requested;
+               memcpy(hwmgr->current_ps, hwmgr->request_ps, hwmgr->ps_size);
        }
        return 0;
 }
index f7ce4cb..5fff1d6 100644 (file)
@@ -3,14 +3,12 @@
 # It provides the hardware management services for the driver.
 
 HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \
-              hardwaremanager.o pp_acpi.o cz_hwmgr.o \
-               cz_clockpowergating.o \
-              tonga_processpptables.o ppatomctrl.o \
-               tonga_hwmgr.o pppcielanes.o  tonga_thermal.o\
-               fiji_powertune.o fiji_hwmgr.o tonga_clockpowergating.o \
-               fiji_clockpowergating.o fiji_thermal.o \
-              polaris10_hwmgr.o polaris10_powertune.o polaris10_thermal.o \
-              polaris10_clockpowergating.o
+               hardwaremanager.o pp_acpi.o cz_hwmgr.o \
+               cz_clockpowergating.o pppcielanes.o\
+               process_pptables_v1_0.o ppatomctrl.o \
+               smu7_hwmgr.o smu7_powertune.o smu7_thermal.o \
+               smu7_clockpowergating.o
+
 
 AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR))
 
index 8cc0df9..7e4fcbb 100644 (file)
@@ -178,7 +178,6 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
        int result;
 
        cz_hwmgr->gfx_ramp_step = 256*25/100;
-
        cz_hwmgr->gfx_ramp_delay = 1; /* by default, we delay 1us */
 
        for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++)
@@ -186,33 +185,19 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
 
        cz_hwmgr->mgcg_cgtt_local0 = 0x00000000;
        cz_hwmgr->mgcg_cgtt_local1 = 0x00000000;
-
        cz_hwmgr->clock_slow_down_freq = 25000;
-
        cz_hwmgr->skip_clock_slow_down = 1;
-
        cz_hwmgr->enable_nb_ps_policy = 1; /* disable until UNB is ready, Enabled */
-
        cz_hwmgr->voltage_drop_in_dce_power_gating = 0; /* disable until fully verified */
-
        cz_hwmgr->voting_rights_clients = 0x00C00033;
-
        cz_hwmgr->static_screen_threshold = 8;
-
        cz_hwmgr->ddi_power_gating_disabled = 0;
-
        cz_hwmgr->bapm_enabled = 1;
-
        cz_hwmgr->voltage_drop_threshold = 0;
-
        cz_hwmgr->gfx_power_gating_threshold = 500;
-
        cz_hwmgr->vce_slow_sclk_threshold = 20000;
-
        cz_hwmgr->dce_slow_sclk_threshold = 30000;
-
        cz_hwmgr->disable_driver_thermal_policy = 1;
-
        cz_hwmgr->disable_nb_ps3_in_battery = 0;
 
        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
@@ -221,9 +206,6 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
                                    PHM_PlatformCaps_NonABMSupportInPPLib);
 
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                          PHM_PlatformCaps_SclkDeepSleep);
-
        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
                                        PHM_PlatformCaps_DynamicM3Arbiter);
 
@@ -233,9 +215,7 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
                                  PHM_PlatformCaps_DynamicPatchPowerState);
 
        cz_hwmgr->thermal_auto_throttling_treshold = 0;
-
        cz_hwmgr->tdr_clock = 0;
-
        cz_hwmgr->disable_gfx_power_gating_in_uvd = 0;
 
        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
@@ -450,19 +430,12 @@ static int cz_construct_boot_state(struct pp_hwmgr *hwmgr)
                        (uint8_t)cz_hwmgr->sys_info.bootup_nb_voltage_index;
 
        cz_hwmgr->boot_power_level.dsDividerIndex = 0;
-
        cz_hwmgr->boot_power_level.ssDividerIndex = 0;
-
        cz_hwmgr->boot_power_level.allowGnbSlow = 1;
-
        cz_hwmgr->boot_power_level.forceNBPstate = 0;
-
        cz_hwmgr->boot_power_level.hysteresis_up = 0;
-
        cz_hwmgr->boot_power_level.numSIMDToPowerDown = 0;
-
        cz_hwmgr->boot_power_level.display_wm = 0;
-
        cz_hwmgr->boot_power_level.vce_wm = 0;
 
        return 0;
@@ -749,7 +722,6 @@ static int cz_tf_update_sclk_limit(struct pp_hwmgr *hwmgr,
                cz_hwmgr->sclk_dpm.soft_max_clk  = table->entries[table->count - 1].clk;
 
        clock = hwmgr->display_config.min_core_set_clock;
-;
        if (clock == 0)
                printk(KERN_INFO "[ powerplay ] min_core_set_clock not set\n");
 
@@ -832,7 +804,7 @@ static int cz_tf_set_watermark_threshold(struct pp_hwmgr *hwmgr,
 
        smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
                                        PPSMC_MSG_SetWatermarkFrequency,
-                                     cz_hwmgr->sclk_dpm.soft_max_clk);
+                                       cz_hwmgr->sclk_dpm.soft_max_clk);
 
        return 0;
 }
@@ -858,9 +830,9 @@ static int cz_tf_enable_nb_dpm(struct pp_hwmgr *hwmgr,
                PP_DBG_LOG("enabling ALL SMU features.\n");
                dpm_features |= NB_DPM_MASK;
                ret = smum_send_msg_to_smc_with_parameter(
-                                                            hwmgr->smumgr,
-                                        PPSMC_MSG_EnableAllSmuFeatures,
-                                                            dpm_features);
+                                                         hwmgr->smumgr,
+                                                         PPSMC_MSG_EnableAllSmuFeatures,
+                                                         dpm_features);
                if (ret == 0)
                        cz_hwmgr->is_nb_dpm_enabled = true;
        }
@@ -1246,7 +1218,7 @@ 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 && hwmgr->backend != NULL) {
                kfree(hwmgr->backend);
                kfree(hwmgr);
        }
@@ -1402,10 +1374,12 @@ int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
                                                   PPSMC_MSG_SetUvdHardMin));
 
                        cz_enable_disable_uvd_dpm(hwmgr, true);
-               } else
+               } else {
                        cz_enable_disable_uvd_dpm(hwmgr, true);
-       } else
+               }
+       } else {
                cz_enable_disable_uvd_dpm(hwmgr, false);
+       }
 
        return 0;
 }
@@ -1564,78 +1538,6 @@ int cz_get_power_state_size(struct pp_hwmgr *hwmgr)
        return sizeof(struct cz_power_state);
 }
 
-static void
-cz_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
-{
-       struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
-
-       struct phm_clock_voltage_dependency_table *table =
-                               hwmgr->dyn_state.vddc_dependency_on_sclk;
-
-       struct phm_vce_clock_voltage_dependency_table *vce_table =
-               hwmgr->dyn_state.vce_clock_voltage_dependency_table;
-
-       struct phm_uvd_clock_voltage_dependency_table *uvd_table =
-               hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
-
-       uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
-                                       TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
-       uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
-                                       TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
-       uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
-                                       TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
-
-       uint32_t sclk, vclk, dclk, ecclk, tmp, activity_percent;
-       uint16_t vddnb, vddgfx;
-       int result;
-
-       if (sclk_index >= NUM_SCLK_LEVELS) {
-               seq_printf(m, "\n invalid sclk dpm profile %d\n", sclk_index);
-       } else {
-               sclk = table->entries[sclk_index].clk;
-               seq_printf(m, "\n index: %u sclk: %u MHz\n", sclk_index, sclk/100);
-       }
-
-       tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
-               CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
-       vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp);
-       tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
-               CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
-       vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp);
-       seq_printf(m, "\n vddnb: %u vddgfx: %u\n", vddnb, vddgfx);
-
-       seq_printf(m, "\n uvd    %sabled\n", cz_hwmgr->uvd_power_gated ? "dis" : "en");
-       if (!cz_hwmgr->uvd_power_gated) {
-               if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
-                       seq_printf(m, "\n 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, "\n index: %u uvd vclk: %u MHz dclk: %u MHz\n", uvd_index, vclk/100, dclk/100);
-               }
-       }
-
-       seq_printf(m, "\n vce    %sabled\n", cz_hwmgr->vce_power_gated ? "dis" : "en");
-       if (!cz_hwmgr->vce_power_gated) {
-               if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
-                       seq_printf(m, "\n invalid vce dpm level %d\n", vce_index);
-               } else {
-                       ecclk = vce_table->entries[vce_index].ecclk;
-                       seq_printf(m, "\n index: %u vce ecclk: %u MHz\n", vce_index, ecclk/100);
-               }
-       }
-
-       result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetAverageGraphicsActivity);
-       if (0 == result) {
-               activity_percent = cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0);
-               activity_percent = activity_percent > 100 ? 100 : activity_percent;
-       } else {
-               activity_percent = 50;
-       }
-
-       seq_printf(m, "\n [GPU load]: %u %%\n\n", activity_percent);
-}
-
 static void cz_hw_print_display_cfg(
        const struct cc6_settings *cc6_settings)
 {
@@ -1690,13 +1592,10 @@ static int cz_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time,
        struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
 
        if (separation_time !=
-               hw_data->cc6_settings.cpu_pstate_separation_time
-               || cc6_disable !=
-               hw_data->cc6_settings.cpu_cc6_disable
-               || pstate_disable !=
-               hw_data->cc6_settings.cpu_pstate_disable
-               || pstate_switch_disable !=
-               hw_data->cc6_settings.nb_pstate_switch_disable) {
+           hw_data->cc6_settings.cpu_pstate_separation_time ||
+           cc6_disable != hw_data->cc6_settings.cpu_cc6_disable ||
+           pstate_disable != hw_data->cc6_settings.cpu_pstate_disable ||
+           pstate_switch_disable != hw_data->cc6_settings.nb_pstate_switch_disable) {
 
                hw_data->cc6_settings.cc6_setting_changed = true;
 
@@ -1799,8 +1698,7 @@ static int cz_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_p
        ps = cast_const_PhwCzPowerState(state);
 
        level_index = index > ps->level - 1 ? ps->level - 1 : index;
-
-       level->coreClock  = ps->levels[level_index].engineClock;
+       level->coreClock = ps->levels[level_index].engineClock;
 
        if (designation == PHM_PerformanceLevelDesignation_PowerContainment) {
                for (i = 1; i < ps->level; i++) {
@@ -1887,6 +1785,107 @@ static int cz_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_c
        return 0;
 }
 
+static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value)
+{
+       struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+       struct phm_clock_voltage_dependency_table *table =
+                               hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+       struct phm_vce_clock_voltage_dependency_table *vce_table =
+               hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+
+       struct phm_uvd_clock_voltage_dependency_table *uvd_table =
+               hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+
+       uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
+                                       TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
+       uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+                                       TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
+       uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+                                       TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
+
+       uint32_t sclk, vclk, dclk, ecclk, tmp, activity_percent;
+       uint16_t vddnb, vddgfx;
+       int result;
+
+       switch (idx) {
+       case AMDGPU_PP_SENSOR_GFX_SCLK:
+               if (sclk_index < NUM_SCLK_LEVELS) {
+                       sclk = table->entries[sclk_index].clk;
+                       *value = sclk;
+                       return 0;
+               }
+               return -EINVAL;
+       case AMDGPU_PP_SENSOR_VDDNB:
+               tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
+                       CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
+               vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp);
+               *value = vddnb;
+               return 0;
+       case AMDGPU_PP_SENSOR_VDDGFX:
+               tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
+                       CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
+               vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp);
+               *value = vddgfx;
+               return 0;
+       case AMDGPU_PP_SENSOR_UVD_VCLK:
+               if (!cz_hwmgr->uvd_power_gated) {
+                       if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+                               return -EINVAL;
+                       } else {
+                               vclk = uvd_table->entries[uvd_index].vclk;
+                               *value = vclk;
+                               return 0;
+                       }
+               }
+               *value = 0;
+               return 0;
+       case AMDGPU_PP_SENSOR_UVD_DCLK:
+               if (!cz_hwmgr->uvd_power_gated) {
+                       if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+                               return -EINVAL;
+                       } else {
+                               dclk = uvd_table->entries[uvd_index].dclk;
+                               *value = dclk;
+                               return 0;
+                       }
+               }
+               *value = 0;
+               return 0;
+       case AMDGPU_PP_SENSOR_VCE_ECCLK:
+               if (!cz_hwmgr->vce_power_gated) {
+                       if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+                               return -EINVAL;
+                       } else {
+                               ecclk = vce_table->entries[vce_index].ecclk;
+                               *value = ecclk;
+                               return 0;
+                       }
+               }
+               *value = 0;
+               return 0;
+       case AMDGPU_PP_SENSOR_GPU_LOAD:
+               result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetAverageGraphicsActivity);
+               if (0 == result) {
+                       activity_percent = cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0);
+                       activity_percent = activity_percent > 100 ? 100 : activity_percent;
+               } else {
+                       activity_percent = 50;
+               }
+               *value = activity_percent;
+               return 0;
+       case AMDGPU_PP_SENSOR_UVD_POWER:
+               *value = cz_hwmgr->uvd_power_gated ? 0 : 1;
+               return 0;
+       case AMDGPU_PP_SENSOR_VCE_POWER:
+               *value = cz_hwmgr->vce_power_gated ? 0 : 1;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 static const struct pp_hwmgr_func cz_hwmgr_funcs = {
        .backend_init = cz_hwmgr_backend_init,
        .backend_fini = cz_hwmgr_backend_fini,
@@ -1902,7 +1901,6 @@ static const struct pp_hwmgr_func cz_hwmgr_funcs = {
        .patch_boot_state = cz_dpm_patch_boot_state,
        .get_pp_table_entry = cz_dpm_get_pp_table_entry,
        .get_num_of_pp_table_entries = cz_dpm_get_num_of_pp_table_entries,
-       .print_current_perforce_level = cz_print_current_perforce_level,
        .set_cpu_power_state = cz_set_cpu_power_state,
        .store_cc6_data = cz_store_cc6_data,
        .force_clock_level = cz_force_clock_level,
@@ -1912,6 +1910,7 @@ static const struct pp_hwmgr_func cz_hwmgr_funcs = {
        .get_current_shallow_sleep_clocks = cz_get_current_shallow_sleep_clocks,
        .get_clock_by_type = cz_get_clock_by_type,
        .get_max_high_clocks = cz_get_max_high_clocks,
+       .read_sensor = cz_read_sensor,
 };
 
 int cz_hwmgr_init(struct pp_hwmgr *hwmgr)
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c
deleted file mode 100644 (file)
index 5afe820..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2015 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 "hwmgr.h"
-#include "fiji_clockpowergating.h"
-#include "fiji_ppsmc.h"
-#include "fiji_hwmgr.h"
-
-int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       data->uvd_power_gated = false;
-       data->vce_power_gated = false;
-       data->samu_power_gated = false;
-       data->acp_power_gated = false;
-
-       return 0;
-}
-
-int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (data->uvd_power_gated == bgate)
-               return 0;
-
-       data->uvd_power_gated = bgate;
-
-       if (bgate) {
-               cgs_set_clockgating_state(hwmgr->device,
-                                         AMD_IP_BLOCK_TYPE_UVD,
-                                         AMD_CG_STATE_GATE);
-               fiji_update_uvd_dpm(hwmgr, true);
-       } else {
-               fiji_update_uvd_dpm(hwmgr, false);
-               cgs_set_clockgating_state(hwmgr->device,
-                                         AMD_IP_BLOCK_TYPE_UVD,
-                                         AMD_CG_STATE_UNGATE);
-       }
-
-       return 0;
-}
-
-int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_set_power_state_input states;
-       const struct pp_power_state  *pcurrent;
-       struct pp_power_state  *requested;
-
-       if (data->vce_power_gated == bgate)
-               return 0;
-
-       data->vce_power_gated = bgate;
-
-       pcurrent = hwmgr->current_ps;
-       requested = hwmgr->request_ps;
-
-       states.pcurrent_state = &(pcurrent->hardware);
-       states.pnew_state = &(requested->hardware);
-
-       fiji_update_vce_dpm(hwmgr, &states);
-       fiji_enable_disable_vce_dpm(hwmgr, !bgate);
-
-       return 0;
-}
-
-int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (data->samu_power_gated == bgate)
-               return 0;
-
-       data->samu_power_gated = bgate;
-
-       if (bgate)
-               fiji_update_samu_dpm(hwmgr, true);
-       else
-               fiji_update_samu_dpm(hwmgr, false);
-
-       return 0;
-}
-
-int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (data->acp_power_gated == bgate)
-               return 0;
-
-       data->acp_power_gated = bgate;
-
-       if (bgate)
-               fiji_update_acp_dpm(hwmgr, true);
-       else
-               fiji_update_acp_dpm(hwmgr, false);
-
-       return 0;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h
deleted file mode 100644 (file)
index 33af5f5..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2015 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 _FIJI_CLOCK_POWER_GATING_H_
-#define _FIJI_CLOCK_POWER_GATING_H_
-
-#include "fiji_hwmgr.h"
-#include "pp_asicblocks.h"
-
-extern int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
-extern int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
-extern int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
-extern int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
-extern int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
-#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h
deleted file mode 100644 (file)
index 32d43e8..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2015 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 FIJI_DYN_DEFAULTS_H
-#define FIJI_DYN_DEFAULTS_H
-
-/** \file
-* Volcanic Islands Dynamic default parameters.
-*/
-
-enum FIJIdpm_TrendDetection
-{
-    FIJIAdpm_TrendDetection_AUTO,
-    FIJIAdpm_TrendDetection_UP,
-    FIJIAdpm_TrendDetection_DOWN
-};
-typedef enum FIJIdpm_TrendDetection FIJIdpm_TrendDetection;
-
-/* We need to fill in the default values!!!!!!!!!!!!!!!!!!!!!!! */
-
-/* Bit vector representing same fields as hardware register. */
-#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0    0x3FFFC102  /* CP_Gfx_busy ????
-                                                         * HDP_busy
-                                                         * IH_busy
-                                                         * UVD_busy
-                                                         * VCE_busy
-                                                         * ACP_busy
-                                                         * SAMU_busy
-                                                         * SDMA enabled */
-#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1    0x000400  /* FE_Gfx_busy  - Intended for primary usage.   Rest are for flexibility. ????
-                                                       * SH_Gfx_busy
-                                                       * RB_Gfx_busy
-                                                       * VCE_busy */
-
-#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2    0xC00080  /* SH_Gfx_busy - Intended for primary usage.   Rest are for flexibility.
-                                                       * FE_Gfx_busy
-                                                       * RB_Gfx_busy
-                                                       * ACP_busy */
-
-#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3    0xC00200  /* RB_Gfx_busy - Intended for primary usage.   Rest are for flexibility.
-                                                       * FE_Gfx_busy
-                                                       * SH_Gfx_busy
-                                                       * UVD_busy */
-
-#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4    0xC01680  /* UVD_busy
-                                                       * VCE_busy
-                                                       * ACP_busy
-                                                       * SAMU_busy */
-
-#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5    0xC00033  /* GFX, HDP */
-#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6    0xC00033  /* GFX, HDP */
-#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7    0x3FFFC000  /* GFX, HDP */
-
-
-/* thermal protection counter (units). */
-#define PPFIJI_THERMALPROTECTCOUNTER_DFLT            0x200 /* ~19us */
-
-/* static screen threshold unit */
-#define PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT    0
-
-/* static screen threshold */
-#define PPFIJI_STATICSCREENTHRESHOLD_DFLT        0x00C8
-
-/* gfx idle clock stop threshold */
-#define PPFIJI_GFXIDLECLOCKSTOPTHRESHOLD_DFLT        0x200 /* ~19us with static screen threshold unit of 0 */
-
-/* Fixed reference divider to use when building baby stepping tables. */
-#define PPFIJI_REFERENCEDIVIDER_DFLT                  4
-
-/* ULV voltage change delay time
- * Used to be delay_vreg in N.I. split for S.I.
- * Using N.I. delay_vreg value as default
- * ReferenceClock = 2700
- * VoltageResponseTime = 1000
- * VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
- */
-#define PPFIJI_ULVVOLTAGECHANGEDELAY_DFLT             1687
-
-#define PPFIJI_CGULVPARAMETER_DFLT                     0x00040035
-#define PPFIJI_CGULVCONTROL_DFLT                       0x00007450
-#define PPFIJI_TARGETACTIVITY_DFLT                     30 /* 30%*/
-#define PPFIJI_MCLK_TARGETACTIVITY_DFLT                10 /* 10% */
-
-#endif
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c
deleted file mode 100644 (file)
index 120a9e2..0000000
+++ /dev/null
@@ -1,5599 +0,0 @@
-/*
- * Copyright 2015 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/module.h>
-#include <linux/slab.h>
-#include <linux/fb.h>
-#include "linux/delay.h"
-
-#include "hwmgr.h"
-#include "fiji_smumgr.h"
-#include "atombios.h"
-#include "hardwaremanager.h"
-#include "ppatomctrl.h"
-#include "atombios.h"
-#include "cgs_common.h"
-#include "fiji_dyn_defaults.h"
-#include "fiji_powertune.h"
-#include "smu73.h"
-#include "smu/smu_7_1_3_d.h"
-#include "smu/smu_7_1_3_sh_mask.h"
-#include "gmc/gmc_8_1_d.h"
-#include "gmc/gmc_8_1_sh_mask.h"
-#include "bif/bif_5_0_d.h"
-#include "bif/bif_5_0_sh_mask.h"
-#include "dce/dce_10_0_d.h"
-#include "dce/dce_10_0_sh_mask.h"
-#include "pppcielanes.h"
-#include "fiji_hwmgr.h"
-#include "tonga_processpptables.h"
-#include "tonga_pptable.h"
-#include "pp_debug.h"
-#include "pp_acpi.h"
-#include "amd_pcie_helpers.h"
-#include "cgs_linux.h"
-#include "ppinterrupt.h"
-
-#include "fiji_clockpowergating.h"
-#include "fiji_thermal.h"
-
-#define VOLTAGE_SCALE  4
-#define SMC_RAM_END            0x40000
-#define VDDC_VDDCI_DELTA       300
-
-#define MC_SEQ_MISC0_GDDR5_SHIFT 28
-#define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
-#define MC_SEQ_MISC0_GDDR5_VALUE 5
-
-#define MC_CG_ARB_FREQ_F0           0x0a /* boot-up default */
-#define MC_CG_ARB_FREQ_F1           0x0b
-#define MC_CG_ARB_FREQ_F2           0x0c
-#define MC_CG_ARB_FREQ_F3           0x0d
-
-/* From smc_reg.h */
-#define SMC_CG_IND_START            0xc0030000
-#define SMC_CG_IND_END              0xc0040000  /* First byte after SMC_CG_IND */
-
-#define VOLTAGE_SCALE               4
-#define VOLTAGE_VID_OFFSET_SCALE1   625
-#define VOLTAGE_VID_OFFSET_SCALE2   100
-
-#define VDDC_VDDCI_DELTA            300
-
-#define ixSWRST_COMMAND_1           0x1400103
-#define MC_SEQ_CNTL__CAC_EN_MASK    0x40000000
-
-/** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
-enum DPM_EVENT_SRC {
-    DPM_EVENT_SRC_ANALOG = 0,               /* Internal analog trip point */
-    DPM_EVENT_SRC_EXTERNAL = 1,             /* External (GPIO 17) signal */
-    DPM_EVENT_SRC_DIGITAL = 2,              /* Internal digital trip point (DIG_THERM_DPM) */
-    DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,   /* Internal analog or external */
-    DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4   /* Internal digital or external */
-};
-
-
-/* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
- * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
- */
-static const uint16_t fiji_clock_stretcher_lookup_table[2][4] =
-{ {600, 1050, 3, 0}, {600, 1050, 6, 1} };
-
-/* [FF, SS] type, [] 4 voltage ranges, and
- * [Floor Freq, Boundary Freq, VID min , VID max]
- */
-static const uint32_t fiji_clock_stretcher_ddt_table[2][4][4] =
-{ { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
-  { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
-
-/* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
- * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
- */
-static const uint8_t fiji_clock_stretch_amount_conversion[2][6] =
-{ {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
-
-static const unsigned long PhwFiji_Magic = (unsigned long)(PHM_VIslands_Magic);
-
-struct fiji_power_state *cast_phw_fiji_power_state(
-                                 struct pp_hw_power_state *hw_ps)
-{
-       PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
-                               "Invalid Powerstate Type!",
-                                return NULL;);
-
-       return (struct fiji_power_state *)hw_ps;
-}
-
-const struct fiji_power_state *cast_const_phw_fiji_power_state(
-                                const struct pp_hw_power_state *hw_ps)
-{
-       PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
-                               "Invalid Powerstate Type!",
-                                return NULL;);
-
-       return (const struct fiji_power_state *)hw_ps;
-}
-
-static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr)
-{
-       return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
-                       CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
-                       ? true : false;
-}
-
-static void fiji_init_dpm_defaults(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_ulv_parm *ulv = &data->ulv;
-
-       ulv->cg_ulv_parameter = PPFIJI_CGULVPARAMETER_DFLT;
-       data->voting_rights_clients0 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0;
-       data->voting_rights_clients1 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1;
-       data->voting_rights_clients2 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2;
-       data->voting_rights_clients3 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3;
-       data->voting_rights_clients4 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4;
-       data->voting_rights_clients5 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5;
-       data->voting_rights_clients6 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6;
-       data->voting_rights_clients7 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7;
-
-       data->static_screen_threshold_unit =
-                       PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT;
-       data->static_screen_threshold =
-                       PPFIJI_STATICSCREENTHRESHOLD_DFLT;
-
-       /* Unset ABM cap as it moved to DAL.
-        * Add PHM_PlatformCaps_NonABMSupportInPPLib
-        * for re-direct ABM related request to DAL
-        */
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ABM);
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_NonABMSupportInPPLib);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_DynamicACTiming);
-
-       fiji_initialize_power_tune_defaults(hwmgr);
-
-       data->mclk_stutter_mode_threshold = 60000;
-       data->pcie_gen_performance.max = PP_PCIEGen1;
-       data->pcie_gen_performance.min = PP_PCIEGen3;
-       data->pcie_gen_power_saving.max = PP_PCIEGen1;
-       data->pcie_gen_power_saving.min = PP_PCIEGen3;
-       data->pcie_lane_performance.max = 0;
-       data->pcie_lane_performance.min = 16;
-       data->pcie_lane_power_saving.max = 0;
-       data->pcie_lane_power_saving.min = 16;
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_DynamicUVDState);
-}
-
-static int fiji_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)
-{
-       uint8_t entryId;
-       uint8_t voltageId;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
-
-       /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
-       for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) {
-               voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd;
-               if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
-                       break;
-       }
-
-       PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count,
-                       "Can't find requested voltage id in vdd_dep_on_sclk table!",
-                       return -EINVAL;
-                       );
-
-       *sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk;
-
-       return 0;
-}
-
-/**
-* Get Leakage VDDC based on leakage ID.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int fiji_get_evv_voltages(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint16_t    vv_id;
-       uint16_t    vddc = 0;
-       uint16_t    evv_default = 1150;
-       uint16_t    i, j;
-       uint32_t  sclk = 0;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)hwmgr->pptable;
-       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
-                       table_info->vdd_dep_on_sclk;
-       int result;
-
-       for (i = 0; i < FIJI_MAX_LEAKAGE_COUNT; i++) {
-               vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
-               if (!fiji_get_sclk_for_voltage_evv(hwmgr,
-                               table_info->vddc_lookup_table, vv_id, &sclk)) {
-                       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_ClockStretcher)) {
-                               for (j = 1; j < sclk_table->count; j++) {
-                                       if (sclk_table->entries[j].clk == sclk &&
-                                                       sclk_table->entries[j].cks_enable == 0) {
-                                               sclk += 5000;
-                                               break;
-                                       }
-                               }
-                       }
-
-                       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_EnableDriverEVV))
-                               result = atomctrl_calculate_voltage_evv_on_sclk(hwmgr,
-                                               VOLTAGE_TYPE_VDDC, sclk, vv_id, &vddc, i, true);
-                       else
-                               result = -EINVAL;
-
-                       if (result)
-                               result = atomctrl_get_voltage_evv_on_sclk(hwmgr,
-                                               VOLTAGE_TYPE_VDDC, sclk,vv_id, &vddc);
-
-                       /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
-                       PP_ASSERT_WITH_CODE((vddc < 2000),
-                                       "Invalid VDDC value, greater than 2v!", result = -EINVAL;);
-
-                       if (result)
-                               /* 1.15V is the default safe value for Fiji */
-                               vddc = evv_default;
-
-                       /* the voltage should not be zero nor equal to leakage ID */
-                       if (vddc != 0 && vddc != vv_id) {
-                               data->vddc_leakage.actual_voltage
-                               [data->vddc_leakage.count] = vddc;
-                               data->vddc_leakage.leakage_id
-                               [data->vddc_leakage.count] = vv_id;
-                               data->vddc_leakage.count++;
-                       }
-               }
-       }
-       return 0;
-}
-
-/**
- * Change virtual leakage voltage to actual value.
- *
- * @param     hwmgr  the address of the powerplay hardware manager.
- * @param     pointer to changing voltage
- * @param     pointer to leakage table
- */
-static void fiji_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
-               uint16_t *voltage, struct fiji_leakage_voltage *leakage_table)
-{
-       uint32_t index;
-
-       /* search for leakage voltage ID 0xff01 ~ 0xff08 */
-       for (index = 0; index < leakage_table->count; index++) {
-               /* if this voltage matches a leakage voltage ID */
-               /* patch with actual leakage voltage */
-               if (leakage_table->leakage_id[index] == *voltage) {
-                       *voltage = leakage_table->actual_voltage[index];
-                       break;
-               }
-       }
-
-       if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
-               printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
-}
-
-/**
-* Patch voltage lookup table by EVV leakages.
-*
-* @param     hwmgr  the address of the powerplay hardware manager.
-* @param     pointer to voltage lookup table
-* @param     pointer to leakage table
-* @return     always 0
-*/
-static int fiji_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_voltage_lookup_table *lookup_table,
-               struct fiji_leakage_voltage *leakage_table)
-{
-       uint32_t i;
-
-       for (i = 0; i < lookup_table->count; i++)
-               fiji_patch_with_vdd_leakage(hwmgr,
-                               &lookup_table->entries[i].us_vdd, leakage_table);
-
-       return 0;
-}
-
-static int fiji_patch_clock_voltage_limits_with_vddc_leakage(
-               struct pp_hwmgr *hwmgr, struct fiji_leakage_voltage *leakage_table,
-               uint16_t *vddc)
-{
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       fiji_patch_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
-       hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
-                       table_info->max_clock_voltage_on_dc.vddc;
-       return 0;
-}
-
-static int fiji_patch_voltage_dependency_tables_with_lookup_table(
-               struct pp_hwmgr *hwmgr)
-{
-       uint8_t entryId;
-       uint8_t voltageId;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
-                       table_info->vdd_dep_on_sclk;
-       struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
-                       table_info->vdd_dep_on_mclk;
-       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
-                       table_info->mm_dep_table;
-
-       for (entryId = 0; entryId < sclk_table->count; ++entryId) {
-               voltageId = sclk_table->entries[entryId].vddInd;
-               sclk_table->entries[entryId].vddc =
-                               table_info->vddc_lookup_table->entries[voltageId].us_vdd;
-       }
-
-       for (entryId = 0; entryId < mclk_table->count; ++entryId) {
-               voltageId = mclk_table->entries[entryId].vddInd;
-               mclk_table->entries[entryId].vddc =
-                       table_info->vddc_lookup_table->entries[voltageId].us_vdd;
-       }
-
-       for (entryId = 0; entryId < mm_table->count; ++entryId) {
-               voltageId = mm_table->entries[entryId].vddcInd;
-               mm_table->entries[entryId].vddc =
-                       table_info->vddc_lookup_table->entries[voltageId].us_vdd;
-       }
-
-       return 0;
-
-}
-
-static int fiji_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
-{
-       /* Need to determine if we need calculated voltage. */
-       return 0;
-}
-
-static int fiji_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
-{
-       /* Need to determine if we need calculated voltage from mm table. */
-       return 0;
-}
-
-static int fiji_sort_lookup_table(struct pp_hwmgr *hwmgr,
-               struct phm_ppt_v1_voltage_lookup_table *lookup_table)
-{
-       uint32_t table_size, i, j;
-       struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
-       table_size = lookup_table->count;
-
-       PP_ASSERT_WITH_CODE(0 != lookup_table->count,
-               "Lookup table is empty", return -EINVAL);
-
-       /* Sorting voltages */
-       for (i = 0; i < table_size - 1; i++) {
-               for (j = i + 1; j > 0; j--) {
-                       if (lookup_table->entries[j].us_vdd <
-                                       lookup_table->entries[j - 1].us_vdd) {
-                               tmp_voltage_lookup_record = lookup_table->entries[j - 1];
-                               lookup_table->entries[j - 1] = lookup_table->entries[j];
-                               lookup_table->entries[j] = tmp_voltage_lookup_record;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int fiji_complete_dependency_tables(struct pp_hwmgr *hwmgr)
-{
-       int result = 0;
-       int tmp_result;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       tmp_result = fiji_patch_lookup_table_with_leakage(hwmgr,
-                       table_info->vddc_lookup_table, &(data->vddc_leakage));
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = fiji_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
-                       &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = fiji_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = fiji_calc_voltage_dependency_tables(hwmgr);
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = fiji_calc_mm_voltage_dependency_table(hwmgr);
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = fiji_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
-       if(tmp_result)
-               result = tmp_result;
-
-       return result;
-}
-
-static int fiji_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
-                       table_info->vdd_dep_on_sclk;
-       struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
-                       table_info->vdd_dep_on_mclk;
-
-       PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
-               "VDD dependency on SCLK table is missing.       \
-               This table is mandatory", return -EINVAL);
-       PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
-               "VDD dependency on SCLK table has to have is missing.   \
-               This table is mandatory", return -EINVAL);
-
-       PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
-               "VDD dependency on MCLK table is missing.       \
-               This table is mandatory", return -EINVAL);
-       PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
-               "VDD dependency on MCLK table has to have is missing.    \
-               This table is mandatory", return -EINVAL);
-
-       data->min_vddc_in_pptable = (uint16_t)allowed_sclk_vdd_table->entries[0].vddc;
-       data->max_vddc_in_pptable =     (uint16_t)allowed_sclk_vdd_table->
-                       entries[allowed_sclk_vdd_table->count - 1].vddc;
-
-       table_info->max_clock_voltage_on_ac.sclk =
-               allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
-       table_info->max_clock_voltage_on_ac.mclk =
-               allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
-       table_info->max_clock_voltage_on_ac.vddc =
-               allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
-       table_info->max_clock_voltage_on_ac.vddci =
-               allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
-
-       hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
-               table_info->max_clock_voltage_on_ac.sclk;
-       hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
-               table_info->max_clock_voltage_on_ac.mclk;
-       hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
-               table_info->max_clock_voltage_on_ac.vddc;
-       hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
-               table_info->max_clock_voltage_on_ac.vddci;
-
-       return 0;
-}
-
-static uint16_t fiji_get_current_pcie_speed(struct pp_hwmgr *hwmgr)
-{
-       uint32_t speedCntl = 0;
-
-       /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
-       speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE,
-                       ixPCIE_LC_SPEED_CNTL);
-       return((uint16_t)PHM_GET_FIELD(speedCntl,
-                       PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
-}
-
-static int fiji_get_current_pcie_lane_number(struct pp_hwmgr *hwmgr)
-{
-       uint32_t link_width;
-
-       /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
-       link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
-                       PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD);
-
-       PP_ASSERT_WITH_CODE((7 >= link_width),
-                       "Invalid PCIe lane width!", return 0);
-
-       return decode_pcie_lane_width(link_width);
-}
-
-/** Patch the Boot State to match VBIOS boot clocks and voltage.
-*
-* @param hwmgr Pointer to the hardware manager.
-* @param pPowerState The address of the PowerState instance being created.
-*
-*/
-static int fiji_patch_boot_state(struct pp_hwmgr *hwmgr,
-               struct pp_hw_power_state *hw_ps)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_power_state *ps = (struct fiji_power_state *)hw_ps;
-       ATOM_FIRMWARE_INFO_V2_2 *fw_info;
-       uint16_t size;
-       uint8_t frev, crev;
-       int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
-
-       /* First retrieve the Boot clocks and VDDC from the firmware info table.
-        * We assume here that fw_info is unchanged if this call fails.
-        */
-       fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
-                       hwmgr->device, index,
-                       &size, &frev, &crev);
-       if (!fw_info)
-               /* During a test, there is no firmware info table. */
-               return 0;
-
-       /* Patch the state. */
-       data->vbios_boot_state.sclk_bootup_value =
-                       le32_to_cpu(fw_info->ulDefaultEngineClock);
-       data->vbios_boot_state.mclk_bootup_value =
-                       le32_to_cpu(fw_info->ulDefaultMemoryClock);
-       data->vbios_boot_state.mvdd_bootup_value =
-                       le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
-       data->vbios_boot_state.vddc_bootup_value =
-                       le16_to_cpu(fw_info->usBootUpVDDCVoltage);
-       data->vbios_boot_state.vddci_bootup_value =
-                       le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
-       data->vbios_boot_state.pcie_gen_bootup_value =
-                       fiji_get_current_pcie_speed(hwmgr);
-       data->vbios_boot_state.pcie_lane_bootup_value =
-                       (uint16_t)fiji_get_current_pcie_lane_number(hwmgr);
-
-       /* set boot power state */
-       ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
-       ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
-       ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
-       ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
-
-       return 0;
-}
-
-static int fiji_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
-{
-       return phm_hwmgr_backend_fini(hwmgr);
-}
-
-static int fiji_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data;
-       uint32_t i;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       bool stay_in_boot;
-       int result;
-
-       data = kzalloc(sizeof(struct fiji_hwmgr), GFP_KERNEL);
-       if (data == NULL)
-               return -ENOMEM;
-
-       hwmgr->backend = data;
-
-       data->dll_default_on = false;
-       data->sram_end = SMC_RAM_END;
-
-       for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++)
-               data->activity_target[i] = FIJI_AT_DFLT;
-
-       data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
-
-       data->mclk_activity_target = PPFIJI_MCLK_TARGETACTIVITY_DFLT;
-       data->mclk_dpm0_activity_target = 0xa;
-
-       data->sclk_dpm_key_disabled = 0;
-       data->mclk_dpm_key_disabled = 0;
-       data->pcie_dpm_key_disabled = 0;
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_UnTabledHardwareInterface);
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_TablelessHardwareInterface);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkDeepSleep);
-
-       data->gpio_debug = 0;
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_DynamicPatchPowerState);
-
-       /* need to set voltage control types before EVV patching */
-       data->voltage_control = FIJI_VOLTAGE_CONTROL_NONE;
-       data->vddci_control = FIJI_VOLTAGE_CONTROL_NONE;
-       data->mvdd_control = FIJI_VOLTAGE_CONTROL_NONE;
-
-       data->force_pcie_gen = PP_PCIEGenInvalid;
-
-       if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                       VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
-               data->voltage_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_EnableMVDDControl))
-               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                               VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
-                       data->mvdd_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
-
-       if (data->mvdd_control == FIJI_VOLTAGE_CONTROL_NONE)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_EnableMVDDControl);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ControlVDDCI)) {
-               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
-                       data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
-               else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
-                       data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
-       }
-
-       if (data->vddci_control == FIJI_VOLTAGE_CONTROL_NONE)
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_ControlVDDCI);
-
-       if (table_info && table_info->cac_dtp_table->usClockStretchAmount)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_ClockStretcher);
-
-       fiji_init_dpm_defaults(hwmgr);
-
-       /* Get leakage voltage based on leakage ID. */
-       fiji_get_evv_voltages(hwmgr);
-
-       /* Patch our voltage dependency table with actual leakage voltage
-        * We need to perform leakage translation before it's used by other functions
-        */
-       fiji_complete_dependency_tables(hwmgr);
-
-       /* Parse pptable data read from VBIOS */
-       fiji_set_private_data_based_on_pptable(hwmgr);
-
-       /* ULV Support */
-       data->ulv.ulv_supported = true; /* ULV feature is enabled by default */
-
-       /* Initalize Dynamic State Adjustment Rule Settings */
-       result = tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
-
-       if (!result) {
-               data->uvd_enabled = false;
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_EnableSMU7ThermalManagement);
-               data->vddc_phase_shed_control = false;
-       }
-
-       stay_in_boot = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_StayInBootState);
-
-       if (0 == result) {
-               struct cgs_system_info sys_info = {0};
-
-               data->is_tlu_enabled = false;
-               hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
-                               FIJI_MAX_HARDWARE_POWERLEVELS;
-               hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
-               hwmgr->platform_descriptor.minimumClocksReductionPercentage  = 50;
-
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_FanSpeedInTableIsRPM);
-
-               if (table_info->cac_dtp_table->usDefaultTargetOperatingTemp &&
-                               hwmgr->thermal_controller.
-                               advanceFanControlParameters.ucFanControlMode) {
-                       hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM =
-                                       hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
-                       hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM =
-                                       hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM;
-                       hwmgr->dyn_state.cac_dtp_table->usOperatingTempMinLimit =
-                                       table_info->cac_dtp_table->usOperatingTempMinLimit;
-                       hwmgr->dyn_state.cac_dtp_table->usOperatingTempMaxLimit =
-                                       table_info->cac_dtp_table->usOperatingTempMaxLimit;
-                       hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
-                                       table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
-                       hwmgr->dyn_state.cac_dtp_table->usOperatingTempStep =
-                                       table_info->cac_dtp_table->usOperatingTempStep;
-                       hwmgr->dyn_state.cac_dtp_table->usTargetOperatingTemp =
-                                       table_info->cac_dtp_table->usTargetOperatingTemp;
-
-                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_ODFuzzyFanControlSupport);
-               }
-
-               sys_info.size = sizeof(struct cgs_system_info);
-               sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
-               result = cgs_query_system_info(hwmgr->device, &sys_info);
-               if (result)
-                       data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK;
-               else
-                       data->pcie_gen_cap = (uint32_t)sys_info.value;
-               if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
-                       data->pcie_spc_cap = 20;
-               sys_info.size = sizeof(struct cgs_system_info);
-               sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
-               result = cgs_query_system_info(hwmgr->device, &sys_info);
-               if (result)
-                       data->pcie_lane_cap = AMDGPU_DEFAULT_PCIE_MLW_MASK;
-               else
-                       data->pcie_lane_cap = (uint32_t)sys_info.value;
-       } else {
-               /* Ignore return value in here, we are cleaning up a mess. */
-               fiji_hwmgr_backend_fini(hwmgr);
-       }
-
-       return 0;
-}
-
-/**
- * Read clock related registers.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-static int fiji_read_clock_registers(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       data->clock_registers.vCG_SPLL_FUNC_CNTL =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixCG_SPLL_FUNC_CNTL);
-       data->clock_registers.vCG_SPLL_FUNC_CNTL_2 =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixCG_SPLL_FUNC_CNTL_2);
-       data->clock_registers.vCG_SPLL_FUNC_CNTL_3 =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixCG_SPLL_FUNC_CNTL_3);
-       data->clock_registers.vCG_SPLL_FUNC_CNTL_4 =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixCG_SPLL_FUNC_CNTL_4);
-       data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixCG_SPLL_SPREAD_SPECTRUM);
-       data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixCG_SPLL_SPREAD_SPECTRUM_2);
-
-       return 0;
-}
-
-/**
- * Find out if memory is GDDR5.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-static int fiji_get_memory_type(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t temp;
-
-       temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
-
-       data->is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
-                       ((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
-                        MC_SEQ_MISC0_GDDR5_SHIFT));
-
-       return 0;
-}
-
-/**
- * Enables Dynamic Power Management by SMC
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-static int fiji_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
-{
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       GENERAL_PWRMGT, STATIC_PM_EN, 1);
-
-       return 0;
-}
-
-/**
- * Initialize PowerGating States for different engines
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-static int fiji_init_power_gate_state(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       data->uvd_power_gated = false;
-       data->vce_power_gated = false;
-       data->samu_power_gated = false;
-       data->acp_power_gated = false;
-       data->pg_acp_init = true;
-
-       return 0;
-}
-
-static int fiji_init_sclk_threshold(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       data->low_sclk_interrupt_threshold = 0;
-
-       return 0;
-}
-
-static int fiji_setup_asic_task(struct pp_hwmgr *hwmgr)
-{
-       int tmp_result, result = 0;
-
-       tmp_result = fiji_read_clock_registers(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to read clock registers!", result = tmp_result);
-
-       tmp_result = fiji_get_memory_type(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to get memory type!", result = tmp_result);
-
-       tmp_result = fiji_enable_acpi_power_management(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable ACPI power management!", result = tmp_result);
-
-       tmp_result = fiji_init_power_gate_state(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to init power gate state!", result = tmp_result);
-
-       tmp_result = tonga_get_mc_microcode_version(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to get MC microcode version!", result = tmp_result);
-
-       tmp_result = fiji_init_sclk_threshold(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to init sclk threshold!", result = tmp_result);
-
-       return result;
-}
-
-/**
-* Checks if we want to support voltage control
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-*/
-static bool fiji_voltage_control(const struct pp_hwmgr *hwmgr)
-{
-       const struct fiji_hwmgr *data =
-                       (const struct fiji_hwmgr *)(hwmgr->backend);
-
-       return (FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control);
-}
-
-/**
-* Enable voltage control
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int fiji_enable_voltage_control(struct pp_hwmgr *hwmgr)
-{
-       /* enable voltage control */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
-
-       return 0;
-}
-
-/**
-* Remove repeated voltage values and create table with unique values.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    vol_table  the pointer to changing voltage table
-* @return    0 in success
-*/
-
-static int fiji_trim_voltage_table(struct pp_hwmgr *hwmgr,
-               struct pp_atomctrl_voltage_table *vol_table)
-{
-       uint32_t i, j;
-       uint16_t vvalue;
-       bool found = false;
-       struct pp_atomctrl_voltage_table *table;
-
-       PP_ASSERT_WITH_CODE((NULL != vol_table),
-                       "Voltage Table empty.", return -EINVAL);
-       table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
-                       GFP_KERNEL);
-
-       if (NULL == table)
-               return -ENOMEM;
-
-       table->mask_low = vol_table->mask_low;
-       table->phase_delay = vol_table->phase_delay;
-
-       for (i = 0; i < vol_table->count; i++) {
-               vvalue = vol_table->entries[i].value;
-               found = false;
-
-               for (j = 0; j < table->count; j++) {
-                       if (vvalue == table->entries[j].value) {
-                               found = true;
-                               break;
-                       }
-               }
-
-               if (!found) {
-                       table->entries[table->count].value = vvalue;
-                       table->entries[table->count].smio_low =
-                                       vol_table->entries[i].smio_low;
-                       table->count++;
-               }
-       }
-
-       memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
-       kfree(table);
-
-       return 0;
-}
-
-static int fiji_get_svi2_mvdd_voltage_table(struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_clock_voltage_dependency_table *dep_table)
-{
-       uint32_t i;
-       int result;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct pp_atomctrl_voltage_table *vol_table = &(data->mvdd_voltage_table);
-
-       PP_ASSERT_WITH_CODE((0 != dep_table->count),
-                       "Voltage Dependency Table empty.", return -EINVAL);
-
-       vol_table->mask_low = 0;
-       vol_table->phase_delay = 0;
-       vol_table->count = dep_table->count;
-
-       for (i = 0; i < dep_table->count; i++) {
-               vol_table->entries[i].value = dep_table->entries[i].mvdd;
-               vol_table->entries[i].smio_low = 0;
-       }
-
-       result = fiji_trim_voltage_table(hwmgr, vol_table);
-       PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to trim MVDD table.", return result);
-
-       return 0;
-}
-
-static int fiji_get_svi2_vddci_voltage_table(struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_clock_voltage_dependency_table *dep_table)
-{
-       uint32_t i;
-       int result;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct pp_atomctrl_voltage_table *vol_table = &(data->vddci_voltage_table);
-
-       PP_ASSERT_WITH_CODE((0 != dep_table->count),
-                       "Voltage Dependency Table empty.", return -EINVAL);
-
-       vol_table->mask_low = 0;
-       vol_table->phase_delay = 0;
-       vol_table->count = dep_table->count;
-
-       for (i = 0; i < dep_table->count; i++) {
-               vol_table->entries[i].value = dep_table->entries[i].vddci;
-               vol_table->entries[i].smio_low = 0;
-       }
-
-       result = fiji_trim_voltage_table(hwmgr, vol_table);
-       PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to trim VDDCI table.", return result);
-
-       return 0;
-}
-
-static int fiji_get_svi2_vdd_voltage_table(struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_voltage_lookup_table *lookup_table)
-{
-       int i = 0;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct pp_atomctrl_voltage_table *vol_table = &(data->vddc_voltage_table);
-
-       PP_ASSERT_WITH_CODE((0 != lookup_table->count),
-                       "Voltage Lookup Table empty.", return -EINVAL);
-
-       vol_table->mask_low = 0;
-       vol_table->phase_delay = 0;
-
-       vol_table->count = lookup_table->count;
-
-       for (i = 0; i < vol_table->count; i++) {
-               vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
-               vol_table->entries[i].smio_low = 0;
-       }
-
-       return 0;
-}
-
-/* ---- Voltage Tables ----
- * If the voltage table would be bigger than
- * what will fit into the state table on
- * the SMC keep only the higher entries.
- */
-static void fiji_trim_voltage_table_to_fit_state_table(struct pp_hwmgr *hwmgr,
-               uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table)
-{
-       unsigned int i, diff;
-
-       if (vol_table->count <= max_vol_steps)
-               return;
-
-       diff = vol_table->count - max_vol_steps;
-
-       for (i = 0; i < max_vol_steps; i++)
-               vol_table->entries[i] = vol_table->entries[i + diff];
-
-       vol_table->count = max_vol_steps;
-
-       return;
-}
-
-/**
-* Create Voltage Tables.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int fiji_construct_voltage_tables(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)hwmgr->pptable;
-       int result;
-
-       if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
-               result = atomctrl_get_voltage_table_v3(hwmgr,
-                               VOLTAGE_TYPE_MVDDC,     VOLTAGE_OBJ_GPIO_LUT,
-                               &(data->mvdd_voltage_table));
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve MVDD table.",
-                               return result);
-       } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
-               result = fiji_get_svi2_mvdd_voltage_table(hwmgr,
-                               table_info->vdd_dep_on_mclk);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve SVI2 MVDD table from dependancy table.",
-                               return result;);
-       }
-
-       if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
-               result = atomctrl_get_voltage_table_v3(hwmgr,
-                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT,
-                               &(data->vddci_voltage_table));
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve VDDCI table.",
-                               return result);
-       } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
-               result = fiji_get_svi2_vddci_voltage_table(hwmgr,
-                               table_info->vdd_dep_on_mclk);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve SVI2 VDDCI table from dependancy table.",
-                               return result);
-       }
-
-       if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
-               result = fiji_get_svi2_vdd_voltage_table(hwmgr,
-                               table_info->vddc_lookup_table);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve SVI2 VDDC table from lookup table.",
-                               return result);
-       }
-
-       PP_ASSERT_WITH_CODE(
-                       (data->vddc_voltage_table.count <= (SMU73_MAX_LEVELS_VDDC)),
-                       "Too many voltage values for VDDC. Trimming to fit state table.",
-                       fiji_trim_voltage_table_to_fit_state_table(hwmgr,
-                                       SMU73_MAX_LEVELS_VDDC, &(data->vddc_voltage_table)));
-
-       PP_ASSERT_WITH_CODE(
-                       (data->vddci_voltage_table.count <= (SMU73_MAX_LEVELS_VDDCI)),
-                       "Too many voltage values for VDDCI. Trimming to fit state table.",
-                       fiji_trim_voltage_table_to_fit_state_table(hwmgr,
-                                       SMU73_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table)));
-
-       PP_ASSERT_WITH_CODE(
-                       (data->mvdd_voltage_table.count <= (SMU73_MAX_LEVELS_MVDD)),
-                       "Too many voltage values for MVDD. Trimming to fit state table.",
-                       fiji_trim_voltage_table_to_fit_state_table(hwmgr,
-                                       SMU73_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table)));
-
-       return 0;
-}
-
-static int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
-{
-       /* Program additional LP registers
-        * that are no longer programmed by VBIOS
-        */
-       cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
-                       cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
-                       cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
-                       cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
-                       cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
-                       cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
-                       cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
-                       cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
-
-       return 0;
-}
-
-/**
-* Programs static screed detection parameters
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int fiji_program_static_screen_threshold_parameters(
-               struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       /* Set static screen threshold unit */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
-                       data->static_screen_threshold_unit);
-       /* Set static screen threshold */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
-                       data->static_screen_threshold);
-
-       return 0;
-}
-
-/**
-* Setup display gap for glitch free memory clock switching.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always  0
-*/
-static int fiji_enable_display_gap(struct pp_hwmgr *hwmgr)
-{
-       uint32_t displayGap =
-                       cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixCG_DISPLAY_GAP_CNTL);
-
-       displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
-                       DISP_GAP, DISPLAY_GAP_IGNORE);
-
-       displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
-                       DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_DISPLAY_GAP_CNTL, displayGap);
-
-       return 0;
-}
-
-/**
-* Programs activity state transition voting clients
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always  0
-*/
-static int fiji_program_voting_clients(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       /* Clear reset for voting clients before enabling DPM */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
-
-       return 0;
-}
-
-static int fiji_clear_voting_clients(struct pp_hwmgr *hwmgr)
-{
-       /* Reset voting clients before disabling DPM */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 1);
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 1);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_0, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_1, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_2, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_3, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_4, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_5, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_6, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_7, 0);
-
-       return 0;
-}
-
-/**
-* Get the location of various tables inside the FW image.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always  0
-*/
-static int fiji_process_firmware_header(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
-       uint32_t tmp;
-       int result;
-       bool error = false;
-
-       result = fiji_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU73_Firmware_Header, DpmTable),
-                       &tmp, data->sram_end);
-
-       if (0 == result)
-               data->dpm_table_start = tmp;
-
-       error |= (0 != result);
-
-       result = fiji_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU73_Firmware_Header, SoftRegisters),
-                       &tmp, data->sram_end);
-
-       if (!result) {
-               data->soft_regs_start = tmp;
-               smu_data->soft_regs_start = tmp;
-       }
-
-       error |= (0 != result);
-
-       result = fiji_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU73_Firmware_Header, mcRegisterTable),
-                       &tmp, data->sram_end);
-
-       if (!result)
-               data->mc_reg_table_start = tmp;
-
-       result = fiji_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU73_Firmware_Header, FanTable),
-                       &tmp, data->sram_end);
-
-       if (!result)
-               data->fan_table_start = tmp;
-
-       error |= (0 != result);
-
-       result = fiji_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU73_Firmware_Header, mcArbDramTimingTable),
-                       &tmp, data->sram_end);
-
-       if (!result)
-               data->arb_table_start = tmp;
-
-       error |= (0 != result);
-
-       result = fiji_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU73_Firmware_Header, Version),
-                       &tmp, data->sram_end);
-
-       if (!result)
-               hwmgr->microcode_version_info.SMC = tmp;
-
-       error |= (0 != result);
-
-       return error ? -1 : 0;
-}
-
-/* Copy one arb setting to another and then switch the active set.
- * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
- */
-static int fiji_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
-               uint32_t arb_src, uint32_t arb_dest)
-{
-       uint32_t mc_arb_dram_timing;
-       uint32_t mc_arb_dram_timing2;
-       uint32_t burst_time;
-       uint32_t mc_cg_config;
-
-       switch (arb_src) {
-       case MC_CG_ARB_FREQ_F0:
-               mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
-               mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
-               burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
-               break;
-       case MC_CG_ARB_FREQ_F1:
-               mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
-               mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
-               burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (arb_dest) {
-       case MC_CG_ARB_FREQ_F0:
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
-               PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
-               break;
-       case MC_CG_ARB_FREQ_F1:
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
-               PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
-       mc_cg_config |= 0x0000000F;
-       cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
-       PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arb_dest);
-
-       return 0;
-}
-
-/**
-* Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   if success then 0;
-*/
-static int fiji_reset_to_default(struct pp_hwmgr *hwmgr)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults);
-}
-
-/**
-* Initial switch from ARB F0->F1
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-* This function is to be called from the SetPowerState table.
-*/
-static int fiji_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr)
-{
-       return fiji_copy_and_switch_arb_sets(hwmgr,
-                       MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
-}
-
-static int fiji_force_switch_to_arbf0(struct pp_hwmgr *hwmgr)
-{
-       uint32_t tmp;
-
-       tmp = (cgs_read_ind_register(hwmgr->device,
-                       CGS_IND_REG__SMC, ixSMC_SCRATCH9) &
-                       0x0000ff00) >> 8;
-
-       if (tmp == MC_CG_ARB_FREQ_F0)
-               return 0;
-
-       return fiji_copy_and_switch_arb_sets(hwmgr,
-                       tmp, MC_CG_ARB_FREQ_F0);
-}
-
-static int fiji_reset_single_dpm_table(struct pp_hwmgr *hwmgr,
-               struct fiji_single_dpm_table *dpm_table, uint32_t count)
-{
-       int i;
-       PP_ASSERT_WITH_CODE(count <= MAX_REGULAR_DPM_NUMBER,
-                       "Fatal error, can not set up single DPM table entries "
-                       "to exceed max number!",);
-
-       dpm_table->count = count;
-       for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++)
-               dpm_table->dpm_levels[i].enabled = false;
-
-       return 0;
-}
-
-static void fiji_setup_pcie_table_entry(
-       struct fiji_single_dpm_table *dpm_table,
-       uint32_t index, uint32_t pcie_gen,
-       uint32_t pcie_lanes)
-{
-       dpm_table->dpm_levels[index].value = pcie_gen;
-       dpm_table->dpm_levels[index].param1 = pcie_lanes;
-       dpm_table->dpm_levels[index].enabled = true;
-}
-
-static int fiji_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
-       uint32_t i, max_entry;
-
-       PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels ||
-                       data->use_pcie_power_saving_levels), "No pcie performance levels!",
-                       return -EINVAL);
-
-       if (data->use_pcie_performance_levels &&
-                       !data->use_pcie_power_saving_levels) {
-               data->pcie_gen_power_saving = data->pcie_gen_performance;
-               data->pcie_lane_power_saving = data->pcie_lane_performance;
-       } else if (!data->use_pcie_performance_levels &&
-                       data->use_pcie_power_saving_levels) {
-               data->pcie_gen_performance = data->pcie_gen_power_saving;
-               data->pcie_lane_performance = data->pcie_lane_power_saving;
-       }
-
-       fiji_reset_single_dpm_table(hwmgr,
-                       &data->dpm_table.pcie_speed_table, SMU73_MAX_LEVELS_LINK);
-
-       if (pcie_table != NULL) {
-               /* max_entry is used to make sure we reserve one PCIE level
-                * for boot level (fix for A+A PSPP issue).
-                * If PCIE table from PPTable have ULV entry + 8 entries,
-                * then ignore the last entry.*/
-               max_entry = (SMU73_MAX_LEVELS_LINK < pcie_table->count) ?
-                               SMU73_MAX_LEVELS_LINK : pcie_table->count;
-               for (i = 1; i < max_entry; i++) {
-                       fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i - 1,
-                                       get_pcie_gen_support(data->pcie_gen_cap,
-                                                       pcie_table->entries[i].gen_speed),
-                                       get_pcie_lane_support(data->pcie_lane_cap,
-                                                       pcie_table->entries[i].lane_width));
-               }
-               data->dpm_table.pcie_speed_table.count = max_entry - 1;
-       } else {
-               /* Hardcode Pcie Table */
-               fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Min_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Min_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Max_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Max_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Max_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Max_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-
-               data->dpm_table.pcie_speed_table.count = 6;
-       }
-       /* Populate last level for boot PCIE level, but do not increment count. */
-       fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
-                       data->dpm_table.pcie_speed_table.count,
-                       get_pcie_gen_support(data->pcie_gen_cap,
-                                       PP_Min_PCIEGen),
-                       get_pcie_lane_support(data->pcie_lane_cap,
-                                       PP_Max_PCIELane));
-
-       return 0;
-}
-
-/*
- * This function is to initalize all DPM state tables
- * for SMU7 based on the dependency table.
- * Dynamic state patching function will then trim these
- * state tables to the allowed range based
- * on the power policy or external client requests,
- * such as UVD request, etc.
- */
-static int fiji_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint32_t i;
-
-       struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table =
-                       table_info->vdd_dep_on_sclk;
-       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
-                       table_info->vdd_dep_on_mclk;
-
-       PP_ASSERT_WITH_CODE(dep_sclk_table != NULL,
-                       "SCLK dependency table is missing. This table is mandatory",
-                       return -EINVAL);
-       PP_ASSERT_WITH_CODE(dep_sclk_table->count >= 1,
-                       "SCLK dependency table has to have is missing. "
-                       "This table is mandatory",
-                       return -EINVAL);
-
-       PP_ASSERT_WITH_CODE(dep_mclk_table != NULL,
-                       "MCLK dependency table is missing. This table is mandatory",
-                       return -EINVAL);
-       PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
-                       "MCLK dependency table has to have is missing. "
-                       "This table is mandatory",
-                       return -EINVAL);
-
-       /* clear the state table to reset everything to default */
-       fiji_reset_single_dpm_table(hwmgr,
-                       &data->dpm_table.sclk_table, SMU73_MAX_LEVELS_GRAPHICS);
-       fiji_reset_single_dpm_table(hwmgr,
-                       &data->dpm_table.mclk_table, SMU73_MAX_LEVELS_MEMORY);
-
-       /* Initialize Sclk DPM table based on allow Sclk values */
-       data->dpm_table.sclk_table.count = 0;
-       for (i = 0; i < dep_sclk_table->count; i++) {
-               if (i == 0 || data->dpm_table.sclk_table.dpm_levels
-                               [data->dpm_table.sclk_table.count - 1].value !=
-                                               dep_sclk_table->entries[i].clk) {
-                       data->dpm_table.sclk_table.dpm_levels
-                       [data->dpm_table.sclk_table.count].value =
-                                       dep_sclk_table->entries[i].clk;
-                       data->dpm_table.sclk_table.dpm_levels
-                       [data->dpm_table.sclk_table.count].enabled =
-                                       (i == 0) ? true : false;
-                       data->dpm_table.sclk_table.count++;
-               }
-       }
-
-       /* Initialize Mclk DPM table based on allow Mclk values */
-       data->dpm_table.mclk_table.count = 0;
-       for (i=0; i<dep_mclk_table->count; i++) {
-               if ( i==0 || data->dpm_table.mclk_table.dpm_levels
-                               [data->dpm_table.mclk_table.count - 1].value !=
-                                               dep_mclk_table->entries[i].clk) {
-                       data->dpm_table.mclk_table.dpm_levels
-                       [data->dpm_table.mclk_table.count].value =
-                                       dep_mclk_table->entries[i].clk;
-                       data->dpm_table.mclk_table.dpm_levels
-                       [data->dpm_table.mclk_table.count].enabled =
-                                       (i == 0) ? true : false;
-                       data->dpm_table.mclk_table.count++;
-               }
-       }
-
-       /* setup PCIE gen speed levels */
-       fiji_setup_default_pcie_table(hwmgr);
-
-       /* save a copy of the default DPM table */
-       memcpy(&(data->golden_dpm_table), &(data->dpm_table),
-                       sizeof(struct fiji_dpm_table));
-
-       return 0;
-}
-
-/**
- * @brief PhwFiji_GetVoltageOrder
- *  Returns index of requested voltage record in lookup(table)
- * @param lookup_table - lookup list to search in
- * @param voltage - voltage to look for
- * @return 0 on success
- */
-uint8_t fiji_get_voltage_index(
-               struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
-{
-       uint8_t count = (uint8_t) (lookup_table->count);
-       uint8_t i;
-
-       PP_ASSERT_WITH_CODE((NULL != lookup_table),
-                       "Lookup Table empty.", return 0);
-       PP_ASSERT_WITH_CODE((0 != count),
-                       "Lookup Table empty.", return 0);
-
-       for (i = 0; i < lookup_table->count; i++) {
-               /* find first voltage equal or bigger than requested */
-               if (lookup_table->entries[i].us_vdd >= voltage)
-                       return i;
-       }
-       /* voltage is bigger than max voltage in the table */
-       return i - 1;
-}
-
-/**
-* Preparation of vddc and vddgfx CAC tables for SMC.
-*
-* @param    hwmgr  the address of the hardware manager
-* @param    table  the SMC DPM table structure to be populated
-* @return   always 0
-*/
-static int fiji_populate_cac_table(struct pp_hwmgr *hwmgr,
-               struct SMU73_Discrete_DpmTable *table)
-{
-       uint32_t count;
-       uint8_t index;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_voltage_lookup_table *lookup_table =
-                       table_info->vddc_lookup_table;
-       /* tables is already swapped, so in order to use the value from it,
-        * we need to swap it back.
-        * We are populating vddc CAC data to BapmVddc table
-        * in split and merged mode
-        */
-       for( count = 0; count<lookup_table->count; count++) {
-               index = fiji_get_voltage_index(lookup_table,
-                               data->vddc_voltage_table.entries[count].value);
-               table->BapmVddcVidLoSidd[count] = (uint8_t) ((6200 -
-                               (lookup_table->entries[index].us_cac_low *
-                                               VOLTAGE_SCALE)) / 25);
-               table->BapmVddcVidHiSidd[count] = (uint8_t) ((6200 -
-                               (lookup_table->entries[index].us_cac_high *
-                                               VOLTAGE_SCALE)) / 25);
-       }
-
-       return 0;
-}
-
-/**
-* Preparation of voltage tables for SMC.
-*
-* @param    hwmgr   the address of the hardware manager
-* @param    table   the SMC DPM table structure to be populated
-* @return   always  0
-*/
-
-int fiji_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
-               struct SMU73_Discrete_DpmTable *table)
-{
-       int result;
-
-       result = fiji_populate_cac_table(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "can not populate CAC voltage tables to SMC",
-                       return -EINVAL);
-
-       return 0;
-}
-
-static int fiji_populate_ulv_level(struct pp_hwmgr *hwmgr,
-               struct SMU73_Discrete_Ulv *state)
-{
-       int result = 0;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       state->CcPwrDynRm = 0;
-       state->CcPwrDynRm1 = 0;
-
-       state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
-       state->VddcOffsetVid = (uint8_t)( table_info->us_ulv_voltage_offset *
-                       VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1 );
-
-       state->VddcPhase = (data->vddc_phase_shed_control) ? 0 : 1;
-
-       if (!result) {
-               CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
-               CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
-               CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
-       }
-       return result;
-}
-
-static int fiji_populate_ulv_state(struct pp_hwmgr *hwmgr,
-               struct SMU73_Discrete_DpmTable *table)
-{
-       return fiji_populate_ulv_level(hwmgr, &table->Ulv);
-}
-
-static int32_t fiji_get_dpm_level_enable_mask_value(
-               struct fiji_single_dpm_table* dpm_table)
-{
-       int32_t i;
-       int32_t mask = 0;
-
-       for (i = dpm_table->count; i > 0; i--) {
-               mask = mask << 1;
-               if (dpm_table->dpm_levels[i - 1].enabled)
-                       mask |= 0x1;
-               else
-                       mask &= 0xFFFFFFFE;
-       }
-       return mask;
-}
-
-static int fiji_populate_smc_link_level(struct pp_hwmgr *hwmgr,
-               struct SMU73_Discrete_DpmTable *table)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_dpm_table *dpm_table = &data->dpm_table;
-       int i;
-
-       /* Index (dpm_table->pcie_speed_table.count)
-        * is reserved for PCIE boot level. */
-       for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
-               table->LinkLevel[i].PcieGenSpeed  =
-                               (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
-               table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width(
-                               dpm_table->pcie_speed_table.dpm_levels[i].param1);
-               table->LinkLevel[i].EnabledForActivity = 1;
-               table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff);
-               table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5);
-               table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30);
-       }
-
-       data->smc_state_table.LinkLevelCount =
-                       (uint8_t)dpm_table->pcie_speed_table.count;
-       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
-                       fiji_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
-
-       return 0;
-}
-
-/**
-* Calculates the SCLK dividers using the provided engine clock
-*
-* @param    hwmgr  the address of the hardware manager
-* @param    clock  the engine clock to use to populate the structure
-* @param    sclk   the SMC SCLK structure to be populated
-*/
-static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr,
-               uint32_t clock, struct SMU73_Discrete_GraphicsLevel *sclk)
-{
-       const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct pp_atomctrl_clock_dividers_vi dividers;
-       uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
-       uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
-       uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
-       uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
-       uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
-       uint32_t ref_clock;
-       uint32_t ref_divider;
-       uint32_t fbdiv;
-       int result;
-
-       /* get the engine clock dividers for this clock value */
-       result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock,  &dividers);
-
-       PP_ASSERT_WITH_CODE(result == 0,
-                       "Error retrieving Engine Clock dividers from VBIOS.",
-                       return result);
-
-       /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
-       ref_clock = atomctrl_get_reference_clock(hwmgr);
-       ref_divider = 1 + dividers.uc_pll_ref_div;
-
-       /* low 14 bits is fraction and high 12 bits is divider */
-       fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
-
-       /* SPLL_FUNC_CNTL setup */
-       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
-                       SPLL_REF_DIV, dividers.uc_pll_ref_div);
-       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
-                       SPLL_PDIV_A,  dividers.uc_pll_post_div);
-
-       /* SPLL_FUNC_CNTL_3 setup*/
-       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
-                       SPLL_FB_DIV, fbdiv);
-
-       /* set to use fractional accumulation*/
-       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
-                       SPLL_DITHEN, 1);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
-               struct pp_atomctrl_internal_ss_info ssInfo;
-
-               uint32_t vco_freq = clock * dividers.uc_pll_post_div;
-               if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr,
-                               vco_freq, &ssInfo)) {
-                       /*
-                        * ss_info.speed_spectrum_percentage -- in unit of 0.01%
-                        * ss_info.speed_spectrum_rate -- in unit of khz
-                        *
-                        * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
-                        */
-                       uint32_t clk_s = ref_clock * 5 /
-                                       (ref_divider * ssInfo.speed_spectrum_rate);
-                       /* clkv = 2 * D * fbdiv / NS */
-                       uint32_t clk_v = 4 * ssInfo.speed_spectrum_percentage *
-                                       fbdiv / (clk_s * 10000);
-
-                       cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
-                                       CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s);
-                       cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
-                                       CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
-                       cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2,
-                                       CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v);
-               }
-       }
-
-       sclk->SclkFrequency        = clock;
-       sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
-       sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
-       sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
-       sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
-       sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
-
-       return 0;
-}
-
-static uint16_t fiji_find_closest_vddci(struct pp_hwmgr *hwmgr, uint16_t vddci)
-{
-       uint32_t  i;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct pp_atomctrl_voltage_table *vddci_table =
-                       &(data->vddci_voltage_table);
-
-       for (i = 0; i < vddci_table->count; i++) {
-               if (vddci_table->entries[i].value >= vddci)
-                       return vddci_table->entries[i].value;
-       }
-
-       PP_ASSERT_WITH_CODE(false,
-                       "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
-                       return vddci_table->entries[i-1].value);
-}
-
-static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
-               struct phm_ppt_v1_clock_voltage_dependency_table* dep_table,
-               uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
-{
-       uint32_t i;
-       uint16_t vddci;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       *voltage = *mvdd = 0;
-
-       /* clock - voltage dependency table is empty table */
-       if (dep_table->count == 0)
-               return -EINVAL;
-
-       for (i = 0; i < dep_table->count; i++) {
-               /* find first sclk bigger than request */
-               if (dep_table->entries[i].clk >= clock) {
-                       *voltage |= (dep_table->entries[i].vddc *
-                                       VOLTAGE_SCALE) << VDDC_SHIFT;
-                       if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
-                               *voltage |= (data->vbios_boot_state.vddci_bootup_value *
-                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
-                       else if (dep_table->entries[i].vddci)
-                               *voltage |= (dep_table->entries[i].vddci *
-                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
-                       else {
-                               vddci = fiji_find_closest_vddci(hwmgr,
-                                               (dep_table->entries[i].vddc -
-                                                               (uint16_t)data->vddc_vddci_delta));
-                               *voltage |= (vddci * VOLTAGE_SCALE) <<  VDDCI_SHIFT;
-                       }
-
-                       if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
-                               *mvdd = data->vbios_boot_state.mvdd_bootup_value *
-                                       VOLTAGE_SCALE;
-                       else if (dep_table->entries[i].mvdd)
-                               *mvdd = (uint32_t) dep_table->entries[i].mvdd *
-                                       VOLTAGE_SCALE;
-
-                       *voltage |= 1 << PHASES_SHIFT;
-                       return 0;
-               }
-       }
-
-       /* sclk is bigger than max sclk in the dependence table */
-       *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
-
-       if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
-               *voltage |= (data->vbios_boot_state.vddci_bootup_value *
-                               VOLTAGE_SCALE) << VDDCI_SHIFT;
-       else if (dep_table->entries[i-1].vddci) {
-               vddci = fiji_find_closest_vddci(hwmgr,
-                               (dep_table->entries[i].vddc -
-                                               (uint16_t)data->vddc_vddci_delta));
-               *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
-       }
-
-       if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
-               *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
-       else if (dep_table->entries[i].mvdd)
-               *mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE;
-
-       return 0;
-}
-
-static uint8_t fiji_get_sleep_divider_id_from_clock(uint32_t clock,
-               uint32_t clock_insr)
-{
-       uint8_t i;
-       uint32_t temp;
-       uint32_t min = max(clock_insr, (uint32_t)FIJI_MINIMUM_ENGINE_CLOCK);
-
-       PP_ASSERT_WITH_CODE((clock >= min), "Engine clock can't satisfy stutter requirement!", return 0);
-       for (i = FIJI_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
-               temp = clock >> i;
-
-               if (temp >= min || i == 0)
-                       break;
-       }
-       return i;
-}
-/**
-* Populates single SMC SCLK structure using the provided engine clock
-*
-* @param    hwmgr      the address of the hardware manager
-* @param    clock the engine clock to use to populate the structure
-* @param    sclk        the SMC SCLK structure to be populated
-*/
-
-static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
-               uint32_t clock, uint16_t sclk_al_threshold,
-               struct SMU73_Discrete_GraphicsLevel *level)
-{
-       int result;
-       /* PP_Clocks minClocks; */
-       uint32_t threshold, mvdd;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       result = fiji_calculate_sclk_params(hwmgr, clock, level);
-
-       /* populate graphics levels */
-       result = fiji_get_dependency_volt_by_clk(hwmgr,
-                       table_info->vdd_dep_on_sclk, clock,
-                       &level->MinVoltage, &mvdd);
-       PP_ASSERT_WITH_CODE((0 == result),
-                       "can not find VDDC voltage value for "
-                       "VDDC engine clock dependency table",
-                       return result);
-
-       level->SclkFrequency = clock;
-       level->ActivityLevel = sclk_al_threshold;
-       level->CcPwrDynRm = 0;
-       level->CcPwrDynRm1 = 0;
-       level->EnabledForActivity = 0;
-       level->EnabledForThrottle = 1;
-       level->UpHyst = 10;
-       level->DownHyst = 0;
-       level->VoltageDownHyst = 0;
-       level->PowerThrottle = 0;
-
-       threshold = clock * data->fast_watermark_threshold / 100;
-
-
-       data->display_timing.min_clock_in_sr = hwmgr->display_config.min_core_set_clock_in_sr;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
-               level->DeepSleepDivId = fiji_get_sleep_divider_id_from_clock(clock,
-                                                               hwmgr->display_config.min_core_set_clock_in_sr);
-
-
-       /* Default to slow, highest DPM level will be
-        * set to PPSMC_DISPLAY_WATERMARK_LOW later.
-        */
-       level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
-
-       CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency);
-       CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
-
-       return 0;
-}
-/**
-* Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
-*
-* @param    hwmgr      the address of the hardware manager
-*/
-static int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_dpm_table *dpm_table = &data->dpm_table;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
-       uint8_t pcie_entry_cnt = (uint8_t) data->dpm_table.pcie_speed_table.count;
-       int result = 0;
-       uint32_t array = data->dpm_table_start +
-                       offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
-       uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) *
-                       SMU73_MAX_LEVELS_GRAPHICS;
-       struct SMU73_Discrete_GraphicsLevel *levels =
-                       data->smc_state_table.GraphicsLevel;
-       uint32_t i, max_entry;
-       uint8_t hightest_pcie_level_enabled = 0,
-                       lowest_pcie_level_enabled = 0,
-                       mid_pcie_level_enabled = 0,
-                       count = 0;
-
-       for (i = 0; i < dpm_table->sclk_table.count; i++) {
-               result = fiji_populate_single_graphic_level(hwmgr,
-                               dpm_table->sclk_table.dpm_levels[i].value,
-                               (uint16_t)data->activity_target[i],
-                               &levels[i]);
-               if (result)
-                       return result;
-
-               /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
-               if (i > 1)
-                       levels[i].DeepSleepDivId = 0;
-       }
-
-       /* Only enable level 0 for now.*/
-       levels[0].EnabledForActivity = 1;
-
-       /* set highest level watermark to high */
-       levels[dpm_table->sclk_table.count - 1].DisplayWatermark =
-                       PPSMC_DISPLAY_WATERMARK_HIGH;
-
-       data->smc_state_table.GraphicsDpmLevelCount =
-                       (uint8_t)dpm_table->sclk_table.count;
-       data->dpm_level_enable_mask.sclk_dpm_enable_mask =
-                       fiji_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
-
-       if (pcie_table != NULL) {
-               PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt),
-                               "There must be 1 or more PCIE levels defined in PPTable.",
-                               return -EINVAL);
-               max_entry = pcie_entry_cnt - 1;
-               for (i = 0; i < dpm_table->sclk_table.count; i++)
-                       levels[i].pcieDpmLevel =
-                                       (uint8_t) ((i < max_entry)? i : max_entry);
-       } else {
-               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
-                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
-                                               (1 << (hightest_pcie_level_enabled + 1))) != 0 ))
-                       hightest_pcie_level_enabled++;
-
-               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
-                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
-                                               (1 << lowest_pcie_level_enabled)) == 0 ))
-                       lowest_pcie_level_enabled++;
-
-               while ((count < hightest_pcie_level_enabled) &&
-                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
-                                               (1 << (lowest_pcie_level_enabled + 1 + count))) == 0 ))
-                       count++;
-
-               mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1+ count) <
-                               hightest_pcie_level_enabled?
-                                               (lowest_pcie_level_enabled + 1 + count) :
-                                               hightest_pcie_level_enabled;
-
-               /* set pcieDpmLevel to hightest_pcie_level_enabled */
-               for(i = 2; i < dpm_table->sclk_table.count; i++)
-                       levels[i].pcieDpmLevel = hightest_pcie_level_enabled;
-
-               /* set pcieDpmLevel to lowest_pcie_level_enabled */
-               levels[0].pcieDpmLevel = lowest_pcie_level_enabled;
-
-               /* set pcieDpmLevel to mid_pcie_level_enabled */
-               levels[1].pcieDpmLevel = mid_pcie_level_enabled;
-       }
-       /* level count will send to smc once at init smc table and never change */
-       result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
-                       (uint32_t)array_size, data->sram_end);
-
-       return result;
-}
-
-/**
- * MCLK Frequency Ratio
- * SEQ_CG_RESP  Bit[31:24] - 0x0
- * Bit[27:24] \96 DDR3 Frequency ratio
- * 0x0 <= 100MHz,       450 < 0x8 <= 500MHz
- * 100 < 0x1 <= 150MHz,       500 < 0x9 <= 550MHz
- * 150 < 0x2 <= 200MHz,       550 < 0xA <= 600MHz
- * 200 < 0x3 <= 250MHz,       600 < 0xB <= 650MHz
- * 250 < 0x4 <= 300MHz,       650 < 0xC <= 700MHz
- * 300 < 0x5 <= 350MHz,       700 < 0xD <= 750MHz
- * 350 < 0x6 <= 400MHz,       750 < 0xE <= 800MHz
- * 400 < 0x7 <= 450MHz,       800 < 0xF
- */
-static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock)
-{
-       if (mem_clock <= 10000) return 0x0;
-       if (mem_clock <= 15000) return 0x1;
-       if (mem_clock <= 20000) return 0x2;
-       if (mem_clock <= 25000) return 0x3;
-       if (mem_clock <= 30000) return 0x4;
-       if (mem_clock <= 35000) return 0x5;
-       if (mem_clock <= 40000) return 0x6;
-       if (mem_clock <= 45000) return 0x7;
-       if (mem_clock <= 50000) return 0x8;
-       if (mem_clock <= 55000) return 0x9;
-       if (mem_clock <= 60000) return 0xa;
-       if (mem_clock <= 65000) return 0xb;
-       if (mem_clock <= 70000) return 0xc;
-       if (mem_clock <= 75000) return 0xd;
-       if (mem_clock <= 80000) return 0xe;
-       /* mem_clock > 800MHz */
-       return 0xf;
-}
-
-/**
-* Populates the SMC MCLK structure using the provided memory clock
-*
-* @param    hwmgr   the address of the hardware manager
-* @param    clock   the memory clock to use to populate the structure
-* @param    sclk    the SMC SCLK structure to be populated
-*/
-static int fiji_calculate_mclk_params(struct pp_hwmgr *hwmgr,
-    uint32_t clock, struct SMU73_Discrete_MemoryLevel *mclk)
-{
-       struct pp_atomctrl_memory_clock_param mem_param;
-       int result;
-
-       result = atomctrl_get_memory_pll_dividers_vi(hwmgr, clock, &mem_param);
-       PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to get Memory PLL Dividers.",);
-
-       /* Save the result data to outpupt memory level structure */
-       mclk->MclkFrequency   = clock;
-       mclk->MclkDivider     = (uint8_t)mem_param.mpll_post_divider;
-       mclk->FreqRange       = fiji_get_mclk_frequency_ratio(clock);
-
-       return result;
-}
-
-static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr,
-               uint32_t clock, struct SMU73_Discrete_MemoryLevel *mem_level)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       int result = 0;
-
-       if (table_info->vdd_dep_on_mclk) {
-               result = fiji_get_dependency_volt_by_clk(hwmgr,
-                               table_info->vdd_dep_on_mclk, clock,
-                               &mem_level->MinVoltage, &mem_level->MinMvdd);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find MinVddc voltage value from memory "
-                               "VDDC voltage dependency table", return result);
-       }
-
-       mem_level->EnabledForThrottle = 1;
-       mem_level->EnabledForActivity = 0;
-       mem_level->UpHyst = 0;
-       mem_level->DownHyst = 100;
-       mem_level->VoltageDownHyst = 0;
-       mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
-       mem_level->StutterEnable = false;
-
-       mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
-
-       /* enable stutter mode if all the follow condition applied
-        * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
-        * &(data->DisplayTiming.numExistingDisplays));
-        */
-       data->display_timing.num_existing_displays = 1;
-
-       if ((data->mclk_stutter_mode_threshold) &&
-               (clock <= data->mclk_stutter_mode_threshold) &&
-               (!data->is_uvd_enabled) &&
-               (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL,
-                               STUTTER_ENABLE) & 0x1))
-               mem_level->StutterEnable = true;
-
-       result = fiji_calculate_mclk_params(hwmgr, clock, mem_level);
-       if (!result) {
-               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd);
-               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency);
-               CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel);
-               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage);
-       }
-       return result;
-}
-
-/**
-* Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
-*
-* @param    hwmgr      the address of the hardware manager
-*/
-static int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_dpm_table *dpm_table = &data->dpm_table;
-       int result;
-       /* populate MCLK dpm table to SMU7 */
-       uint32_t array = data->dpm_table_start +
-                       offsetof(SMU73_Discrete_DpmTable, MemoryLevel);
-       uint32_t array_size = sizeof(SMU73_Discrete_MemoryLevel) *
-                       SMU73_MAX_LEVELS_MEMORY;
-       struct SMU73_Discrete_MemoryLevel *levels =
-                       data->smc_state_table.MemoryLevel;
-       uint32_t i;
-
-       for (i = 0; i < dpm_table->mclk_table.count; i++) {
-               PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
-                               "can not populate memory level as memory clock is zero",
-                               return -EINVAL);
-               result = fiji_populate_single_memory_level(hwmgr,
-                               dpm_table->mclk_table.dpm_levels[i].value,
-                               &levels[i]);
-               if (result)
-                       return result;
-       }
-
-       /* Only enable level 0 for now. */
-       levels[0].EnabledForActivity = 1;
-
-       /* in order to prevent MC activity from stutter mode to push DPM up.
-        * the UVD change complements this by putting the MCLK in
-        * a higher state by default such that we are not effected by
-        * up threshold or and MCLK DPM latency.
-        */
-       levels[0].ActivityLevel = (uint16_t)data->mclk_dpm0_activity_target;
-       CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel);
-
-       data->smc_state_table.MemoryDpmLevelCount =
-                       (uint8_t)dpm_table->mclk_table.count;
-       data->dpm_level_enable_mask.mclk_dpm_enable_mask =
-                       fiji_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
-       /* set highest level watermark to high */
-       levels[dpm_table->mclk_table.count - 1].DisplayWatermark =
-                       PPSMC_DISPLAY_WATERMARK_HIGH;
-
-       /* level count will send to smc once at init smc table and never change */
-       result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
-                       (uint32_t)array_size, data->sram_end);
-
-       return result;
-}
-
-/**
-* Populates the SMC MVDD structure using the provided memory clock.
-*
-* @param    hwmgr      the address of the hardware manager
-* @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
-* @param    voltage     the SMC VOLTAGE structure to be populated
-*/
-int fiji_populate_mvdd_value(struct pp_hwmgr *hwmgr,
-               uint32_t mclk, SMIO_Pattern *smio_pat)
-{
-       const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint32_t i = 0;
-
-       if (FIJI_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
-               /* find mvdd value which clock is more than request */
-               for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
-                       if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
-                               smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value;
-                               break;
-                       }
-               }
-               PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
-                               "MVDD Voltage is outside the supported range.",
-                               return -EINVAL);
-       } else
-               return -EINVAL;
-
-       return 0;
-}
-
-static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
-               SMU73_Discrete_DpmTable *table)
-{
-       int result = 0;
-       const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct pp_atomctrl_clock_dividers_vi dividers;
-       SMIO_Pattern vol_level;
-       uint32_t mvdd;
-       uint16_t us_mvdd;
-       uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
-       uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
-
-       table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
-
-       if (!data->sclk_dpm_key_disabled) {
-               /* Get MinVoltage and Frequency from DPM0,
-                * already converted to SMC_UL */
-               table->ACPILevel.SclkFrequency =
-                               data->dpm_table.sclk_table.dpm_levels[0].value;
-               result = fiji_get_dependency_volt_by_clk(hwmgr,
-                               table_info->vdd_dep_on_sclk,
-                               table->ACPILevel.SclkFrequency,
-                               &table->ACPILevel.MinVoltage, &mvdd);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Cannot find ACPI VDDC voltage value "
-                               "in Clock Dependency Table",);
-       } else {
-               table->ACPILevel.SclkFrequency =
-                               data->vbios_boot_state.sclk_bootup_value;
-               table->ACPILevel.MinVoltage =
-                               data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE;
-       }
-
-       /* get the engine clock dividers for this clock value */
-       result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
-                       table->ACPILevel.SclkFrequency,  &dividers);
-       PP_ASSERT_WITH_CODE(result == 0,
-                       "Error retrieving Engine Clock dividers from VBIOS.",
-                       return result);
-
-       table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
-       table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
-       table->ACPILevel.DeepSleepDivId = 0;
-
-       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
-                       SPLL_PWRON, 0);
-       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
-                       SPLL_RESET, 1);
-       spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
-                       SCLK_MUX_SEL, 4);
-
-       table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
-       table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
-       table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
-       table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
-       table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
-       table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
-       table->ACPILevel.CcPwrDynRm = 0;
-       table->ACPILevel.CcPwrDynRm1 = 0;
-
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
-
-       if (!data->mclk_dpm_key_disabled) {
-               /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
-               table->MemoryACPILevel.MclkFrequency =
-                               data->dpm_table.mclk_table.dpm_levels[0].value;
-               result = fiji_get_dependency_volt_by_clk(hwmgr,
-                               table_info->vdd_dep_on_mclk,
-                               table->MemoryACPILevel.MclkFrequency,
-                               &table->MemoryACPILevel.MinVoltage, &mvdd);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Cannot find ACPI VDDCI voltage value "
-                               "in Clock Dependency Table",);
-       } else {
-               table->MemoryACPILevel.MclkFrequency =
-                               data->vbios_boot_state.mclk_bootup_value;
-               table->MemoryACPILevel.MinVoltage =
-                               data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE;
-       }
-
-       us_mvdd = 0;
-       if ((FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control) ||
-                       (data->mclk_dpm_key_disabled))
-               us_mvdd = data->vbios_boot_state.mvdd_bootup_value;
-       else {
-               if (!fiji_populate_mvdd_value(hwmgr,
-                               data->dpm_table.mclk_table.dpm_levels[0].value,
-                               &vol_level))
-                       us_mvdd = vol_level.Voltage;
-       }
-
-       table->MemoryACPILevel.MinMvdd =
-                       PP_HOST_TO_SMC_UL(us_mvdd * VOLTAGE_SCALE);
-
-       table->MemoryACPILevel.EnabledForThrottle = 0;
-       table->MemoryACPILevel.EnabledForActivity = 0;
-       table->MemoryACPILevel.UpHyst = 0;
-       table->MemoryACPILevel.DownHyst = 100;
-       table->MemoryACPILevel.VoltageDownHyst = 0;
-       table->MemoryACPILevel.ActivityLevel =
-                       PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
-
-       table->MemoryACPILevel.StutterEnable = false;
-       CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);
-
-       return result;
-}
-
-static int fiji_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
-               SMU73_Discrete_DpmTable *table)
-{
-       int result = -EINVAL;
-       uint8_t count;
-       struct pp_atomctrl_clock_dividers_vi dividers;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
-                       table_info->mm_dep_table;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       table->VceLevelCount = (uint8_t)(mm_table->count);
-       table->VceBootLevel = 0;
-
-       for(count = 0; count < table->VceLevelCount; count++) {
-               table->VceLevel[count].Frequency = mm_table->entries[count].eclk;
-               table->VceLevel[count].MinVoltage = 0;
-               table->VceLevel[count].MinVoltage |=
-                               (mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
-               table->VceLevel[count].MinVoltage |=
-                               ((mm_table->entries[count].vddc - data->vddc_vddci_delta) *
-                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
-               table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
-
-               /*retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                               table->VceLevel[count].Frequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for VCE engine clock",
-                               return result);
-
-               table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage);
-       }
-       return result;
-}
-
-static int fiji_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
-               SMU73_Discrete_DpmTable *table)
-{
-       int result = -EINVAL;
-       uint8_t count;
-       struct pp_atomctrl_clock_dividers_vi dividers;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
-                       table_info->mm_dep_table;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       table->AcpLevelCount = (uint8_t)(mm_table->count);
-       table->AcpBootLevel = 0;
-
-       for (count = 0; count < table->AcpLevelCount; count++) {
-               table->AcpLevel[count].Frequency = mm_table->entries[count].aclk;
-               table->AcpLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
-                               VOLTAGE_SCALE) << VDDC_SHIFT;
-               table->AcpLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
-                               data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
-               table->AcpLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
-
-               /* retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                               table->AcpLevel[count].Frequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for engine clock", return result);
-
-               table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].MinVoltage);
-       }
-       return result;
-}
-
-static int fiji_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
-               SMU73_Discrete_DpmTable *table)
-{
-       int result = -EINVAL;
-       uint8_t count;
-       struct pp_atomctrl_clock_dividers_vi dividers;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
-                       table_info->mm_dep_table;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       table->SamuBootLevel = 0;
-       table->SamuLevelCount = (uint8_t)(mm_table->count);
-
-       for (count = 0; count < table->SamuLevelCount; count++) {
-               /* not sure whether we need evclk or not */
-               table->SamuLevel[count].MinVoltage = 0;
-               table->SamuLevel[count].Frequency = mm_table->entries[count].samclock;
-               table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
-                               VOLTAGE_SCALE) << VDDC_SHIFT;
-               table->SamuLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
-                               data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
-               table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
-
-               /* retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                               table->SamuLevel[count].Frequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for samu clock", return result);
-
-               table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage);
-       }
-       return result;
-}
-
-static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr,
-               int32_t eng_clock, int32_t mem_clock,
-               struct SMU73_Discrete_MCArbDramTimingTableEntry *arb_regs)
-{
-       uint32_t dram_timing;
-       uint32_t dram_timing2;
-       uint32_t burstTime;
-       ULONG state, trrds, trrdl;
-       int result;
-
-       result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
-                       eng_clock, mem_clock);
-       PP_ASSERT_WITH_CODE(result == 0,
-                       "Error calling VBIOS to set DRAM_TIMING.", return result);
-
-       dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
-       dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
-       burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME);
-
-       state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0);
-       trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0);
-       trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0);
-
-       arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dram_timing);
-       arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2);
-       arb_regs->McArbBurstTime   = (uint8_t)burstTime;
-       arb_regs->TRRDS            = (uint8_t)trrds;
-       arb_regs->TRRDL            = (uint8_t)trrdl;
-
-       return 0;
-}
-
-static int fiji_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct SMU73_Discrete_MCArbDramTimingTable arb_regs;
-       uint32_t i, j;
-       int result = 0;
-
-       for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
-               for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
-                       result = fiji_populate_memory_timing_parameters(hwmgr,
-                                       data->dpm_table.sclk_table.dpm_levels[i].value,
-                                       data->dpm_table.mclk_table.dpm_levels[j].value,
-                                       &arb_regs.entries[i][j]);
-                       if (result)
-                               break;
-               }
-       }
-
-       if (!result)
-               result = fiji_copy_bytes_to_smc(
-                               hwmgr->smumgr,
-                               data->arb_table_start,
-                               (uint8_t *)&arb_regs,
-                               sizeof(SMU73_Discrete_MCArbDramTimingTable),
-                               data->sram_end);
-       return result;
-}
-
-static int fiji_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
-               struct SMU73_Discrete_DpmTable *table)
-{
-       int result = -EINVAL;
-       uint8_t count;
-       struct pp_atomctrl_clock_dividers_vi dividers;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
-                       table_info->mm_dep_table;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       table->UvdLevelCount = (uint8_t)(mm_table->count);
-       table->UvdBootLevel = 0;
-
-       for (count = 0; count < table->UvdLevelCount; count++) {
-               table->UvdLevel[count].MinVoltage = 0;
-               table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
-               table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
-               table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
-                               VOLTAGE_SCALE) << VDDC_SHIFT;
-               table->UvdLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
-                               data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
-               table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
-
-               /* retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                               table->UvdLevel[count].VclkFrequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for Vclk clock", return result);
-
-               table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
-
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                               table->UvdLevel[count].DclkFrequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for Dclk clock", return result);
-
-               table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage);
-
-       }
-       return result;
-}
-
-static int fiji_find_boot_level(struct fiji_single_dpm_table *table,
-               uint32_t value, uint32_t *boot_level)
-{
-       int result = -EINVAL;
-       uint32_t i;
-
-       for (i = 0; i < table->count; i++) {
-               if (value == table->dpm_levels[i].value) {
-                       *boot_level = i;
-                       result = 0;
-               }
-       }
-       return result;
-}
-
-static int fiji_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
-               struct SMU73_Discrete_DpmTable *table)
-{
-       int result = 0;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       table->GraphicsBootLevel = 0;
-       table->MemoryBootLevel = 0;
-
-       /* find boot level from dpm table */
-       result = fiji_find_boot_level(&(data->dpm_table.sclk_table),
-                       data->vbios_boot_state.sclk_bootup_value,
-                       (uint32_t *)&(table->GraphicsBootLevel));
-
-       result = fiji_find_boot_level(&(data->dpm_table.mclk_table),
-                       data->vbios_boot_state.mclk_bootup_value,
-                       (uint32_t *)&(table->MemoryBootLevel));
-
-       table->BootVddc  = data->vbios_boot_state.vddc_bootup_value *
-                       VOLTAGE_SCALE;
-       table->BootVddci = data->vbios_boot_state.vddci_bootup_value *
-                       VOLTAGE_SCALE;
-       table->BootMVdd  = data->vbios_boot_state.mvdd_bootup_value *
-                       VOLTAGE_SCALE;
-
-       CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc);
-       CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci);
-       CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
-
-       return 0;
-}
-
-static int fiji_populate_smc_initailial_state(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint8_t count, level;
-
-       count = (uint8_t)(table_info->vdd_dep_on_sclk->count);
-       for (level = 0; level < count; level++) {
-               if(table_info->vdd_dep_on_sclk->entries[level].clk >=
-                               data->vbios_boot_state.sclk_bootup_value) {
-                       data->smc_state_table.GraphicsBootLevel = level;
-                       break;
-               }
-       }
-
-       count = (uint8_t)(table_info->vdd_dep_on_mclk->count);
-       for (level = 0; level < count; level++) {
-               if(table_info->vdd_dep_on_mclk->entries[level].clk >=
-                               data->vbios_boot_state.mclk_bootup_value) {
-                       data->smc_state_table.MemoryBootLevel = level;
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
-{
-       uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
-                       volt_with_cks, value;
-       uint16_t clock_freq_u16;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
-                       volt_offset = 0;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
-                       table_info->vdd_dep_on_sclk;
-
-       stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
-
-       /* Read SMU_Eefuse to read and calculate RO and determine
-        * if the part is SS or FF. if RO >= 1660MHz, part is FF.
-        */
-       efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixSMU_EFUSE_0 + (146 * 4));
-       efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixSMU_EFUSE_0 + (148 * 4));
-       efuse &= 0xFF000000;
-       efuse = efuse >> 24;
-       efuse2 &= 0xF;
-
-       if (efuse2 == 1)
-               ro = (2300 - 1350) * efuse / 255 + 1350;
-       else
-               ro = (2500 - 1000) * efuse / 255 + 1000;
-
-       if (ro >= 1660)
-               type = 0;
-       else
-               type = 1;
-
-       /* Populate Stretch amount */
-       data->smc_state_table.ClockStretcherAmount = stretch_amount;
-
-       /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
-       for (i = 0; i < sclk_table->count; i++) {
-               data->smc_state_table.Sclk_CKS_masterEn0_7 |=
-                               sclk_table->entries[i].cks_enable << i;
-               volt_without_cks = (uint32_t)((14041 *
-                       (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
-                       (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
-               volt_with_cks = (uint32_t)((13946 *
-                       (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
-                       (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
-               if (volt_without_cks >= volt_with_cks)
-                       volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
-                                       sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
-               data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
-       }
-
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
-                       STRETCH_ENABLE, 0x0);
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
-                       masterReset, 0x1);
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
-                       staticEnable, 0x1);
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
-                       masterReset, 0x0);
-
-       /* Populate CKS Lookup Table */
-       if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
-               stretch_amount2 = 0;
-       else if (stretch_amount == 3 || stretch_amount == 4)
-               stretch_amount2 = 1;
-       else {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_ClockStretcher);
-               PP_ASSERT_WITH_CODE(false,
-                               "Stretch Amount in PPTable not supported\n",
-                               return -EINVAL);
-       }
-
-       value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixPWR_CKS_CNTL);
-       value &= 0xFFC2FF87;
-       data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
-                       fiji_clock_stretcher_lookup_table[stretch_amount2][0];
-       data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
-                       fiji_clock_stretcher_lookup_table[stretch_amount2][1];
-       clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(data->smc_state_table.
-                       GraphicsLevel[data->smc_state_table.GraphicsDpmLevelCount - 1].
-                       SclkFrequency) / 100);
-       if (fiji_clock_stretcher_lookup_table[stretch_amount2][0] <
-                       clock_freq_u16 &&
-           fiji_clock_stretcher_lookup_table[stretch_amount2][1] >
-                       clock_freq_u16) {
-               /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
-               value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
-               /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
-               value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
-               /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
-               value |= (fiji_clock_stretch_amount_conversion
-                               [fiji_clock_stretcher_lookup_table[stretch_amount2][3]]
-                                [stretch_amount]) << 3;
-       }
-       CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
-                       CKS_LOOKUPTableEntry[0].minFreq);
-       CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
-                       CKS_LOOKUPTableEntry[0].maxFreq);
-       data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
-                       fiji_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
-       data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
-                       (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixPWR_CKS_CNTL, value);
-
-       /* Populate DDT Lookup Table */
-       for (i = 0; i < 4; i++) {
-               /* Assign the minimum and maximum VID stored
-                * in the last row of Clock Stretcher Voltage Table.
-                */
-               data->smc_state_table.ClockStretcherDataTable.
-               ClockStretcherDataTableEntry[i].minVID =
-                               (uint8_t) fiji_clock_stretcher_ddt_table[type][i][2];
-               data->smc_state_table.ClockStretcherDataTable.
-               ClockStretcherDataTableEntry[i].maxVID =
-                               (uint8_t) fiji_clock_stretcher_ddt_table[type][i][3];
-               /* Loop through each SCLK and check the frequency
-                * to see if it lies within the frequency for clock stretcher.
-                */
-               for (j = 0; j < data->smc_state_table.GraphicsDpmLevelCount; j++) {
-                       cks_setting = 0;
-                       clock_freq = PP_SMC_TO_HOST_UL(
-                                       data->smc_state_table.GraphicsLevel[j].SclkFrequency);
-                       /* Check the allowed frequency against the sclk level[j].
-                        *  Sclk's endianness has already been converted,
-                        *  and it's in 10Khz unit,
-                        *  as opposed to Data table, which is in Mhz unit.
-                        */
-                       if (clock_freq >=
-                                       (fiji_clock_stretcher_ddt_table[type][i][0]) * 100) {
-                               cks_setting |= 0x2;
-                               if (clock_freq <
-                                               (fiji_clock_stretcher_ddt_table[type][i][1]) * 100)
-                                       cks_setting |= 0x1;
-                       }
-                       data->smc_state_table.ClockStretcherDataTable.
-                       ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
-               }
-               CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.
-                               ClockStretcherDataTable.
-                               ClockStretcherDataTableEntry[i].setting);
-       }
-
-       value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL);
-       value &= 0xFFFFFFFE;
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value);
-
-       return 0;
-}
-
-/**
-* Populates the SMC VRConfig field in DPM table.
-*
-* @param    hwmgr   the address of the hardware manager
-* @param    table   the SMC DPM table structure to be populated
-* @return   always 0
-*/
-static int fiji_populate_vr_config(struct pp_hwmgr *hwmgr,
-               struct SMU73_Discrete_DpmTable *table)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint16_t config;
-
-       config = VR_MERGED_WITH_VDDC;
-       table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT);
-
-       /* Set Vddc Voltage Controller */
-       if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
-               config = VR_SVI2_PLANE_1;
-               table->VRConfig |= config;
-       } else {
-               PP_ASSERT_WITH_CODE(false,
-                               "VDDC should be on SVI2 control in merged mode!",);
-       }
-       /* Set Vddci Voltage Controller */
-       if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
-               config = VR_SVI2_PLANE_2;  /* only in merged mode */
-               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
-       } else if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
-               config = VR_SMIO_PATTERN_1;
-               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
-       } else {
-               config = VR_STATIC_VOLTAGE;
-               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
-       }
-       /* Set Mvdd Voltage Controller */
-       if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
-               config = VR_SVI2_PLANE_2;
-               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
-       } else if(FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
-               config = VR_SMIO_PATTERN_2;
-               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
-       } else {
-               config = VR_STATIC_VOLTAGE;
-               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
-       }
-
-       return 0;
-}
-
-/**
-* Initializes the SMC table and uploads it
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput  the pointer to input data (PowerState)
-* @return   always 0
-*/
-static int fiji_init_smc_table(struct pp_hwmgr *hwmgr)
-{
-       int result;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct SMU73_Discrete_DpmTable *table = &(data->smc_state_table);
-       const struct fiji_ulv_parm *ulv = &(data->ulv);
-       uint8_t i;
-       struct pp_atomctrl_gpio_pin_assignment gpio_pin;
-
-       result = fiji_setup_default_dpm_tables(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to setup default DPM tables!", return result);
-
-       if(FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control)
-               fiji_populate_smc_voltage_tables(hwmgr, table);
-
-       table->SystemFlags = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_AutomaticDCTransition))
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_StepVddc))
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
-
-       if (data->is_memory_gddr5)
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
-
-       if (ulv->ulv_supported && table_info->us_ulv_voltage_offset) {
-               result = fiji_populate_ulv_state(hwmgr, table);
-               PP_ASSERT_WITH_CODE(0 == result,
-                               "Failed to initialize ULV state!", return result);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixCG_ULV_PARAMETER, ulv->cg_ulv_parameter);
-       }
-
-       result = fiji_populate_smc_link_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Link Level!", return result);
-
-       result = fiji_populate_all_graphic_levels(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Graphics Level!", return result);
-
-       result = fiji_populate_all_memory_levels(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Memory Level!", return result);
-
-       result = fiji_populate_smc_acpi_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize ACPI Level!", return result);
-
-       result = fiji_populate_smc_vce_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize VCE Level!", return result);
-
-       result = fiji_populate_smc_acp_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize ACP Level!", return result);
-
-       result = fiji_populate_smc_samu_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize SAMU Level!", return result);
-
-       /* Since only the initial state is completely set up at this point
-        * (the other states are just copies of the boot state) we only
-        * need to populate the  ARB settings for the initial state.
-        */
-       result = fiji_program_memory_timing_parameters(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to Write ARB settings for the initial state.", return result);
-
-       result = fiji_populate_smc_uvd_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize UVD Level!", return result);
-
-       result = fiji_populate_smc_boot_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Boot Level!", return result);
-
-       result = fiji_populate_smc_initailial_state(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Boot State!", return result);
-
-       result = fiji_populate_bapm_parameters_in_dpm_table(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to populate BAPM Parameters!", return result);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ClockStretcher)) {
-               result = fiji_populate_clock_stretcher_data_table(hwmgr);
-               PP_ASSERT_WITH_CODE(0 == result,
-                               "Failed to populate Clock Stretcher Data Table!",
-                               return result);
-       }
-
-       table->GraphicsVoltageChangeEnable  = 1;
-       table->GraphicsThermThrottleEnable  = 1;
-       table->GraphicsInterval = 1;
-       table->VoltageInterval  = 1;
-       table->ThermalInterval  = 1;
-       table->TemperatureLimitHigh =
-                       table_info->cac_dtp_table->usTargetOperatingTemp *
-                       FIJI_Q88_FORMAT_CONVERSION_UNIT;
-       table->TemperatureLimitLow  =
-                       (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
-                       FIJI_Q88_FORMAT_CONVERSION_UNIT;
-       table->MemoryVoltageChangeEnable = 1;
-       table->MemoryInterval = 1;
-       table->VoltageResponseTime = 0;
-       table->PhaseResponseTime = 0;
-       table->MemoryThermThrottleEnable = 1;
-       table->PCIeBootLinkLevel = 0;      /* 0:Gen1 1:Gen2 2:Gen3*/
-       table->PCIeGenInterval = 1;
-       table->VRConfig = 0;
-
-       result = fiji_populate_vr_config(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to populate VRConfig setting!", return result);
-
-       table->ThermGpio = 17;
-       table->SclkStepSize = 0x4000;
-
-       if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
-               table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_RegulatorHot);
-       } else {
-               table->VRHotGpio = FIJI_UNUSED_GPIO_PIN;
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_RegulatorHot);
-       }
-
-       if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
-                       &gpio_pin)) {
-               table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift;
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_AutomaticDCTransition);
-       } else {
-               table->AcDcGpio = FIJI_UNUSED_GPIO_PIN;
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_AutomaticDCTransition);
-       }
-
-       /* Thermal Output GPIO */
-       if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID,
-                       &gpio_pin)) {
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_ThermalOutGPIO);
-
-               table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift;
-
-               /* For porlarity read GPIOPAD_A with assigned Gpio pin
-                * since VBIOS will program this register to set 'inactive state',
-                * driver can then determine 'active state' from this and
-                * program SMU with correct polarity
-                */
-               table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
-                               (1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0;
-               table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
-
-               /* if required, combine VRHot/PCC with thermal out GPIO */
-               if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_RegulatorHot) &&
-                       phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_CombinePCCWithThermalSignal))
-                       table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
-       } else {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_ThermalOutGPIO);
-               table->ThermOutGpio = 17;
-               table->ThermOutPolarity = 1;
-               table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
-       }
-
-       for (i = 0; i < SMU73_MAX_ENTRIES_SMIO; i++)
-               table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
-
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
-       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
-       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
-       CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
-       CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
-
-       /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
-       result = fiji_copy_bytes_to_smc(hwmgr->smumgr,
-                       data->dpm_table_start +
-                       offsetof(SMU73_Discrete_DpmTable, SystemFlags),
-                       (uint8_t *)&(table->SystemFlags),
-                       sizeof(SMU73_Discrete_DpmTable) - 3 * sizeof(SMU73_PIDController),
-                       data->sram_end);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to upload dpm data to SMC memory!", return result);
-
-       return 0;
-}
-
-/**
-* Initialize the ARB DRAM timing table's index field.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int fiji_init_arb_table_index(struct pp_hwmgr *hwmgr)
-{
-       const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t tmp;
-       int result;
-
-       /* This is a read-modify-write on the first byte of the ARB table.
-        * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
-        * is the field 'current'.
-        * This solution is ugly, but we never write the whole table only
-        * individual fields in it.
-        * In reality this field should not be in that structure
-        * but in a soft register.
-        */
-       result = fiji_read_smc_sram_dword(hwmgr->smumgr,
-                       data->arb_table_start, &tmp, data->sram_end);
-
-       if (result)
-               return result;
-
-       tmp &= 0x00FFFFFF;
-       tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
-
-       return fiji_write_smc_sram_dword(hwmgr->smumgr,
-                       data->arb_table_start,  tmp, data->sram_end);
-}
-
-static int fiji_enable_vrhot_gpio_interrupt(struct pp_hwmgr *hwmgr)
-{
-       if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_RegulatorHot))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_EnableVRHotGPIOInterrupt);
-
-       return 0;
-}
-
-static int fiji_enable_sclk_control(struct pp_hwmgr *hwmgr)
-{
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
-                       SCLK_PWRMGT_OFF, 0);
-       return 0;
-}
-
-static int fiji_enable_ulv(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_ulv_parm *ulv = &(data->ulv);
-
-       if (ulv->ulv_supported)
-               return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_EnableULV);
-
-       return 0;
-}
-
-static int fiji_disable_ulv(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_ulv_parm *ulv = &(data->ulv);
-
-       if (ulv->ulv_supported)
-               return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableULV);
-
-       return 0;
-}
-
-static int fiji_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkDeepSleep)) {
-               if (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MASTER_DeepSleep_ON))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to enable Master Deep Sleep switch failed!",
-                                       return -1);
-       } else {
-               if (smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_MASTER_DeepSleep_OFF)) {
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to disable Master Deep Sleep switch failed!",
-                                       return -1);
-               }
-       }
-
-       return 0;
-}
-
-static int fiji_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkDeepSleep)) {
-               if (smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_MASTER_DeepSleep_OFF)) {
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to disable Master Deep Sleep switch failed!",
-                                       return -1);
-               }
-       }
-
-       return 0;
-}
-
-static int fiji_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t   val, val0, val2;
-       uint32_t   i, cpl_cntl, cpl_threshold, mc_threshold;
-
-       /* enable SCLK dpm */
-       if(!data->sclk_dpm_key_disabled)
-               PP_ASSERT_WITH_CODE(
-               (0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Enable)),
-               "Failed to enable SCLK DPM during DPM Start Function!",
-               return -1);
-
-       /* enable MCLK dpm */
-       if(0 == data->mclk_dpm_key_disabled) {
-               cpl_threshold = 0;
-               mc_threshold = 0;
-
-               /* Read per MCD tile (0 - 7) */
-               for (i = 0; i < 8; i++) {
-                       PHM_WRITE_FIELD(hwmgr->device, MC_CONFIG_MCD, MC_RD_ENABLE, i);
-                       val = cgs_read_register(hwmgr->device, mmMC_SEQ_RESERVE_0_S) & 0xf0000000;
-                       if (0xf0000000 != val) {
-                               /* count number of MCQ that has channel(s) enabled */
-                               cpl_threshold++;
-                               /* only harvest 3 or full 4 supported */
-                               mc_threshold = val ? 3 : 4;
-                       }
-               }
-               PP_ASSERT_WITH_CODE(0 != cpl_threshold,
-                               "Number of MCQ is zero!", return -EINVAL;);
-
-               mc_threshold = ((mc_threshold & LCAC_MC0_CNTL__MC0_THRESHOLD_MASK) <<
-                               LCAC_MC0_CNTL__MC0_THRESHOLD__SHIFT) |
-                                               LCAC_MC0_CNTL__MC0_ENABLE_MASK;
-               cpl_cntl = ((cpl_threshold & LCAC_CPL_CNTL__CPL_THRESHOLD_MASK) <<
-                               LCAC_CPL_CNTL__CPL_THRESHOLD__SHIFT) |
-                                               LCAC_CPL_CNTL__CPL_ENABLE_MASK;
-               cpl_cntl = (cpl_cntl | (8 << LCAC_CPL_CNTL__CPL_BLOCK_ID__SHIFT));
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixLCAC_MC0_CNTL, mc_threshold);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixLCAC_MC1_CNTL, mc_threshold);
-               if (8 == cpl_threshold) {
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC2_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC3_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC4_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC5_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC6_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC7_CNTL, mc_threshold);
-               }
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixLCAC_CPL_CNTL, cpl_cntl);
-
-               udelay(5);
-
-               mc_threshold = mc_threshold |
-                               (1 << LCAC_MC0_CNTL__MC0_SIGNAL_ID__SHIFT);
-               cpl_cntl = cpl_cntl | (1 << LCAC_CPL_CNTL__CPL_SIGNAL_ID__SHIFT);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixLCAC_MC0_CNTL, mc_threshold);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixLCAC_MC1_CNTL, mc_threshold);
-               if (8 == cpl_threshold) {
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC2_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC3_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC4_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC5_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC6_CNTL, mc_threshold);
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixLCAC_MC7_CNTL, mc_threshold);
-               }
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixLCAC_CPL_CNTL, cpl_cntl);
-
-               /* Program CAC_EN per MCD (0-7) Tile */
-               val0 = val = cgs_read_register(hwmgr->device, mmMC_CONFIG_MCD);
-               val &= ~(MC_CONFIG_MCD__MCD0_WR_ENABLE_MASK |
-                               MC_CONFIG_MCD__MCD1_WR_ENABLE_MASK |
-                               MC_CONFIG_MCD__MCD2_WR_ENABLE_MASK |
-                               MC_CONFIG_MCD__MCD3_WR_ENABLE_MASK |
-                               MC_CONFIG_MCD__MCD4_WR_ENABLE_MASK |
-                               MC_CONFIG_MCD__MCD5_WR_ENABLE_MASK |
-                               MC_CONFIG_MCD__MCD6_WR_ENABLE_MASK |
-                               MC_CONFIG_MCD__MCD7_WR_ENABLE_MASK |
-                               MC_CONFIG_MCD__MC_RD_ENABLE_MASK);
-
-               for (i = 0; i < 8; i++) {
-                       /* Enable MCD i Tile read & write */
-                       val2  = (val | (i << MC_CONFIG_MCD__MC_RD_ENABLE__SHIFT) |
-                                       (1 << i));
-                       cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val2);
-                       /* Enbale CAC_ON MCD i Tile */
-                       val2 = cgs_read_register(hwmgr->device, mmMC_SEQ_CNTL);
-                       val2 |= MC_SEQ_CNTL__CAC_EN_MASK;
-                       cgs_write_register(hwmgr->device, mmMC_SEQ_CNTL, val2);
-               }
-               /* Set MC_CONFIG_MCD back to its default setting val0 */
-               cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val0);
-
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_MCLKDPM_Enable)),
-                               "Failed to enable MCLK DPM during DPM Start Function!",
-                               return -1);
-       }
-       return 0;
-}
-
-static int fiji_start_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       /*enable general power management */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
-                       GLOBAL_PWRMGT_EN, 1);
-       /* enable sclk deep sleep */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
-                       DYNAMIC_PM_EN, 1);
-       /* prepare for PCIE DPM */
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       data->soft_regs_start + offsetof(SMU73_SoftRegisters,
-                                       VoltageChangeTimeout), 0x1000);
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
-                       SWRST_COMMAND_1, RESETLC, 0x0);
-
-       PP_ASSERT_WITH_CODE(
-                       (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                       PPSMC_MSG_Voltage_Cntl_Enable)),
-                       "Failed to enable voltage DPM during DPM Start Function!",
-                       return -1);
-
-       if (fiji_enable_sclk_mclk_dpm(hwmgr)) {
-               printk(KERN_ERR "Failed to enable Sclk DPM and Mclk DPM!");
-               return -1;
-       }
-
-       /* enable PCIE dpm */
-       if(!data->pcie_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_PCIeDPM_Enable)),
-                               "Failed to enable pcie DPM during DPM Start Function!",
-                               return -1);
-       }
-
-       return 0;
-}
-
-static int fiji_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       /* disable SCLK dpm */
-       if (!data->sclk_dpm_key_disabled)
-               PP_ASSERT_WITH_CODE(
-                               (smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_DPM_Disable) == 0),
-                               "Failed to disable SCLK DPM!",
-                               return -1);
-
-       /* disable MCLK dpm */
-       if (!data->mclk_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_MCLKDPM_SetEnabledMask, 1) == 0),
-                               "Failed to force MCLK DPM0!",
-                               return -1);
-
-               PP_ASSERT_WITH_CODE(
-                               (smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_MCLKDPM_Disable) == 0),
-                               "Failed to disable MCLK DPM!",
-                               return -1);
-       }
-
-       return 0;
-}
-
-static int fiji_stop_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       /* disable general power management */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
-                       GLOBAL_PWRMGT_EN, 0);
-       /* disable sclk deep sleep */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
-                       DYNAMIC_PM_EN, 0);
-
-       /* disable PCIE dpm */
-       if (!data->pcie_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_PCIeDPM_Disable) == 0),
-                               "Failed to disable pcie DPM during DPM Stop Function!",
-                               return -1);
-       }
-
-       if (fiji_disable_sclk_mclk_dpm(hwmgr)) {
-               printk(KERN_ERR "Failed to disable Sclk DPM and Mclk DPM!");
-               return -1;
-       }
-
-       PP_ASSERT_WITH_CODE(
-                       (smum_send_msg_to_smc(hwmgr->smumgr,
-                                       PPSMC_MSG_Voltage_Cntl_Disable) == 0),
-                       "Failed to disable voltage DPM during DPM Stop Function!",
-                       return -1);
-
-       return 0;
-}
-
-static void fiji_set_dpm_event_sources(struct pp_hwmgr *hwmgr,
-               uint32_t sources)
-{
-       bool protection;
-       enum DPM_EVENT_SRC src;
-
-       switch (sources) {
-       default:
-               printk(KERN_ERR "Unknown throttling event sources.");
-               /* fall through */
-       case 0:
-               protection = false;
-               /* src is unused */
-               break;
-       case (1 << PHM_AutoThrottleSource_Thermal):
-               protection = true;
-               src = DPM_EVENT_SRC_DIGITAL;
-               break;
-       case (1 << PHM_AutoThrottleSource_External):
-               protection = true;
-               src = DPM_EVENT_SRC_EXTERNAL;
-               break;
-       case (1 << PHM_AutoThrottleSource_External) |
-                       (1 << PHM_AutoThrottleSource_Thermal):
-               protection = true;
-               src = DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL;
-               break;
-       }
-       /* Order matters - don't enable thermal protection for the wrong source. */
-       if (protection) {
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL,
-                               DPM_EVENT_SRC, src);
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
-                               THERMAL_PROTECTION_DIS,
-                               !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                               PHM_PlatformCaps_ThermalController));
-       } else
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
-                               THERMAL_PROTECTION_DIS, 1);
-}
-
-static int fiji_enable_auto_throttle_source(struct pp_hwmgr *hwmgr,
-               PHM_AutoThrottleSource source)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (!(data->active_auto_throttle_sources & (1 << source))) {
-               data->active_auto_throttle_sources |= 1 << source;
-               fiji_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
-       }
-       return 0;
-}
-
-static int fiji_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
-{
-       return fiji_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
-}
-
-static int fiji_disable_auto_throttle_source(struct pp_hwmgr *hwmgr,
-               PHM_AutoThrottleSource source)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (data->active_auto_throttle_sources & (1 << source)) {
-               data->active_auto_throttle_sources &= ~(1 << source);
-               fiji_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
-       }
-       return 0;
-}
-
-static int fiji_disable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
-{
-       return fiji_disable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
-}
-
-static int fiji_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
-{
-       int tmp_result, result = 0;
-
-       tmp_result = (!fiji_is_dpm_running(hwmgr))? 0 : -1;
-       PP_ASSERT_WITH_CODE(result == 0,
-                       "DPM is already running right now, no need to enable DPM!",
-                       return 0);
-
-       if (fiji_voltage_control(hwmgr)) {
-               tmp_result = fiji_enable_voltage_control(hwmgr);
-               PP_ASSERT_WITH_CODE(tmp_result == 0,
-                               "Failed to enable voltage control!",
-                               result = tmp_result);
-       }
-
-       if (fiji_voltage_control(hwmgr)) {
-               tmp_result = fiji_construct_voltage_tables(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == tmp_result),
-                               "Failed to contruct voltage tables!",
-                               result = tmp_result);
-       }
-
-       tmp_result = fiji_initialize_mc_reg_table(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to initialize MC reg table!", result = tmp_result);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_EngineSpreadSpectrumSupport))
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 1);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ThermalController))
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 0);
-
-       tmp_result = fiji_program_static_screen_threshold_parameters(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to program static screen threshold parameters!",
-                       result = tmp_result);
-
-       tmp_result = fiji_enable_display_gap(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable display gap!", result = tmp_result);
-
-       tmp_result = fiji_program_voting_clients(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to program voting clients!", result = tmp_result);
-
-       tmp_result = fiji_process_firmware_header(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to process firmware header!", result = tmp_result);
-
-       tmp_result = fiji_initial_switch_from_arbf0_to_f1(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to initialize switch from ArbF0 to F1!",
-                       result = tmp_result);
-
-       tmp_result = fiji_init_smc_table(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to initialize SMC table!", result = tmp_result);
-
-       tmp_result = fiji_init_arb_table_index(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to initialize ARB table index!", result = tmp_result);
-
-       tmp_result = fiji_populate_pm_fuses(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to populate PM fuses!", result = tmp_result);
-
-       tmp_result = fiji_enable_vrhot_gpio_interrupt(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable VR hot GPIO interrupt!", result = tmp_result);
-
-       tmp_result = tonga_notify_smc_display_change(hwmgr, false);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to notify no display!", result = tmp_result);
-
-       tmp_result = fiji_enable_sclk_control(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable SCLK control!", result = tmp_result);
-
-       tmp_result = fiji_enable_ulv(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable ULV!", result = tmp_result);
-
-       tmp_result = fiji_enable_deep_sleep_master_switch(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable deep sleep master switch!", result = tmp_result);
-
-       tmp_result = fiji_start_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to start DPM!", result = tmp_result);
-
-       tmp_result = fiji_enable_smc_cac(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable SMC CAC!", result = tmp_result);
-
-       tmp_result = fiji_enable_power_containment(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable power containment!", result = tmp_result);
-
-       tmp_result = fiji_power_control_set_level(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to power control set level!", result = tmp_result);
-
-       tmp_result = fiji_enable_thermal_auto_throttle(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable thermal auto throttle!", result = tmp_result);
-
-       return result;
-}
-
-static int fiji_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
-{
-       int tmp_result, result = 0;
-
-       tmp_result = (fiji_is_dpm_running(hwmgr)) ? 0 : -1;
-       PP_ASSERT_WITH_CODE(tmp_result == 0,
-                       "DPM is not running right now, no need to disable DPM!",
-                       return 0);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ThermalController))
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 1);
-
-       tmp_result = fiji_disable_power_containment(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable power containment!", result = tmp_result);
-
-       tmp_result = fiji_disable_smc_cac(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable SMC CAC!", 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,
-                       GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 0);
-
-       tmp_result = fiji_disable_thermal_auto_throttle(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable thermal auto throttle!", result = tmp_result);
-
-       tmp_result = fiji_stop_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to stop DPM!", result = tmp_result);
-
-       tmp_result = fiji_disable_deep_sleep_master_switch(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable deep sleep master switch!", result = tmp_result);
-
-       tmp_result = fiji_disable_ulv(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable ULV!", result = tmp_result);
-
-       tmp_result = fiji_clear_voting_clients(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to clear voting clients!", result = tmp_result);
-
-       tmp_result = fiji_reset_to_default(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to reset to default!", result = tmp_result);
-
-       tmp_result = fiji_force_switch_to_arbf0(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to force to switch arbf0!", result = tmp_result);
-
-       return result;
-}
-
-static int fiji_force_dpm_highest(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t level, tmp;
-
-       if (!data->sclk_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
-                       level = 0;
-                       tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
-                       while (tmp >>= 1)
-                               level++;
-                       if (level)
-                               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                               PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                               (1 << level));
-               }
-       }
-
-       if (!data->mclk_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
-                       level = 0;
-                       tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
-                       while (tmp >>= 1)
-                               level++;
-                       if (level)
-                               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                               PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                                               (1 << level));
-               }
-       }
-
-       if (!data->pcie_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
-                       level = 0;
-                       tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
-                       while (tmp >>= 1)
-                               level++;
-                       if (level)
-                               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                               PPSMC_MSG_PCIeDPM_ForceLevel,
-                                               (1 << level));
-               }
-       }
-       return 0;
-}
-
-static int fiji_upload_dpmlevel_enable_mask(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       phm_apply_dal_min_voltage_request(hwmgr);
-
-       if (!data->sclk_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.sclk_dpm_enable_mask);
-       }
-       return 0;
-}
-
-static int fiji_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (!fiji_is_dpm_running(hwmgr))
-               return -EINVAL;
-
-       if (!data->pcie_dpm_key_disabled) {
-               smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_PCIeDPM_UnForceLevel);
-       }
-
-       return fiji_upload_dpmlevel_enable_mask(hwmgr);
-}
-
-static uint32_t fiji_get_lowest_enabled_level(
-               struct pp_hwmgr *hwmgr, uint32_t mask)
-{
-       uint32_t level = 0;
-
-       while(0 == (mask & (1 << level)))
-               level++;
-
-       return level;
-}
-
-static int fiji_force_dpm_lowest(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data =
-                       (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t level;
-
-       if (!data->sclk_dpm_key_disabled)
-               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
-                       level = fiji_get_lowest_enabled_level(hwmgr,
-                                                             data->dpm_level_enable_mask.sclk_dpm_enable_mask);
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                                           PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                                           (1 << level));
-
-       }
-
-       if (!data->mclk_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
-                       level = fiji_get_lowest_enabled_level(hwmgr,
-                                                             data->dpm_level_enable_mask.mclk_dpm_enable_mask);
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                                           PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                                                           (1 << level));
-               }
-       }
-
-       if (!data->pcie_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
-                       level = fiji_get_lowest_enabled_level(hwmgr,
-                                                             data->dpm_level_enable_mask.pcie_dpm_enable_mask);
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                                           PPSMC_MSG_PCIeDPM_ForceLevel,
-                                                           (1 << level));
-               }
-       }
-
-       return 0;
-
-}
-static int fiji_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
-                               enum amd_dpm_forced_level level)
-{
-       int ret = 0;
-
-       switch (level) {
-       case AMD_DPM_FORCED_LEVEL_HIGH:
-               ret = fiji_force_dpm_highest(hwmgr);
-               if (ret)
-                       return ret;
-               break;
-       case AMD_DPM_FORCED_LEVEL_LOW:
-               ret = fiji_force_dpm_lowest(hwmgr);
-               if (ret)
-                       return ret;
-               break;
-       case AMD_DPM_FORCED_LEVEL_AUTO:
-               ret = fiji_unforce_dpm_levels(hwmgr);
-               if (ret)
-                       return ret;
-               break;
-       default:
-               break;
-       }
-
-       hwmgr->dpm_level = level;
-
-       return ret;
-}
-
-static int fiji_get_power_state_size(struct pp_hwmgr *hwmgr)
-{
-       return sizeof(struct fiji_power_state);
-}
-
-static int fiji_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
-               void *state, struct pp_power_state *power_state,
-               void *pp_table, uint32_t classification_flag)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_power_state  *fiji_power_state =
-                       (struct fiji_power_state *)(&(power_state->hardware));
-       struct fiji_performance_level *performance_level;
-       ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
-       ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
-                       (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
-       ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
-                       (ATOM_Tonga_SCLK_Dependency_Table *)
-                       (((unsigned long)powerplay_table) +
-                               le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
-       ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
-                       (ATOM_Tonga_MCLK_Dependency_Table *)
-                       (((unsigned long)powerplay_table) +
-                               le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
-
-       /* The following fields are not initialized here: id orderedList allStatesList */
-       power_state->classification.ui_label =
-                       (le16_to_cpu(state_entry->usClassification) &
-                       ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
-                       ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
-       power_state->classification.flags = classification_flag;
-       /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
-
-       power_state->classification.temporary_state = false;
-       power_state->classification.to_be_deleted = false;
-
-       power_state->validation.disallowOnDC =
-                       (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
-                                       ATOM_Tonga_DISALLOW_ON_DC));
-
-       power_state->pcie.lanes = 0;
-
-       power_state->display.disableFrameModulation = false;
-       power_state->display.limitRefreshrate = false;
-       power_state->display.enableVariBright =
-                       (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
-                                       ATOM_Tonga_ENABLE_VARIBRIGHT));
-
-       power_state->validation.supportedPowerLevels = 0;
-       power_state->uvd_clocks.VCLK = 0;
-       power_state->uvd_clocks.DCLK = 0;
-       power_state->temperatures.min = 0;
-       power_state->temperatures.max = 0;
-
-       performance_level = &(fiji_power_state->performance_levels
-                       [fiji_power_state->performance_level_count++]);
-
-       PP_ASSERT_WITH_CODE(
-                       (fiji_power_state->performance_level_count < SMU73_MAX_LEVELS_GRAPHICS),
-                       "Performance levels exceeds SMC limit!",
-                       return -1);
-
-       PP_ASSERT_WITH_CODE(
-                       (fiji_power_state->performance_level_count <=
-                                       hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
-                       "Performance levels exceeds Driver limit!",
-                       return -1);
-
-       /* Performance levels are arranged from low to high. */
-       performance_level->memory_clock = mclk_dep_table->entries
-                       [state_entry->ucMemoryClockIndexLow].ulMclk;
-       performance_level->engine_clock = sclk_dep_table->entries
-                       [state_entry->ucEngineClockIndexLow].ulSclk;
-       performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
-                       state_entry->ucPCIEGenLow);
-       performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
-                       state_entry->ucPCIELaneHigh);
-
-       performance_level = &(fiji_power_state->performance_levels
-                       [fiji_power_state->performance_level_count++]);
-       performance_level->memory_clock = mclk_dep_table->entries
-                       [state_entry->ucMemoryClockIndexHigh].ulMclk;
-       performance_level->engine_clock = sclk_dep_table->entries
-                       [state_entry->ucEngineClockIndexHigh].ulSclk;
-       performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
-                       state_entry->ucPCIEGenHigh);
-       performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
-                       state_entry->ucPCIELaneHigh);
-
-       return 0;
-}
-
-static int fiji_get_pp_table_entry(struct pp_hwmgr *hwmgr,
-               unsigned long entry_index, struct pp_power_state *state)
-{
-       int result;
-       struct fiji_power_state *ps;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
-                       table_info->vdd_dep_on_mclk;
-
-       state->hardware.magic = PHM_VIslands_Magic;
-
-       ps = (struct fiji_power_state *)(&state->hardware);
-
-       result = tonga_get_powerplay_table_entry(hwmgr, entry_index, state,
-                       fiji_get_pp_table_entry_callback_func);
-
-       /* This is the earliest time we have all the dependency table and the VBIOS boot state
-        * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
-        * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
-        */
-       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 "
-                                       "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 "
-                                       "does not match VBIOS boot VDDCI level");
-       }
-
-       /* set DC compatible flag if this state supports DC */
-       if (!state->validation.disallowOnDC)
-               ps->dc_compatible = true;
-
-       if (state->classification.flags & PP_StateClassificationFlag_ACPI)
-               data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
-
-       ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
-       ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
-
-       if (!result) {
-               uint32_t i;
-
-               switch (state->classification.ui_label) {
-               case PP_StateUILabel_Performance:
-                       data->use_pcie_performance_levels = true;
-
-                       for (i = 0; i < ps->performance_level_count; i++) {
-                               if (data->pcie_gen_performance.max <
-                                               ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_performance.max =
-                                                       ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_gen_performance.min >
-                                               ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_performance.min =
-                                                       ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_lane_performance.max <
-                                               ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_performance.max =
-                                                       ps->performance_levels[i].pcie_lane;
-
-                               if (data->pcie_lane_performance.min >
-                                               ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_performance.min =
-                                                       ps->performance_levels[i].pcie_lane;
-                       }
-                       break;
-               case PP_StateUILabel_Battery:
-                       data->use_pcie_power_saving_levels = true;
-
-                       for (i = 0; i < ps->performance_level_count; i++) {
-                               if (data->pcie_gen_power_saving.max <
-                                               ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_power_saving.max =
-                                                       ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_gen_power_saving.min >
-                                               ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_power_saving.min =
-                                                       ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_lane_power_saving.max <
-                                               ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_power_saving.max =
-                                                       ps->performance_levels[i].pcie_lane;
-
-                               if (data->pcie_lane_power_saving.min >
-                                               ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_power_saving.min =
-                                                       ps->performance_levels[i].pcie_lane;
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-       return 0;
-}
-
-static int fiji_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
-                               struct pp_power_state  *request_ps,
-                       const struct pp_power_state *current_ps)
-{
-       struct fiji_power_state *fiji_ps =
-                               cast_phw_fiji_power_state(&request_ps->hardware);
-       uint32_t sclk;
-       uint32_t mclk;
-       struct PP_Clocks minimum_clocks = {0};
-       bool disable_mclk_switching;
-       bool disable_mclk_switching_for_frame_lock;
-       struct cgs_display_info info = {0};
-       const struct phm_clock_and_voltage_limits *max_limits;
-       uint32_t i;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       int32_t count;
-       int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
-
-       data->battery_state = (PP_StateUILabel_Battery ==
-                       request_ps->classification.ui_label);
-
-       PP_ASSERT_WITH_CODE(fiji_ps->performance_level_count == 2,
-                                "VI should always have 2 performance levels",);
-
-       max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
-                       &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
-                       &(hwmgr->dyn_state.max_clock_voltage_on_dc);
-
-       /* Cap clock DPM tables at DC MAX if it is in DC. */
-       if (PP_PowerSource_DC == hwmgr->power_source) {
-               for (i = 0; i < fiji_ps->performance_level_count; i++) {
-                       if (fiji_ps->performance_levels[i].memory_clock > max_limits->mclk)
-                               fiji_ps->performance_levels[i].memory_clock = max_limits->mclk;
-                       if (fiji_ps->performance_levels[i].engine_clock > max_limits->sclk)
-                               fiji_ps->performance_levels[i].engine_clock = max_limits->sclk;
-               }
-       }
-
-       fiji_ps->vce_clks.evclk = hwmgr->vce_arbiter.evclk;
-       fiji_ps->vce_clks.ecclk = hwmgr->vce_arbiter.ecclk;
-
-       fiji_ps->acp_clk = hwmgr->acp_arbiter.acpclk;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
-
-       /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_StablePState)) {
-               max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
-               stable_pstate_sclk = (max_limits->sclk * 75) / 100;
-
-               for (count = table_info->vdd_dep_on_sclk->count - 1;
-                               count >= 0; count--) {
-                       if (stable_pstate_sclk >=
-                                       table_info->vdd_dep_on_sclk->entries[count].clk) {
-                               stable_pstate_sclk =
-                                               table_info->vdd_dep_on_sclk->entries[count].clk;
-                               break;
-                       }
-               }
-
-               if (count < 0)
-                       stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
-
-               stable_pstate_mclk = max_limits->mclk;
-
-               minimum_clocks.engineClock = stable_pstate_sclk;
-               minimum_clocks.memoryClock = stable_pstate_mclk;
-       }
-
-       if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
-               minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
-
-       if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
-               minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
-
-       fiji_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
-
-       if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
-               PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <=
-                               hwmgr->platform_descriptor.overdriveLimit.engineClock),
-                               "Overdrive sclk exceeds limit",
-                               hwmgr->gfx_arbiter.sclk_over_drive =
-                                               hwmgr->platform_descriptor.overdriveLimit.engineClock);
-
-               if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
-                       fiji_ps->performance_levels[1].engine_clock =
-                                       hwmgr->gfx_arbiter.sclk_over_drive;
-       }
-
-       if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
-               PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <=
-                               hwmgr->platform_descriptor.overdriveLimit.memoryClock),
-                               "Overdrive mclk exceeds limit",
-                               hwmgr->gfx_arbiter.mclk_over_drive =
-                                               hwmgr->platform_descriptor.overdriveLimit.memoryClock);
-
-               if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
-                       fiji_ps->performance_levels[1].memory_clock =
-                                       hwmgr->gfx_arbiter.mclk_over_drive;
-       }
-
-       disable_mclk_switching_for_frame_lock = phm_cap_enabled(
-                                   hwmgr->platform_descriptor.platformCaps,
-                                   PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
-
-       disable_mclk_switching = (1 < info.display_count) ||
-                                   disable_mclk_switching_for_frame_lock;
-
-       sclk = fiji_ps->performance_levels[0].engine_clock;
-       mclk = fiji_ps->performance_levels[0].memory_clock;
-
-       if (disable_mclk_switching)
-               mclk = fiji_ps->performance_levels
-               [fiji_ps->performance_level_count - 1].memory_clock;
-
-       if (sclk < minimum_clocks.engineClock)
-               sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
-                               max_limits->sclk : minimum_clocks.engineClock;
-
-       if (mclk < minimum_clocks.memoryClock)
-               mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
-                               max_limits->mclk : minimum_clocks.memoryClock;
-
-       fiji_ps->performance_levels[0].engine_clock = sclk;
-       fiji_ps->performance_levels[0].memory_clock = mclk;
-
-       fiji_ps->performance_levels[1].engine_clock =
-               (fiji_ps->performance_levels[1].engine_clock >=
-                               fiji_ps->performance_levels[0].engine_clock) ?
-                                               fiji_ps->performance_levels[1].engine_clock :
-                                               fiji_ps->performance_levels[0].engine_clock;
-
-       if (disable_mclk_switching) {
-               if (mclk < fiji_ps->performance_levels[1].memory_clock)
-                       mclk = fiji_ps->performance_levels[1].memory_clock;
-
-               fiji_ps->performance_levels[0].memory_clock = mclk;
-               fiji_ps->performance_levels[1].memory_clock = mclk;
-       } else {
-               if (fiji_ps->performance_levels[1].memory_clock <
-                               fiji_ps->performance_levels[0].memory_clock)
-                       fiji_ps->performance_levels[1].memory_clock =
-                                       fiji_ps->performance_levels[0].memory_clock;
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_StablePState)) {
-               for (i = 0; i < fiji_ps->performance_level_count; i++) {
-                       fiji_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
-                       fiji_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
-                       fiji_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
-                       fiji_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
-               }
-       }
-
-       return 0;
-}
-
-static int fiji_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       const struct fiji_power_state *fiji_ps =
-                       cast_const_phw_fiji_power_state(states->pnew_state);
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
-       uint32_t sclk = fiji_ps->performance_levels
-                       [fiji_ps->performance_level_count - 1].engine_clock;
-       struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
-       uint32_t mclk = fiji_ps->performance_levels
-                       [fiji_ps->performance_level_count - 1].memory_clock;
-       uint32_t i;
-       struct cgs_display_info info = {0};
-
-       data->need_update_smu7_dpm_table = 0;
-
-       for (i = 0; i < sclk_table->count; i++) {
-               if (sclk == sclk_table->dpm_levels[i].value)
-                       break;
-       }
-
-       if (i >= sclk_table->count)
-               data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
-       else {
-               if(data->display_timing.min_clock_in_sr !=
-                       hwmgr->display_config.min_core_set_clock_in_sr)
-                       data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
-       }
-
-       for (i = 0; i < mclk_table->count; i++) {
-               if (mclk == mclk_table->dpm_levels[i].value)
-                       break;
-       }
-
-       if (i >= mclk_table->count)
-               data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       if (data->display_timing.num_existing_displays != info.display_count)
-               data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
-
-       return 0;
-}
-
-static uint16_t fiji_get_maximum_link_speed(struct pp_hwmgr *hwmgr,
-               const struct fiji_power_state *fiji_ps)
-{
-       uint32_t i;
-       uint32_t sclk, max_sclk = 0;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_dpm_table *dpm_table = &data->dpm_table;
-
-       for (i = 0; i < fiji_ps->performance_level_count; i++) {
-               sclk = fiji_ps->performance_levels[i].engine_clock;
-               if (max_sclk < sclk)
-                       max_sclk = sclk;
-       }
-
-       for (i = 0; i < dpm_table->sclk_table.count; i++) {
-               if (dpm_table->sclk_table.dpm_levels[i].value == max_sclk)
-                       return (uint16_t) ((i >= dpm_table->pcie_speed_table.count) ?
-                                       dpm_table->pcie_speed_table.dpm_levels
-                                       [dpm_table->pcie_speed_table.count - 1].value :
-                                       dpm_table->pcie_speed_table.dpm_levels[i].value);
-       }
-
-       return 0;
-}
-
-static int fiji_request_link_speed_change_before_state_change(
-               struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       const struct fiji_power_state *fiji_nps =
-                       cast_const_phw_fiji_power_state(states->pnew_state);
-       const struct fiji_power_state *fiji_cps =
-                       cast_const_phw_fiji_power_state(states->pcurrent_state);
-
-       uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_nps);
-       uint16_t current_link_speed;
-
-       if (data->force_pcie_gen == PP_PCIEGenInvalid)
-               current_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_cps);
-       else
-               current_link_speed = data->force_pcie_gen;
-
-       data->force_pcie_gen = PP_PCIEGenInvalid;
-       data->pspp_notify_required = false;
-       if (target_link_speed > current_link_speed) {
-               switch(target_link_speed) {
-               case PP_PCIEGen3:
-                       if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
-                               break;
-                       data->force_pcie_gen = PP_PCIEGen2;
-                       if (current_link_speed == PP_PCIEGen2)
-                               break;
-               case PP_PCIEGen2:
-                       if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
-                               break;
-               default:
-                       data->force_pcie_gen = fiji_get_current_pcie_speed(hwmgr);
-                       break;
-               }
-       } else {
-               if (target_link_speed < current_link_speed)
-                       data->pspp_notify_required = true;
-       }
-
-       return 0;
-}
-
-static int fiji_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (0 == data->need_update_smu7_dpm_table)
-               return 0;
-
-       if ((0 == data->sclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table &
-                       (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
-               PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
-                                   "Trying to freeze SCLK DPM when DPM is disabled",
-                                   );
-               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_SCLKDPM_FreezeLevel),
-                               "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
-                               return -1);
-       }
-
-       if ((0 == data->mclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table &
-                DPMTABLE_OD_UPDATE_MCLK)) {
-               PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
-                                   "Trying to freeze MCLK DPM when DPM is disabled",
-                                   );
-               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_MCLKDPM_FreezeLevel),
-                               "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
-                               return -1);
-       }
-
-       return 0;
-}
-
-static int fiji_populate_and_upload_sclk_mclk_dpm_levels(
-               struct pp_hwmgr *hwmgr, const void *input)
-{
-       int result = 0;
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       const struct fiji_power_state *fiji_ps =
-                       cast_const_phw_fiji_power_state(states->pnew_state);
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t sclk = fiji_ps->performance_levels
-                       [fiji_ps->performance_level_count - 1].engine_clock;
-       uint32_t mclk = fiji_ps->performance_levels
-                       [fiji_ps->performance_level_count - 1].memory_clock;
-       struct fiji_dpm_table *dpm_table = &data->dpm_table;
-
-       struct fiji_dpm_table *golden_dpm_table = &data->golden_dpm_table;
-       uint32_t dpm_count, clock_percent;
-       uint32_t i;
-
-       if (0 == data->need_update_smu7_dpm_table)
-               return 0;
-
-       if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
-               dpm_table->sclk_table.dpm_levels
-               [dpm_table->sclk_table.count - 1].value = sclk;
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_OD6PlusinACSupport) ||
-                       phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_OD6PlusinDCSupport)) {
-               /* Need to do calculation based on the golden DPM table
-                * as the Heatmap GPU Clock axis is also based on the default values
-                */
-                       PP_ASSERT_WITH_CODE(
-                               (golden_dpm_table->sclk_table.dpm_levels
-                                               [golden_dpm_table->sclk_table.count - 1].value != 0),
-                               "Divide by 0!",
-                               return -1);
-                       dpm_count = dpm_table->sclk_table.count < 2 ?
-                                       0 : dpm_table->sclk_table.count - 2;
-                       for (i = dpm_count; i > 1; i--) {
-                               if (sclk > golden_dpm_table->sclk_table.dpm_levels
-                                               [golden_dpm_table->sclk_table.count-1].value) {
-                                       clock_percent =
-                                               ((sclk - golden_dpm_table->sclk_table.dpm_levels
-                                                       [golden_dpm_table->sclk_table.count-1].value) * 100) /
-                                               golden_dpm_table->sclk_table.dpm_levels
-                                                       [golden_dpm_table->sclk_table.count-1].value;
-
-                                       dpm_table->sclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->sclk_table.dpm_levels[i].value +
-                                                       (golden_dpm_table->sclk_table.dpm_levels[i].value *
-                                                               clock_percent)/100;
-
-                               } else if (golden_dpm_table->sclk_table.dpm_levels
-                                               [dpm_table->sclk_table.count-1].value > sclk) {
-                                       clock_percent =
-                                               ((golden_dpm_table->sclk_table.dpm_levels
-                                               [golden_dpm_table->sclk_table.count - 1].value - sclk) *
-                                                               100) /
-                                               golden_dpm_table->sclk_table.dpm_levels
-                                                       [golden_dpm_table->sclk_table.count-1].value;
-
-                                       dpm_table->sclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->sclk_table.dpm_levels[i].value -
-                                                       (golden_dpm_table->sclk_table.dpm_levels[i].value *
-                                                                       clock_percent) / 100;
-                               } else
-                                       dpm_table->sclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->sclk_table.dpm_levels[i].value;
-                       }
-               }
-       }
-
-       if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
-               dpm_table->mclk_table.dpm_levels
-                       [dpm_table->mclk_table.count - 1].value = mclk;
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_OD6PlusinACSupport) ||
-                       phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_OD6PlusinDCSupport)) {
-
-                       PP_ASSERT_WITH_CODE(
-                                       (golden_dpm_table->mclk_table.dpm_levels
-                                               [golden_dpm_table->mclk_table.count-1].value != 0),
-                                       "Divide by 0!",
-                                       return -1);
-                       dpm_count = dpm_table->mclk_table.count < 2 ?
-                                       0 : dpm_table->mclk_table.count - 2;
-                       for (i = dpm_count; i > 1; i--) {
-                               if (mclk > golden_dpm_table->mclk_table.dpm_levels
-                                               [golden_dpm_table->mclk_table.count-1].value) {
-                                       clock_percent = ((mclk -
-                                                       golden_dpm_table->mclk_table.dpm_levels
-                                                       [golden_dpm_table->mclk_table.count-1].value) * 100) /
-                                                       golden_dpm_table->mclk_table.dpm_levels
-                                                       [golden_dpm_table->mclk_table.count-1].value;
-
-                                       dpm_table->mclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->mclk_table.dpm_levels[i].value +
-                                                       (golden_dpm_table->mclk_table.dpm_levels[i].value *
-                                                                       clock_percent) / 100;
-
-                               } else if (golden_dpm_table->mclk_table.dpm_levels
-                                               [dpm_table->mclk_table.count-1].value > mclk) {
-                                       clock_percent = ((golden_dpm_table->mclk_table.dpm_levels
-                                                       [golden_dpm_table->mclk_table.count-1].value - mclk) * 100) /
-                                                                       golden_dpm_table->mclk_table.dpm_levels
-                                                                       [golden_dpm_table->mclk_table.count-1].value;
-
-                                       dpm_table->mclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->mclk_table.dpm_levels[i].value -
-                                                       (golden_dpm_table->mclk_table.dpm_levels[i].value *
-                                                                       clock_percent) / 100;
-                               } else
-                                       dpm_table->mclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->mclk_table.dpm_levels[i].value;
-                       }
-               }
-       }
-
-       if (data->need_update_smu7_dpm_table &
-                       (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
-               result = fiji_populate_all_graphic_levels(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
-                               return result);
-       }
-
-       if (data->need_update_smu7_dpm_table &
-                       (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
-               /*populate MCLK dpm table to SMU7 */
-               result = fiji_populate_all_memory_levels(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
-                               return result);
-       }
-
-       return result;
-}
-
-static int fiji_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
-                         struct fiji_single_dpm_table * dpm_table,
-                            uint32_t low_limit, uint32_t high_limit)
-{
-       uint32_t i;
-
-       for (i = 0; i < dpm_table->count; i++) {
-               if ((dpm_table->dpm_levels[i].value < low_limit) ||
-                   (dpm_table->dpm_levels[i].value > high_limit))
-                       dpm_table->dpm_levels[i].enabled = false;
-               else
-                       dpm_table->dpm_levels[i].enabled = true;
-       }
-       return 0;
-}
-
-static int fiji_trim_dpm_states(struct pp_hwmgr *hwmgr,
-               const struct fiji_power_state *fiji_ps)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t high_limit_count;
-
-       PP_ASSERT_WITH_CODE((fiji_ps->performance_level_count >= 1),
-                       "power state did not have any performance level",
-                       return -1);
-
-       high_limit_count = (1 == fiji_ps->performance_level_count) ? 0 : 1;
-
-       fiji_trim_single_dpm_states(hwmgr,
-                       &(data->dpm_table.sclk_table),
-                       fiji_ps->performance_levels[0].engine_clock,
-                       fiji_ps->performance_levels[high_limit_count].engine_clock);
-
-       fiji_trim_single_dpm_states(hwmgr,
-                       &(data->dpm_table.mclk_table),
-                       fiji_ps->performance_levels[0].memory_clock,
-                       fiji_ps->performance_levels[high_limit_count].memory_clock);
-
-       return 0;
-}
-
-static int fiji_generate_dpm_level_enable_mask(
-               struct pp_hwmgr *hwmgr, const void *input)
-{
-       int result;
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       const struct fiji_power_state *fiji_ps =
-                       cast_const_phw_fiji_power_state(states->pnew_state);
-
-       result = fiji_trim_dpm_states(hwmgr, fiji_ps);
-       if (result)
-               return result;
-
-       data->dpm_level_enable_mask.sclk_dpm_enable_mask =
-                       fiji_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
-       data->dpm_level_enable_mask.mclk_dpm_enable_mask =
-                       fiji_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
-       data->last_mclk_dpm_enable_mask =
-                       data->dpm_level_enable_mask.mclk_dpm_enable_mask;
-
-       if (data->uvd_enabled) {
-               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)
-                       data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
-       }
-
-       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
-                       fiji_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
-
-       return 0;
-}
-
-int fiji_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
-                                 (PPSMC_Msg)PPSMC_MSG_UVDDPM_Enable :
-                                 (PPSMC_Msg)PPSMC_MSG_UVDDPM_Disable);
-}
-
-int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, enable?
-                       PPSMC_MSG_VCEDPM_Enable :
-                       PPSMC_MSG_VCEDPM_Disable);
-}
-
-int fiji_enable_disable_samu_dpm(struct pp_hwmgr *hwmgr, bool enable)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, enable?
-                       PPSMC_MSG_SAMUDPM_Enable :
-                       PPSMC_MSG_SAMUDPM_Disable);
-}
-
-int fiji_enable_disable_acp_dpm(struct pp_hwmgr *hwmgr, bool enable)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, enable?
-                       PPSMC_MSG_ACPDPM_Enable :
-                       PPSMC_MSG_ACPDPM_Disable);
-}
-
-int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t mm_boot_level_offset, mm_boot_level_value;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (!bgate) {
-               data->smc_state_table.UvdBootLevel = 0;
-               if (table_info->mm_dep_table->count > 0)
-                       data->smc_state_table.UvdBootLevel =
-                                       (uint8_t) (table_info->mm_dep_table->count - 1);
-               mm_boot_level_offset = data->dpm_table_start +
-                               offsetof(SMU73_Discrete_DpmTable, UvdBootLevel);
-               mm_boot_level_offset /= 4;
-               mm_boot_level_offset *= 4;
-               mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset);
-               mm_boot_level_value &= 0x00FFFFFF;
-               mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
-               cgs_write_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
-
-               if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_UVDDPM) ||
-                       phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_StablePState))
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_UVDDPM_SetEnabledMask,
-                                       (uint32_t)(1 << data->smc_state_table.UvdBootLevel));
-       }
-
-       return fiji_enable_disable_uvd_dpm(hwmgr, !bgate);
-}
-
-int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       const struct fiji_power_state *fiji_nps =
-                       cast_const_phw_fiji_power_state(states->pnew_state);
-       const struct fiji_power_state *fiji_cps =
-                       cast_const_phw_fiji_power_state(states->pcurrent_state);
-
-       uint32_t mm_boot_level_offset, mm_boot_level_value;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (fiji_nps->vce_clks.evclk >0 &&
-       (fiji_cps == NULL || fiji_cps->vce_clks.evclk == 0)) {
-               data->smc_state_table.VceBootLevel =
-                               (uint8_t) (table_info->mm_dep_table->count - 1);
-
-               mm_boot_level_offset = data->dpm_table_start +
-                               offsetof(SMU73_Discrete_DpmTable, VceBootLevel);
-               mm_boot_level_offset /= 4;
-               mm_boot_level_offset *= 4;
-               mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset);
-               mm_boot_level_value &= 0xFF00FFFF;
-               mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
-               cgs_write_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_StablePState)) {
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_VCEDPM_SetEnabledMask,
-                                       (uint32_t)1 << data->smc_state_table.VceBootLevel);
-
-                       fiji_enable_disable_vce_dpm(hwmgr, true);
-               } else if (fiji_nps->vce_clks.evclk == 0 &&
-                               fiji_cps != NULL &&
-                               fiji_cps->vce_clks.evclk > 0)
-                       fiji_enable_disable_vce_dpm(hwmgr, false);
-       }
-
-       return 0;
-}
-
-int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t mm_boot_level_offset, mm_boot_level_value;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (!bgate) {
-               data->smc_state_table.SamuBootLevel =
-                               (uint8_t) (table_info->mm_dep_table->count - 1);
-               mm_boot_level_offset = data->dpm_table_start +
-                               offsetof(SMU73_Discrete_DpmTable, SamuBootLevel);
-               mm_boot_level_offset /= 4;
-               mm_boot_level_offset *= 4;
-               mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset);
-               mm_boot_level_value &= 0xFFFFFF00;
-               mm_boot_level_value |= data->smc_state_table.SamuBootLevel << 0;
-               cgs_write_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_StablePState))
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_SAMUDPM_SetEnabledMask,
-                                       (uint32_t)(1 << data->smc_state_table.SamuBootLevel));
-       }
-
-       return fiji_enable_disable_samu_dpm(hwmgr, !bgate);
-}
-
-int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t mm_boot_level_offset, mm_boot_level_value;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (!bgate) {
-               data->smc_state_table.AcpBootLevel =
-                               (uint8_t) (table_info->mm_dep_table->count - 1);
-               mm_boot_level_offset = data->dpm_table_start +
-                               offsetof(SMU73_Discrete_DpmTable, AcpBootLevel);
-               mm_boot_level_offset /= 4;
-               mm_boot_level_offset *= 4;
-               mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset);
-               mm_boot_level_value &= 0xFFFF00FF;
-               mm_boot_level_value |= data->smc_state_table.AcpBootLevel << 8;
-               cgs_write_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_StablePState))
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                               PPSMC_MSG_ACPDPM_SetEnabledMask,
-                                               (uint32_t)(1 << data->smc_state_table.AcpBootLevel));
-       }
-
-       return fiji_enable_disable_acp_dpm(hwmgr, !bgate);
-}
-
-static int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       int result = 0;
-       uint32_t low_sclk_interrupt_threshold = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkThrottleLowNotification)
-               && (hwmgr->gfx_arbiter.sclk_threshold !=
-                               data->low_sclk_interrupt_threshold)) {
-               data->low_sclk_interrupt_threshold =
-                               hwmgr->gfx_arbiter.sclk_threshold;
-               low_sclk_interrupt_threshold =
-                               data->low_sclk_interrupt_threshold;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
-
-               result = fiji_copy_bytes_to_smc(
-                               hwmgr->smumgr,
-                               data->dpm_table_start +
-                               offsetof(SMU73_Discrete_DpmTable,
-                                       LowSclkInterruptThreshold),
-                               (uint8_t *)&low_sclk_interrupt_threshold,
-                               sizeof(uint32_t),
-                               data->sram_end);
-       }
-
-       return result;
-}
-
-static int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (data->need_update_smu7_dpm_table &
-               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
-               return fiji_program_memory_timing_parameters(hwmgr);
-
-       return 0;
-}
-
-static int fiji_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (0 == data->need_update_smu7_dpm_table)
-               return 0;
-
-       if ((0 == data->sclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table &
-               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
-
-               PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
-                                   "Trying to Unfreeze SCLK DPM when DPM is disabled",
-                                   );
-               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_SCLKDPM_UnfreezeLevel),
-                       "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
-                       return -1);
-       }
-
-       if ((0 == data->mclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
-
-               PP_ASSERT_WITH_CODE(fiji_is_dpm_running(hwmgr),
-                                   "Trying to Unfreeze MCLK DPM when DPM is disabled",
-                                   );
-               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_SCLKDPM_UnfreezeLevel),
-                   "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
-                   return -1);
-       }
-
-       data->need_update_smu7_dpm_table = 0;
-
-       return 0;
-}
-
-/* Look up the voltaged based on DAL's requested level.
- * and then send the requested VDDC voltage to SMC
- */
-static void fiji_apply_dal_minimum_voltage_request(struct pp_hwmgr *hwmgr)
-{
-       return;
-}
-
-int fiji_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
-{
-       int result;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       /* Apply minimum voltage based on DAL's request level */
-       fiji_apply_dal_minimum_voltage_request(hwmgr);
-
-       if (0 == data->sclk_dpm_key_disabled) {
-               /* Checking if DPM is running.  If we discover hang because of this,
-                *  we should skip this message.
-                */
-               if (!fiji_is_dpm_running(hwmgr))
-                       printk(KERN_ERR "[ powerplay ] "
-                                       "Trying to set Enable Mask when DPM is disabled \n");
-
-               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
-                       result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.sclk_dpm_enable_mask);
-                       PP_ASSERT_WITH_CODE((0 == result),
-                               "Set Sclk Dpm enable Mask failed", return -1);
-               }
-       }
-
-       if (0 == data->mclk_dpm_key_disabled) {
-               /* Checking if DPM is running.  If we discover hang because of this,
-                *  we should skip this message.
-                */
-               if (!fiji_is_dpm_running(hwmgr))
-                       printk(KERN_ERR "[ powerplay ]"
-                                       " Trying to set Enable Mask when DPM is disabled \n");
-
-               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
-                       result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.mclk_dpm_enable_mask);
-                       PP_ASSERT_WITH_CODE((0 == result),
-                               "Set Mclk Dpm enable Mask failed", return -1);
-               }
-       }
-
-       return 0;
-}
-
-static int fiji_notify_link_speed_change_after_state_change(
-               struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       const struct fiji_power_state *fiji_ps =
-                       cast_const_phw_fiji_power_state(states->pnew_state);
-       uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_ps);
-       uint8_t  request;
-
-       if (data->pspp_notify_required) {
-               if (target_link_speed == PP_PCIEGen3)
-                       request = PCIE_PERF_REQ_GEN3;
-               else if (target_link_speed == PP_PCIEGen2)
-                       request = PCIE_PERF_REQ_GEN2;
-               else
-                       request = PCIE_PERF_REQ_GEN1;
-
-               if(request == PCIE_PERF_REQ_GEN1 &&
-                               fiji_get_current_pcie_speed(hwmgr) > 0)
-                       return 0;
-
-               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!");
-                       else
-                               printk("PSPP request to switch to Gen1 from Gen2 Failed!");
-               }
-       }
-
-       return 0;
-}
-
-static int fiji_set_power_state_tasks(struct pp_hwmgr *hwmgr,
-               const void *input)
-{
-       int tmp_result, result = 0;
-
-       tmp_result = fiji_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to find DPM states clocks in DPM table!",
-                       result = tmp_result);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PCIEPerformanceRequest)) {
-               tmp_result =
-                       fiji_request_link_speed_change_before_state_change(hwmgr, input);
-               PP_ASSERT_WITH_CODE((0 == tmp_result),
-                               "Failed to request link speed change before state change!",
-                               result = tmp_result);
-       }
-
-       tmp_result = fiji_freeze_sclk_mclk_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
-
-       tmp_result = fiji_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to populate and upload SCLK MCLK DPM levels!",
-                       result = tmp_result);
-
-       tmp_result = fiji_generate_dpm_level_enable_mask(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to generate DPM level enabled mask!",
-                       result = tmp_result);
-
-       tmp_result = fiji_update_vce_dpm(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to update VCE DPM!",
-                       result = tmp_result);
-
-       tmp_result = fiji_update_sclk_threshold(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to update SCLK threshold!",
-                       result = tmp_result);
-
-       tmp_result = fiji_program_mem_timing_parameters(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to program memory timing parameters!",
-                       result = tmp_result);
-
-       tmp_result = fiji_unfreeze_sclk_mclk_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to unfreeze SCLK MCLK DPM!",
-                       result = tmp_result);
-
-       tmp_result = fiji_upload_dpm_level_enable_mask(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to upload DPM level enabled mask!",
-                       result = tmp_result);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PCIEPerformanceRequest)) {
-               tmp_result =
-                       fiji_notify_link_speed_change_after_state_change(hwmgr, input);
-               PP_ASSERT_WITH_CODE((0 == tmp_result),
-                               "Failed to notify link speed change after state change!",
-                               result = tmp_result);
-       }
-
-       return result;
-}
-
-static int fiji_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
-{
-       struct pp_power_state  *ps;
-       struct fiji_power_state  *fiji_ps;
-
-       if (hwmgr == NULL)
-               return -EINVAL;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
-
-       if (low)
-               return fiji_ps->performance_levels[0].engine_clock;
-       else
-               return fiji_ps->performance_levels
-                               [fiji_ps->performance_level_count-1].engine_clock;
-}
-
-static int fiji_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
-{
-       struct pp_power_state  *ps;
-       struct fiji_power_state  *fiji_ps;
-
-       if (hwmgr == NULL)
-               return -EINVAL;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
-
-       if (low)
-               return fiji_ps->performance_levels[0].memory_clock;
-       else
-               return fiji_ps->performance_levels
-                               [fiji_ps->performance_level_count-1].memory_clock;
-}
-
-static void fiji_print_current_perforce_level(
-               struct pp_hwmgr *hwmgr, struct seq_file *m)
-{
-       uint32_t sclk, mclk, activity_percent = 0;
-       uint32_t offset;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
-
-       sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-
-       smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
-
-       mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-       seq_printf(m, "\n [  mclk  ]: %u MHz\n\n [  sclk  ]: %u MHz\n",
-                       mclk / 100, sclk / 100);
-
-       offset = data->soft_regs_start + offsetof(SMU73_SoftRegisters, AverageGraphicsActivity);
-       activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
-       activity_percent += 0x80;
-       activity_percent >>= 8;
-
-       seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent);
-
-       seq_printf(m, "uvd    %sabled\n", data->uvd_power_gated ? "dis" : "en");
-
-       seq_printf(m, "vce    %sabled\n", data->vce_power_gated ? "dis" : "en");
-}
-
-static int fiji_program_display_gap(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t num_active_displays = 0;
-       uint32_t display_gap = cgs_read_ind_register(hwmgr->device,
-                       CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
-       uint32_t display_gap2;
-       uint32_t pre_vbi_time_in_us;
-       uint32_t frame_time_in_us;
-       uint32_t ref_clock;
-       uint32_t refresh_rate = 0;
-       struct cgs_display_info info = {0};
-       struct cgs_mode_info mode_info;
-
-       info.mode_info = &mode_info;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-       num_active_displays = info.display_count;
-
-       display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
-                       DISP_GAP, (num_active_displays > 0)?
-                       DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_DISPLAY_GAP_CNTL, display_gap);
-
-       ref_clock = mode_info.ref_clock;
-       refresh_rate = mode_info.refresh_rate;
-
-       if (refresh_rate == 0)
-               refresh_rate = 60;
-
-       frame_time_in_us = 1000000 / refresh_rate;
-
-       pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
-       display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_DISPLAY_GAP_CNTL2, display_gap2);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       data->soft_regs_start +
-                       offsetof(SMU73_SoftRegisters, PreVBlankGap), 0x64);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       data->soft_regs_start +
-                       offsetof(SMU73_SoftRegisters, VBlankTimeout),
-                       (frame_time_in_us - pre_vbi_time_in_us));
-
-       if (num_active_displays == 1)
-               tonga_notify_smc_display_change(hwmgr, true);
-
-       return 0;
-}
-
-int fiji_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
-{
-       return fiji_program_display_gap(hwmgr);
-}
-
-static int fiji_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr,
-               uint16_t us_max_fan_pwm)
-{
-       hwmgr->thermal_controller.
-       advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
-
-       if (phm_is_hw_access_blocked(hwmgr))
-               return 0;
-
-       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                       PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
-}
-
-static int fiji_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr,
-               uint16_t us_max_fan_rpm)
-{
-       hwmgr->thermal_controller.
-       advanceFanControlParameters.usMaxFanRPM = us_max_fan_rpm;
-
-       if (phm_is_hw_access_blocked(hwmgr))
-               return 0;
-
-       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                       PPSMC_MSG_SetFanRpmMax, us_max_fan_rpm);
-}
-
-int fiji_dpm_set_interrupt_state(void *private_data,
-                                        unsigned src_id, unsigned type,
-                                        int enabled)
-{
-       uint32_t cg_thermal_int;
-       struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr;
-
-       if (hwmgr == NULL)
-               return -EINVAL;
-
-       switch (type) {
-       case AMD_THERMAL_IRQ_LOW_TO_HIGH:
-               if (enabled) {
-                       cg_thermal_int = cgs_read_ind_register(hwmgr->device,
-                                       CGS_IND_REG__SMC, ixCG_THERMAL_INT);
-                       cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
-                       cgs_write_ind_register(hwmgr->device,
-                                       CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
-               } else {
-                       cg_thermal_int = cgs_read_ind_register(hwmgr->device,
-                                       CGS_IND_REG__SMC, ixCG_THERMAL_INT);
-                       cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
-                       cgs_write_ind_register(hwmgr->device,
-                                       CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
-               }
-               break;
-
-       case AMD_THERMAL_IRQ_HIGH_TO_LOW:
-               if (enabled) {
-                       cg_thermal_int = cgs_read_ind_register(hwmgr->device,
-                                       CGS_IND_REG__SMC, ixCG_THERMAL_INT);
-                       cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
-                       cgs_write_ind_register(hwmgr->device,
-                                       CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
-               } else {
-                       cg_thermal_int = cgs_read_ind_register(hwmgr->device,
-                                       CGS_IND_REG__SMC, ixCG_THERMAL_INT);
-                       cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
-                       cgs_write_ind_register(hwmgr->device,
-                                       CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
-               }
-               break;
-       default:
-               break;
-       }
-       return 0;
-}
-
-int fiji_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
-                                       const void *thermal_interrupt_info)
-{
-       int result;
-       const struct pp_interrupt_registration_info *info =
-                       (const struct pp_interrupt_registration_info *)
-                       thermal_interrupt_info;
-
-       if (info == NULL)
-               return -EINVAL;
-
-       result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST,
-                               fiji_dpm_set_interrupt_state,
-                               info->call_back, info->context);
-
-       if (result)
-               return -EINVAL;
-
-       result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST,
-                               fiji_dpm_set_interrupt_state,
-                               info->call_back, info->context);
-
-       if (result)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int fiji_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
-{
-       if (mode) {
-               /* stop auto-manage */
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_MicrocodeFanControl))
-                       fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
-               fiji_fan_ctrl_set_static_mode(hwmgr, mode);
-       } else
-               /* restart auto-manage */
-               fiji_fan_ctrl_reset_fan_speed_to_default(hwmgr);
-
-       return 0;
-}
-
-static int fiji_get_fan_control_mode(struct pp_hwmgr *hwmgr)
-{
-       if (hwmgr->fan_ctrl_is_in_default_mode)
-               return hwmgr->fan_ctrl_default_mode;
-       else
-               return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_FDO_CTRL2, FDO_PWM_MODE);
-}
-
-static int fiji_force_clock_level(struct pp_hwmgr *hwmgr,
-               enum pp_clock_type type, uint32_t mask)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
-               return -EINVAL;
-
-       switch (type) {
-       case PP_SCLK:
-               if (!data->sclk_dpm_key_disabled)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
-               break;
-
-       case PP_MCLK:
-               if (!data->mclk_dpm_key_disabled)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
-               break;
-
-       case PP_PCIE:
-       {
-               uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
-               uint32_t level = 0;
-
-               while (tmp >>= 1)
-                       level++;
-
-               if (!data->pcie_dpm_key_disabled)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_PCIeDPM_ForceLevel,
-                                       level);
-               break;
-       }
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int fiji_print_clock_levels(struct pp_hwmgr *hwmgr,
-               enum pp_clock_type type, char *buf)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
-       struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
-       struct fiji_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table);
-       int i, now, size = 0;
-       uint32_t clock, pcie_speed;
-
-       switch (type) {
-       case PP_SCLK:
-               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
-               clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-
-               for (i = 0; i < sclk_table->count; i++) {
-                       if (clock > sclk_table->dpm_levels[i].value)
-                               continue;
-                       break;
-               }
-               now = i;
-
-               for (i = 0; i < sclk_table->count; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
-                                       i, sclk_table->dpm_levels[i].value / 100,
-                                       (i == now) ? "*" : "");
-               break;
-       case PP_MCLK:
-               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
-               clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-
-               for (i = 0; i < mclk_table->count; i++) {
-                       if (clock > mclk_table->dpm_levels[i].value)
-                               continue;
-                       break;
-               }
-               now = i;
-
-               for (i = 0; i < mclk_table->count; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
-                                       i, mclk_table->dpm_levels[i].value / 100,
-                                       (i == now) ? "*" : "");
-               break;
-       case PP_PCIE:
-               pcie_speed = fiji_get_current_pcie_speed(hwmgr);
-               for (i = 0; i < pcie_table->count; i++) {
-                       if (pcie_speed != pcie_table->dpm_levels[i].value)
-                               continue;
-                       break;
-               }
-               now = i;
-
-               for (i = 0; i < pcie_table->count; i++)
-                       size += sprintf(buf + size, "%d: %s %s\n", i,
-                                       (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x1" :
-                                       (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" :
-                                       (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "",
-                                       (i == now) ? "*" : "");
-               break;
-       default:
-               break;
-       }
-       return size;
-}
-
-static inline bool fiji_are_power_levels_equal(const struct fiji_performance_level *pl1,
-                                                          const struct fiji_performance_level *pl2)
-{
-       return ((pl1->memory_clock == pl2->memory_clock) &&
-                 (pl1->engine_clock == pl2->engine_clock) &&
-                 (pl1->pcie_gen == pl2->pcie_gen) &&
-                 (pl1->pcie_lane == pl2->pcie_lane));
-}
-
-int fiji_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal)
-{
-       const struct fiji_power_state *psa = cast_const_phw_fiji_power_state(pstate1);
-       const struct fiji_power_state *psb = cast_const_phw_fiji_power_state(pstate2);
-       int i;
-
-       if (equal == NULL || psa == NULL || psb == NULL)
-               return -EINVAL;
-
-       /* If the two states don't even have the same number of performance levels they cannot be the same state. */
-       if (psa->performance_level_count != psb->performance_level_count) {
-               *equal = false;
-               return 0;
-       }
-
-       for (i = 0; i < psa->performance_level_count; i++) {
-               if (!fiji_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
-                       /* If we have found even one performance level pair that is different the states are different. */
-                       *equal = false;
-                       return 0;
-               }
-       }
-
-       /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
-       *equal = ((psa->uvd_clks.vclk == psb->uvd_clks.vclk) && (psa->uvd_clks.dclk == psb->uvd_clks.dclk));
-       *equal &= ((psa->vce_clks.evclk == psb->vce_clks.evclk) && (psa->vce_clks.ecclk == psb->vce_clks.ecclk));
-       *equal &= (psa->sclk_threshold == psb->sclk_threshold);
-       *equal &= (psa->acp_clk == psb->acp_clk);
-
-       return 0;
-}
-
-bool fiji_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       bool is_update_required = false;
-       struct cgs_display_info info = {0,0,NULL};
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       if (data->display_timing.num_existing_displays != info.display_count)
-               is_update_required = true;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
-               if(hwmgr->display_config.min_core_set_clock_in_sr != data->display_timing.min_clock_in_sr)
-                       is_update_required = true;
-       }
-
-       return is_update_required;
-}
-
-static int fiji_get_sclk_od(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
-       struct fiji_single_dpm_table *golden_sclk_table =
-                       &(data->golden_dpm_table.sclk_table);
-       int value;
-
-       value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
-                       100 /
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
-
-       return value;
-}
-
-static int fiji_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_single_dpm_table *golden_sclk_table =
-                       &(data->golden_dpm_table.sclk_table);
-       struct pp_power_state  *ps;
-       struct fiji_power_state  *fiji_ps;
-
-       if (value > 20)
-               value = 20;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
-
-       fiji_ps->performance_levels[fiji_ps->performance_level_count - 1].engine_clock =
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
-                       value / 100 +
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
-
-       return 0;
-}
-
-static int fiji_get_mclk_od(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
-       struct fiji_single_dpm_table *golden_mclk_table =
-                       &(data->golden_dpm_table.mclk_table);
-       int value;
-
-       value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
-                       100 /
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
-
-       return value;
-}
-
-static int fiji_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct fiji_single_dpm_table *golden_mclk_table =
-                       &(data->golden_dpm_table.mclk_table);
-       struct pp_power_state  *ps;
-       struct fiji_power_state  *fiji_ps;
-
-       if (value > 20)
-               value = 20;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
-
-       fiji_ps->performance_levels[fiji_ps->performance_level_count - 1].memory_clock =
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
-                       value / 100 +
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
-
-       return 0;
-}
-
-static const struct pp_hwmgr_func fiji_hwmgr_funcs = {
-       .backend_init = &fiji_hwmgr_backend_init,
-       .backend_fini = &fiji_hwmgr_backend_fini,
-       .asic_setup = &fiji_setup_asic_task,
-       .dynamic_state_management_enable = &fiji_enable_dpm_tasks,
-       .dynamic_state_management_disable = &fiji_disable_dpm_tasks,
-       .force_dpm_level = &fiji_dpm_force_dpm_level,
-       .get_num_of_pp_table_entries = &tonga_get_number_of_powerplay_table_entries,
-       .get_power_state_size = &fiji_get_power_state_size,
-       .get_pp_table_entry = &fiji_get_pp_table_entry,
-       .patch_boot_state = &fiji_patch_boot_state,
-       .apply_state_adjust_rules = &fiji_apply_state_adjust_rules,
-       .power_state_set = &fiji_set_power_state_tasks,
-       .get_sclk = &fiji_dpm_get_sclk,
-       .get_mclk = &fiji_dpm_get_mclk,
-       .print_current_perforce_level = &fiji_print_current_perforce_level,
-       .powergate_uvd = &fiji_phm_powergate_uvd,
-       .powergate_vce = &fiji_phm_powergate_vce,
-       .disable_clock_power_gating = &fiji_phm_disable_clock_power_gating,
-       .notify_smc_display_config_after_ps_adjustment =
-                       &tonga_notify_smc_display_config_after_ps_adjustment,
-       .display_config_changed = &fiji_display_configuration_changed_task,
-       .set_max_fan_pwm_output = fiji_set_max_fan_pwm_output,
-       .set_max_fan_rpm_output = fiji_set_max_fan_rpm_output,
-       .get_temperature = fiji_thermal_get_temperature,
-       .stop_thermal_controller = fiji_thermal_stop_thermal_controller,
-       .get_fan_speed_info = fiji_fan_ctrl_get_fan_speed_info,
-       .get_fan_speed_percent = fiji_fan_ctrl_get_fan_speed_percent,
-       .set_fan_speed_percent = fiji_fan_ctrl_set_fan_speed_percent,
-       .reset_fan_speed_to_default = fiji_fan_ctrl_reset_fan_speed_to_default,
-       .get_fan_speed_rpm = fiji_fan_ctrl_get_fan_speed_rpm,
-       .set_fan_speed_rpm = fiji_fan_ctrl_set_fan_speed_rpm,
-       .uninitialize_thermal_controller = fiji_thermal_ctrl_uninitialize_thermal_controller,
-       .register_internal_thermal_interrupt = fiji_register_internal_thermal_interrupt,
-       .set_fan_control_mode = fiji_set_fan_control_mode,
-       .get_fan_control_mode = fiji_get_fan_control_mode,
-       .check_states_equal = fiji_check_states_equal,
-       .check_smc_update_required_for_display_configuration = fiji_check_smc_update_required_for_display_configuration,
-       .force_clock_level = fiji_force_clock_level,
-       .print_clock_levels = fiji_print_clock_levels,
-       .get_sclk_od = fiji_get_sclk_od,
-       .set_sclk_od = fiji_set_sclk_od,
-       .get_mclk_od = fiji_get_mclk_od,
-       .set_mclk_od = fiji_set_mclk_od,
-};
-
-int fiji_hwmgr_init(struct pp_hwmgr *hwmgr)
-{
-       hwmgr->hwmgr_func = &fiji_hwmgr_funcs;
-       hwmgr->pptable_func = &tonga_pptable_funcs;
-       pp_fiji_thermal_initialize(hwmgr);
-       return 0;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h
deleted file mode 100644 (file)
index bf67c2a..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright 2015 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 _FIJI_HWMGR_H_
-#define _FIJI_HWMGR_H_
-
-#include "hwmgr.h"
-#include "smu73.h"
-#include "smu73_discrete.h"
-#include "ppatomctrl.h"
-#include "fiji_ppsmc.h"
-#include "pp_endian.h"
-
-#define FIJI_MAX_HARDWARE_POWERLEVELS  2
-#define FIJI_AT_DFLT   30
-
-#define FIJI_VOLTAGE_CONTROL_NONE                   0x0
-#define FIJI_VOLTAGE_CONTROL_BY_GPIO                0x1
-#define FIJI_VOLTAGE_CONTROL_BY_SVID2               0x2
-#define FIJI_VOLTAGE_CONTROL_MERGED                 0x3
-
-#define DPMTABLE_OD_UPDATE_SCLK     0x00000001
-#define DPMTABLE_OD_UPDATE_MCLK     0x00000002
-#define DPMTABLE_UPDATE_SCLK        0x00000004
-#define DPMTABLE_UPDATE_MCLK        0x00000008
-
-struct fiji_performance_level {
-       uint32_t  memory_clock;
-       uint32_t  engine_clock;
-       uint16_t  pcie_gen;
-       uint16_t  pcie_lane;
-};
-
-struct fiji_uvd_clocks {
-       uint32_t  vclk;
-       uint32_t  dclk;
-};
-
-struct fiji_vce_clocks {
-       uint32_t  evclk;
-       uint32_t  ecclk;
-};
-
-struct fiji_power_state {
-    uint32_t                  magic;
-    struct fiji_uvd_clocks    uvd_clks;
-    struct fiji_vce_clocks    vce_clks;
-    uint32_t                  sam_clk;
-    uint32_t                  acp_clk;
-    uint16_t                  performance_level_count;
-    bool                      dc_compatible;
-    uint32_t                  sclk_threshold;
-    struct fiji_performance_level  performance_levels[FIJI_MAX_HARDWARE_POWERLEVELS];
-};
-
-struct fiji_dpm_level {
-       bool    enabled;
-    uint32_t   value;
-    uint32_t   param1;
-};
-
-#define FIJI_MAX_DEEPSLEEP_DIVIDER_ID 5
-#define MAX_REGULAR_DPM_NUMBER 8
-#define FIJI_MINIMUM_ENGINE_CLOCK 2500
-
-struct fiji_single_dpm_table {
-       uint32_t                count;
-       struct fiji_dpm_level   dpm_levels[MAX_REGULAR_DPM_NUMBER];
-};
-
-struct fiji_dpm_table {
-       struct fiji_single_dpm_table  sclk_table;
-       struct fiji_single_dpm_table  mclk_table;
-       struct fiji_single_dpm_table  pcie_speed_table;
-       struct fiji_single_dpm_table  vddc_table;
-       struct fiji_single_dpm_table  vddci_table;
-       struct fiji_single_dpm_table  mvdd_table;
-};
-
-struct fiji_clock_registers {
-       uint32_t  vCG_SPLL_FUNC_CNTL;
-       uint32_t  vCG_SPLL_FUNC_CNTL_2;
-       uint32_t  vCG_SPLL_FUNC_CNTL_3;
-       uint32_t  vCG_SPLL_FUNC_CNTL_4;
-       uint32_t  vCG_SPLL_SPREAD_SPECTRUM;
-       uint32_t  vCG_SPLL_SPREAD_SPECTRUM_2;
-       uint32_t  vDLL_CNTL;
-       uint32_t  vMCLK_PWRMGT_CNTL;
-       uint32_t  vMPLL_AD_FUNC_CNTL;
-       uint32_t  vMPLL_DQ_FUNC_CNTL;
-       uint32_t  vMPLL_FUNC_CNTL;
-       uint32_t  vMPLL_FUNC_CNTL_1;
-       uint32_t  vMPLL_FUNC_CNTL_2;
-       uint32_t  vMPLL_SS1;
-       uint32_t  vMPLL_SS2;
-};
-
-struct fiji_voltage_smio_registers {
-       uint32_t vS0_VID_LOWER_SMIO_CNTL;
-};
-
-#define FIJI_MAX_LEAKAGE_COUNT  8
-struct fiji_leakage_voltage {
-       uint16_t  count;
-       uint16_t  leakage_id[FIJI_MAX_LEAKAGE_COUNT];
-       uint16_t  actual_voltage[FIJI_MAX_LEAKAGE_COUNT];
-};
-
-struct fiji_vbios_boot_state {
-       uint16_t    mvdd_bootup_value;
-       uint16_t    vddc_bootup_value;
-       uint16_t    vddci_bootup_value;
-       uint32_t    sclk_bootup_value;
-       uint32_t    mclk_bootup_value;
-       uint16_t    pcie_gen_bootup_value;
-       uint16_t    pcie_lane_bootup_value;
-};
-
-struct fiji_bacos {
-       uint32_t                       best_match;
-       uint32_t                       baco_flags;
-       struct fiji_performance_level  performance_level;
-};
-
-/* Ultra Low Voltage parameter structure */
-struct fiji_ulv_parm {
-       bool                           ulv_supported;
-       uint32_t                       cg_ulv_parameter;
-       uint32_t                       ulv_volt_change_delay;
-       struct fiji_performance_level  ulv_power_level;
-};
-
-struct fiji_display_timing {
-       uint32_t  min_clock_in_sr;
-       uint32_t  num_existing_displays;
-};
-
-struct fiji_dpmlevel_enable_mask {
-       uint32_t  uvd_dpm_enable_mask;
-       uint32_t  vce_dpm_enable_mask;
-       uint32_t  acp_dpm_enable_mask;
-       uint32_t  samu_dpm_enable_mask;
-       uint32_t  sclk_dpm_enable_mask;
-       uint32_t  mclk_dpm_enable_mask;
-       uint32_t  pcie_dpm_enable_mask;
-};
-
-struct fiji_pcie_perf_range {
-       uint16_t  max;
-       uint16_t  min;
-};
-
-struct fiji_hwmgr {
-       struct fiji_dpm_table                   dpm_table;
-       struct fiji_dpm_table                   golden_dpm_table;
-
-       uint32_t                                                voting_rights_clients0;
-       uint32_t                                                voting_rights_clients1;
-       uint32_t                                                voting_rights_clients2;
-       uint32_t                                                voting_rights_clients3;
-       uint32_t                                                voting_rights_clients4;
-       uint32_t                                                voting_rights_clients5;
-       uint32_t                                                voting_rights_clients6;
-       uint32_t                                                voting_rights_clients7;
-       uint32_t                                                static_screen_threshold_unit;
-       uint32_t                                                static_screen_threshold;
-       uint32_t                                                voltage_control;
-       uint32_t                                                vddc_vddci_delta;
-
-       uint32_t                                                active_auto_throttle_sources;
-
-       struct fiji_clock_registers            clock_registers;
-       struct fiji_voltage_smio_registers      voltage_smio_registers;
-
-       bool                           is_memory_gddr5;
-       uint16_t                       acpi_vddc;
-       bool                           pspp_notify_required;
-       uint16_t                       force_pcie_gen;
-       uint16_t                       acpi_pcie_gen;
-       uint32_t                       pcie_gen_cap;
-       uint32_t                       pcie_lane_cap;
-       uint32_t                       pcie_spc_cap;
-       struct fiji_leakage_voltage          vddc_leakage;
-       struct fiji_leakage_voltage          Vddci_leakage;
-
-       uint32_t                             mvdd_control;
-       uint32_t                             vddc_mask_low;
-       uint32_t                             mvdd_mask_low;
-       uint16_t                            max_vddc_in_pptable;
-       uint16_t                            min_vddc_in_pptable;
-       uint16_t                            max_vddci_in_pptable;
-       uint16_t                            min_vddci_in_pptable;
-       uint32_t                             mclk_strobe_mode_threshold;
-       uint32_t                             mclk_stutter_mode_threshold;
-       uint32_t                             mclk_edc_enable_threshold;
-       uint32_t                             mclk_edcwr_enable_threshold;
-       bool                                is_uvd_enabled;
-       struct fiji_vbios_boot_state        vbios_boot_state;
-
-       bool                           battery_state;
-       bool                           is_tlu_enabled;
-
-       /* ---- SMC SRAM Address of firmware header tables ---- */
-       uint32_t                             sram_end;
-       uint32_t                             dpm_table_start;
-       uint32_t                             soft_regs_start;
-       uint32_t                             mc_reg_table_start;
-       uint32_t                             fan_table_start;
-       uint32_t                             arb_table_start;
-       struct SMU73_Discrete_DpmTable       smc_state_table;
-       struct SMU73_Discrete_Ulv            ulv_setting;
-
-       /* ---- Stuff originally coming from Evergreen ---- */
-       uint32_t                             vddci_control;
-       struct pp_atomctrl_voltage_table     vddc_voltage_table;
-       struct pp_atomctrl_voltage_table     vddci_voltage_table;
-       struct pp_atomctrl_voltage_table     mvdd_voltage_table;
-
-       uint32_t                             mgcg_cgtt_local2;
-       uint32_t                             mgcg_cgtt_local3;
-       uint32_t                             gpio_debug;
-       uint32_t                             mc_micro_code_feature;
-       uint32_t                             highest_mclk;
-       uint16_t                             acpi_vddci;
-       uint8_t                              mvdd_high_index;
-       uint8_t                              mvdd_low_index;
-       bool                                 dll_default_on;
-       bool                                 performance_request_registered;
-
-       /* ---- Low Power Features ---- */
-       struct fiji_bacos                    bacos;
-       struct fiji_ulv_parm                 ulv;
-
-       /* ---- CAC Stuff ---- */
-       uint32_t                       cac_table_start;
-       bool                           cac_configuration_required;
-       bool                           driver_calculate_cac_leakage;
-       bool                           cac_enabled;
-
-       /* ---- DPM2 Parameters ---- */
-       uint32_t                       power_containment_features;
-       bool                           enable_dte_feature;
-       bool                           enable_tdc_limit_feature;
-       bool                           enable_pkg_pwr_tracking_feature;
-       bool                           disable_uvd_power_tune_feature;
-       const struct fiji_pt_defaults  *power_tune_defaults;
-       struct SMU73_Discrete_PmFuses  power_tune_table;
-       uint32_t                       dte_tj_offset;
-       uint32_t                       fast_watermark_threshold;
-
-       /* ---- Phase Shedding ---- */
-       bool                           vddc_phase_shed_control;
-
-       /* ---- DI/DT ---- */
-       struct fiji_display_timing        display_timing;
-
-       /* ---- Thermal Temperature Setting ---- */
-       struct fiji_dpmlevel_enable_mask     dpm_level_enable_mask;
-       uint32_t                             need_update_smu7_dpm_table;
-       uint32_t                             sclk_dpm_key_disabled;
-       uint32_t                             mclk_dpm_key_disabled;
-       uint32_t                             pcie_dpm_key_disabled;
-       uint32_t                             min_engine_clocks;
-       struct fiji_pcie_perf_range          pcie_gen_performance;
-       struct fiji_pcie_perf_range          pcie_lane_performance;
-       struct fiji_pcie_perf_range          pcie_gen_power_saving;
-       struct fiji_pcie_perf_range          pcie_lane_power_saving;
-       bool                                 use_pcie_performance_levels;
-       bool                                 use_pcie_power_saving_levels;
-       uint32_t                             activity_target[SMU73_MAX_LEVELS_GRAPHICS];
-       uint32_t                             mclk_activity_target;
-       uint32_t                             mclk_dpm0_activity_target;
-       uint32_t                             low_sclk_interrupt_threshold;
-       uint32_t                             last_mclk_dpm_enable_mask;
-       bool                                 uvd_enabled;
-
-       /* ---- Power Gating States ---- */
-       bool                           uvd_power_gated;
-       bool                           vce_power_gated;
-       bool                           samu_power_gated;
-       bool                           acp_power_gated;
-       bool                           pg_acp_init;
-       bool                           frtc_enabled;
-       bool                           frtc_status_changed;
-};
-
-/* To convert to Q8.8 format for firmware */
-#define FIJI_Q88_FORMAT_CONVERSION_UNIT             256
-
-enum Fiji_I2CLineID {
-    Fiji_I2CLineID_DDC1 = 0x90,
-    Fiji_I2CLineID_DDC2 = 0x91,
-    Fiji_I2CLineID_DDC3 = 0x92,
-    Fiji_I2CLineID_DDC4 = 0x93,
-    Fiji_I2CLineID_DDC5 = 0x94,
-    Fiji_I2CLineID_DDC6 = 0x95,
-    Fiji_I2CLineID_SCLSDA = 0x96,
-    Fiji_I2CLineID_DDCVGA = 0x97
-};
-
-#define Fiji_I2C_DDC1DATA          0
-#define Fiji_I2C_DDC1CLK           1
-#define Fiji_I2C_DDC2DATA          2
-#define Fiji_I2C_DDC2CLK           3
-#define Fiji_I2C_DDC3DATA          4
-#define Fiji_I2C_DDC3CLK           5
-#define Fiji_I2C_SDA               40
-#define Fiji_I2C_SCL               41
-#define Fiji_I2C_DDC4DATA          65
-#define Fiji_I2C_DDC4CLK           66
-#define Fiji_I2C_DDC5DATA          0x48
-#define Fiji_I2C_DDC5CLK           0x49
-#define Fiji_I2C_DDC6DATA          0x4a
-#define Fiji_I2C_DDC6CLK           0x4b
-#define Fiji_I2C_DDCVGADATA        0x4c
-#define Fiji_I2C_DDCVGACLK         0x4d
-
-#define FIJI_UNUSED_GPIO_PIN       0x7F
-
-extern int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
-extern int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr);
-extern int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr);
-extern int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display);
-int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
-int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
-int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate);
-int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate);
-int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
-
-#endif /* _FIJI_HWMGR_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c
deleted file mode 100644 (file)
index 4465845..0000000
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
- * Copyright 2015 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 "hwmgr.h"
-#include "smumgr.h"
-#include "fiji_hwmgr.h"
-#include "fiji_powertune.h"
-#include "fiji_smumgr.h"
-#include "smu73_discrete.h"
-#include "pp_debug.h"
-
-#define VOLTAGE_SCALE  4
-#define POWERTUNE_DEFAULT_SET_MAX    1
-
-const struct fiji_pt_defaults fiji_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
-               /*sviLoadLIneEn,  SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */
-               {1,               0xF,             0xFD,
-               /* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */
-               0x19,        5,               45}
-};
-
-void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *fiji_hwmgr = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct  phm_ppt_v1_information *table_info =
-                       (struct  phm_ppt_v1_information *)(hwmgr->pptable);
-       uint32_t tmp = 0;
-
-       if(table_info &&
-                       table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
-                       table_info->cac_dtp_table->usPowerTuneDataSetID)
-               fiji_hwmgr->power_tune_defaults =
-                               &fiji_power_tune_data_set_array
-                               [table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
-       else
-               fiji_hwmgr->power_tune_defaults = &fiji_power_tune_data_set_array[0];
-
-       /* Assume disabled */
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerContainment);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_CAC);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SQRamping);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_DBRamping);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_TDRamping);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_TCPRamping);
-
-       fiji_hwmgr->dte_tj_offset = tmp;
-
-       if (!tmp) {
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_CAC);
-
-               fiji_hwmgr->fast_watermark_threshold = 100;
-
-               if (hwmgr->powercontainment_enabled) {
-                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                   PHM_PlatformCaps_PowerContainment);
-                       tmp = 1;
-                       fiji_hwmgr->enable_dte_feature = tmp ? false : true;
-                       fiji_hwmgr->enable_tdc_limit_feature = tmp ? true : false;
-                       fiji_hwmgr->enable_pkg_pwr_tracking_feature = tmp ? true : false;
-               }
-       }
-}
-
-/* PPGen has the gain setting generated in x * 100 unit
- * This function is to convert the unit to x * 4096(0x1000) unit.
- *  This is the unit expected by SMC firmware
- */
-static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
-{
-       uint32_t tmp;
-       tmp = raw_setting * 4096 / 100;
-       return (uint16_t)tmp;
-}
-
-static void get_scl_sda_value(uint8_t line, uint8_t *scl, uint8_t* sda)
-{
-       switch (line) {
-       case Fiji_I2CLineID_DDC1 :
-               *scl = Fiji_I2C_DDC1CLK;
-               *sda = Fiji_I2C_DDC1DATA;
-               break;
-       case Fiji_I2CLineID_DDC2 :
-               *scl = Fiji_I2C_DDC2CLK;
-               *sda = Fiji_I2C_DDC2DATA;
-               break;
-       case Fiji_I2CLineID_DDC3 :
-               *scl = Fiji_I2C_DDC3CLK;
-               *sda = Fiji_I2C_DDC3DATA;
-               break;
-       case Fiji_I2CLineID_DDC4 :
-               *scl = Fiji_I2C_DDC4CLK;
-               *sda = Fiji_I2C_DDC4DATA;
-               break;
-       case Fiji_I2CLineID_DDC5 :
-               *scl = Fiji_I2C_DDC5CLK;
-               *sda = Fiji_I2C_DDC5DATA;
-               break;
-       case Fiji_I2CLineID_DDC6 :
-               *scl = Fiji_I2C_DDC6CLK;
-               *sda = Fiji_I2C_DDC6DATA;
-               break;
-       case Fiji_I2CLineID_SCLSDA :
-               *scl = Fiji_I2C_SCL;
-               *sda = Fiji_I2C_SDA;
-               break;
-       case Fiji_I2CLineID_DDCVGA :
-               *scl = Fiji_I2C_DDCVGACLK;
-               *sda = Fiji_I2C_DDCVGADATA;
-               break;
-       default:
-               *scl = 0;
-               *sda = 0;
-               break;
-       }
-}
-
-int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
-       SMU73_Discrete_DpmTable  *dpm_table = &(data->smc_state_table);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
-       struct pp_advance_fan_control_parameters *fan_table=
-                       &hwmgr->thermal_controller.advanceFanControlParameters;
-       uint8_t uc_scl, uc_sda;
-
-       /* TDP number of fraction bits are changed from 8 to 7 for Fiji
-        * as requested by SMC team
-        */
-       dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
-                       (uint16_t)(cac_dtp_table->usTDP * 128));
-       dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
-                       (uint16_t)(cac_dtp_table->usTDP * 128));
-
-       PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
-                       "Target Operating Temp is out of Range!",);
-
-       dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
-       dpm_table->GpuTjHyst = 8;
-
-       dpm_table->DTEAmbientTempBase = defaults->DTEAmbientTempBase;
-
-       /* The following are for new Fiji Multi-input fan/thermal control */
-       dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
-                       cac_dtp_table->usTargetOperatingTemp * 256);
-       dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
-                       cac_dtp_table->usTemperatureLimitHotspot * 256);
-       dpm_table->TemperatureLimitLiquid1 = PP_HOST_TO_SMC_US(
-                       cac_dtp_table->usTemperatureLimitLiquid1 * 256);
-       dpm_table->TemperatureLimitLiquid2 = PP_HOST_TO_SMC_US(
-                       cac_dtp_table->usTemperatureLimitLiquid2 * 256);
-       dpm_table->TemperatureLimitVrVddc = PP_HOST_TO_SMC_US(
-                       cac_dtp_table->usTemperatureLimitVrVddc * 256);
-       dpm_table->TemperatureLimitVrMvdd = PP_HOST_TO_SMC_US(
-                       cac_dtp_table->usTemperatureLimitVrMvdd * 256);
-       dpm_table->TemperatureLimitPlx = PP_HOST_TO_SMC_US(
-                       cac_dtp_table->usTemperatureLimitPlx * 256);
-
-       dpm_table->FanGainEdge = PP_HOST_TO_SMC_US(
-                       scale_fan_gain_settings(fan_table->usFanGainEdge));
-       dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US(
-                       scale_fan_gain_settings(fan_table->usFanGainHotspot));
-       dpm_table->FanGainLiquid = PP_HOST_TO_SMC_US(
-                       scale_fan_gain_settings(fan_table->usFanGainLiquid));
-       dpm_table->FanGainVrVddc = PP_HOST_TO_SMC_US(
-                       scale_fan_gain_settings(fan_table->usFanGainVrVddc));
-       dpm_table->FanGainVrMvdd = PP_HOST_TO_SMC_US(
-                       scale_fan_gain_settings(fan_table->usFanGainVrMvdd));
-       dpm_table->FanGainPlx = PP_HOST_TO_SMC_US(
-                       scale_fan_gain_settings(fan_table->usFanGainPlx));
-       dpm_table->FanGainHbm = PP_HOST_TO_SMC_US(
-                       scale_fan_gain_settings(fan_table->usFanGainHbm));
-
-       dpm_table->Liquid1_I2C_address = cac_dtp_table->ucLiquid1_I2C_address;
-       dpm_table->Liquid2_I2C_address = cac_dtp_table->ucLiquid2_I2C_address;
-       dpm_table->Vr_I2C_address = cac_dtp_table->ucVr_I2C_address;
-       dpm_table->Plx_I2C_address = cac_dtp_table->ucPlx_I2C_address;
-
-       get_scl_sda_value(cac_dtp_table->ucLiquid_I2C_Line, &uc_scl, &uc_sda);
-       dpm_table->Liquid_I2C_LineSCL = uc_scl;
-       dpm_table->Liquid_I2C_LineSDA = uc_sda;
-
-       get_scl_sda_value(cac_dtp_table->ucVr_I2C_Line, &uc_scl, &uc_sda);
-       dpm_table->Vr_I2C_LineSCL = uc_scl;
-       dpm_table->Vr_I2C_LineSDA = uc_sda;
-
-       get_scl_sda_value(cac_dtp_table->ucPlx_I2C_Line, &uc_scl, &uc_sda);
-       dpm_table->Plx_I2C_LineSCL = uc_scl;
-       dpm_table->Plx_I2C_LineSDA = uc_sda;
-
-       return 0;
-}
-
-static int fiji_populate_svi_load_line(struct pp_hwmgr *hwmgr)
-{
-    struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-    const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
-
-    data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
-    data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
-    data->power_tune_table.SviLoadLineTrimVddC = 3;
-    data->power_tune_table.SviLoadLineOffsetVddC = 0;
-
-    return 0;
-}
-
-static int fiji_populate_tdc_limit(struct pp_hwmgr *hwmgr)
-{
-       uint16_t tdc_limit;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
-
-       /* TDC number of fraction bits are changed from 8 to 7
-        * for Fiji as requested by SMC team
-        */
-       tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
-       data->power_tune_table.TDC_VDDC_PkgLimit =
-                       CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
-       data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
-                       defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
-       data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
-
-       return 0;
-}
-
-static int fiji_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
-       uint32_t temp;
-
-       if (fiji_read_smc_sram_dword(hwmgr->smumgr,
-                       fuse_table_offset +
-                       offsetof(SMU73_Discrete_PmFuses, TdcWaterfallCtl),
-                       (uint32_t *)&temp, data->sram_end))
-               PP_ASSERT_WITH_CODE(false,
-                               "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
-                               return -EINVAL);
-       else {
-               data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
-               data->power_tune_table.LPMLTemperatureMin =
-                               (uint8_t)((temp >> 16) & 0xff);
-               data->power_tune_table.LPMLTemperatureMax =
-                               (uint8_t)((temp >> 8) & 0xff);
-               data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
-       }
-       return 0;
-}
-
-static int fiji_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
-{
-       int i;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       /* Currently not used. Set all to zero. */
-       for (i = 0; i < 16; i++)
-               data->power_tune_table.LPMLTemperatureScaler[i] = 0;
-
-       return 0;
-}
-
-static int fiji_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if( (hwmgr->thermal_controller.advanceFanControlParameters.
-                       usFanOutputSensitivity & (1 << 15)) ||
-                       0 == hwmgr->thermal_controller.advanceFanControlParameters.
-                       usFanOutputSensitivity )
-               hwmgr->thermal_controller.advanceFanControlParameters.
-               usFanOutputSensitivity = hwmgr->thermal_controller.
-                       advanceFanControlParameters.usDefaultFanOutputSensitivity;
-
-       data->power_tune_table.FuzzyFan_PwmSetDelta =
-                       PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
-                                       advanceFanControlParameters.usFanOutputSensitivity);
-       return 0;
-}
-
-static int fiji_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
-{
-       int i;
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       /* Currently not used. Set all to zero. */
-       for (i = 0; i < 16; i++)
-               data->power_tune_table.GnbLPML[i] = 0;
-
-       return 0;
-}
-
-static int fiji_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
-{
- /*   int  i, min, max;
-    struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-    uint8_t * pHiVID = data->power_tune_table.BapmVddCVidHiSidd;
-    uint8_t * pLoVID = data->power_tune_table.BapmVddCVidLoSidd;
-
-    min = max = pHiVID[0];
-    for (i = 0; i < 8; i++) {
-        if (0 != pHiVID[i]) {
-            if (min > pHiVID[i])
-                min = pHiVID[i];
-            if (max < pHiVID[i])
-                max = pHiVID[i];
-        }
-
-        if (0 != pLoVID[i]) {
-            if (min > pLoVID[i])
-                min = pLoVID[i];
-            if (max < pLoVID[i])
-                max = pLoVID[i];
-        }
-    }
-
-    PP_ASSERT_WITH_CODE((0 != min) && (0 != max), "BapmVddcVidSidd table does not exist!", return int_Failed);
-    data->power_tune_table.GnbLPMLMaxVid = (uint8_t)max;
-    data->power_tune_table.GnbLPMLMinVid = (uint8_t)min;
-*/
-    return 0;
-}
-
-static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint16_t HiSidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
-       uint16_t LoSidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
-       struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
-
-       HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
-       LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
-
-       data->power_tune_table.BapmVddCBaseLeakageHiSidd =
-                       CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
-       data->power_tune_table.BapmVddCBaseLeakageLoSidd =
-                       CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
-
-       return 0;
-}
-
-int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       uint32_t pm_fuse_table_offset;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerContainment)) {
-               if (fiji_read_smc_sram_dword(hwmgr->smumgr,
-                               SMU7_FIRMWARE_HEADER_LOCATION +
-                               offsetof(SMU73_Firmware_Header, PmFuseTable),
-                               &pm_fuse_table_offset, data->sram_end))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to get pm_fuse_table_offset Failed!",
-                                       return -EINVAL);
-
-               /* DW6 */
-               if (fiji_populate_svi_load_line(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate SviLoadLine Failed!",
-                                       return -EINVAL);
-               /* DW7 */
-               if (fiji_populate_tdc_limit(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate TDCLimit Failed!", return -EINVAL);
-               /* DW8 */
-               if (fiji_populate_dw8(hwmgr, pm_fuse_table_offset))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate TdcWaterfallCtl, "
-                                       "LPMLTemperature Min and Max Failed!",
-                                       return -EINVAL);
-
-               /* DW9-DW12 */
-               if (0 != fiji_populate_temperature_scaler(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate LPMLTemperatureScaler Failed!",
-                                       return -EINVAL);
-
-               /* DW13-DW14 */
-               if(fiji_populate_fuzzy_fan(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate Fuzzy Fan Control parameters Failed!",
-                                       return -EINVAL);
-
-               /* DW15-DW18 */
-               if (fiji_populate_gnb_lpml(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate GnbLPML Failed!",
-                                       return -EINVAL);
-
-               /* DW19 */
-               if (fiji_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate GnbLPML Min and Max Vid Failed!",
-                                       return -EINVAL);
-
-               /* DW20 */
-               if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate BapmVddCBaseLeakage Hi and Lo "
-                                       "Sidd Failed!", return -EINVAL);
-
-               if (fiji_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
-                               (uint8_t *)&data->power_tune_table,
-                               sizeof(struct SMU73_Discrete_PmFuses), data->sram_end))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to download PmFuseTable Failed!",
-                                       return -EINVAL);
-       }
-       return 0;
-}
-
-int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       int result = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_CAC)) {
-               int smc_result;
-               smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                               (uint16_t)(PPSMC_MSG_EnableCac));
-               PP_ASSERT_WITH_CODE((0 == smc_result),
-                               "Failed to enable CAC in SMC.", result = -1);
-
-        data->cac_enabled = (0 == smc_result) ? true : false;
-       }
-       return result;
-}
-
-int fiji_disable_smc_cac(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       int result = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_CAC) && data->cac_enabled) {
-               int smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                               (uint16_t)(PPSMC_MSG_DisableCac));
-               PP_ASSERT_WITH_CODE((smc_result == 0),
-                               "Failed to disable CAC in SMC.", result = -1);
-
-               data->cac_enabled = false;
-       }
-       return result;
-}
-
-int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-
-       if(data->power_containment_features &
-                       POWERCONTAINMENT_FEATURE_PkgPwrLimit)
-               return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_PkgPwrSetLimit, n);
-       return 0;
-}
-
-static int fiji_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
-{
-       return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
-                       PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
-}
-
-int fiji_enable_power_containment(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       int smc_result;
-       int result = 0;
-
-       data->power_containment_features = 0;
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerContainment)) {
-               if (data->enable_dte_feature) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_EnableDTE));
-                       PP_ASSERT_WITH_CODE((0 == smc_result),
-                                       "Failed to enable DTE in SMC.", result = -1;);
-                       if (0 == smc_result)
-                               data->power_containment_features |= POWERCONTAINMENT_FEATURE_DTE;
-               }
-
-               if (data->enable_tdc_limit_feature) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_TDCLimitEnable));
-                       PP_ASSERT_WITH_CODE((0 == smc_result),
-                                       "Failed to enable TDCLimit in SMC.", result = -1;);
-                       if (0 == smc_result)
-                               data->power_containment_features |=
-                                               POWERCONTAINMENT_FEATURE_TDCLimit;
-               }
-
-               if (data->enable_pkg_pwr_tracking_feature) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
-                       PP_ASSERT_WITH_CODE((0 == smc_result),
-                                       "Failed to enable PkgPwrTracking in SMC.", result = -1;);
-                       if (0 == smc_result) {
-                               struct phm_cac_tdp_table *cac_table =
-                                               table_info->cac_dtp_table;
-                               uint32_t default_limit =
-                                       (uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
-
-                               data->power_containment_features |=
-                                               POWERCONTAINMENT_FEATURE_PkgPwrLimit;
-
-                               if (fiji_set_power_limit(hwmgr, default_limit))
-                                       printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
-                       }
-               }
-       }
-       return result;
-}
-
-int fiji_disable_power_containment(struct pp_hwmgr *hwmgr)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       int result = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerContainment) &&
-                       data->power_containment_features) {
-               int smc_result;
-
-               if (data->power_containment_features &
-                               POWERCONTAINMENT_FEATURE_TDCLimit) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_TDCLimitDisable));
-                       PP_ASSERT_WITH_CODE((smc_result == 0),
-                                       "Failed to disable TDCLimit in SMC.",
-                                       result = smc_result);
-               }
-
-               if (data->power_containment_features &
-                               POWERCONTAINMENT_FEATURE_DTE) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_DisableDTE));
-                       PP_ASSERT_WITH_CODE((smc_result == 0),
-                                       "Failed to disable DTE in SMC.",
-                                       result = smc_result);
-               }
-
-               if (data->power_containment_features &
-                               POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_PkgPwrLimitDisable));
-                       PP_ASSERT_WITH_CODE((smc_result == 0),
-                                       "Failed to disable PkgPwrTracking in SMC.",
-                                       result = smc_result);
-               }
-               data->power_containment_features = 0;
-       }
-
-       return result;
-}
-
-int fiji_power_control_set_level(struct pp_hwmgr *hwmgr)
-{
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
-       int adjust_percent, target_tdp;
-       int result = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerContainment)) {
-               /* adjustment percentage has already been validated */
-               adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
-                               hwmgr->platform_descriptor.TDPAdjustment :
-                               (-1 * hwmgr->platform_descriptor.TDPAdjustment);
-               /* SMC requested that target_tdp to be 7 bit fraction in DPM table
-                * but message to be 8 bit fraction for messages
-                */
-               target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
-               result = fiji_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
-       }
-
-       return result;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h
deleted file mode 100644 (file)
index fec7724..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2015 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 FIJI_POWERTUNE_H
-#define FIJI_POWERTUNE_H
-
-enum fiji_pt_config_reg_type {
-       FIJI_CONFIGREG_MMR = 0,
-       FIJI_CONFIGREG_SMC_IND,
-       FIJI_CONFIGREG_DIDT_IND,
-       FIJI_CONFIGREG_CACHE,
-       FIJI_CONFIGREG_MAX
-};
-
-/* PowerContainment Features */
-#define POWERCONTAINMENT_FEATURE_DTE             0x00000001
-#define POWERCONTAINMENT_FEATURE_TDCLimit        0x00000002
-#define POWERCONTAINMENT_FEATURE_PkgPwrLimit     0x00000004
-
-#define DIDT_SQ_CTRL0__UNUSED_0_MASK             0xffffffc0
-#define DIDT_SQ_CTRL0__UNUSED_0__SHIFT           0x6
-#define DIDT_TD_CTRL0__UNUSED_0_MASK             0xffffffc0
-#define DIDT_TD_CTRL0__UNUSED_0__SHIFT           0x6
-#define DIDT_TCP_CTRL0__UNUSED_0_MASK            0xffffffc0
-#define DIDT_TCP_CTRL0__UNUSED_0__SHIFT          0x6
-#define DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK                 0xe0000000
-#define DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT               0x0000001d
-#define DIDT_TD_TUNING_CTRL__UNUSED_0_MASK                 0xe0000000
-#define DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT               0x0000001d
-#define DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK                0xe0000000
-#define DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT              0x0000001d
-
-struct fiji_pt_config_reg {
-       uint32_t                           offset;
-       uint32_t                           mask;
-       uint32_t                           shift;
-       uint32_t                           value;
-       enum fiji_pt_config_reg_type       type;
-};
-
-struct fiji_pt_defaults
-{
-    uint8_t   SviLoadLineEn;
-    uint8_t   SviLoadLineVddC;
-    uint8_t   TDC_VDDC_ThrottleReleaseLimitPerc;
-    uint8_t   TDC_MAWt;
-    uint8_t   TdcWaterfallCtl;
-    uint8_t   DTEAmbientTempBase;
-};
-
-void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
-int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
-int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr);
-int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr);
-int fiji_disable_smc_cac(struct pp_hwmgr *hwmgr);
-int fiji_enable_power_containment(struct pp_hwmgr *hwmgr);
-int fiji_disable_power_containment(struct pp_hwmgr *hwmgr);
-int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
-int fiji_power_control_set_level(struct pp_hwmgr *hwmgr);
-
-#endif  /* FIJI_POWERTUNE_H */
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c
deleted file mode 100644 (file)
index 92976b6..0000000
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * Copyright 2015 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 <asm/div64.h>
-#include "fiji_thermal.h"
-#include "fiji_hwmgr.h"
-#include "fiji_smumgr.h"
-#include "fiji_ppsmc.h"
-#include "smu/smu_7_1_3_d.h"
-#include "smu/smu_7_1_3_sh_mask.h"
-
-int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
-               struct phm_fan_speed_info *fan_speed_info)
-{
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       fan_speed_info->supports_percent_read = true;
-       fan_speed_info->supports_percent_write = true;
-       fan_speed_info->min_percent = 0;
-       fan_speed_info->max_percent = 100;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
-               hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
-               fan_speed_info->supports_rpm_read = true;
-               fan_speed_info->supports_rpm_write = true;
-               fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
-               fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
-       } else {
-               fan_speed_info->min_rpm = 0;
-               fan_speed_info->max_rpm = 0;
-       }
-
-       return 0;
-}
-
-int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
-               uint32_t *speed)
-{
-       uint32_t duty100;
-       uint32_t duty;
-       uint64_t tmp64;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL1, FMAX_DUTY100);
-       duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_STATUS, FDO_PWM_DUTY);
-
-       if (duty100 == 0)
-               return -EINVAL;
-
-
-       tmp64 = (uint64_t)duty * 100;
-       do_div(tmp64, duty100);
-       *speed = (uint32_t)tmp64;
-
-       if (*speed > 100)
-               *speed = 100;
-
-       return 0;
-}
-
-int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
-{
-       uint32_t tach_period;
-       uint32_t crystal_clock_freq;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan ||
-                       (hwmgr->thermal_controller.fanInfo.
-                               ucTachometerPulsesPerRevolution == 0))
-               return 0;
-
-       tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_TACH_STATUS, TACH_PERIOD);
-
-       if (tach_period == 0)
-               return -EINVAL;
-
-       crystal_clock_freq = tonga_get_xclk(hwmgr);
-
-       *speed = 60 * crystal_clock_freq * 10000/ tach_period;
-
-       return 0;
-}
-
-/**
-* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
-* @param    hwmgr  the address of the powerplay hardware manager.
-*           mode    the fan control mode, 0 default, 1 by percent, 5, by RPM
-* @exception Should always succeed.
-*/
-int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
-{
-
-       if (hwmgr->fan_ctrl_is_in_default_mode) {
-               hwmgr->fan_ctrl_default_mode =
-                               PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,     CGS_IND_REG__SMC,
-                                               CG_FDO_CTRL2, FDO_PWM_MODE);
-               hwmgr->tmin =
-                               PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                                               CG_FDO_CTRL2, TMIN);
-               hwmgr->fan_ctrl_is_in_default_mode = false;
-       }
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL2, TMIN, 0);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL2, FDO_PWM_MODE, mode);
-
-       return 0;
-}
-
-/**
-* Reset Fan Speed Control to default mode.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @exception Should always succeed.
-*/
-int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
-{
-       if (!hwmgr->fan_ctrl_is_in_default_mode) {
-               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
-               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_FDO_CTRL2, TMIN, hwmgr->tmin);
-               hwmgr->fan_ctrl_is_in_default_mode = true;
-       }
-
-       return 0;
-}
-
-int fiji_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
-               cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
-               result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_FanSpeedInTableIsRPM))
-                       hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
-                                       hwmgr->thermal_controller.
-                                       advanceFanControlParameters.usMaxFanRPM);
-               else
-                       hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
-                                       hwmgr->thermal_controller.
-                                       advanceFanControlParameters.usMaxFanPWM);
-
-       } else {
-               cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
-               result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
-       }
-
-       if (!result && hwmgr->thermal_controller.
-                       advanceFanControlParameters.ucTargetTemperature)
-               result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_SetFanTemperatureTarget,
-                               hwmgr->thermal_controller.
-                               advanceFanControlParameters.ucTargetTemperature);
-
-       return result;
-}
-
-
-int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
-}
-
-/**
-* Set Fan Speed in percent.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    speed is the percentage value (0% - 100%) to be set.
-* @exception Fails is the 100% setting appears to be 0.
-*/
-int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
-               uint32_t speed)
-{
-       uint32_t duty100;
-       uint32_t duty;
-       uint64_t tmp64;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       if (speed > 100)
-               speed = 100;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_MicrocodeFanControl))
-               fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
-
-       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL1, FMAX_DUTY100);
-
-       if (duty100 == 0)
-               return -EINVAL;
-
-       tmp64 = (uint64_t)speed * duty100;
-       do_div(tmp64, 100);
-       duty = (uint32_t)tmp64;
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
-
-       return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-}
-
-/**
-* Reset Fan Speed to default.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @exception Always succeeds.
-*/
-int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_MicrocodeFanControl)) {
-               result = fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-               if (!result)
-                       result = fiji_fan_ctrl_start_smc_fan_control(hwmgr);
-       } else
-               result = fiji_fan_ctrl_set_default_mode(hwmgr);
-
-       return result;
-}
-
-/**
-* Set Fan Speed in RPM.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    speed is the percentage value (min - max) to be set.
-* @exception Fails is the speed not lie between min and max.
-*/
-int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
-{
-       uint32_t tach_period;
-       uint32_t crystal_clock_freq;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan ||
-                       (hwmgr->thermal_controller.fanInfo.
-                       ucTachometerPulsesPerRevolution == 0) ||
-                       (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
-                       (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
-               return 0;
-
-       crystal_clock_freq = tonga_get_xclk(hwmgr);
-
-       tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_TACH_STATUS, TACH_PERIOD, tach_period);
-
-       return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-}
-
-/**
-* Reads the remote temperature from the SIslands thermal controller.
-*
-* @param    hwmgr The address of the hardware manager.
-*/
-int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr)
-{
-       int temp;
-
-       temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_MULT_THERMAL_STATUS, CTF_TEMP);
-
-       /* Bit 9 means the reading is lower than the lowest usable value. */
-       if (temp & 0x200)
-               temp = FIJI_THERMAL_MAXIMUM_TEMP_READING;
-       else
-               temp = temp & 0x1ff;
-
-       temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-
-       return temp;
-}
-
-/**
-* Set the requested temperature range for high and low alert signals
-*
-* @param    hwmgr The address of the hardware manager.
-* @param    range Temperature range to be programmed for high and low alert signals
-* @exception PP_Result_BadInput if the input data is not valid.
-*/
-static int fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
-               uint32_t low_temp, uint32_t high_temp)
-{
-       uint32_t low = FIJI_THERMAL_MINIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-       uint32_t high = FIJI_THERMAL_MAXIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-
-       if (low < low_temp)
-               low = low_temp;
-       if (high > high_temp)
-               high = high_temp;
-
-       if (low > high)
-               return -EINVAL;
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, DIG_THERM_INTH,
-                       (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, DIG_THERM_INTL,
-                       (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_CTRL, DIG_THERM_DPM,
-                       (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-
-       return 0;
-}
-
-/**
-* Programs thermal controller one-time setting registers
-*
-* @param    hwmgr The address of the hardware manager.
-*/
-static int fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
-{
-       if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
-               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_TACH_CTRL, EDGE_PER_REV,
-                               hwmgr->thermal_controller.fanInfo.
-                               ucTachometerPulsesPerRevolution - 1);
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
-
-       return 0;
-}
-
-/**
-* Enable thermal alerts on the RV770 thermal controller.
-*
-* @param    hwmgr The address of the hardware manager.
-*/
-static int fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr)
-{
-       uint32_t alert;
-
-       alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, THERM_INT_MASK);
-       alert &= ~(FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, THERM_INT_MASK, alert);
-
-       /* send message to SMU to enable internal thermal interrupts */
-       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable);
-}
-
-/**
-* Disable thermal alerts on the RV770 thermal controller.
-* @param    hwmgr The address of the hardware manager.
-*/
-static int fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr)
-{
-       uint32_t alert;
-
-       alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, THERM_INT_MASK);
-       alert |= (FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, THERM_INT_MASK, alert);
-
-       /* send message to SMU to disable internal thermal interrupts */
-       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable);
-}
-
-/**
-* Uninitialize the thermal controller.
-* Currently just disables alerts.
-* @param    hwmgr The address of the hardware manager.
-*/
-int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
-{
-       int result = fiji_thermal_disable_alert(hwmgr);
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               fiji_fan_ctrl_set_default_mode(hwmgr);
-
-       return result;
-}
-
-/**
-* Set up the fan table to control the fan using the SMC.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from set temperature range routine
-*/
-int tf_fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-       struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
-       SMU73_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
-       uint32_t duty100;
-       uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
-       uint16_t fdo_min, slope1, slope2;
-       uint32_t reference_clock;
-       int res;
-       uint64_t tmp64;
-
-       if (data->fan_table_start == 0) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_MicrocodeFanControl);
-               return 0;
-       }
-
-       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL1, FMAX_DUTY100);
-
-       if (duty100 == 0) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_MicrocodeFanControl);
-               return 0;
-       }
-
-       tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
-                       usPWMMin * duty100;
-       do_div(tmp64, 10000);
-       fdo_min = (uint16_t)tmp64;
-
-       t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
-                       hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
-       t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
-                       hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
-
-       pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
-                       hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
-       pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
-                       hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
-
-       slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
-       slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
-
-       fan_table.TempMin = cpu_to_be16((50 + hwmgr->
-                       thermal_controller.advanceFanControlParameters.usTMin) / 100);
-       fan_table.TempMed = cpu_to_be16((50 + hwmgr->
-                       thermal_controller.advanceFanControlParameters.usTMed) / 100);
-       fan_table.TempMax = cpu_to_be16((50 + hwmgr->
-                       thermal_controller.advanceFanControlParameters.usTMax) / 100);
-
-       fan_table.Slope1 = cpu_to_be16(slope1);
-       fan_table.Slope2 = cpu_to_be16(slope2);
-
-       fan_table.FdoMin = cpu_to_be16(fdo_min);
-
-       fan_table.HystDown = cpu_to_be16(hwmgr->
-                       thermal_controller.advanceFanControlParameters.ucTHyst);
-
-       fan_table.HystUp = cpu_to_be16(1);
-
-       fan_table.HystSlope = cpu_to_be16(1);
-
-       fan_table.TempRespLim = cpu_to_be16(5);
-
-       reference_clock = tonga_get_xclk(hwmgr);
-
-       fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
-                       thermal_controller.advanceFanControlParameters.ulCycleDelay *
-                       reference_clock) / 1600);
-
-       fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
-
-       fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
-                       hwmgr->device, CGS_IND_REG__SMC,
-                       CG_MULT_THERMAL_CTRL, TEMP_SEL);
-
-       res = fiji_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start,
-                       (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
-                       data->sram_end);
-
-       if (!res && hwmgr->thermal_controller.
-                       advanceFanControlParameters.ucMinimumPWMLimit)
-               res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_SetFanMinPwm,
-                               hwmgr->thermal_controller.
-                               advanceFanControlParameters.ucMinimumPWMLimit);
-
-       if (!res && hwmgr->thermal_controller.
-                       advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
-               res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_SetFanSclkTarget,
-                               hwmgr->thermal_controller.
-                               advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
-
-       if (res)
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_MicrocodeFanControl);
-
-       return 0;
-}
-
-/**
-* Start the fan control on the SMC.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from set temperature range routine
-*/
-int tf_fiji_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-/* If the fantable setup has failed we could have disabled
- * PHM_PlatformCaps_MicrocodeFanControl even after
- * this function was included in the table.
- * Make sure that we still think controlling the fan is OK.
-*/
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_MicrocodeFanControl)) {
-               fiji_fan_ctrl_start_smc_fan_control(hwmgr);
-               fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-       }
-
-       return 0;
-}
-
-/**
-* Set temperature range for high and low alerts
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from set temperature range routine
-*/
-int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-       struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
-
-       if (range == NULL)
-               return -EINVAL;
-
-       return fiji_thermal_set_temperature_range(hwmgr, range->min, range->max);
-}
-
-/**
-* Programs one-time setting registers
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from initialize thermal controller routine
-*/
-int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-    return fiji_thermal_initialize(hwmgr);
-}
-
-/**
-* Enable high and low alerts
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from enable alert routine
-*/
-int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-       return fiji_thermal_enable_alert(hwmgr);
-}
-
-/**
-* Disable high and low alerts
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from disable alert routine
-*/
-static int tf_fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-       return fiji_thermal_disable_alert(hwmgr);
-}
-
-static const struct phm_master_table_item
-fiji_thermal_start_thermal_controller_master_list[] = {
-       {NULL, tf_fiji_thermal_initialize},
-       {NULL, tf_fiji_thermal_set_temperature_range},
-       {NULL, tf_fiji_thermal_enable_alert},
-/* 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, tf_fiji_thermal_setup_fan_table},
-       {NULL, tf_fiji_thermal_start_smc_fan_control},
-       {NULL, NULL}
-};
-
-static const struct phm_master_table_header
-fiji_thermal_start_thermal_controller_master = {
-       0,
-       PHM_MasterTableFlag_None,
-       fiji_thermal_start_thermal_controller_master_list
-};
-
-static const struct phm_master_table_item
-fiji_thermal_set_temperature_range_master_list[] = {
-       {NULL, tf_fiji_thermal_disable_alert},
-       {NULL, tf_fiji_thermal_set_temperature_range},
-       {NULL, tf_fiji_thermal_enable_alert},
-       {NULL, NULL}
-};
-
-static const struct phm_master_table_header
-fiji_thermal_set_temperature_range_master = {
-       0,
-       PHM_MasterTableFlag_None,
-       fiji_thermal_set_temperature_range_master_list
-};
-
-int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
-{
-       if (!hwmgr->thermal_controller.fanInfo.bNoFan)
-               fiji_fan_ctrl_set_default_mode(hwmgr);
-       return 0;
-}
-
-/**
-* Initializes the thermal controller related functions in the Hardware Manager structure.
-* @param    hwmgr The address of the hardware manager.
-* @exception Any error code from the low-level communication.
-*/
-int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       result = phm_construct_table(hwmgr,
-                       &fiji_thermal_set_temperature_range_master,
-                       &(hwmgr->set_temperature_range));
-
-       if (!result) {
-               result = phm_construct_table(hwmgr,
-                               &fiji_thermal_start_thermal_controller_master,
-                               &(hwmgr->start_thermal_controller));
-               if (result)
-                       phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
-       }
-
-       if (!result)
-               hwmgr->fan_ctrl_is_in_default_mode = true;
-       return result;
-}
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h
deleted file mode 100644 (file)
index 8621493..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2015 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 FIJI_THERMAL_H
-#define FIJI_THERMAL_H
-
-#include "hwmgr.h"
-
-#define FIJI_THERMAL_HIGH_ALERT_MASK         0x1
-#define FIJI_THERMAL_LOW_ALERT_MASK          0x2
-
-#define FIJI_THERMAL_MINIMUM_TEMP_READING    -256
-#define FIJI_THERMAL_MAXIMUM_TEMP_READING    255
-
-#define FIJI_THERMAL_MINIMUM_ALERT_TEMP      0
-#define FIJI_THERMAL_MAXIMUM_ALERT_TEMP      255
-
-#define FDO_PWM_MODE_STATIC  1
-#define FDO_PWM_MODE_STATIC_RPM 5
-
-
-extern int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
-extern int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
-extern int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
-
-extern int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr);
-extern int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
-extern int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
-extern int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
-extern int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
-extern int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
-extern int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
-extern int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
-extern int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr);
-extern int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
-extern int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
-extern int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
-extern int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
-extern uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
-
-#endif
-
index 789f98a..14f8c1f 100644 (file)
@@ -24,8 +24,6 @@
 #include "hwmgr.h"
 #include "hardwaremanager.h"
 #include "power_state.h"
-#include "pp_acpi.h"
-#include "amd_acpi.h"
 #include "pp_debug.h"
 
 #define PHM_FUNC_CHECK(hw) \
                        return -EINVAL;                         \
        } while (0)
 
-void phm_init_dynamic_caps(struct pp_hwmgr *hwmgr)
-{
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableVoltageTransition);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableEngineTransition);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMemoryTransition);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGClockGating);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGCGTSSM);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLSClockGating);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_Force3DClockSupport);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLightSleep);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMCLS);
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisablePowerGating);
-
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableDPM);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableSMUUVDHandshake);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ThermalAutoThrottling);
-
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
-
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_NoOD5Support);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UserMaxClockForMultiDisplays);
-
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VpuRecoveryInProgress);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDDPM);
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEDPM);
-
-       if (acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST) &&
-               acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION))
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
-}
-
 bool phm_is_hw_access_blocked(struct pp_hwmgr *hwmgr)
 {
        return hwmgr->block_hw_access;
index 27e0762..1167205 100644 (file)
 #include "pp_debug.h"
 #include "ppatomctrl.h"
 #include "ppsmc.h"
-
-#define VOLTAGE_SCALE               4
+#include "pp_acpi.h"
+#include "amd_acpi.h"
 
 extern int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
-extern int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
-extern int fiji_hwmgr_init(struct pp_hwmgr *hwmgr);
-extern int polaris10_hwmgr_init(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);
+static int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr);
+static int fiji_set_asic_special_caps(struct pp_hwmgr *hwmgr);
+static int tonga_set_asic_special_caps(struct pp_hwmgr *hwmgr);
+static int topaz_set_asic_special_caps(struct pp_hwmgr *hwmgr);
+
+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)
 {
@@ -56,10 +65,12 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
        hwmgr->device = pp_init->device;
        hwmgr->chip_family = pp_init->chip_family;
        hwmgr->chip_id = pp_init->chip_id;
-       hwmgr->hw_revision = pp_init->rev_id;
        hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
        hwmgr->power_source = PP_PowerSource_AC;
-       hwmgr->powercontainment_enabled = pp_init->powercontainment_enabled;
+       hwmgr->pp_table_version = PP_TABLE_V1;
+
+       hwmgr_init_default_caps(hwmgr);
+       hwmgr_set_user_specify_caps(hwmgr);
 
        switch (hwmgr->chip_family) {
        case AMDGPU_FAMILY_CZ:
@@ -67,26 +78,38 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
                break;
        case AMDGPU_FAMILY_VI:
                switch (hwmgr->chip_id) {
+               case CHIP_TOPAZ:
+                       topaz_set_asic_special_caps(hwmgr);
+                       hwmgr->feature_mask &= ~(PP_SMC_VOLTAGE_CONTROL_MASK |
+                                               PP_VBI_TIME_SUPPORT_MASK |
+                                               PP_ENABLE_GFX_CG_THRU_SMU);
+                       hwmgr->pp_table_version = PP_TABLE_V0;
+                       break;
                case CHIP_TONGA:
-                       tonga_hwmgr_init(hwmgr);
+                       tonga_set_asic_special_caps(hwmgr);
+                       hwmgr->feature_mask &= ~(PP_SMC_VOLTAGE_CONTROL_MASK |
+                                               PP_VBI_TIME_SUPPORT_MASK);
                        break;
                case CHIP_FIJI:
-                       fiji_hwmgr_init(hwmgr);
+                       fiji_set_asic_special_caps(hwmgr);
+                       hwmgr->feature_mask &= ~(PP_SMC_VOLTAGE_CONTROL_MASK |
+                                               PP_VBI_TIME_SUPPORT_MASK |
+                                               PP_ENABLE_GFX_CG_THRU_SMU);
                        break;
                case CHIP_POLARIS11:
                case CHIP_POLARIS10:
-                       polaris10_hwmgr_init(hwmgr);
+                       polaris_set_asic_special_caps(hwmgr);
+                       hwmgr->feature_mask &= ~(PP_UVD_HANDSHAKE_MASK);
                        break;
                default:
                        return -EINVAL;
                }
+               smu7_hwmgr_init(hwmgr);
                break;
        default:
                return -EINVAL;
        }
 
-       phm_init_dynamic_caps(hwmgr);
-
        return 0;
 }
 
@@ -105,6 +128,8 @@ int hwmgr_fini(struct pp_hwmgr *hwmgr)
        kfree(hwmgr->set_temperature_range.function_list);
 
        kfree(hwmgr->ps);
+       kfree(hwmgr->current_ps);
+       kfree(hwmgr->request_ps);
        kfree(hwmgr);
        return 0;
 }
@@ -129,10 +154,17 @@ int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
                                          sizeof(struct pp_power_state);
 
        hwmgr->ps = kzalloc(size * table_entries, GFP_KERNEL);
-
        if (hwmgr->ps == NULL)
                return -ENOMEM;
 
+       hwmgr->request_ps = kzalloc(size, GFP_KERNEL);
+       if (hwmgr->request_ps == NULL)
+               return -ENOMEM;
+
+       hwmgr->current_ps = kzalloc(size, GFP_KERNEL);
+       if (hwmgr->current_ps == NULL)
+               return -ENOMEM;
+
        state = hwmgr->ps;
 
        for (i = 0; i < table_entries; i++) {
@@ -140,7 +172,8 @@ int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
 
                if (state->classification.flags & PP_StateClassificationFlag_Boot) {
                        hwmgr->boot_ps = state;
-                       hwmgr->current_ps = hwmgr->request_ps = state;
+                       memcpy(hwmgr->current_ps, state, size);
+                       memcpy(hwmgr->request_ps, state, size);
                }
 
                state->id = i + 1; /* assigned unique num for every power state id */
@@ -150,6 +183,7 @@ int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
                state = (struct pp_power_state *)((unsigned long)state + size);
        }
 
+
        return 0;
 }
 
@@ -182,30 +216,6 @@ int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
        return 0;
 }
 
-int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
-                               uint32_t index, uint32_t value, uint32_t mask)
-{
-       uint32_t i;
-       uint32_t cur_value;
-
-       if (hwmgr == NULL || hwmgr->device == NULL) {
-               printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < hwmgr->usec_timeout; i++) {
-               cur_value = cgs_read_register(hwmgr->device, index);
-               if ((cur_value & mask) != (value & mask))
-                       break;
-               udelay(1);
-       }
-
-       /* timeout means wrong logic*/
-       if (i == hwmgr->usec_timeout)
-               return -1;
-       return 0;
-}
-
 
 /**
  * Returns once the part of the register indicated by the mask has
@@ -227,21 +237,7 @@ void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
        phm_wait_on_register(hwmgr, indirect_port + 1, mask, value);
 }
 
-void phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr,
-                                       uint32_t indirect_port,
-                                       uint32_t index,
-                                       uint32_t value,
-                                       uint32_t mask)
-{
-       if (hwmgr == NULL || hwmgr->device == NULL) {
-               printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
-               return;
-       }
 
-       cgs_write_register(hwmgr->device, indirect_port, index);
-       phm_wait_for_register_unequal(hwmgr, indirect_port + 1,
-                                     value, mask);
-}
 
 bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr)
 {
@@ -403,12 +399,9 @@ int phm_reset_single_dpm_table(void *table,
 
        struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
 
-       PP_ASSERT_WITH_CODE(count <= max,
-                       "Fatal error, can not set up single DPM table entries to exceed max number!",
-                          );
+       dpm_table->count = count > max ? max : count;
 
-       dpm_table->count = count;
-       for (i = 0; i < max; i++)
+       for (i = 0; i < dpm_table->count; i++)
                dpm_table->dpm_level[i].enabled = false;
 
        return 0;
@@ -462,6 +455,27 @@ uint8_t phm_get_voltage_index(
        return i - 1;
 }
 
+uint8_t phm_get_voltage_id(pp_atomctrl_voltage_table *voltage_table,
+               uint32_t voltage)
+{
+       uint8_t count = (uint8_t) (voltage_table->count);
+       uint8_t i = 0;
+
+       PP_ASSERT_WITH_CODE((NULL != voltage_table),
+               "Voltage Table empty.", return 0;);
+       PP_ASSERT_WITH_CODE((0 != count),
+               "Voltage Table empty.", return 0;);
+
+       for (i = 0; i < count; i++) {
+               /* find first voltage bigger than requested */
+               if (voltage_table->entries[i].value >= voltage)
+                       return i;
+       }
+
+       /* voltage is bigger than max voltage in the table */
+       return i - 1;
+}
+
 uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci)
 {
        uint32_t  i;
@@ -549,7 +563,8 @@ int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr
                table_clk_vlt->entries[2].v = 810;
                table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
                table_clk_vlt->entries[3].v = 900;
-               pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
+               if (pptable_info != NULL)
+                       pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
                hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
        }
 
@@ -615,3 +630,186 @@ void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr)
        printk(KERN_ERR "DAL requested level can not"
                        " found a available voltage in VDDC DPM Table \n");
 }
+
+void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr)
+{
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableVoltageTransition);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableEngineTransition);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMemoryTransition);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGClockGating);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGCGTSSM);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLSClockGating);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_Force3DClockSupport);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLightSleep);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMCLS);
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisablePowerGating);
+
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableDPM);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableSMUUVDHandshake);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ThermalAutoThrottling);
+
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
+
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_NoOD5Support);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UserMaxClockForMultiDisplays);
+
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VpuRecoveryInProgress);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDDPM);
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEDPM);
+
+       if (acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST) &&
+               acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION))
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+               PHM_PlatformCaps_DynamicPatchPowerState);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+               PHM_PlatformCaps_EnableSMU7ThermalManagement);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_DynamicPowerManagement);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_SMC);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_DynamicUVDState);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                               PHM_PlatformCaps_FanSpeedInTableIsRPM);
+
+       return;
+}
+
+int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr)
+{
+       if (amdgpu_sclk_deep_sleep_en)
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkDeepSleep);
+       else
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkDeepSleep);
+
+       if (amdgpu_powercontainment)
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                           PHM_PlatformCaps_PowerContainment);
+       else
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                           PHM_PlatformCaps_PowerContainment);
+
+       hwmgr->feature_mask = amdgpu_pp_feature_mask;
+
+       return 0;
+}
+
+int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
+                               uint32_t sclk, uint16_t id, uint16_t *voltage)
+{
+       uint32_t vol;
+       int ret = 0;
+
+       if (hwmgr->chip_id < CHIP_POLARIS10) {
+               atomctrl_get_voltage_evv_on_sclk(hwmgr, voltage_type, sclk, id, voltage);
+               if (*voltage >= 2000 || *voltage == 0)
+                       *voltage = 1150;
+       } else {
+               ret = atomctrl_get_voltage_evv_on_sclk_ai(hwmgr, voltage_type, sclk, id, &vol);
+               *voltage = (uint16_t)vol/100;
+       }
+       return ret;
+}
+
+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_CAC);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                               PHM_PlatformCaps_RegulatorHot);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_AutomaticDCTransition);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_TablelessHardwareInterface);
+
+       if (hwmgr->chip_id == CHIP_POLARIS11)
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_SPLLShutdownSupport);
+       return 0;
+}
+
+int fiji_set_asic_special_caps(struct pp_hwmgr *hwmgr)
+{
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SQRamping);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_DBRamping);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_TDRamping);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_TCPRamping);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_TablelessHardwareInterface);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_CAC);
+       return 0;
+}
+
+int tonga_set_asic_special_caps(struct pp_hwmgr *hwmgr)
+{
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SQRamping);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_DBRamping);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_TDRamping);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_TCPRamping);
+
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                     PHM_PlatformCaps_UVDPowerGating);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                     PHM_PlatformCaps_VCEPowerGating);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                        PHM_PlatformCaps_TablelessHardwareInterface);
+
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_CAC);
+
+       return 0;
+}
+
+int topaz_set_asic_special_caps(struct pp_hwmgr *hwmgr)
+{
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SQRamping);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_DBRamping);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_TDRamping);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_TCPRamping);
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                        PHM_PlatformCaps_TablelessHardwareInterface);
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_CAC);
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                   PHM_PlatformCaps_EVV);
+       return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_clockpowergating.c
deleted file mode 100644 (file)
index b5edb51..0000000
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * 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 "polaris10_clockpowergating.h"
-
-int polaris10_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cf_want_uvd_power_gating(hwmgr))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_UVDPowerOFF);
-       return 0;
-}
-
-int polaris10_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cf_want_uvd_power_gating(hwmgr)) {
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                 PHM_PlatformCaps_UVDDynamicPowerGating)) {
-                       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_UVDPowerON, 1);
-               } else {
-                       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_UVDPowerON, 0);
-               }
-       }
-
-       return 0;
-}
-
-int polaris10_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cf_want_vce_power_gating(hwmgr))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_VCEPowerOFF);
-       return 0;
-}
-
-int polaris10_phm_powerup_vce(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cf_want_vce_power_gating(hwmgr))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_VCEPowerON);
-       return 0;
-}
-
-int polaris10_phm_powerdown_samu(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SamuPowerGating))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_SAMPowerOFF);
-       return 0;
-}
-
-int polaris10_phm_powerup_samu(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SamuPowerGating))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_SAMPowerON);
-       return 0;
-}
-
-int polaris10_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       data->uvd_power_gated = false;
-       data->vce_power_gated = false;
-       data->samu_power_gated = false;
-
-       polaris10_phm_powerup_uvd(hwmgr);
-       polaris10_phm_powerup_vce(hwmgr);
-       polaris10_phm_powerup_samu(hwmgr);
-
-       return 0;
-}
-
-int polaris10_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (data->uvd_power_gated == bgate)
-               return 0;
-
-       data->uvd_power_gated = bgate;
-
-       if (bgate) {
-               cgs_set_clockgating_state(hwmgr->device,
-                               AMD_IP_BLOCK_TYPE_UVD,
-                               AMD_CG_STATE_GATE);
-               polaris10_update_uvd_dpm(hwmgr, true);
-               polaris10_phm_powerdown_uvd(hwmgr);
-       } else {
-               polaris10_phm_powerup_uvd(hwmgr);
-               polaris10_update_uvd_dpm(hwmgr, false);
-               cgs_set_clockgating_state(hwmgr->device,
-                               AMD_IP_BLOCK_TYPE_UVD,
-                               AMD_CG_STATE_UNGATE);
-       }
-
-       return 0;
-}
-
-int polaris10_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (data->vce_power_gated == bgate)
-               return 0;
-
-       data->vce_power_gated = bgate;
-
-       if (bgate) {
-               cgs_set_clockgating_state(hwmgr->device,
-                               AMD_IP_BLOCK_TYPE_VCE,
-                               AMD_CG_STATE_GATE);
-               polaris10_update_vce_dpm(hwmgr, true);
-               polaris10_phm_powerdown_vce(hwmgr);
-       } else {
-               polaris10_phm_powerup_vce(hwmgr);
-               polaris10_update_vce_dpm(hwmgr, false);
-               cgs_set_clockgating_state(hwmgr->device,
-                               AMD_IP_BLOCK_TYPE_VCE,
-                               AMD_CG_STATE_UNGATE);
-       }
-       return 0;
-}
-
-int polaris10_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (data->samu_power_gated == bgate)
-               return 0;
-
-       data->samu_power_gated = bgate;
-
-       if (bgate) {
-               polaris10_update_samu_dpm(hwmgr, true);
-               polaris10_phm_powerdown_samu(hwmgr);
-       } else {
-               polaris10_phm_powerup_samu(hwmgr);
-               polaris10_update_samu_dpm(hwmgr, false);
-       }
-
-       return 0;
-}
-
-int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
-                                       const uint32_t *msg_id)
-{
-       PPSMC_Msg msg;
-       uint32_t value;
-
-       switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
-       case PP_GROUP_GFX:
-               switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
-               case PP_BLOCK_GFX_CG:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_GFX_CGCG_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
-                                       ? PPSMC_MSG_EnableClockGatingFeature
-                                       : PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_GFX_CGLS_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_GFX_3D:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_GFX_3DCG_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-
-                       if  (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_GFX_3DLS_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_GFX_RLC:
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_GFX_RLC_LS_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_GFX_CP:
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_GFX_CP_LS_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_GFX_MG:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = (CG_CPF_MGCG_MASK | CG_RLC_MGCG_MASK |
-                                               CG_GFX_OTHERS_MGCG_MASK);
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               default:
-                       return -1;
-               }
-               break;
-
-       case PP_GROUP_SYS:
-               switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
-               case PP_BLOCK_SYS_BIF:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_BIF_MGCG_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       if  (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_BIF_MGLS_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_SYS_MC:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_MC_MGCG_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_MC_MGLS_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_SYS_DRM:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_DRM_MGCG_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_DRM_MGLS_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_SYS_HDP:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_HDP_MGCG_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_HDP_MGLS_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_SYS_SDMA:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_SDMA_MGCG_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_SDMA_MGLS_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_SYS_ROM:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
-                                               PPSMC_MSG_EnableClockGatingFeature :
-                                               PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_ROM_MASK;
-
-                               if (smum_send_msg_to_smc_with_parameter(
-                                               hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               default:
-                       return -1;
-
-               }
-               break;
-
-       default:
-               return -1;
-
-       }
-
-       return 0;
-}
-
-/* This function is for Polaris11 only for now,
- * Powerplay will only control the static per CU Power Gating.
- * Dynamic per CU Power Gating will be done in gfx.
- */
-int polaris10_phm_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable)
-{
-       struct cgs_system_info sys_info = {0};
-       uint32_t active_cus;
-       int result;
-
-       sys_info.size = sizeof(struct cgs_system_info);
-       sys_info.info_id = CGS_SYSTEM_INFO_GFX_CU_INFO;
-
-       result = cgs_query_system_info(hwmgr->device, &sys_info);
-
-       if (result)
-               return -EINVAL;
-       else
-               active_cus = sys_info.value;
-
-       if (enable)
-               return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_GFX_CU_PG_ENABLE, active_cus);
-       else
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_GFX_CU_PG_DISABLE);
-}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_clockpowergating.h
deleted file mode 100644 (file)
index 88d68cb..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- *
- */
-
-#ifndef _POLARIS10_CLOCK_POWER_GATING_H_
-#define _POLARIS10_CLOCK_POWER_GATING_H_
-
-#include "polaris10_hwmgr.h"
-#include "pp_asicblocks.h"
-
-int polaris10_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
-int polaris10_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
-int polaris10_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
-int polaris10_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
-int polaris10_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
-int polaris10_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
-int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
-                                       const uint32_t *msg_id);
-int polaris10_phm_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable);
-
-#endif /* _POLARIS10_CLOCK_POWER_GATING_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_dyn_defaults.h b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_dyn_defaults.h
deleted file mode 100644 (file)
index f78ffd9..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2015 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 POLARIS10_DYN_DEFAULTS_H
-#define POLARIS10_DYN_DEFAULTS_H
-
-
-enum Polaris10dpm_TrendDetection {
-       Polaris10Adpm_TrendDetection_AUTO,
-       Polaris10Adpm_TrendDetection_UP,
-       Polaris10Adpm_TrendDetection_DOWN
-};
-typedef enum Polaris10dpm_TrendDetection Polaris10dpm_TrendDetection;
-
-/*  We need to fill in the default values */
-
-
-#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT0              0x3FFFC102
-#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT1              0x000400
-#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT2              0xC00080
-#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT3              0xC00200
-#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT4              0xC01680
-#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT5              0xC00033
-#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT6              0xC00033
-#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT7              0x3FFFC000
-
-
-#define PPPOLARIS10_THERMALPROTECTCOUNTER_DFLT            0x200
-#define PPPOLARIS10_STATICSCREENTHRESHOLDUNIT_DFLT        0
-#define PPPOLARIS10_STATICSCREENTHRESHOLD_DFLT            0x00C8
-#define PPPOLARIS10_GFXIDLECLOCKSTOPTHRESHOLD_DFLT        0x200
-#define PPPOLARIS10_REFERENCEDIVIDER_DFLT                  4
-
-#define PPPOLARIS10_ULVVOLTAGECHANGEDELAY_DFLT             1687
-
-#define PPPOLARIS10_CGULVPARAMETER_DFLT                    0x00040035
-#define PPPOLARIS10_CGULVCONTROL_DFLT                      0x00007450
-#define PPPOLARIS10_TARGETACTIVITY_DFLT                     50
-#define PPPOLARIS10_MCLK_TARGETACTIVITY_DFLT                10
-
-#endif
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c
deleted file mode 100644 (file)
index 769636a..0000000
+++ /dev/null
@@ -1,5290 +0,0 @@
-/*
- * Copyright 2015 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/module.h>
-#include <linux/slab.h>
-#include <linux/fb.h>
-#include <asm/div64.h>
-#include "linux/delay.h"
-#include "pp_acpi.h"
-#include "hwmgr.h"
-#include "polaris10_hwmgr.h"
-#include "polaris10_powertune.h"
-#include "polaris10_dyn_defaults.h"
-#include "polaris10_smumgr.h"
-#include "pp_debug.h"
-#include "ppatomctrl.h"
-#include "atombios.h"
-#include "tonga_pptable.h"
-#include "pppcielanes.h"
-#include "amd_pcie_helpers.h"
-#include "hardwaremanager.h"
-#include "tonga_processpptables.h"
-#include "cgs_common.h"
-#include "smu74.h"
-#include "smu_ucode_xfer_vi.h"
-#include "smu74_discrete.h"
-#include "smu/smu_7_1_3_d.h"
-#include "smu/smu_7_1_3_sh_mask.h"
-#include "gmc/gmc_8_1_d.h"
-#include "gmc/gmc_8_1_sh_mask.h"
-#include "oss/oss_3_0_d.h"
-#include "gca/gfx_8_0_d.h"
-#include "bif/bif_5_0_d.h"
-#include "bif/bif_5_0_sh_mask.h"
-#include "gmc/gmc_8_1_d.h"
-#include "gmc/gmc_8_1_sh_mask.h"
-#include "bif/bif_5_0_d.h"
-#include "bif/bif_5_0_sh_mask.h"
-#include "dce/dce_10_0_d.h"
-#include "dce/dce_10_0_sh_mask.h"
-
-#include "polaris10_thermal.h"
-#include "polaris10_clockpowergating.h"
-
-#define MC_CG_ARB_FREQ_F0           0x0a
-#define MC_CG_ARB_FREQ_F1           0x0b
-#define MC_CG_ARB_FREQ_F2           0x0c
-#define MC_CG_ARB_FREQ_F3           0x0d
-
-#define MC_CG_SEQ_DRAMCONF_S0       0x05
-#define MC_CG_SEQ_DRAMCONF_S1       0x06
-#define MC_CG_SEQ_YCLK_SUSPEND      0x04
-#define MC_CG_SEQ_YCLK_RESUME       0x0a
-
-
-#define SMC_RAM_END 0x40000
-
-#define SMC_CG_IND_START            0xc0030000
-#define SMC_CG_IND_END              0xc0040000
-
-#define VOLTAGE_SCALE               4
-#define VOLTAGE_VID_OFFSET_SCALE1   625
-#define VOLTAGE_VID_OFFSET_SCALE2   100
-
-#define VDDC_VDDCI_DELTA            200
-
-#define MEM_FREQ_LOW_LATENCY        25000
-#define MEM_FREQ_HIGH_LATENCY       80000
-
-#define MEM_LATENCY_HIGH            45
-#define MEM_LATENCY_LOW             35
-#define MEM_LATENCY_ERR             0xFFFF
-
-#define MC_SEQ_MISC0_GDDR5_SHIFT 28
-#define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
-#define MC_SEQ_MISC0_GDDR5_VALUE 5
-
-
-#define PCIE_BUS_CLK                10000
-#define TCLK                        (PCIE_BUS_CLK / 10)
-
-
-static const uint16_t polaris10_clock_stretcher_lookup_table[2][4] =
-{ {600, 1050, 3, 0}, {600, 1050, 6, 1} };
-
-/*  [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */
-static const uint32_t polaris10_clock_stretcher_ddt_table[2][4][4] =
-{ { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
-  { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
-
-/*  [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */
-static const uint8_t polaris10_clock_stretch_amount_conversion[2][6] =
-{ {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
-
-/** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
-enum DPM_EVENT_SRC {
-       DPM_EVENT_SRC_ANALOG = 0,
-       DPM_EVENT_SRC_EXTERNAL = 1,
-       DPM_EVENT_SRC_DIGITAL = 2,
-       DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,
-       DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4
-};
-
-static const unsigned long PhwPolaris10_Magic = (unsigned long)(PHM_VIslands_Magic);
-
-struct polaris10_power_state *cast_phw_polaris10_power_state(
-                                 struct pp_hw_power_state *hw_ps)
-{
-       PP_ASSERT_WITH_CODE((PhwPolaris10_Magic == hw_ps->magic),
-                               "Invalid Powerstate Type!",
-                                return NULL);
-
-       return (struct polaris10_power_state *)hw_ps;
-}
-
-const struct polaris10_power_state *cast_const_phw_polaris10_power_state(
-                                const struct pp_hw_power_state *hw_ps)
-{
-       PP_ASSERT_WITH_CODE((PhwPolaris10_Magic == hw_ps->magic),
-                               "Invalid Powerstate Type!",
-                                return NULL);
-
-       return (const struct polaris10_power_state *)hw_ps;
-}
-
-static bool polaris10_is_dpm_running(struct pp_hwmgr *hwmgr)
-{
-       return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
-                       CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
-                       ? true : false;
-}
-
-/**
- * Find the MC microcode version and store it in the HwMgr struct
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int phm_get_mc_microcode_version (struct pp_hwmgr *hwmgr)
-{
-       cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX, 0x9F);
-
-       hwmgr->microcode_version_info.MC = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA);
-
-       return 0;
-}
-
-uint16_t phm_get_current_pcie_speed(struct pp_hwmgr *hwmgr)
-{
-       uint32_t speedCntl = 0;
-
-       /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
-       speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE,
-                       ixPCIE_LC_SPEED_CNTL);
-       return((uint16_t)PHM_GET_FIELD(speedCntl,
-                       PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
-}
-
-int phm_get_current_pcie_lane_number(struct pp_hwmgr *hwmgr)
-{
-       uint32_t link_width;
-
-       /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
-       link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
-                       PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD);
-
-       PP_ASSERT_WITH_CODE((7 >= link_width),
-                       "Invalid PCIe lane width!", return 0);
-
-       return decode_pcie_lane_width(link_width);
-}
-
-/**
-* Enable voltage control
-*
-* @param    pHwMgr  the address of the powerplay hardware manager.
-* @return   always PP_Result_OK
-*/
-int polaris10_enable_smc_voltage_controller(struct pp_hwmgr *hwmgr)
-{
-       PP_ASSERT_WITH_CODE(
-               (hwmgr->smumgr->smumgr_funcs->send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Voltage_Cntl_Enable) == 0),
-               "Failed to enable voltage DPM during DPM Start Function!",
-               return 1;
-       );
-
-       return 0;
-}
-
-/**
-* Checks if we want to support voltage control
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-*/
-static bool polaris10_voltage_control(const struct pp_hwmgr *hwmgr)
-{
-       const struct polaris10_hwmgr *data =
-                       (const struct polaris10_hwmgr *)(hwmgr->backend);
-
-       return (POLARIS10_VOLTAGE_CONTROL_NONE != data->voltage_control);
-}
-
-/**
-* Enable voltage control
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int polaris10_enable_voltage_control(struct pp_hwmgr *hwmgr)
-{
-       /* enable voltage control */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
-
-       return 0;
-}
-
-/**
-* Create Voltage Tables.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int polaris10_construct_voltage_tables(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)hwmgr->pptable;
-       int result;
-
-       if (POLARIS10_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
-               result = atomctrl_get_voltage_table_v3(hwmgr,
-                               VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT,
-                               &(data->mvdd_voltage_table));
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve MVDD table.",
-                               return result);
-       } else if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
-               result = phm_get_svi2_mvdd_voltage_table(&(data->mvdd_voltage_table),
-                               table_info->vdd_dep_on_mclk);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve SVI2 MVDD table from dependancy table.",
-                               return result;);
-       }
-
-       if (POLARIS10_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
-               result = atomctrl_get_voltage_table_v3(hwmgr,
-                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT,
-                               &(data->vddci_voltage_table));
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve VDDCI table.",
-                               return result);
-       } else if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
-               result = phm_get_svi2_vddci_voltage_table(&(data->vddci_voltage_table),
-                               table_info->vdd_dep_on_mclk);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve SVI2 VDDCI table from dependancy table.",
-                               return result);
-       }
-
-       if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
-               result = phm_get_svi2_vdd_voltage_table(&(data->vddc_voltage_table),
-                               table_info->vddc_lookup_table);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve SVI2 VDDC table from lookup table.",
-                               return result);
-       }
-
-       PP_ASSERT_WITH_CODE(
-                       (data->vddc_voltage_table.count <= (SMU74_MAX_LEVELS_VDDC)),
-                       "Too many voltage values for VDDC. Trimming to fit state table.",
-                       phm_trim_voltage_table_to_fit_state_table(SMU74_MAX_LEVELS_VDDC,
-                                                               &(data->vddc_voltage_table)));
-
-       PP_ASSERT_WITH_CODE(
-                       (data->vddci_voltage_table.count <= (SMU74_MAX_LEVELS_VDDCI)),
-                       "Too many voltage values for VDDCI. Trimming to fit state table.",
-                       phm_trim_voltage_table_to_fit_state_table(SMU74_MAX_LEVELS_VDDCI,
-                                       &(data->vddci_voltage_table)));
-
-       PP_ASSERT_WITH_CODE(
-                       (data->mvdd_voltage_table.count <= (SMU74_MAX_LEVELS_MVDD)),
-                       "Too many voltage values for MVDD. Trimming to fit state table.",
-                       phm_trim_voltage_table_to_fit_state_table(SMU74_MAX_LEVELS_MVDD,
-                                                          &(data->mvdd_voltage_table)));
-
-       return 0;
-}
-
-/**
-* Programs static screed detection parameters
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int polaris10_program_static_screen_threshold_parameters(
-                                                       struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       /* Set static screen threshold unit */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
-                       data->static_screen_threshold_unit);
-       /* Set static screen threshold */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
-                       data->static_screen_threshold);
-
-       return 0;
-}
-
-/**
-* Setup display gap for glitch free memory clock switching.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always  0
-*/
-static int polaris10_enable_display_gap(struct pp_hwmgr *hwmgr)
-{
-       uint32_t display_gap =
-                       cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                                       ixCG_DISPLAY_GAP_CNTL);
-
-       display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
-                       DISP_GAP, DISPLAY_GAP_IGNORE);
-
-       display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
-                       DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_DISPLAY_GAP_CNTL, display_gap);
-
-       return 0;
-}
-
-/**
-* Programs activity state transition voting clients
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always  0
-*/
-static int polaris10_program_voting_clients(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       /* Clear reset for voting clients before enabling DPM */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
-
-       return 0;
-}
-
-static int polaris10_clear_voting_clients(struct pp_hwmgr *hwmgr)
-{
-       /* Reset voting clients before disabling DPM */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 1);
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 1);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_0, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_1, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_2, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_3, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_4, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_5, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_6, 0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_FREQ_TRAN_VOTING_7, 0);
-
-       return 0;
-}
-
-/**
-* Get the location of various tables inside the FW image.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always  0
-*/
-static int polaris10_process_firmware_header(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
-       uint32_t tmp;
-       int result;
-       bool error = false;
-
-       result = polaris10_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU74_Firmware_Header, DpmTable),
-                       &tmp, data->sram_end);
-
-       if (0 == result)
-               data->dpm_table_start = tmp;
-
-       error |= (0 != result);
-
-       result = polaris10_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU74_Firmware_Header, SoftRegisters),
-                       &tmp, data->sram_end);
-
-       if (!result) {
-               data->soft_regs_start = tmp;
-               smu_data->soft_regs_start = tmp;
-       }
-
-       error |= (0 != result);
-
-       result = polaris10_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU74_Firmware_Header, mcRegisterTable),
-                       &tmp, data->sram_end);
-
-       if (!result)
-               data->mc_reg_table_start = tmp;
-
-       result = polaris10_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU74_Firmware_Header, FanTable),
-                       &tmp, data->sram_end);
-
-       if (!result)
-               data->fan_table_start = tmp;
-
-       error |= (0 != result);
-
-       result = polaris10_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU74_Firmware_Header, mcArbDramTimingTable),
-                       &tmp, data->sram_end);
-
-       if (!result)
-               data->arb_table_start = tmp;
-
-       error |= (0 != result);
-
-       result = polaris10_read_smc_sram_dword(hwmgr->smumgr,
-                       SMU7_FIRMWARE_HEADER_LOCATION +
-                       offsetof(SMU74_Firmware_Header, Version),
-                       &tmp, data->sram_end);
-
-       if (!result)
-               hwmgr->microcode_version_info.SMC = tmp;
-
-       error |= (0 != result);
-
-       return error ? -1 : 0;
-}
-
-/* Copy one arb setting to another and then switch the active set.
- * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
- */
-static int polaris10_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
-               uint32_t arb_src, uint32_t arb_dest)
-{
-       uint32_t mc_arb_dram_timing;
-       uint32_t mc_arb_dram_timing2;
-       uint32_t burst_time;
-       uint32_t mc_cg_config;
-
-       switch (arb_src) {
-       case MC_CG_ARB_FREQ_F0:
-               mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
-               mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
-               burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
-               break;
-       case MC_CG_ARB_FREQ_F1:
-               mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
-               mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
-               burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (arb_dest) {
-       case MC_CG_ARB_FREQ_F0:
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
-               PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
-               break;
-       case MC_CG_ARB_FREQ_F1:
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
-               PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
-       mc_cg_config |= 0x0000000F;
-       cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
-       PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arb_dest);
-
-       return 0;
-}
-
-static int polaris10_reset_to_default(struct pp_hwmgr *hwmgr)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults);
-}
-
-/**
-* Initial switch from ARB F0->F1
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-* This function is to be called from the SetPowerState table.
-*/
-static int polaris10_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr)
-{
-       return polaris10_copy_and_switch_arb_sets(hwmgr,
-                       MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
-}
-
-static int polaris10_force_switch_to_arbf0(struct pp_hwmgr *hwmgr)
-{
-       uint32_t tmp;
-
-       tmp = (cgs_read_ind_register(hwmgr->device,
-                       CGS_IND_REG__SMC, ixSMC_SCRATCH9) &
-                       0x0000ff00) >> 8;
-
-       if (tmp == MC_CG_ARB_FREQ_F0)
-               return 0;
-
-       return polaris10_copy_and_switch_arb_sets(hwmgr,
-                       tmp, MC_CG_ARB_FREQ_F0);
-}
-
-static int polaris10_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
-       uint32_t i, max_entry;
-
-       PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels ||
-                       data->use_pcie_power_saving_levels), "No pcie performance levels!",
-                       return -EINVAL);
-
-       if (data->use_pcie_performance_levels &&
-                       !data->use_pcie_power_saving_levels) {
-               data->pcie_gen_power_saving = data->pcie_gen_performance;
-               data->pcie_lane_power_saving = data->pcie_lane_performance;
-       } else if (!data->use_pcie_performance_levels &&
-                       data->use_pcie_power_saving_levels) {
-               data->pcie_gen_performance = data->pcie_gen_power_saving;
-               data->pcie_lane_performance = data->pcie_lane_power_saving;
-       }
-
-       phm_reset_single_dpm_table(&data->dpm_table.pcie_speed_table,
-                                       SMU74_MAX_LEVELS_LINK,
-                                       MAX_REGULAR_DPM_NUMBER);
-
-       if (pcie_table != NULL) {
-               /* max_entry is used to make sure we reserve one PCIE level
-                * for boot level (fix for A+A PSPP issue).
-                * If PCIE table from PPTable have ULV entry + 8 entries,
-                * then ignore the last entry.*/
-               max_entry = (SMU74_MAX_LEVELS_LINK < pcie_table->count) ?
-                               SMU74_MAX_LEVELS_LINK : pcie_table->count;
-               for (i = 1; i < max_entry; i++) {
-                       phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i - 1,
-                                       get_pcie_gen_support(data->pcie_gen_cap,
-                                                       pcie_table->entries[i].gen_speed),
-                                       get_pcie_lane_support(data->pcie_lane_cap,
-                                                       pcie_table->entries[i].lane_width));
-               }
-               data->dpm_table.pcie_speed_table.count = max_entry - 1;
-
-               /* Setup BIF_SCLK levels */
-               for (i = 0; i < max_entry; i++)
-                       data->bif_sclk_table[i] = pcie_table->entries[i].pcie_sclk;
-       } else {
-               /* Hardcode Pcie Table */
-               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Min_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Min_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Max_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Max_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Max_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
-                               get_pcie_gen_support(data->pcie_gen_cap,
-                                               PP_Max_PCIEGen),
-                               get_pcie_lane_support(data->pcie_lane_cap,
-                                               PP_Max_PCIELane));
-
-               data->dpm_table.pcie_speed_table.count = 6;
-       }
-       /* Populate last level for boot PCIE level, but do not increment count. */
-       phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
-                       data->dpm_table.pcie_speed_table.count,
-                       get_pcie_gen_support(data->pcie_gen_cap,
-                                       PP_Min_PCIEGen),
-                       get_pcie_lane_support(data->pcie_lane_cap,
-                                       PP_Max_PCIELane));
-
-       return 0;
-}
-
-/*
- * This function is to initalize all DPM state tables
- * for SMU7 based on the dependency table.
- * Dynamic state patching function will then trim these
- * state tables to the allowed range based
- * on the power policy or external client requests,
- * such as UVD request, etc.
- */
-int polaris10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint32_t i;
-
-       struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table =
-                       table_info->vdd_dep_on_sclk;
-       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
-                       table_info->vdd_dep_on_mclk;
-
-       PP_ASSERT_WITH_CODE(dep_sclk_table != NULL,
-                       "SCLK dependency table is missing. This table is mandatory",
-                       return -EINVAL);
-       PP_ASSERT_WITH_CODE(dep_sclk_table->count >= 1,
-                       "SCLK dependency table has to have is missing."
-                       "This table is mandatory",
-                       return -EINVAL);
-
-       PP_ASSERT_WITH_CODE(dep_mclk_table != NULL,
-                       "MCLK dependency table is missing. This table is mandatory",
-                       return -EINVAL);
-       PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
-                       "MCLK dependency table has to have is missing."
-                       "This table is mandatory",
-                       return -EINVAL);
-
-       /* clear the state table to reset everything to default */
-       phm_reset_single_dpm_table(
-                       &data->dpm_table.sclk_table, SMU74_MAX_LEVELS_GRAPHICS, MAX_REGULAR_DPM_NUMBER);
-       phm_reset_single_dpm_table(
-                       &data->dpm_table.mclk_table, SMU74_MAX_LEVELS_MEMORY, MAX_REGULAR_DPM_NUMBER);
-
-
-       /* Initialize Sclk DPM table based on allow Sclk values */
-       data->dpm_table.sclk_table.count = 0;
-       for (i = 0; i < dep_sclk_table->count; i++) {
-               if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count - 1].value !=
-                                               dep_sclk_table->entries[i].clk) {
-
-                       data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
-                                       dep_sclk_table->entries[i].clk;
-
-                       data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled =
-                                       (i == 0) ? true : false;
-                       data->dpm_table.sclk_table.count++;
-               }
-       }
-
-       /* Initialize Mclk DPM table based on allow Mclk values */
-       data->dpm_table.mclk_table.count = 0;
-       for (i = 0; i < dep_mclk_table->count; i++) {
-               if (i == 0 || data->dpm_table.mclk_table.dpm_levels
-                               [data->dpm_table.mclk_table.count - 1].value !=
-                                               dep_mclk_table->entries[i].clk) {
-                       data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
-                                                       dep_mclk_table->entries[i].clk;
-                       data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled =
-                                                       (i == 0) ? true : false;
-                       data->dpm_table.mclk_table.count++;
-               }
-       }
-
-       /* setup PCIE gen speed levels */
-       polaris10_setup_default_pcie_table(hwmgr);
-
-       /* save a copy of the default DPM table */
-       memcpy(&(data->golden_dpm_table), &(data->dpm_table),
-                       sizeof(struct polaris10_dpm_table));
-
-       return 0;
-}
-
-uint8_t convert_to_vid(uint16_t vddc)
-{
-       return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
-}
-
-/**
- * Mvdd table preparation for SMC.
- *
- * @param    *hwmgr The address of the hardware manager.
- * @param    *table The SMC DPM table structure to be populated.
- * @return   0
- */
-static int polaris10_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
-                       SMU74_Discrete_DpmTable *table)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t count, level;
-
-       if (POLARIS10_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
-               count = data->mvdd_voltage_table.count;
-               if (count > SMU_MAX_SMIO_LEVELS)
-                       count = SMU_MAX_SMIO_LEVELS;
-               for (level = 0; level < count; level++) {
-                       table->SmioTable2.Pattern[level].Voltage =
-                               PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE);
-                       /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
-                       table->SmioTable2.Pattern[level].Smio =
-                               (uint8_t) level;
-                       table->Smio[level] |=
-                               data->mvdd_voltage_table.entries[level].smio_low;
-               }
-               table->SmioMask2 = data->mvdd_voltage_table.mask_low;
-
-               table->MvddLevelCount = (uint32_t) PP_HOST_TO_SMC_UL(count);
-       }
-
-       return 0;
-}
-
-static int polaris10_populate_smc_vddci_table(struct pp_hwmgr *hwmgr,
-                                       struct SMU74_Discrete_DpmTable *table)
-{
-       uint32_t count, level;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       count = data->vddci_voltage_table.count;
-
-       if (POLARIS10_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
-               if (count > SMU_MAX_SMIO_LEVELS)
-                       count = SMU_MAX_SMIO_LEVELS;
-               for (level = 0; level < count; ++level) {
-                       table->SmioTable1.Pattern[level].Voltage =
-                               PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[level].value * VOLTAGE_SCALE);
-                       table->SmioTable1.Pattern[level].Smio = (uint8_t) level;
-
-                       table->Smio[level] |= data->vddci_voltage_table.entries[level].smio_low;
-               }
-       }
-
-       table->SmioMask1 = data->vddci_voltage_table.mask_low;
-
-       return 0;
-}
-
-/**
-* Preparation of vddc and vddgfx CAC tables for SMC.
-*
-* @param    hwmgr  the address of the hardware manager
-* @param    table  the SMC DPM table structure to be populated
-* @return   always 0
-*/
-static int polaris10_populate_cac_table(struct pp_hwmgr *hwmgr,
-               struct SMU74_Discrete_DpmTable *table)
-{
-       uint32_t count;
-       uint8_t index;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_voltage_lookup_table *lookup_table =
-                       table_info->vddc_lookup_table;
-       /* tables is already swapped, so in order to use the value from it,
-        * we need to swap it back.
-        * We are populating vddc CAC data to BapmVddc table
-        * in split and merged mode
-        */
-       for (count = 0; count < lookup_table->count; count++) {
-               index = phm_get_voltage_index(lookup_table,
-                               data->vddc_voltage_table.entries[count].value);
-               table->BapmVddcVidLoSidd[count] = convert_to_vid(lookup_table->entries[index].us_cac_low);
-               table->BapmVddcVidHiSidd[count] = convert_to_vid(lookup_table->entries[index].us_cac_mid);
-               table->BapmVddcVidHiSidd2[count] = convert_to_vid(lookup_table->entries[index].us_cac_high);
-       }
-
-       return 0;
-}
-
-/**
-* Preparation of voltage tables for SMC.
-*
-* @param    hwmgr   the address of the hardware manager
-* @param    table   the SMC DPM table structure to be populated
-* @return   always  0
-*/
-
-int polaris10_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
-               struct SMU74_Discrete_DpmTable *table)
-{
-       polaris10_populate_smc_vddci_table(hwmgr, table);
-       polaris10_populate_smc_mvdd_table(hwmgr, table);
-       polaris10_populate_cac_table(hwmgr, table);
-
-       return 0;
-}
-
-static int polaris10_populate_ulv_level(struct pp_hwmgr *hwmgr,
-               struct SMU74_Discrete_Ulv *state)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       state->CcPwrDynRm = 0;
-       state->CcPwrDynRm1 = 0;
-
-       state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
-       state->VddcOffsetVid = (uint8_t)(table_info->us_ulv_voltage_offset *
-                       VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
-
-       state->VddcPhase = (data->vddc_phase_shed_control) ? 0 : 1;
-
-       CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
-       CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
-       CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
-
-       return 0;
-}
-
-static int polaris10_populate_ulv_state(struct pp_hwmgr *hwmgr,
-               struct SMU74_Discrete_DpmTable *table)
-{
-       return polaris10_populate_ulv_level(hwmgr, &table->Ulv);
-}
-
-static int polaris10_populate_smc_link_level(struct pp_hwmgr *hwmgr,
-               struct SMU74_Discrete_DpmTable *table)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_dpm_table *dpm_table = &data->dpm_table;
-       int i;
-
-       /* Index (dpm_table->pcie_speed_table.count)
-        * is reserved for PCIE boot level. */
-       for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
-               table->LinkLevel[i].PcieGenSpeed  =
-                               (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
-               table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width(
-                               dpm_table->pcie_speed_table.dpm_levels[i].param1);
-               table->LinkLevel[i].EnabledForActivity = 1;
-               table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff);
-               table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5);
-               table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30);
-       }
-
-       data->smc_state_table.LinkLevelCount =
-                       (uint8_t)dpm_table->pcie_speed_table.count;
-       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
-                       phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
-
-       return 0;
-}
-
-static uint32_t polaris10_get_xclk(struct pp_hwmgr *hwmgr)
-{
-       uint32_t reference_clock, tmp;
-       struct cgs_display_info info = {0};
-       struct cgs_mode_info mode_info;
-
-       info.mode_info = &mode_info;
-
-       tmp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK);
-
-       if (tmp)
-               return TCLK;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-       reference_clock = mode_info.ref_clock;
-
-       tmp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL, XTALIN_DIVIDE);
-
-       if (0 != tmp)
-               return reference_clock / 4;
-
-       return reference_clock;
-}
-
-/**
-* Calculates the SCLK dividers using the provided engine clock
-*
-* @param    hwmgr  the address of the hardware manager
-* @param    clock  the engine clock to use to populate the structure
-* @param    sclk   the SMC SCLK structure to be populated
-*/
-static int polaris10_calculate_sclk_params(struct pp_hwmgr *hwmgr,
-               uint32_t clock, SMU_SclkSetting *sclk_setting)
-{
-       const struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       const SMU74_Discrete_DpmTable *table = &(data->smc_state_table);
-       struct pp_atomctrl_clock_dividers_ai dividers;
-
-       uint32_t ref_clock;
-       uint32_t pcc_target_percent, pcc_target_freq, ss_target_percent, ss_target_freq;
-       uint8_t i;
-       int result;
-       uint64_t temp;
-
-       sclk_setting->SclkFrequency = clock;
-       /* get the engine clock dividers for this clock value */
-       result = atomctrl_get_engine_pll_dividers_ai(hwmgr, clock,  &dividers);
-       if (result == 0) {
-               sclk_setting->Fcw_int = dividers.usSclk_fcw_int;
-               sclk_setting->Fcw_frac = dividers.usSclk_fcw_frac;
-               sclk_setting->Pcc_fcw_int = dividers.usPcc_fcw_int;
-               sclk_setting->PllRange = dividers.ucSclkPllRange;
-               sclk_setting->Sclk_slew_rate = 0x400;
-               sclk_setting->Pcc_up_slew_rate = dividers.usPcc_fcw_slew_frac;
-               sclk_setting->Pcc_down_slew_rate = 0xffff;
-               sclk_setting->SSc_En = dividers.ucSscEnable;
-               sclk_setting->Fcw1_int = dividers.usSsc_fcw1_int;
-               sclk_setting->Fcw1_frac = dividers.usSsc_fcw1_frac;
-               sclk_setting->Sclk_ss_slew_rate = dividers.usSsc_fcw_slew_frac;
-               return result;
-       }
-
-       ref_clock = polaris10_get_xclk(hwmgr);
-
-       for (i = 0; i < NUM_SCLK_RANGE; i++) {
-               if (clock > data->range_table[i].trans_lower_frequency
-               && clock <= data->range_table[i].trans_upper_frequency) {
-                       sclk_setting->PllRange = i;
-                       break;
-               }
-       }
-
-       sclk_setting->Fcw_int = (uint16_t)((clock << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv) / ref_clock);
-       temp = clock << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv;
-       temp <<= 0x10;
-       do_div(temp, ref_clock);
-       sclk_setting->Fcw_frac = temp & 0xffff;
-
-       pcc_target_percent = 10; /*  Hardcode 10% for now. */
-       pcc_target_freq = clock - (clock * pcc_target_percent / 100);
-       sclk_setting->Pcc_fcw_int = (uint16_t)((pcc_target_freq << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv) / ref_clock);
-
-       ss_target_percent = 2; /*  Hardcode 2% for now. */
-       sclk_setting->SSc_En = 0;
-       if (ss_target_percent) {
-               sclk_setting->SSc_En = 1;
-               ss_target_freq = clock - (clock * ss_target_percent / 100);
-               sclk_setting->Fcw1_int = (uint16_t)((ss_target_freq << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv) / ref_clock);
-               temp = ss_target_freq << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv;
-               temp <<= 0x10;
-               do_div(temp, ref_clock);
-               sclk_setting->Fcw1_frac = temp & 0xffff;
-       }
-
-       return 0;
-}
-
-static int polaris10_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
-               struct phm_ppt_v1_clock_voltage_dependency_table *dep_table,
-               uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
-{
-       uint32_t i;
-       uint16_t vddci;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       *voltage = *mvdd = 0;
-
-       /* clock - voltage dependency table is empty table */
-       if (dep_table->count == 0)
-               return -EINVAL;
-
-       for (i = 0; i < dep_table->count; i++) {
-               /* find first sclk bigger than request */
-               if (dep_table->entries[i].clk >= clock) {
-                       *voltage |= (dep_table->entries[i].vddc *
-                                       VOLTAGE_SCALE) << VDDC_SHIFT;
-                       if (POLARIS10_VOLTAGE_CONTROL_NONE == data->vddci_control)
-                               *voltage |= (data->vbios_boot_state.vddci_bootup_value *
-                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
-                       else if (dep_table->entries[i].vddci)
-                               *voltage |= (dep_table->entries[i].vddci *
-                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
-                       else {
-                               vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
-                                               (dep_table->entries[i].vddc -
-                                                               (uint16_t)data->vddc_vddci_delta));
-                               *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
-                       }
-
-                       if (POLARIS10_VOLTAGE_CONTROL_NONE == data->mvdd_control)
-                               *mvdd = data->vbios_boot_state.mvdd_bootup_value *
-                                       VOLTAGE_SCALE;
-                       else if (dep_table->entries[i].mvdd)
-                               *mvdd = (uint32_t) dep_table->entries[i].mvdd *
-                                       VOLTAGE_SCALE;
-
-                       *voltage |= 1 << PHASES_SHIFT;
-                       return 0;
-               }
-       }
-
-       /* sclk is bigger than max sclk in the dependence table */
-       *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
-
-       if (POLARIS10_VOLTAGE_CONTROL_NONE == data->vddci_control)
-               *voltage |= (data->vbios_boot_state.vddci_bootup_value *
-                               VOLTAGE_SCALE) << VDDCI_SHIFT;
-       else if (dep_table->entries[i-1].vddci) {
-               vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
-                               (dep_table->entries[i].vddc -
-                                               (uint16_t)data->vddc_vddci_delta));
-               *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
-       }
-
-       if (POLARIS10_VOLTAGE_CONTROL_NONE == data->mvdd_control)
-               *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
-       else if (dep_table->entries[i].mvdd)
-               *mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE;
-
-       return 0;
-}
-
-static const sclkFcwRange_t Range_Table[NUM_SCLK_RANGE] =
-{ {VCO_2_4, POSTDIV_DIV_BY_16,  75, 160, 112},
-  {VCO_3_6, POSTDIV_DIV_BY_16, 112, 224, 160},
-  {VCO_2_4, POSTDIV_DIV_BY_8,   75, 160, 112},
-  {VCO_3_6, POSTDIV_DIV_BY_8,  112, 224, 160},
-  {VCO_2_4, POSTDIV_DIV_BY_4,   75, 160, 112},
-  {VCO_3_6, POSTDIV_DIV_BY_4,  112, 216, 160},
-  {VCO_2_4, POSTDIV_DIV_BY_2,   75, 160, 108},
-  {VCO_3_6, POSTDIV_DIV_BY_2,  112, 216, 160} };
-
-static void polaris10_get_sclk_range_table(struct pp_hwmgr *hwmgr)
-{
-       uint32_t i, ref_clk;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       SMU74_Discrete_DpmTable  *table = &(data->smc_state_table);
-       struct pp_atom_ctrl_sclk_range_table range_table_from_vbios = { { {0} } };
-
-       ref_clk = polaris10_get_xclk(hwmgr);
-
-       if (0 == atomctrl_get_smc_sclk_range_table(hwmgr, &range_table_from_vbios)) {
-               for (i = 0; i < NUM_SCLK_RANGE; i++) {
-                       table->SclkFcwRangeTable[i].vco_setting = range_table_from_vbios.entry[i].ucVco_setting;
-                       table->SclkFcwRangeTable[i].postdiv = range_table_from_vbios.entry[i].ucPostdiv;
-                       table->SclkFcwRangeTable[i].fcw_pcc = range_table_from_vbios.entry[i].usFcw_pcc;
-
-                       table->SclkFcwRangeTable[i].fcw_trans_upper = range_table_from_vbios.entry[i].usFcw_trans_upper;
-                       table->SclkFcwRangeTable[i].fcw_trans_lower = range_table_from_vbios.entry[i].usRcw_trans_lower;
-
-                       CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_pcc);
-                       CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_trans_upper);
-                       CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_trans_lower);
-               }
-               return;
-       }
-
-       for (i = 0; i < NUM_SCLK_RANGE; i++) {
-
-               data->range_table[i].trans_lower_frequency = (ref_clk * Range_Table[i].fcw_trans_lower) >> Range_Table[i].postdiv;
-               data->range_table[i].trans_upper_frequency = (ref_clk * Range_Table[i].fcw_trans_upper) >> Range_Table[i].postdiv;
-
-               table->SclkFcwRangeTable[i].vco_setting = Range_Table[i].vco_setting;
-               table->SclkFcwRangeTable[i].postdiv = Range_Table[i].postdiv;
-               table->SclkFcwRangeTable[i].fcw_pcc = Range_Table[i].fcw_pcc;
-
-               table->SclkFcwRangeTable[i].fcw_trans_upper = Range_Table[i].fcw_trans_upper;
-               table->SclkFcwRangeTable[i].fcw_trans_lower = Range_Table[i].fcw_trans_lower;
-
-               CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_pcc);
-               CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_trans_upper);
-               CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_trans_lower);
-       }
-}
-
-/**
-* Populates single SMC SCLK structure using the provided engine clock
-*
-* @param    hwmgr      the address of the hardware manager
-* @param    clock the engine clock to use to populate the structure
-* @param    sclk        the SMC SCLK structure to be populated
-*/
-
-static int polaris10_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
-               uint32_t clock, uint16_t sclk_al_threshold,
-               struct SMU74_Discrete_GraphicsLevel *level)
-{
-       int result, i, temp;
-       /* PP_Clocks minClocks; */
-       uint32_t mvdd;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       SMU_SclkSetting curr_sclk_setting = { 0 };
-
-       result = polaris10_calculate_sclk_params(hwmgr, clock, &curr_sclk_setting);
-
-       /* populate graphics levels */
-       result = polaris10_get_dependency_volt_by_clk(hwmgr,
-                       table_info->vdd_dep_on_sclk, clock,
-                       &level->MinVoltage, &mvdd);
-
-       PP_ASSERT_WITH_CODE((0 == result),
-                       "can not find VDDC voltage value for "
-                       "VDDC engine clock dependency table",
-                       return result);
-       level->ActivityLevel = sclk_al_threshold;
-
-       level->CcPwrDynRm = 0;
-       level->CcPwrDynRm1 = 0;
-       level->EnabledForActivity = 0;
-       level->EnabledForThrottle = 1;
-       level->UpHyst = 10;
-       level->DownHyst = 0;
-       level->VoltageDownHyst = 0;
-       level->PowerThrottle = 0;
-
-       /*
-       * TODO: get minimum clocks from dal configaration
-       * PECI_GetMinClockSettings(hwmgr->pPECI, &minClocks);
-       */
-       /* data->DisplayTiming.minClockInSR = minClocks.engineClockInSR; */
-
-       /* get level->DeepSleepDivId
-       if (phm_cap_enabled(hwmgr->platformDescriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
-               level->DeepSleepDivId = PhwFiji_GetSleepDividerIdFromClock(hwmgr, clock, minClocks.engineClockInSR);
-       */
-       PP_ASSERT_WITH_CODE((clock >= POLARIS10_MINIMUM_ENGINE_CLOCK), "Engine clock can't satisfy stutter requirement!", return 0);
-       for (i = POLARIS10_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
-               temp = clock >> i;
-
-               if (temp >= POLARIS10_MINIMUM_ENGINE_CLOCK || i == 0)
-                       break;
-       }
-
-       level->DeepSleepDivId = i;
-
-       /* Default to slow, highest DPM level will be
-        * set to PPSMC_DISPLAY_WATERMARK_LOW later.
-        */
-       if (data->update_up_hyst)
-               level->UpHyst = (uint8_t)data->up_hyst;
-       if (data->update_down_hyst)
-               level->DownHyst = (uint8_t)data->down_hyst;
-
-       level->SclkSetting = curr_sclk_setting;
-
-       CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
-       CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
-       CONVERT_FROM_HOST_TO_SMC_UL(level->SclkSetting.SclkFrequency);
-       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Fcw_int);
-       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Fcw_frac);
-       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Pcc_fcw_int);
-       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Sclk_slew_rate);
-       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Pcc_up_slew_rate);
-       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Pcc_down_slew_rate);
-       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Fcw1_int);
-       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Fcw1_frac);
-       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Sclk_ss_slew_rate);
-       return 0;
-}
-
-/**
-* Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
-*
-* @param    hwmgr      the address of the hardware manager
-*/
-static int polaris10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_dpm_table *dpm_table = &data->dpm_table;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
-       uint8_t pcie_entry_cnt = (uint8_t) data->dpm_table.pcie_speed_table.count;
-       int result = 0;
-       uint32_t array = data->dpm_table_start +
-                       offsetof(SMU74_Discrete_DpmTable, GraphicsLevel);
-       uint32_t array_size = sizeof(struct SMU74_Discrete_GraphicsLevel) *
-                       SMU74_MAX_LEVELS_GRAPHICS;
-       struct SMU74_Discrete_GraphicsLevel *levels =
-                       data->smc_state_table.GraphicsLevel;
-       uint32_t i, max_entry;
-       uint8_t hightest_pcie_level_enabled = 0,
-               lowest_pcie_level_enabled = 0,
-               mid_pcie_level_enabled = 0,
-               count = 0;
-
-       polaris10_get_sclk_range_table(hwmgr);
-
-       for (i = 0; i < dpm_table->sclk_table.count; i++) {
-
-               result = polaris10_populate_single_graphic_level(hwmgr,
-                               dpm_table->sclk_table.dpm_levels[i].value,
-                               (uint16_t)data->activity_target[i],
-                               &(data->smc_state_table.GraphicsLevel[i]));
-               if (result)
-                       return result;
-
-               /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
-               if (i > 1)
-                       levels[i].DeepSleepDivId = 0;
-       }
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_SPLLShutdownSupport))
-               data->smc_state_table.GraphicsLevel[0].SclkSetting.SSc_En = 0;
-
-       data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
-       data->smc_state_table.GraphicsDpmLevelCount =
-                       (uint8_t)dpm_table->sclk_table.count;
-       data->dpm_level_enable_mask.sclk_dpm_enable_mask =
-                       phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
-
-
-       if (pcie_table != NULL) {
-               PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt),
-                               "There must be 1 or more PCIE levels defined in PPTable.",
-                               return -EINVAL);
-               max_entry = pcie_entry_cnt - 1;
-               for (i = 0; i < dpm_table->sclk_table.count; i++)
-                       levels[i].pcieDpmLevel =
-                                       (uint8_t) ((i < max_entry) ? i : max_entry);
-       } else {
-               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
-                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
-                                               (1 << (hightest_pcie_level_enabled + 1))) != 0))
-                       hightest_pcie_level_enabled++;
-
-               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
-                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
-                                               (1 << lowest_pcie_level_enabled)) == 0))
-                       lowest_pcie_level_enabled++;
-
-               while ((count < hightest_pcie_level_enabled) &&
-                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
-                                               (1 << (lowest_pcie_level_enabled + 1 + count))) == 0))
-                       count++;
-
-               mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1 + count) <
-                               hightest_pcie_level_enabled ?
-                                               (lowest_pcie_level_enabled + 1 + count) :
-                                               hightest_pcie_level_enabled;
-
-               /* set pcieDpmLevel to hightest_pcie_level_enabled */
-               for (i = 2; i < dpm_table->sclk_table.count; i++)
-                       levels[i].pcieDpmLevel = hightest_pcie_level_enabled;
-
-               /* set pcieDpmLevel to lowest_pcie_level_enabled */
-               levels[0].pcieDpmLevel = lowest_pcie_level_enabled;
-
-               /* set pcieDpmLevel to mid_pcie_level_enabled */
-               levels[1].pcieDpmLevel = mid_pcie_level_enabled;
-       }
-       /* level count will send to smc once at init smc table and never change */
-       result = polaris10_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
-                       (uint32_t)array_size, data->sram_end);
-
-       return result;
-}
-
-static int polaris10_populate_single_memory_level(struct pp_hwmgr *hwmgr,
-               uint32_t clock, struct SMU74_Discrete_MemoryLevel *mem_level)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       int result = 0;
-       struct cgs_display_info info = {0, 0, NULL};
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       if (table_info->vdd_dep_on_mclk) {
-               result = polaris10_get_dependency_volt_by_clk(hwmgr,
-                               table_info->vdd_dep_on_mclk, clock,
-                               &mem_level->MinVoltage, &mem_level->MinMvdd);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find MinVddc voltage value from memory "
-                               "VDDC voltage dependency table", return result);
-       }
-
-       mem_level->MclkFrequency = clock;
-       mem_level->EnabledForThrottle = 1;
-       mem_level->EnabledForActivity = 0;
-       mem_level->UpHyst = 0;
-       mem_level->DownHyst = 100;
-       mem_level->VoltageDownHyst = 0;
-       mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
-       mem_level->StutterEnable = false;
-       mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
-
-       data->display_timing.num_existing_displays = info.display_count;
-
-       if ((data->mclk_stutter_mode_threshold) &&
-               (clock <= data->mclk_stutter_mode_threshold) &&
-               (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL,
-                               STUTTER_ENABLE) & 0x1))
-               mem_level->StutterEnable = true;
-
-       if (!result) {
-               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd);
-               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency);
-               CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel);
-               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage);
-       }
-       return result;
-}
-
-/**
-* Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
-*
-* @param    hwmgr      the address of the hardware manager
-*/
-static int polaris10_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_dpm_table *dpm_table = &data->dpm_table;
-       int result;
-       /* populate MCLK dpm table to SMU7 */
-       uint32_t array = data->dpm_table_start +
-                       offsetof(SMU74_Discrete_DpmTable, MemoryLevel);
-       uint32_t array_size = sizeof(SMU74_Discrete_MemoryLevel) *
-                       SMU74_MAX_LEVELS_MEMORY;
-       struct SMU74_Discrete_MemoryLevel *levels =
-                       data->smc_state_table.MemoryLevel;
-       uint32_t i;
-
-       for (i = 0; i < dpm_table->mclk_table.count; i++) {
-               PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
-                               "can not populate memory level as memory clock is zero",
-                               return -EINVAL);
-               result = polaris10_populate_single_memory_level(hwmgr,
-                               dpm_table->mclk_table.dpm_levels[i].value,
-                               &levels[i]);
-               if (i == dpm_table->mclk_table.count - 1) {
-                       levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
-                       levels[i].EnabledForActivity = 1;
-               }
-               if (result)
-                       return result;
-       }
-
-       /* In order to prevent MC activity from stutter mode to push DPM up,
-        * the UVD change complements this by putting the MCLK in
-        * a higher state by default such that we are not affected by
-        * up threshold or and MCLK DPM latency.
-        */
-       levels[0].ActivityLevel = 0x1f;
-       CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel);
-
-       data->smc_state_table.MemoryDpmLevelCount =
-                       (uint8_t)dpm_table->mclk_table.count;
-       data->dpm_level_enable_mask.mclk_dpm_enable_mask =
-                       phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
-
-       /* level count will send to smc once at init smc table and never change */
-       result = polaris10_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
-                       (uint32_t)array_size, data->sram_end);
-
-       return result;
-}
-
-/**
-* Populates the SMC MVDD structure using the provided memory clock.
-*
-* @param    hwmgr      the address of the hardware manager
-* @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
-* @param    voltage     the SMC VOLTAGE structure to be populated
-*/
-int polaris10_populate_mvdd_value(struct pp_hwmgr *hwmgr,
-               uint32_t mclk, SMIO_Pattern *smio_pat)
-{
-       const struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint32_t i = 0;
-
-       if (POLARIS10_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
-               /* find mvdd value which clock is more than request */
-               for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
-                       if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
-                               smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value;
-                               break;
-                       }
-               }
-               PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
-                               "MVDD Voltage is outside the supported range.",
-                               return -EINVAL);
-       } else
-               return -EINVAL;
-
-       return 0;
-}
-
-static int polaris10_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
-               SMU74_Discrete_DpmTable *table)
-{
-       int result = 0;
-       uint32_t sclk_frequency;
-       const struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       SMIO_Pattern vol_level;
-       uint32_t mvdd;
-       uint16_t us_mvdd;
-
-       table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
-
-
-       /* Get MinVoltage and Frequency from DPM0,
-        * already converted to SMC_UL */
-       sclk_frequency = data->vbios_boot_state.sclk_bootup_value;
-       result = polaris10_get_dependency_volt_by_clk(hwmgr,
-                       table_info->vdd_dep_on_sclk,
-                       sclk_frequency,
-                       &table->ACPILevel.MinVoltage, &mvdd);
-       PP_ASSERT_WITH_CODE((0 == result),
-                       "Cannot find ACPI VDDC voltage value "
-                       "in Clock Dependency Table",
-                       );
-
-
-       result = polaris10_calculate_sclk_params(hwmgr, sclk_frequency,  &(table->ACPILevel.SclkSetting));
-       PP_ASSERT_WITH_CODE(result == 0, "Error retrieving Engine Clock dividers from VBIOS.", return result);
-
-       table->ACPILevel.DeepSleepDivId = 0;
-       table->ACPILevel.CcPwrDynRm = 0;
-       table->ACPILevel.CcPwrDynRm1 = 0;
-
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
-
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkSetting.SclkFrequency);
-       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Fcw_int);
-       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Fcw_frac);
-       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Pcc_fcw_int);
-       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Sclk_slew_rate);
-       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Pcc_up_slew_rate);
-       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Pcc_down_slew_rate);
-       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Fcw1_int);
-       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Fcw1_frac);
-       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Sclk_ss_slew_rate);
-
-
-       /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
-       table->MemoryACPILevel.MclkFrequency = data->vbios_boot_state.mclk_bootup_value;
-       result = polaris10_get_dependency_volt_by_clk(hwmgr,
-                       table_info->vdd_dep_on_mclk,
-                       table->MemoryACPILevel.MclkFrequency,
-                       &table->MemoryACPILevel.MinVoltage, &mvdd);
-       PP_ASSERT_WITH_CODE((0 == result),
-                       "Cannot find ACPI VDDCI voltage value "
-                       "in Clock Dependency Table",
-                       );
-
-       us_mvdd = 0;
-       if ((POLARIS10_VOLTAGE_CONTROL_NONE == data->mvdd_control) ||
-                       (data->mclk_dpm_key_disabled))
-               us_mvdd = data->vbios_boot_state.mvdd_bootup_value;
-       else {
-               if (!polaris10_populate_mvdd_value(hwmgr,
-                               data->dpm_table.mclk_table.dpm_levels[0].value,
-                               &vol_level))
-                       us_mvdd = vol_level.Voltage;
-       }
-
-       if (0 == polaris10_populate_mvdd_value(hwmgr, 0, &vol_level))
-               table->MemoryACPILevel.MinMvdd = PP_HOST_TO_SMC_UL(vol_level.Voltage);
-       else
-               table->MemoryACPILevel.MinMvdd = 0;
-
-       table->MemoryACPILevel.StutterEnable = false;
-
-       table->MemoryACPILevel.EnabledForThrottle = 0;
-       table->MemoryACPILevel.EnabledForActivity = 0;
-       table->MemoryACPILevel.UpHyst = 0;
-       table->MemoryACPILevel.DownHyst = 100;
-       table->MemoryACPILevel.VoltageDownHyst = 0;
-       table->MemoryACPILevel.ActivityLevel =
-                       PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
-
-       CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);
-
-       return result;
-}
-
-static int polaris10_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
-               SMU74_Discrete_DpmTable *table)
-{
-       int result = -EINVAL;
-       uint8_t count;
-       struct pp_atomctrl_clock_dividers_vi dividers;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
-                       table_info->mm_dep_table;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t vddci;
-
-       table->VceLevelCount = (uint8_t)(mm_table->count);
-       table->VceBootLevel = 0;
-
-       for (count = 0; count < table->VceLevelCount; count++) {
-               table->VceLevel[count].Frequency = mm_table->entries[count].eclk;
-               table->VceLevel[count].MinVoltage = 0;
-               table->VceLevel[count].MinVoltage |=
-                               (mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
-
-               if (POLARIS10_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control)
-                       vddci = (uint32_t)phm_find_closest_vddci(&(data->vddci_voltage_table),
-                                               mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
-               else if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control)
-                       vddci = mm_table->entries[count].vddc - VDDC_VDDCI_DELTA;
-               else
-                       vddci = (data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE) << VDDCI_SHIFT;
-
-
-               table->VceLevel[count].MinVoltage |=
-                               (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
-               table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
-
-               /*retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                               table->VceLevel[count].Frequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for VCE engine clock",
-                               return result);
-
-               table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage);
-       }
-       return result;
-}
-
-static int polaris10_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
-               SMU74_Discrete_DpmTable *table)
-{
-       int result = -EINVAL;
-       uint8_t count;
-       struct pp_atomctrl_clock_dividers_vi dividers;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
-                       table_info->mm_dep_table;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t vddci;
-
-       table->SamuBootLevel = 0;
-       table->SamuLevelCount = (uint8_t)(mm_table->count);
-
-       for (count = 0; count < table->SamuLevelCount; count++) {
-               /* not sure whether we need evclk or not */
-               table->SamuLevel[count].MinVoltage = 0;
-               table->SamuLevel[count].Frequency = mm_table->entries[count].samclock;
-               table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
-                               VOLTAGE_SCALE) << VDDC_SHIFT;
-
-               if (POLARIS10_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control)
-                       vddci = (uint32_t)phm_find_closest_vddci(&(data->vddci_voltage_table),
-                                               mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
-               else if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control)
-                       vddci = mm_table->entries[count].vddc - VDDC_VDDCI_DELTA;
-               else
-                       vddci = (data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE) << VDDCI_SHIFT;
-
-               table->SamuLevel[count].MinVoltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
-               table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
-
-               /* retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                               table->SamuLevel[count].Frequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for samu clock", return result);
-
-               table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage);
-       }
-       return result;
-}
-
-static int polaris10_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr,
-               int32_t eng_clock, int32_t mem_clock,
-               SMU74_Discrete_MCArbDramTimingTableEntry *arb_regs)
-{
-       uint32_t dram_timing;
-       uint32_t dram_timing2;
-       uint32_t burst_time;
-       int result;
-
-       result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
-                       eng_clock, mem_clock);
-       PP_ASSERT_WITH_CODE(result == 0,
-                       "Error calling VBIOS to set DRAM_TIMING.", return result);
-
-       dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
-       dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
-       burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
-
-
-       arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dram_timing);
-       arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2);
-       arb_regs->McArbBurstTime   = (uint8_t)burst_time;
-
-       return 0;
-}
-
-static int polaris10_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct SMU74_Discrete_MCArbDramTimingTable arb_regs;
-       uint32_t i, j;
-       int result = 0;
-
-       for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
-               for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
-                       result = polaris10_populate_memory_timing_parameters(hwmgr,
-                                       data->dpm_table.sclk_table.dpm_levels[i].value,
-                                       data->dpm_table.mclk_table.dpm_levels[j].value,
-                                       &arb_regs.entries[i][j]);
-                       if (result == 0)
-                               result = atomctrl_set_ac_timing_ai(hwmgr, data->dpm_table.mclk_table.dpm_levels[j].value, j);
-                       if (result != 0)
-                               return result;
-               }
-       }
-
-       result = polaris10_copy_bytes_to_smc(
-                       hwmgr->smumgr,
-                       data->arb_table_start,
-                       (uint8_t *)&arb_regs,
-                       sizeof(SMU74_Discrete_MCArbDramTimingTable),
-                       data->sram_end);
-       return result;
-}
-
-static int polaris10_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
-               struct SMU74_Discrete_DpmTable *table)
-{
-       int result = -EINVAL;
-       uint8_t count;
-       struct pp_atomctrl_clock_dividers_vi dividers;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
-                       table_info->mm_dep_table;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t vddci;
-
-       table->UvdLevelCount = (uint8_t)(mm_table->count);
-       table->UvdBootLevel = 0;
-
-       for (count = 0; count < table->UvdLevelCount; count++) {
-               table->UvdLevel[count].MinVoltage = 0;
-               table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
-               table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
-               table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
-                               VOLTAGE_SCALE) << VDDC_SHIFT;
-
-               if (POLARIS10_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control)
-                       vddci = (uint32_t)phm_find_closest_vddci(&(data->vddci_voltage_table),
-                                               mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
-               else if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control)
-                       vddci = mm_table->entries[count].vddc - VDDC_VDDCI_DELTA;
-               else
-                       vddci = (data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE) << VDDCI_SHIFT;
-
-               table->UvdLevel[count].MinVoltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
-               table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
-
-               /* retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                               table->UvdLevel[count].VclkFrequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for Vclk clock", return result);
-
-               table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
-
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                               table->UvdLevel[count].DclkFrequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for Dclk clock", return result);
-
-               table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage);
-       }
-
-       return result;
-}
-
-static int polaris10_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
-               struct SMU74_Discrete_DpmTable *table)
-{
-       int result = 0;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       table->GraphicsBootLevel = 0;
-       table->MemoryBootLevel = 0;
-
-       /* find boot level from dpm table */
-       result = phm_find_boot_level(&(data->dpm_table.sclk_table),
-                       data->vbios_boot_state.sclk_bootup_value,
-                       (uint32_t *)&(table->GraphicsBootLevel));
-
-       result = phm_find_boot_level(&(data->dpm_table.mclk_table),
-                       data->vbios_boot_state.mclk_bootup_value,
-                       (uint32_t *)&(table->MemoryBootLevel));
-
-       table->BootVddc  = data->vbios_boot_state.vddc_bootup_value *
-                       VOLTAGE_SCALE;
-       table->BootVddci = data->vbios_boot_state.vddci_bootup_value *
-                       VOLTAGE_SCALE;
-       table->BootMVdd  = data->vbios_boot_state.mvdd_bootup_value *
-                       VOLTAGE_SCALE;
-
-       CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc);
-       CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci);
-       CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
-
-       return 0;
-}
-
-
-static int polaris10_populate_smc_initailial_state(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint8_t count, level;
-
-       count = (uint8_t)(table_info->vdd_dep_on_sclk->count);
-
-       for (level = 0; level < count; level++) {
-               if (table_info->vdd_dep_on_sclk->entries[level].clk >=
-                               data->vbios_boot_state.sclk_bootup_value) {
-                       data->smc_state_table.GraphicsBootLevel = level;
-                       break;
-               }
-       }
-
-       count = (uint8_t)(table_info->vdd_dep_on_mclk->count);
-       for (level = 0; level < count; level++) {
-               if (table_info->vdd_dep_on_mclk->entries[level].clk >=
-                               data->vbios_boot_state.mclk_bootup_value) {
-                       data->smc_state_table.MemoryBootLevel = level;
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
-{
-       uint32_t ro, efuse, volt_without_cks, volt_with_cks, value, max, min;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint8_t i, stretch_amount, volt_offset = 0;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
-                       table_info->vdd_dep_on_sclk;
-
-       stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
-
-       /* Read SMU_Eefuse to read and calculate RO and determine
-        * if the part is SS or FF. if RO >= 1660MHz, part is FF.
-        */
-       efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixSMU_EFUSE_0 + (67 * 4));
-       efuse &= 0xFF000000;
-       efuse = efuse >> 24;
-
-       if (hwmgr->chip_id == CHIP_POLARIS10) {
-               min = 1000;
-               max = 2300;
-       } else {
-               min = 1100;
-               max = 2100;
-       }
-
-       ro = efuse * (max -min)/255 + min;
-
-       /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
-       for (i = 0; i < sclk_table->count; i++) {
-               data->smc_state_table.Sclk_CKS_masterEn0_7 |=
-                               sclk_table->entries[i].cks_enable << i;
-               if (hwmgr->chip_id == CHIP_POLARIS10) {
-                       volt_without_cks = (uint32_t)((2753594000U + (sclk_table->entries[i].clk/100) * 136418 -(ro - 70) * 1000000) / \
-                                               (2424180 - (sclk_table->entries[i].clk/100) * 1132925/1000));
-                       volt_with_cks = (uint32_t)((2797202000U + sclk_table->entries[i].clk/100 * 3232 - (ro - 65) * 1000000) / \
-                                       (2522480 - sclk_table->entries[i].clk/100 * 115764/100));
-               } else {
-                       volt_without_cks = (uint32_t)((2416794800U + (sclk_table->entries[i].clk/100) * 1476925/10 -(ro - 50) * 1000000) / \
-                                               (2625416 - (sclk_table->entries[i].clk/100) * (12586807/10000)));
-                       volt_with_cks = (uint32_t)((2999656000U - sclk_table->entries[i].clk/100 * 392803 - (ro - 44) * 1000000) / \
-                                       (3422454 - sclk_table->entries[i].clk/100 * (18886376/10000)));
-               }
-
-               if (volt_without_cks >= volt_with_cks)
-                       volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
-                                       sclk_table->entries[i].cks_voffset) * 100 + 624) / 625);
-
-               data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
-       }
-
-       data->smc_state_table.LdoRefSel = (table_info->cac_dtp_table->ucCKS_LDO_REFSEL != 0) ? table_info->cac_dtp_table->ucCKS_LDO_REFSEL : 6;
-       /* Populate CKS Lookup Table */
-       if (stretch_amount != 1 && stretch_amount != 2 && stretch_amount != 3 &&
-                       stretch_amount != 4 && stretch_amount != 5) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_ClockStretcher);
-               PP_ASSERT_WITH_CODE(false,
-                               "Stretch Amount in PPTable not supported\n",
-                               return -EINVAL);
-       }
-
-       value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL);
-       value &= 0xFFFFFFFE;
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value);
-
-       return 0;
-}
-
-/**
-* Populates the SMC VRConfig field in DPM table.
-*
-* @param    hwmgr   the address of the hardware manager
-* @param    table   the SMC DPM table structure to be populated
-* @return   always 0
-*/
-static int polaris10_populate_vr_config(struct pp_hwmgr *hwmgr,
-               struct SMU74_Discrete_DpmTable *table)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint16_t config;
-
-       config = VR_MERGED_WITH_VDDC;
-       table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT);
-
-       /* Set Vddc Voltage Controller */
-       if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
-               config = VR_SVI2_PLANE_1;
-               table->VRConfig |= config;
-       } else {
-               PP_ASSERT_WITH_CODE(false,
-                               "VDDC should be on SVI2 control in merged mode!",
-                               );
-       }
-       /* Set Vddci Voltage Controller */
-       if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
-               config = VR_SVI2_PLANE_2;  /* only in merged mode */
-               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
-       } else if (POLARIS10_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
-               config = VR_SMIO_PATTERN_1;
-               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
-       } else {
-               config = VR_STATIC_VOLTAGE;
-               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
-       }
-       /* Set Mvdd Voltage Controller */
-       if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
-               config = VR_SVI2_PLANE_2;
-               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start +
-                       offsetof(SMU74_SoftRegisters, AllowMvddSwitch), 0x1);
-       } else {
-               config = VR_STATIC_VOLTAGE;
-               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
-       }
-
-       return 0;
-}
-
-
-int polaris10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       SMU74_Discrete_DpmTable  *table = &(data->smc_state_table);
-       int result = 0;
-       struct pp_atom_ctrl__avfs_parameters avfs_params = {0};
-       AVFS_meanNsigma_t AVFS_meanNsigma = { {0} };
-       AVFS_Sclk_Offset_t AVFS_SclkOffset = { {0} };
-       uint32_t tmp, i;
-       struct pp_smumgr *smumgr = hwmgr->smumgr;
-       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
-
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)hwmgr->pptable;
-       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
-                       table_info->vdd_dep_on_sclk;
-
-
-       if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED)
-               return result;
-
-       result = atomctrl_get_avfs_information(hwmgr, &avfs_params);
-
-       if (0 == result) {
-               table->BTCGB_VDROOP_TABLE[0].a0  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSON_a0);
-               table->BTCGB_VDROOP_TABLE[0].a1  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSON_a1);
-               table->BTCGB_VDROOP_TABLE[0].a2  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSON_a2);
-               table->BTCGB_VDROOP_TABLE[1].a0  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a0);
-               table->BTCGB_VDROOP_TABLE[1].a1  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a1);
-               table->BTCGB_VDROOP_TABLE[1].a2  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a2);
-               table->AVFSGB_VDROOP_TABLE[0].m1 = PP_HOST_TO_SMC_UL(avfs_params.ulAVFSGB_FUSE_TABLE_CKSON_m1);
-               table->AVFSGB_VDROOP_TABLE[0].m2 = PP_HOST_TO_SMC_US(avfs_params.usAVFSGB_FUSE_TABLE_CKSON_m2);
-               table->AVFSGB_VDROOP_TABLE[0].b  = PP_HOST_TO_SMC_UL(avfs_params.ulAVFSGB_FUSE_TABLE_CKSON_b);
-               table->AVFSGB_VDROOP_TABLE[0].m1_shift = 24;
-               table->AVFSGB_VDROOP_TABLE[0].m2_shift  = 12;
-               table->AVFSGB_VDROOP_TABLE[1].m1 = PP_HOST_TO_SMC_UL(avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_m1);
-               table->AVFSGB_VDROOP_TABLE[1].m2 = PP_HOST_TO_SMC_US(avfs_params.usAVFSGB_FUSE_TABLE_CKSOFF_m2);
-               table->AVFSGB_VDROOP_TABLE[1].b  = PP_HOST_TO_SMC_UL(avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_b);
-               table->AVFSGB_VDROOP_TABLE[1].m1_shift = 24;
-               table->AVFSGB_VDROOP_TABLE[1].m2_shift  = 12;
-               table->MaxVoltage                = PP_HOST_TO_SMC_US(avfs_params.usMaxVoltage_0_25mv);
-               AVFS_meanNsigma.Aconstant[0]      = PP_HOST_TO_SMC_UL(avfs_params.ulAVFS_meanNsigma_Acontant0);
-               AVFS_meanNsigma.Aconstant[1]      = PP_HOST_TO_SMC_UL(avfs_params.ulAVFS_meanNsigma_Acontant1);
-               AVFS_meanNsigma.Aconstant[2]      = PP_HOST_TO_SMC_UL(avfs_params.ulAVFS_meanNsigma_Acontant2);
-               AVFS_meanNsigma.DC_tol_sigma      = PP_HOST_TO_SMC_US(avfs_params.usAVFS_meanNsigma_DC_tol_sigma);
-               AVFS_meanNsigma.Platform_mean     = PP_HOST_TO_SMC_US(avfs_params.usAVFS_meanNsigma_Platform_mean);
-               AVFS_meanNsigma.PSM_Age_CompFactor = PP_HOST_TO_SMC_US(avfs_params.usPSM_Age_ComFactor);
-               AVFS_meanNsigma.Platform_sigma     = PP_HOST_TO_SMC_US(avfs_params.usAVFS_meanNsigma_Platform_sigma);
-
-               for (i = 0; i < NUM_VFT_COLUMNS; i++) {
-                       AVFS_meanNsigma.Static_Voltage_Offset[i] = (uint8_t)(sclk_table->entries[i].cks_voffset * 100 / 625);
-                       AVFS_SclkOffset.Sclk_Offset[i] = PP_HOST_TO_SMC_US((uint16_t)(sclk_table->entries[i].sclk_offset) / 100);
-               }
-
-               result = polaris10_read_smc_sram_dword(smumgr,
-                               SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, AvfsMeanNSigma),
-                               &tmp, data->sram_end);
-
-               polaris10_copy_bytes_to_smc(smumgr,
-                                       tmp,
-                                       (uint8_t *)&AVFS_meanNsigma,
-                                       sizeof(AVFS_meanNsigma_t),
-                                       data->sram_end);
-
-               result = polaris10_read_smc_sram_dword(smumgr,
-                               SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, AvfsSclkOffsetTable),
-                               &tmp, data->sram_end);
-               polaris10_copy_bytes_to_smc(smumgr,
-                                       tmp,
-                                       (uint8_t *)&AVFS_SclkOffset,
-                                       sizeof(AVFS_Sclk_Offset_t),
-                                       data->sram_end);
-
-               data->avfs_vdroop_override_setting = (avfs_params.ucEnableGB_VDROOP_TABLE_CKSON << BTCGB0_Vdroop_Enable_SHIFT) |
-                                               (avfs_params.ucEnableGB_VDROOP_TABLE_CKSOFF << BTCGB1_Vdroop_Enable_SHIFT) |
-                                               (avfs_params.ucEnableGB_FUSE_TABLE_CKSON << AVFSGB0_Vdroop_Enable_SHIFT) |
-                                               (avfs_params.ucEnableGB_FUSE_TABLE_CKSOFF << AVFSGB1_Vdroop_Enable_SHIFT);
-               data->apply_avfs_cks_off_voltage = (avfs_params.ucEnableApplyAVFS_CKS_OFF_Voltage == 1) ? true : false;
-       }
-       return result;
-}
-
-
-/**
-* Initializes the SMC table and uploads it
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int polaris10_init_smc_table(struct pp_hwmgr *hwmgr)
-{
-       int result;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct SMU74_Discrete_DpmTable *table = &(data->smc_state_table);
-       const struct polaris10_ulv_parm *ulv = &(data->ulv);
-       uint8_t i;
-       struct pp_atomctrl_gpio_pin_assignment gpio_pin;
-       pp_atomctrl_clock_dividers_vi dividers;
-
-       result = polaris10_setup_default_dpm_tables(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to setup default DPM tables!", return result);
-
-       if (POLARIS10_VOLTAGE_CONTROL_NONE != data->voltage_control)
-               polaris10_populate_smc_voltage_tables(hwmgr, table);
-
-       table->SystemFlags = 0;
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_AutomaticDCTransition))
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_StepVddc))
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
-
-       if (data->is_memory_gddr5)
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
-
-       if (ulv->ulv_supported && table_info->us_ulv_voltage_offset) {
-               result = polaris10_populate_ulv_state(hwmgr, table);
-               PP_ASSERT_WITH_CODE(0 == result,
-                               "Failed to initialize ULV state!", return result);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               ixCG_ULV_PARAMETER, PPPOLARIS10_CGULVPARAMETER_DFLT);
-       }
-
-       result = polaris10_populate_smc_link_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Link Level!", return result);
-
-       result = polaris10_populate_all_graphic_levels(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Graphics Level!", return result);
-
-       result = polaris10_populate_all_memory_levels(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Memory Level!", return result);
-
-       result = polaris10_populate_smc_acpi_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize ACPI Level!", return result);
-
-       result = polaris10_populate_smc_vce_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize VCE Level!", return result);
-
-       result = polaris10_populate_smc_samu_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize SAMU Level!", return result);
-
-       /* Since only the initial state is completely set up at this point
-        * (the other states are just copies of the boot state) we only
-        * need to populate the  ARB settings for the initial state.
-        */
-       result = polaris10_program_memory_timing_parameters(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to Write ARB settings for the initial state.", return result);
-
-       result = polaris10_populate_smc_uvd_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize UVD Level!", return result);
-
-       result = polaris10_populate_smc_boot_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Boot Level!", return result);
-
-       result = polaris10_populate_smc_initailial_state(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize Boot State!", return result);
-
-       result = polaris10_populate_bapm_parameters_in_dpm_table(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to populate BAPM Parameters!", return result);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ClockStretcher)) {
-               result = polaris10_populate_clock_stretcher_data_table(hwmgr);
-               PP_ASSERT_WITH_CODE(0 == result,
-                               "Failed to populate Clock Stretcher Data Table!",
-                               return result);
-       }
-
-       result = polaris10_populate_avfs_parameters(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result, "Failed to populate AVFS Parameters!", return result;);
-
-       table->CurrSclkPllRange = 0xff;
-       table->GraphicsVoltageChangeEnable  = 1;
-       table->GraphicsThermThrottleEnable  = 1;
-       table->GraphicsInterval = 1;
-       table->VoltageInterval  = 1;
-       table->ThermalInterval  = 1;
-       table->TemperatureLimitHigh =
-                       table_info->cac_dtp_table->usTargetOperatingTemp *
-                       POLARIS10_Q88_FORMAT_CONVERSION_UNIT;
-       table->TemperatureLimitLow  =
-                       (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
-                       POLARIS10_Q88_FORMAT_CONVERSION_UNIT;
-       table->MemoryVoltageChangeEnable = 1;
-       table->MemoryInterval = 1;
-       table->VoltageResponseTime = 0;
-       table->PhaseResponseTime = 0;
-       table->MemoryThermThrottleEnable = 1;
-       table->PCIeBootLinkLevel = 0;
-       table->PCIeGenInterval = 1;
-       table->VRConfig = 0;
-
-       result = polaris10_populate_vr_config(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to populate VRConfig setting!", return result);
-
-       table->ThermGpio = 17;
-       table->SclkStepSize = 0x4000;
-
-       if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
-               table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
-       } else {
-               table->VRHotGpio = POLARIS10_UNUSED_GPIO_PIN;
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_RegulatorHot);
-       }
-
-       if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
-                       &gpio_pin)) {
-               table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift;
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_AutomaticDCTransition);
-       } else {
-               table->AcDcGpio = POLARIS10_UNUSED_GPIO_PIN;
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_AutomaticDCTransition);
-       }
-
-       /* Thermal Output GPIO */
-       if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID,
-                       &gpio_pin)) {
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_ThermalOutGPIO);
-
-               table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift;
-
-               /* For porlarity read GPIOPAD_A with assigned Gpio pin
-                * since VBIOS will program this register to set 'inactive state',
-                * driver can then determine 'active state' from this and
-                * program SMU with correct polarity
-                */
-               table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A)
-                                       & (1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0;
-               table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
-
-               /* if required, combine VRHot/PCC with thermal out GPIO */
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_RegulatorHot)
-               && phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_CombinePCCWithThermalSignal))
-                       table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
-       } else {
-               table->ThermOutGpio = 17;
-               table->ThermOutPolarity = 1;
-               table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
-       }
-
-       /* Populate BIF_SCLK levels into SMC DPM table */
-       for (i = 0; i <= data->dpm_table.pcie_speed_table.count; i++) {
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, data->bif_sclk_table[i], &dividers);
-               PP_ASSERT_WITH_CODE((result == 0), "Can not find DFS divide id for Sclk", return result);
-
-               if (i == 0)
-                       table->Ulv.BifSclkDfs = PP_HOST_TO_SMC_US((USHORT)(dividers.pll_post_divider));
-               else
-                       table->LinkLevel[i-1].BifSclkDfs = PP_HOST_TO_SMC_US((USHORT)(dividers.pll_post_divider));
-       }
-
-       for (i = 0; i < SMU74_MAX_ENTRIES_SMIO; i++)
-               table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
-
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->CurrSclkPllRange);
-       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
-       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
-       CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
-       CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
-
-       /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
-       result = polaris10_copy_bytes_to_smc(hwmgr->smumgr,
-                       data->dpm_table_start +
-                       offsetof(SMU74_Discrete_DpmTable, SystemFlags),
-                       (uint8_t *)&(table->SystemFlags),
-                       sizeof(SMU74_Discrete_DpmTable) - 3 * sizeof(SMU74_PIDController),
-                       data->sram_end);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to upload dpm data to SMC memory!", return result);
-
-       return 0;
-}
-
-/**
-* Initialize the ARB DRAM timing table's index field.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int polaris10_init_arb_table_index(struct pp_hwmgr *hwmgr)
-{
-       const struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t tmp;
-       int result;
-
-       /* This is a read-modify-write on the first byte of the ARB table.
-        * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
-        * is the field 'current'.
-        * This solution is ugly, but we never write the whole table only
-        * individual fields in it.
-        * In reality this field should not be in that structure
-        * but in a soft register.
-        */
-       result = polaris10_read_smc_sram_dword(hwmgr->smumgr,
-                       data->arb_table_start, &tmp, data->sram_end);
-
-       if (result)
-               return result;
-
-       tmp &= 0x00FFFFFF;
-       tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
-
-       return polaris10_write_smc_sram_dword(hwmgr->smumgr,
-                       data->arb_table_start, tmp, data->sram_end);
-}
-
-static int polaris10_enable_vrhot_gpio_interrupt(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_RegulatorHot))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_EnableVRHotGPIOInterrupt);
-
-       return 0;
-}
-
-static int polaris10_enable_sclk_control(struct pp_hwmgr *hwmgr)
-{
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
-                       SCLK_PWRMGT_OFF, 0);
-       return 0;
-}
-
-static int polaris10_enable_ulv(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_ulv_parm *ulv = &(data->ulv);
-
-       if (ulv->ulv_supported)
-               return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_EnableULV);
-
-       return 0;
-}
-
-static int polaris10_disable_ulv(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_ulv_parm *ulv = &(data->ulv);
-
-       if (ulv->ulv_supported)
-               return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableULV);
-
-       return 0;
-}
-
-static int polaris10_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkDeepSleep)) {
-               if (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MASTER_DeepSleep_ON))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to enable Master Deep Sleep switch failed!",
-                                       return -1);
-       } else {
-               if (smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_MASTER_DeepSleep_OFF)) {
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to disable Master Deep Sleep switch failed!",
-                                       return -1);
-               }
-       }
-
-       return 0;
-}
-
-static int polaris10_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkDeepSleep)) {
-               if (smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_MASTER_DeepSleep_OFF)) {
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to disable Master Deep Sleep switch failed!",
-                                       return -1);
-               }
-       }
-
-       return 0;
-}
-
-static int polaris10_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t soft_register_value = 0;
-       uint32_t handshake_disables_offset = data->soft_regs_start
-                               + offsetof(SMU74_SoftRegisters, HandshakeDisables);
-
-       /* enable SCLK dpm */
-       if (!data->sclk_dpm_key_disabled)
-               PP_ASSERT_WITH_CODE(
-               (0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Enable)),
-               "Failed to enable SCLK DPM during DPM Start Function!",
-               return -1);
-
-       /* enable MCLK dpm */
-       if (0 == data->mclk_dpm_key_disabled) {
-/* Disable UVD - SMU handshake for MCLK. */
-               soft_register_value = cgs_read_ind_register(hwmgr->device,
-                                       CGS_IND_REG__SMC, handshake_disables_offset);
-               soft_register_value |= SMU7_UVD_MCLK_HANDSHAKE_DISABLE;
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                               handshake_disables_offset, soft_register_value);
-
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_MCLKDPM_Enable)),
-                               "Failed to enable MCLK DPM during DPM Start Function!",
-                               return -1);
-
-               PHM_WRITE_FIELD(hwmgr->device, MC_SEQ_CNTL_3, CAC_EN, 0x1);
-
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x5);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x5);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x100005);
-               udelay(10);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x400005);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x400005);
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x500005);
-       }
-
-       return 0;
-}
-
-static int polaris10_start_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       /*enable general power management */
-
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
-                       GLOBAL_PWRMGT_EN, 1);
-
-       /* enable sclk deep sleep */
-
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
-                       DYNAMIC_PM_EN, 1);
-
-       /* prepare for PCIE DPM */
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       data->soft_regs_start + offsetof(SMU74_SoftRegisters,
-                                       VoltageChangeTimeout), 0x1000);
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
-                       SWRST_COMMAND_1, RESETLC, 0x0);
-/*
-       PP_ASSERT_WITH_CODE(
-                       (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                       PPSMC_MSG_Voltage_Cntl_Enable)),
-                       "Failed to enable voltage DPM during DPM Start Function!",
-                       return -1);
-*/
-
-       if (polaris10_enable_sclk_mclk_dpm(hwmgr)) {
-               printk(KERN_ERR "Failed to enable Sclk DPM and Mclk DPM!");
-               return -1;
-       }
-
-       /* enable PCIE dpm */
-       if (0 == data->pcie_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_PCIeDPM_Enable)),
-                               "Failed to enable pcie DPM during DPM Start Function!",
-                               return -1);
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_Falcon_QuickTransition)) {
-               PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_EnableACDCGPIOInterrupt)),
-                               "Failed to enable AC DC GPIO Interrupt!",
-                               );
-       }
-
-       return 0;
-}
-
-static int polaris10_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       /* disable SCLK dpm */
-       if (!data->sclk_dpm_key_disabled)
-               PP_ASSERT_WITH_CODE(
-                               (smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_DPM_Disable) == 0),
-                               "Failed to disable SCLK DPM!",
-                               return -1);
-
-       /* disable MCLK dpm */
-       if (!data->mclk_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_MCLKDPM_Disable) == 0),
-                               "Failed to disable MCLK DPM!",
-                               return -1);
-       }
-
-       return 0;
-}
-
-static int polaris10_stop_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       /* disable general power management */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
-                       GLOBAL_PWRMGT_EN, 0);
-       /* disable sclk deep sleep */
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
-                       DYNAMIC_PM_EN, 0);
-
-       /* disable PCIE dpm */
-       if (!data->pcie_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_PCIeDPM_Disable) == 0),
-                               "Failed to disable pcie DPM during DPM Stop Function!",
-                               return -1);
-       }
-
-       if (polaris10_disable_sclk_mclk_dpm(hwmgr)) {
-               printk(KERN_ERR "Failed to disable Sclk DPM and Mclk DPM!");
-               return -1;
-       }
-
-       return 0;
-}
-
-static void polaris10_set_dpm_event_sources(struct pp_hwmgr *hwmgr, uint32_t sources)
-{
-       bool protection;
-       enum DPM_EVENT_SRC src;
-
-       switch (sources) {
-       default:
-               printk(KERN_ERR "Unknown throttling event sources.");
-               /* fall through */
-       case 0:
-               protection = false;
-               /* src is unused */
-               break;
-       case (1 << PHM_AutoThrottleSource_Thermal):
-               protection = true;
-               src = DPM_EVENT_SRC_DIGITAL;
-               break;
-       case (1 << PHM_AutoThrottleSource_External):
-               protection = true;
-               src = DPM_EVENT_SRC_EXTERNAL;
-               break;
-       case (1 << PHM_AutoThrottleSource_External) |
-                       (1 << PHM_AutoThrottleSource_Thermal):
-               protection = true;
-               src = DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL;
-               break;
-       }
-       /* Order matters - don't enable thermal protection for the wrong source. */
-       if (protection) {
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL,
-                               DPM_EVENT_SRC, src);
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
-                               THERMAL_PROTECTION_DIS,
-                               !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                               PHM_PlatformCaps_ThermalController));
-       } else
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
-                               THERMAL_PROTECTION_DIS, 1);
-}
-
-static int polaris10_enable_auto_throttle_source(struct pp_hwmgr *hwmgr,
-               PHM_AutoThrottleSource source)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (!(data->active_auto_throttle_sources & (1 << source))) {
-               data->active_auto_throttle_sources |= 1 << source;
-               polaris10_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
-       }
-       return 0;
-}
-
-static int polaris10_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
-{
-       return polaris10_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
-}
-
-static int polaris10_disable_auto_throttle_source(struct pp_hwmgr *hwmgr,
-               PHM_AutoThrottleSource source)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (data->active_auto_throttle_sources & (1 << source)) {
-               data->active_auto_throttle_sources &= ~(1 << source);
-               polaris10_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
-       }
-       return 0;
-}
-
-static int polaris10_disable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
-{
-       return polaris10_disable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
-}
-
-int polaris10_pcie_performance_request(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       data->pcie_performance_request = true;
-
-       return 0;
-}
-
-int polaris10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
-{
-       int tmp_result, result = 0;
-       tmp_result = (!polaris10_is_dpm_running(hwmgr)) ? 0 : -1;
-       PP_ASSERT_WITH_CODE(result == 0,
-                       "DPM is already running right now, no need to enable DPM!",
-                       return 0);
-
-       if (polaris10_voltage_control(hwmgr)) {
-               tmp_result = polaris10_enable_voltage_control(hwmgr);
-               PP_ASSERT_WITH_CODE(tmp_result == 0,
-                               "Failed to enable voltage control!",
-                               result = tmp_result);
-
-               tmp_result = polaris10_construct_voltage_tables(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == tmp_result),
-                               "Failed to contruct voltage tables!",
-                               result = tmp_result);
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_EngineSpreadSpectrumSupport))
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 1);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ThermalController))
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 0);
-
-       tmp_result = polaris10_program_static_screen_threshold_parameters(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to program static screen threshold parameters!",
-                       result = tmp_result);
-
-       tmp_result = polaris10_enable_display_gap(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable display gap!", result = tmp_result);
-
-       tmp_result = polaris10_program_voting_clients(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to program voting clients!", result = tmp_result);
-
-       tmp_result = polaris10_process_firmware_header(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to process firmware header!", result = tmp_result);
-
-       tmp_result = polaris10_initial_switch_from_arbf0_to_f1(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to initialize switch from ArbF0 to F1!",
-                       result = tmp_result);
-
-       tmp_result = polaris10_init_smc_table(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to initialize SMC table!", result = tmp_result);
-
-       tmp_result = polaris10_init_arb_table_index(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to initialize ARB table index!", result = tmp_result);
-
-       tmp_result = polaris10_populate_pm_fuses(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to populate PM fuses!", result = tmp_result);
-
-       tmp_result = polaris10_enable_vrhot_gpio_interrupt(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable VR hot GPIO interrupt!", result = tmp_result);
-
-       smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_HasDisplay);
-
-       tmp_result = polaris10_enable_sclk_control(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable SCLK control!", result = tmp_result);
-
-       tmp_result = polaris10_enable_smc_voltage_controller(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable voltage control!", result = tmp_result);
-
-       tmp_result = polaris10_enable_ulv(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable ULV!", result = tmp_result);
-
-       tmp_result = polaris10_enable_deep_sleep_master_switch(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable deep sleep master switch!", result = tmp_result);
-
-       tmp_result = polaris10_enable_didt_config(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to enable deep sleep master switch!", result = tmp_result);
-
-       tmp_result = polaris10_start_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to start DPM!", result = tmp_result);
-
-       tmp_result = polaris10_enable_smc_cac(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable SMC CAC!", result = tmp_result);
-
-       tmp_result = polaris10_enable_power_containment(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable power containment!", result = tmp_result);
-
-       tmp_result = polaris10_power_control_set_level(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to power control set level!", result = tmp_result);
-
-       tmp_result = polaris10_enable_thermal_auto_throttle(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable thermal auto throttle!", result = tmp_result);
-
-       tmp_result = polaris10_pcie_performance_request(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "pcie performance request failed!", result = tmp_result);
-
-       return result;
-}
-
-int polaris10_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
-{
-       int tmp_result, result = 0;
-
-       tmp_result = (polaris10_is_dpm_running(hwmgr)) ? 0 : -1;
-       PP_ASSERT_WITH_CODE(tmp_result == 0,
-                       "DPM is not running right now, no need to disable DPM!",
-                       return 0);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ThermalController))
-               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 1);
-
-       tmp_result = polaris10_disable_power_containment(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable power containment!", result = tmp_result);
-
-       tmp_result = polaris10_disable_smc_cac(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable SMC CAC!", 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,
-                       GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 0);
-
-       tmp_result = polaris10_disable_thermal_auto_throttle(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable thermal auto throttle!", result = tmp_result);
-
-       tmp_result = polaris10_stop_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to stop DPM!", result = tmp_result);
-
-       tmp_result = polaris10_disable_deep_sleep_master_switch(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable deep sleep master switch!", result = tmp_result);
-
-       tmp_result = polaris10_disable_ulv(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to disable ULV!", result = tmp_result);
-
-       tmp_result = polaris10_clear_voting_clients(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to clear voting clients!", result = tmp_result);
-
-       tmp_result = polaris10_reset_to_default(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to reset to default!", result = tmp_result);
-
-       tmp_result = polaris10_force_switch_to_arbf0(hwmgr);
-       PP_ASSERT_WITH_CODE((tmp_result == 0),
-                       "Failed to force to switch arbf0!", result = tmp_result);
-
-       return result;
-}
-
-int polaris10_reset_asic_tasks(struct pp_hwmgr *hwmgr)
-{
-
-       return 0;
-}
-
-int polaris10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
-{
-       return phm_hwmgr_backend_fini(hwmgr);
-}
-
-int polaris10_set_features_platform_caps(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkDeepSleep);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_DynamicPatchPowerState);
-
-       if (data->mvdd_control == POLARIS10_VOLTAGE_CONTROL_NONE)
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_EnableMVDDControl);
-
-       if (data->vddci_control == POLARIS10_VOLTAGE_CONTROL_NONE)
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_ControlVDDCI);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                        PHM_PlatformCaps_TablelessHardwareInterface);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_EnableSMU7ThermalManagement);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_DynamicPowerManagement);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_UnTabledHardwareInterface);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_TablelessHardwareInterface);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_SMC);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_NonABMSupportInPPLib);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_DynamicUVDState);
-
-       /* 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);
-
-       if (hwmgr->powercontainment_enabled)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                           PHM_PlatformCaps_PowerContainment);
-       else
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                           PHM_PlatformCaps_PowerContainment);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                                       PHM_PlatformCaps_CAC);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                               PHM_PlatformCaps_RegulatorHot);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                               PHM_PlatformCaps_AutomaticDCTransition);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                               PHM_PlatformCaps_ODFuzzyFanControlSupport);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                               PHM_PlatformCaps_FanSpeedInTableIsRPM);
-
-       if (hwmgr->chip_id == CHIP_POLARIS11)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_SPLLShutdownSupport);
-       return 0;
-}
-
-static void polaris10_init_dpm_defaults(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       polaris10_initialize_power_tune_defaults(hwmgr);
-
-       data->pcie_gen_performance.max = PP_PCIEGen1;
-       data->pcie_gen_performance.min = PP_PCIEGen3;
-       data->pcie_gen_power_saving.max = PP_PCIEGen1;
-       data->pcie_gen_power_saving.min = PP_PCIEGen3;
-       data->pcie_lane_performance.max = 0;
-       data->pcie_lane_performance.min = 16;
-       data->pcie_lane_power_saving.max = 0;
-       data->pcie_lane_power_saving.min = 16;
-}
-
-/**
-* Get Leakage VDDC based on leakage ID.
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always 0
-*/
-static int polaris10_get_evv_voltages(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint16_t vv_id;
-       uint32_t vddc = 0;
-       uint16_t i, j;
-       uint32_t sclk = 0;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)hwmgr->pptable;
-       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
-                       table_info->vdd_dep_on_sclk;
-       int result;
-
-       for (i = 0; i < POLARIS10_MAX_LEAKAGE_COUNT; i++) {
-               vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
-               if (!phm_get_sclk_for_voltage_evv(hwmgr,
-                               table_info->vddc_lookup_table, vv_id, &sclk)) {
-                       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_ClockStretcher)) {
-                               for (j = 1; j < sclk_table->count; j++) {
-                                       if (sclk_table->entries[j].clk == sclk &&
-                                                       sclk_table->entries[j].cks_enable == 0) {
-                                               sclk += 5000;
-                                               break;
-                                       }
-                               }
-                       }
-
-                       if (atomctrl_get_voltage_evv_on_sclk_ai(hwmgr,
-                                               VOLTAGE_TYPE_VDDC,
-                                               sclk, vv_id, &vddc) != 0) {
-                               printk(KERN_WARNING "failed to retrieving EVV voltage!\n");
-                               continue;
-                       }
-
-                       /* need to make sure vddc is less than 2v or else, it could burn the ASIC.
-                        * real voltage level in unit of 0.01mv */
-                       PP_ASSERT_WITH_CODE((vddc < 200000 && vddc != 0),
-                                       "Invalid VDDC value", result = -EINVAL;);
-
-                       /* the voltage should not be zero nor equal to leakage ID */
-                       if (vddc != 0 && vddc != vv_id) {
-                               data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = (uint16_t)(vddc/100);
-                               data->vddc_leakage.leakage_id[data->vddc_leakage.count] = vv_id;
-                               data->vddc_leakage.count++;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/**
- * Change virtual leakage voltage to actual value.
- *
- * @param     hwmgr  the address of the powerplay hardware manager.
- * @param     pointer to changing voltage
- * @param     pointer to leakage table
- */
-static void polaris10_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
-               uint16_t *voltage, struct polaris10_leakage_voltage *leakage_table)
-{
-       uint32_t index;
-
-       /* search for leakage voltage ID 0xff01 ~ 0xff08 */
-       for (index = 0; index < leakage_table->count; index++) {
-               /* if this voltage matches a leakage voltage ID */
-               /* patch with actual leakage voltage */
-               if (leakage_table->leakage_id[index] == *voltage) {
-                       *voltage = leakage_table->actual_voltage[index];
-                       break;
-               }
-       }
-
-       if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
-               printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
-}
-
-/**
-* Patch voltage lookup table by EVV leakages.
-*
-* @param     hwmgr  the address of the powerplay hardware manager.
-* @param     pointer to voltage lookup table
-* @param     pointer to leakage table
-* @return     always 0
-*/
-static int polaris10_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_voltage_lookup_table *lookup_table,
-               struct polaris10_leakage_voltage *leakage_table)
-{
-       uint32_t i;
-
-       for (i = 0; i < lookup_table->count; i++)
-               polaris10_patch_with_vdd_leakage(hwmgr,
-                               &lookup_table->entries[i].us_vdd, leakage_table);
-
-       return 0;
-}
-
-static int polaris10_patch_clock_voltage_limits_with_vddc_leakage(
-               struct pp_hwmgr *hwmgr, struct polaris10_leakage_voltage *leakage_table,
-               uint16_t *vddc)
-{
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       polaris10_patch_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
-       hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
-                       table_info->max_clock_voltage_on_dc.vddc;
-       return 0;
-}
-
-static int polaris10_patch_voltage_dependency_tables_with_lookup_table(
-               struct pp_hwmgr *hwmgr)
-{
-       uint8_t entryId;
-       uint8_t voltageId;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
-                       table_info->vdd_dep_on_sclk;
-       struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
-                       table_info->vdd_dep_on_mclk;
-       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
-                       table_info->mm_dep_table;
-
-       for (entryId = 0; entryId < sclk_table->count; ++entryId) {
-               voltageId = sclk_table->entries[entryId].vddInd;
-               sclk_table->entries[entryId].vddc =
-                               table_info->vddc_lookup_table->entries[voltageId].us_vdd;
-       }
-
-       for (entryId = 0; entryId < mclk_table->count; ++entryId) {
-               voltageId = mclk_table->entries[entryId].vddInd;
-               mclk_table->entries[entryId].vddc =
-                       table_info->vddc_lookup_table->entries[voltageId].us_vdd;
-       }
-
-       for (entryId = 0; entryId < mm_table->count; ++entryId) {
-               voltageId = mm_table->entries[entryId].vddcInd;
-               mm_table->entries[entryId].vddc =
-                       table_info->vddc_lookup_table->entries[voltageId].us_vdd;
-       }
-
-       return 0;
-
-}
-
-static int polaris10_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
-{
-       /* Need to determine if we need calculated voltage. */
-       return 0;
-}
-
-static int polaris10_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
-{
-       /* Need to determine if we need calculated voltage from mm table. */
-       return 0;
-}
-
-static int polaris10_sort_lookup_table(struct pp_hwmgr *hwmgr,
-               struct phm_ppt_v1_voltage_lookup_table *lookup_table)
-{
-       uint32_t table_size, i, j;
-       struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
-       table_size = lookup_table->count;
-
-       PP_ASSERT_WITH_CODE(0 != lookup_table->count,
-               "Lookup table is empty", return -EINVAL);
-
-       /* Sorting voltages */
-       for (i = 0; i < table_size - 1; i++) {
-               for (j = i + 1; j > 0; j--) {
-                       if (lookup_table->entries[j].us_vdd <
-                                       lookup_table->entries[j - 1].us_vdd) {
-                               tmp_voltage_lookup_record = lookup_table->entries[j - 1];
-                               lookup_table->entries[j - 1] = lookup_table->entries[j];
-                               lookup_table->entries[j] = tmp_voltage_lookup_record;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int polaris10_complete_dependency_tables(struct pp_hwmgr *hwmgr)
-{
-       int result = 0;
-       int tmp_result;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       tmp_result = polaris10_patch_lookup_table_with_leakage(hwmgr,
-                       table_info->vddc_lookup_table, &(data->vddc_leakage));
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = polaris10_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
-                       &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = polaris10_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = polaris10_calc_voltage_dependency_tables(hwmgr);
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = polaris10_calc_mm_voltage_dependency_table(hwmgr);
-       if (tmp_result)
-               result = tmp_result;
-
-       tmp_result = polaris10_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
-       if (tmp_result)
-               result = tmp_result;
-
-       return result;
-}
-
-static int polaris10_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
-{
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
-                                               table_info->vdd_dep_on_sclk;
-       struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
-                                               table_info->vdd_dep_on_mclk;
-
-       PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
-               "VDD dependency on SCLK table is missing.       \
-               This table is mandatory", return -EINVAL);
-       PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
-               "VDD dependency on SCLK table has to have is missing.   \
-               This table is mandatory", return -EINVAL);
-
-       PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
-               "VDD dependency on MCLK table is missing.       \
-               This table is mandatory", return -EINVAL);
-       PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
-               "VDD dependency on MCLK table has to have is missing.    \
-               This table is mandatory", return -EINVAL);
-
-       table_info->max_clock_voltage_on_ac.sclk =
-               allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
-       table_info->max_clock_voltage_on_ac.mclk =
-               allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
-       table_info->max_clock_voltage_on_ac.vddc =
-               allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
-       table_info->max_clock_voltage_on_ac.vddci =
-               allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
-
-       hwmgr->dyn_state.max_clock_voltage_on_ac.sclk = table_info->max_clock_voltage_on_ac.sclk;
-       hwmgr->dyn_state.max_clock_voltage_on_ac.mclk = table_info->max_clock_voltage_on_ac.mclk;
-       hwmgr->dyn_state.max_clock_voltage_on_ac.vddc = table_info->max_clock_voltage_on_ac.vddc;
-       hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =table_info->max_clock_voltage_on_ac.vddci;
-
-       return 0;
-}
-
-int polaris10_patch_voltage_workaround(struct pp_hwmgr *hwmgr)
-{
-       struct phm_ppt_v1_information *table_info =
-                      (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
-                       table_info->vdd_dep_on_mclk;
-       struct phm_ppt_v1_voltage_lookup_table *lookup_table =
-                       table_info->vddc_lookup_table;
-       uint32_t i;
-
-       if (hwmgr->chip_id == CHIP_POLARIS10 && hwmgr->hw_revision == 0xC7) {
-               if (lookup_table->entries[dep_mclk_table->entries[dep_mclk_table->count-1].vddInd].us_vdd >= 1000)
-                       return 0;
-
-               for (i = 0; i < lookup_table->count; i++) {
-                       if (lookup_table->entries[i].us_vdd < 0xff01 && lookup_table->entries[i].us_vdd >= 1000) {
-                               dep_mclk_table->entries[dep_mclk_table->count-1].vddInd = (uint8_t) i;
-                               return 0;
-                       }
-               }
-       }
-       return 0;
-}
-
-
-int polaris10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data;
-       struct pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
-       uint32_t temp_reg;
-       int result;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       data = kzalloc(sizeof(struct polaris10_hwmgr), GFP_KERNEL);
-       if (data == NULL)
-               return -ENOMEM;
-
-       hwmgr->backend = data;
-
-       data->dll_default_on = false;
-       data->sram_end = SMC_RAM_END;
-       data->mclk_dpm0_activity_target = 0xa;
-       data->disable_dpm_mask = 0xFF;
-       data->static_screen_threshold = PPPOLARIS10_STATICSCREENTHRESHOLD_DFLT;
-       data->static_screen_threshold_unit = PPPOLARIS10_STATICSCREENTHRESHOLD_DFLT;
-       data->activity_target[0] = PPPOLARIS10_TARGETACTIVITY_DFLT;
-       data->activity_target[1] = PPPOLARIS10_TARGETACTIVITY_DFLT;
-       data->activity_target[2] = PPPOLARIS10_TARGETACTIVITY_DFLT;
-       data->activity_target[3] = PPPOLARIS10_TARGETACTIVITY_DFLT;
-       data->activity_target[4] = PPPOLARIS10_TARGETACTIVITY_DFLT;
-       data->activity_target[5] = PPPOLARIS10_TARGETACTIVITY_DFLT;
-       data->activity_target[6] = PPPOLARIS10_TARGETACTIVITY_DFLT;
-       data->activity_target[7] = PPPOLARIS10_TARGETACTIVITY_DFLT;
-
-       data->voting_rights_clients0 = PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT0;
-       data->voting_rights_clients1 = PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT1;
-       data->voting_rights_clients2 = PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT2;
-       data->voting_rights_clients3 = PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT3;
-       data->voting_rights_clients4 = PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT4;
-       data->voting_rights_clients5 = PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT5;
-       data->voting_rights_clients6 = PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT6;
-       data->voting_rights_clients7 = PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT7;
-
-       data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
-
-       data->mclk_activity_target = PPPOLARIS10_MCLK_TARGETACTIVITY_DFLT;
-
-       /* need to set voltage control types before EVV patching */
-       data->voltage_control = POLARIS10_VOLTAGE_CONTROL_NONE;
-       data->vddci_control = POLARIS10_VOLTAGE_CONTROL_NONE;
-       data->mvdd_control = POLARIS10_VOLTAGE_CONTROL_NONE;
-
-       data->enable_tdc_limit_feature = true;
-       data->enable_pkg_pwr_tracking_feature = true;
-       data->force_pcie_gen = PP_PCIEGenInvalid;
-       data->mclk_stutter_mode_threshold = 40000;
-
-       if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                       VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
-               data->voltage_control = POLARIS10_VOLTAGE_CONTROL_BY_SVID2;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_EnableMVDDControl)) {
-               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                               VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
-                       data->mvdd_control = POLARIS10_VOLTAGE_CONTROL_BY_GPIO;
-               else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                               VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2))
-                       data->mvdd_control = POLARIS10_VOLTAGE_CONTROL_BY_SVID2;
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ControlVDDCI)) {
-               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
-                       data->vddci_control = POLARIS10_VOLTAGE_CONTROL_BY_GPIO;
-               else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
-                       data->vddci_control = POLARIS10_VOLTAGE_CONTROL_BY_SVID2;
-       }
-
-       if (table_info->cac_dtp_table->usClockStretchAmount != 0)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_ClockStretcher);
-
-       polaris10_set_features_platform_caps(hwmgr);
-
-       polaris10_patch_voltage_workaround(hwmgr);
-       polaris10_init_dpm_defaults(hwmgr);
-
-       /* Get leakage voltage based on leakage ID. */
-       result = polaris10_get_evv_voltages(hwmgr);
-
-       if (result) {
-               printk("Get EVV Voltage Failed.  Abort Driver loading!\n");
-               return -1;
-       }
-
-       polaris10_complete_dependency_tables(hwmgr);
-       polaris10_set_private_data_based_on_pptable(hwmgr);
-
-       /* Initalize Dynamic State Adjustment Rule Settings */
-       result = phm_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
-
-       if (0 == result) {
-               struct cgs_system_info sys_info = {0};
-
-               data->is_tlu_enabled = false;
-
-               hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
-                                                       POLARIS10_MAX_HARDWARE_POWERLEVELS;
-               hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
-               hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
-
-
-               if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_PCC_GPIO_PINID, &gpio_pin_assignment)) {
-                       temp_reg = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL);
-                       switch (gpio_pin_assignment.uc_gpio_pin_bit_shift) {
-                       case 0:
-                               temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x1);
-                               break;
-                       case 1:
-                               temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x2);
-                               break;
-                       case 2:
-                               temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, GNB_SLOW, 0x1);
-                               break;
-                       case 3:
-                               temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, FORCE_NB_PS1, 0x1);
-                               break;
-                       case 4:
-                               temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, DPM_ENABLED, 0x1);
-                               break;
-                       default:
-                               PP_ASSERT_WITH_CODE(0,
-                               "Failed to setup PCC HW register! Wrong GPIO assigned for VDDC_PCC_GPIO_PINID!",
-                               );
-                               break;
-                       }
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL, temp_reg);
-               }
-
-               if (table_info->cac_dtp_table->usDefaultTargetOperatingTemp != 0 &&
-                       hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode) {
-                       hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMMinLimit =
-                               (uint16_t)hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit;
-
-                       hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMMaxLimit =
-                               (uint16_t)hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
-
-                       hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMStep = 1;
-
-                       hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMaxLimit = 100;
-
-                       hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMinLimit =
-                               (uint16_t)hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit;
-
-                       hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMStep = 1;
-
-                       table_info->cac_dtp_table->usDefaultTargetOperatingTemp = (table_info->cac_dtp_table->usDefaultTargetOperatingTemp >= 50) ?
-                                                                       (table_info->cac_dtp_table->usDefaultTargetOperatingTemp -50) : 0;
-
-                       table_info->cac_dtp_table->usOperatingTempMaxLimit = table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
-                       table_info->cac_dtp_table->usOperatingTempStep = 1;
-                       table_info->cac_dtp_table->usOperatingTempHyst = 1;
-
-                       hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM =
-                                      hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
-
-                       hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM =
-                                      hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM;
-
-                       hwmgr->dyn_state.cac_dtp_table->usOperatingTempMinLimit =
-                                      table_info->cac_dtp_table->usOperatingTempMinLimit;
-
-                       hwmgr->dyn_state.cac_dtp_table->usOperatingTempMaxLimit =
-                                      table_info->cac_dtp_table->usOperatingTempMaxLimit;
-
-                       hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
-                                      table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
-
-                       hwmgr->dyn_state.cac_dtp_table->usOperatingTempStep =
-                                      table_info->cac_dtp_table->usOperatingTempStep;
-
-                       hwmgr->dyn_state.cac_dtp_table->usTargetOperatingTemp =
-                                      table_info->cac_dtp_table->usTargetOperatingTemp;
-               }
-
-               sys_info.size = sizeof(struct cgs_system_info);
-               sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
-               result = cgs_query_system_info(hwmgr->device, &sys_info);
-               if (result)
-                       data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK;
-               else
-                       data->pcie_gen_cap = (uint32_t)sys_info.value;
-               if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
-                       data->pcie_spc_cap = 20;
-               sys_info.size = sizeof(struct cgs_system_info);
-               sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
-               result = cgs_query_system_info(hwmgr->device, &sys_info);
-               if (result)
-                       data->pcie_lane_cap = AMDGPU_DEFAULT_PCIE_MLW_MASK;
-               else
-                       data->pcie_lane_cap = (uint32_t)sys_info.value;
-
-               hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */
-/* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */
-               hwmgr->platform_descriptor.clockStep.engineClock = 500;
-               hwmgr->platform_descriptor.clockStep.memoryClock = 500;
-       } else {
-               /* Ignore return value in here, we are cleaning up a mess. */
-               polaris10_hwmgr_backend_fini(hwmgr);
-       }
-
-       return 0;
-}
-
-static int polaris10_force_dpm_highest(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t level, tmp;
-
-       if (!data->pcie_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
-                       level = 0;
-                       tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
-                       while (tmp >>= 1)
-                               level++;
-
-                       if (level)
-                               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                               PPSMC_MSG_PCIeDPM_ForceLevel, level);
-               }
-       }
-
-       if (!data->sclk_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
-                       level = 0;
-                       tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
-                       while (tmp >>= 1)
-                               level++;
-
-                       if (level)
-                               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                               PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                               (1 << level));
-               }
-       }
-
-       if (!data->mclk_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
-                       level = 0;
-                       tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
-                       while (tmp >>= 1)
-                               level++;
-
-                       if (level)
-                               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                               PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                                               (1 << level));
-               }
-       }
-
-       return 0;
-}
-
-static int polaris10_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       phm_apply_dal_min_voltage_request(hwmgr);
-
-       if (!data->sclk_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.sclk_dpm_enable_mask);
-       }
-
-       if (!data->mclk_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.mclk_dpm_enable_mask);
-       }
-
-       return 0;
-}
-
-static int polaris10_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (!polaris10_is_dpm_running(hwmgr))
-               return -EINVAL;
-
-       if (!data->pcie_dpm_key_disabled) {
-               smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_PCIeDPM_UnForceLevel);
-       }
-
-       return polaris10_upload_dpm_level_enable_mask(hwmgr);
-}
-
-static int polaris10_force_dpm_lowest(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data =
-                       (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t level;
-
-       if (!data->sclk_dpm_key_disabled)
-               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
-                       level = phm_get_lowest_enabled_level(hwmgr,
-                                                             data->dpm_level_enable_mask.sclk_dpm_enable_mask);
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                                           PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                                           (1 << level));
-
-       }
-
-       if (!data->mclk_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
-                       level = phm_get_lowest_enabled_level(hwmgr,
-                                                             data->dpm_level_enable_mask.mclk_dpm_enable_mask);
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                                           PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                                                           (1 << level));
-               }
-       }
-
-       if (!data->pcie_dpm_key_disabled) {
-               if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
-                       level = phm_get_lowest_enabled_level(hwmgr,
-                                                             data->dpm_level_enable_mask.pcie_dpm_enable_mask);
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                                           PPSMC_MSG_PCIeDPM_ForceLevel,
-                                                           (level));
-               }
-       }
-
-       return 0;
-
-}
-static int polaris10_force_dpm_level(struct pp_hwmgr *hwmgr,
-                               enum amd_dpm_forced_level level)
-{
-       int ret = 0;
-
-       switch (level) {
-       case AMD_DPM_FORCED_LEVEL_HIGH:
-               ret = polaris10_force_dpm_highest(hwmgr);
-               if (ret)
-                       return ret;
-               break;
-       case AMD_DPM_FORCED_LEVEL_LOW:
-               ret = polaris10_force_dpm_lowest(hwmgr);
-               if (ret)
-                       return ret;
-               break;
-       case AMD_DPM_FORCED_LEVEL_AUTO:
-               ret = polaris10_unforce_dpm_levels(hwmgr);
-               if (ret)
-                       return ret;
-               break;
-       default:
-               break;
-       }
-
-       hwmgr->dpm_level = level;
-
-       return ret;
-}
-
-static int polaris10_get_power_state_size(struct pp_hwmgr *hwmgr)
-{
-       return sizeof(struct polaris10_power_state);
-}
-
-
-static int polaris10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
-                               struct pp_power_state *request_ps,
-                       const struct pp_power_state *current_ps)
-{
-
-       struct polaris10_power_state *polaris10_ps =
-                               cast_phw_polaris10_power_state(&request_ps->hardware);
-       uint32_t sclk;
-       uint32_t mclk;
-       struct PP_Clocks minimum_clocks = {0};
-       bool disable_mclk_switching;
-       bool disable_mclk_switching_for_frame_lock;
-       struct cgs_display_info info = {0};
-       const struct phm_clock_and_voltage_limits *max_limits;
-       uint32_t i;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       int32_t count;
-       int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
-
-       data->battery_state = (PP_StateUILabel_Battery ==
-                       request_ps->classification.ui_label);
-
-       PP_ASSERT_WITH_CODE(polaris10_ps->performance_level_count == 2,
-                                "VI should always have 2 performance levels",
-                               );
-
-       max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
-                       &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
-                       &(hwmgr->dyn_state.max_clock_voltage_on_dc);
-
-       /* Cap clock DPM tables at DC MAX if it is in DC. */
-       if (PP_PowerSource_DC == hwmgr->power_source) {
-               for (i = 0; i < polaris10_ps->performance_level_count; i++) {
-                       if (polaris10_ps->performance_levels[i].memory_clock > max_limits->mclk)
-                               polaris10_ps->performance_levels[i].memory_clock = max_limits->mclk;
-                       if (polaris10_ps->performance_levels[i].engine_clock > max_limits->sclk)
-                               polaris10_ps->performance_levels[i].engine_clock = max_limits->sclk;
-               }
-       }
-
-       polaris10_ps->vce_clks.evclk = hwmgr->vce_arbiter.evclk;
-       polaris10_ps->vce_clks.ecclk = hwmgr->vce_arbiter.ecclk;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
-
-       /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_StablePState)) {
-               max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
-               stable_pstate_sclk = (max_limits->sclk * 75) / 100;
-
-               for (count = table_info->vdd_dep_on_sclk->count - 1;
-                               count >= 0; count--) {
-                       if (stable_pstate_sclk >=
-                                       table_info->vdd_dep_on_sclk->entries[count].clk) {
-                               stable_pstate_sclk =
-                                               table_info->vdd_dep_on_sclk->entries[count].clk;
-                               break;
-                       }
-               }
-
-               if (count < 0)
-                       stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
-
-               stable_pstate_mclk = max_limits->mclk;
-
-               minimum_clocks.engineClock = stable_pstate_sclk;
-               minimum_clocks.memoryClock = stable_pstate_mclk;
-       }
-
-       if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
-               minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
-
-       if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
-               minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
-
-       polaris10_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
-
-       if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
-               PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <=
-                               hwmgr->platform_descriptor.overdriveLimit.engineClock),
-                               "Overdrive sclk exceeds limit",
-                               hwmgr->gfx_arbiter.sclk_over_drive =
-                                               hwmgr->platform_descriptor.overdriveLimit.engineClock);
-
-               if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
-                       polaris10_ps->performance_levels[1].engine_clock =
-                                       hwmgr->gfx_arbiter.sclk_over_drive;
-       }
-
-       if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
-               PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <=
-                               hwmgr->platform_descriptor.overdriveLimit.memoryClock),
-                               "Overdrive mclk exceeds limit",
-                               hwmgr->gfx_arbiter.mclk_over_drive =
-                                               hwmgr->platform_descriptor.overdriveLimit.memoryClock);
-
-               if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
-                       polaris10_ps->performance_levels[1].memory_clock =
-                                       hwmgr->gfx_arbiter.mclk_over_drive;
-       }
-
-       disable_mclk_switching_for_frame_lock = phm_cap_enabled(
-                                   hwmgr->platform_descriptor.platformCaps,
-                                   PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
-
-
-       disable_mclk_switching = (1 < info.display_count) ||
-                                   disable_mclk_switching_for_frame_lock;
-
-       sclk = polaris10_ps->performance_levels[0].engine_clock;
-       mclk = polaris10_ps->performance_levels[0].memory_clock;
-
-       if (disable_mclk_switching)
-               mclk = polaris10_ps->performance_levels
-               [polaris10_ps->performance_level_count - 1].memory_clock;
-
-       if (sclk < minimum_clocks.engineClock)
-               sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
-                               max_limits->sclk : minimum_clocks.engineClock;
-
-       if (mclk < minimum_clocks.memoryClock)
-               mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
-                               max_limits->mclk : minimum_clocks.memoryClock;
-
-       polaris10_ps->performance_levels[0].engine_clock = sclk;
-       polaris10_ps->performance_levels[0].memory_clock = mclk;
-
-       polaris10_ps->performance_levels[1].engine_clock =
-               (polaris10_ps->performance_levels[1].engine_clock >=
-                               polaris10_ps->performance_levels[0].engine_clock) ?
-                                               polaris10_ps->performance_levels[1].engine_clock :
-                                               polaris10_ps->performance_levels[0].engine_clock;
-
-       if (disable_mclk_switching) {
-               if (mclk < polaris10_ps->performance_levels[1].memory_clock)
-                       mclk = polaris10_ps->performance_levels[1].memory_clock;
-
-               polaris10_ps->performance_levels[0].memory_clock = mclk;
-               polaris10_ps->performance_levels[1].memory_clock = mclk;
-       } else {
-               if (polaris10_ps->performance_levels[1].memory_clock <
-                               polaris10_ps->performance_levels[0].memory_clock)
-                       polaris10_ps->performance_levels[1].memory_clock =
-                                       polaris10_ps->performance_levels[0].memory_clock;
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_StablePState)) {
-               for (i = 0; i < polaris10_ps->performance_level_count; i++) {
-                       polaris10_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
-                       polaris10_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
-                       polaris10_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
-                       polaris10_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
-               }
-       }
-       return 0;
-}
-
-
-static int polaris10_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
-{
-       struct pp_power_state  *ps;
-       struct polaris10_power_state  *polaris10_ps;
-
-       if (hwmgr == NULL)
-               return -EINVAL;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       polaris10_ps = cast_phw_polaris10_power_state(&ps->hardware);
-
-       if (low)
-               return polaris10_ps->performance_levels[0].memory_clock;
-       else
-               return polaris10_ps->performance_levels
-                               [polaris10_ps->performance_level_count-1].memory_clock;
-}
-
-static int polaris10_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
-{
-       struct pp_power_state  *ps;
-       struct polaris10_power_state  *polaris10_ps;
-
-       if (hwmgr == NULL)
-               return -EINVAL;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       polaris10_ps = cast_phw_polaris10_power_state(&ps->hardware);
-
-       if (low)
-               return polaris10_ps->performance_levels[0].engine_clock;
-       else
-               return polaris10_ps->performance_levels
-                               [polaris10_ps->performance_level_count-1].engine_clock;
-}
-
-static int polaris10_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
-                                       struct pp_hw_power_state *hw_ps)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_power_state *ps = (struct polaris10_power_state *)hw_ps;
-       ATOM_FIRMWARE_INFO_V2_2 *fw_info;
-       uint16_t size;
-       uint8_t frev, crev;
-       int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
-
-       /* First retrieve the Boot clocks and VDDC from the firmware info table.
-        * We assume here that fw_info is unchanged if this call fails.
-        */
-       fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
-                       hwmgr->device, index,
-                       &size, &frev, &crev);
-       if (!fw_info)
-               /* During a test, there is no firmware info table. */
-               return 0;
-
-       /* Patch the state. */
-       data->vbios_boot_state.sclk_bootup_value =
-                       le32_to_cpu(fw_info->ulDefaultEngineClock);
-       data->vbios_boot_state.mclk_bootup_value =
-                       le32_to_cpu(fw_info->ulDefaultMemoryClock);
-       data->vbios_boot_state.mvdd_bootup_value =
-                       le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
-       data->vbios_boot_state.vddc_bootup_value =
-                       le16_to_cpu(fw_info->usBootUpVDDCVoltage);
-       data->vbios_boot_state.vddci_bootup_value =
-                       le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
-       data->vbios_boot_state.pcie_gen_bootup_value =
-                       phm_get_current_pcie_speed(hwmgr);
-
-       data->vbios_boot_state.pcie_lane_bootup_value =
-                       (uint16_t)phm_get_current_pcie_lane_number(hwmgr);
-
-       /* set boot power state */
-       ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
-       ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
-       ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
-       ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
-
-       return 0;
-}
-
-static int polaris10_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
-               void *state, struct pp_power_state *power_state,
-               void *pp_table, uint32_t classification_flag)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_power_state  *polaris10_power_state =
-                       (struct polaris10_power_state *)(&(power_state->hardware));
-       struct polaris10_performance_level *performance_level;
-       ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
-       ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
-                       (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
-       PPTable_Generic_SubTable_Header *sclk_dep_table =
-                       (PPTable_Generic_SubTable_Header *)
-                       (((unsigned long)powerplay_table) +
-                               le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
-
-       ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
-                       (ATOM_Tonga_MCLK_Dependency_Table *)
-                       (((unsigned long)powerplay_table) +
-                               le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
-
-       /* The following fields are not initialized here: id orderedList allStatesList */
-       power_state->classification.ui_label =
-                       (le16_to_cpu(state_entry->usClassification) &
-                       ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
-                       ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
-       power_state->classification.flags = classification_flag;
-       /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
-
-       power_state->classification.temporary_state = false;
-       power_state->classification.to_be_deleted = false;
-
-       power_state->validation.disallowOnDC =
-                       (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
-                                       ATOM_Tonga_DISALLOW_ON_DC));
-
-       power_state->pcie.lanes = 0;
-
-       power_state->display.disableFrameModulation = false;
-       power_state->display.limitRefreshrate = false;
-       power_state->display.enableVariBright =
-                       (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
-                                       ATOM_Tonga_ENABLE_VARIBRIGHT));
-
-       power_state->validation.supportedPowerLevels = 0;
-       power_state->uvd_clocks.VCLK = 0;
-       power_state->uvd_clocks.DCLK = 0;
-       power_state->temperatures.min = 0;
-       power_state->temperatures.max = 0;
-
-       performance_level = &(polaris10_power_state->performance_levels
-                       [polaris10_power_state->performance_level_count++]);
-
-       PP_ASSERT_WITH_CODE(
-                       (polaris10_power_state->performance_level_count < SMU74_MAX_LEVELS_GRAPHICS),
-                       "Performance levels exceeds SMC limit!",
-                       return -1);
-
-       PP_ASSERT_WITH_CODE(
-                       (polaris10_power_state->performance_level_count <=
-                                       hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
-                       "Performance levels exceeds Driver limit!",
-                       return -1);
-
-       /* Performance levels are arranged from low to high. */
-       performance_level->memory_clock = mclk_dep_table->entries
-                       [state_entry->ucMemoryClockIndexLow].ulMclk;
-       if (sclk_dep_table->ucRevId == 0)
-               performance_level->engine_clock = ((ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table)->entries
-                       [state_entry->ucEngineClockIndexLow].ulSclk;
-       else if (sclk_dep_table->ucRevId == 1)
-               performance_level->engine_clock = ((ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table)->entries
-                       [state_entry->ucEngineClockIndexLow].ulSclk;
-       performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
-                       state_entry->ucPCIEGenLow);
-       performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
-                       state_entry->ucPCIELaneHigh);
-
-       performance_level = &(polaris10_power_state->performance_levels
-                       [polaris10_power_state->performance_level_count++]);
-       performance_level->memory_clock = mclk_dep_table->entries
-                       [state_entry->ucMemoryClockIndexHigh].ulMclk;
-
-       if (sclk_dep_table->ucRevId == 0)
-               performance_level->engine_clock = ((ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table)->entries
-                       [state_entry->ucEngineClockIndexHigh].ulSclk;
-       else if (sclk_dep_table->ucRevId == 1)
-               performance_level->engine_clock = ((ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table)->entries
-                       [state_entry->ucEngineClockIndexHigh].ulSclk;
-
-       performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
-                       state_entry->ucPCIEGenHigh);
-       performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
-                       state_entry->ucPCIELaneHigh);
-
-       return 0;
-}
-
-static int polaris10_get_pp_table_entry(struct pp_hwmgr *hwmgr,
-               unsigned long entry_index, struct pp_power_state *state)
-{
-       int result;
-       struct polaris10_power_state *ps;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
-                       table_info->vdd_dep_on_mclk;
-
-       state->hardware.magic = PHM_VIslands_Magic;
-
-       ps = (struct polaris10_power_state *)(&state->hardware);
-
-       result = tonga_get_powerplay_table_entry(hwmgr, entry_index, state,
-                       polaris10_get_pp_table_entry_callback_func);
-
-       /* This is the earliest time we have all the dependency table and the VBIOS boot state
-        * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
-        * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
-        */
-       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 "
-                                       "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 "
-                                       "does not match VBIOS boot VDDCI level");
-       }
-
-       /* set DC compatible flag if this state supports DC */
-       if (!state->validation.disallowOnDC)
-               ps->dc_compatible = true;
-
-       if (state->classification.flags & PP_StateClassificationFlag_ACPI)
-               data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
-
-       ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
-       ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
-
-       if (!result) {
-               uint32_t i;
-
-               switch (state->classification.ui_label) {
-               case PP_StateUILabel_Performance:
-                       data->use_pcie_performance_levels = true;
-                       for (i = 0; i < ps->performance_level_count; i++) {
-                               if (data->pcie_gen_performance.max <
-                                               ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_performance.max =
-                                                       ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_gen_performance.min >
-                                               ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_performance.min =
-                                                       ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_lane_performance.max <
-                                               ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_performance.max =
-                                                       ps->performance_levels[i].pcie_lane;
-                               if (data->pcie_lane_performance.min >
-                                               ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_performance.min =
-                                                       ps->performance_levels[i].pcie_lane;
-                       }
-                       break;
-               case PP_StateUILabel_Battery:
-                       data->use_pcie_power_saving_levels = true;
-
-                       for (i = 0; i < ps->performance_level_count; i++) {
-                               if (data->pcie_gen_power_saving.max <
-                                               ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_power_saving.max =
-                                                       ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_gen_power_saving.min >
-                                               ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_power_saving.min =
-                                                       ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_lane_power_saving.max <
-                                               ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_power_saving.max =
-                                                       ps->performance_levels[i].pcie_lane;
-
-                               if (data->pcie_lane_power_saving.min >
-                                               ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_power_saving.min =
-                                                       ps->performance_levels[i].pcie_lane;
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-       return 0;
-}
-
-static void
-polaris10_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
-{
-       uint32_t sclk, mclk, activity_percent;
-       uint32_t offset;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
-
-       sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-
-       smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
-
-       mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-       seq_printf(m, "\n [  mclk  ]: %u MHz\n\n [  sclk  ]: %u MHz\n",
-                       mclk / 100, sclk / 100);
-
-       offset = data->soft_regs_start + offsetof(SMU74_SoftRegisters, AverageGraphicsActivity);
-       activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
-       activity_percent += 0x80;
-       activity_percent >>= 8;
-
-       seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent);
-
-       seq_printf(m, "uvd    %sabled\n", data->uvd_power_gated ? "dis" : "en");
-
-       seq_printf(m, "vce    %sabled\n", data->vce_power_gated ? "dis" : "en");
-}
-
-static int polaris10_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       const struct polaris10_power_state *polaris10_ps =
-                       cast_const_phw_polaris10_power_state(states->pnew_state);
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
-       uint32_t sclk = polaris10_ps->performance_levels
-                       [polaris10_ps->performance_level_count - 1].engine_clock;
-       struct polaris10_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
-       uint32_t mclk = polaris10_ps->performance_levels
-                       [polaris10_ps->performance_level_count - 1].memory_clock;
-       struct PP_Clocks min_clocks = {0};
-       uint32_t i;
-       struct cgs_display_info info = {0};
-
-       data->need_update_smu7_dpm_table = 0;
-
-       for (i = 0; i < sclk_table->count; i++) {
-               if (sclk == sclk_table->dpm_levels[i].value)
-                       break;
-       }
-
-       if (i >= sclk_table->count)
-               data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
-       else {
-       /* TODO: Check SCLK in DAL's minimum clocks
-        * in case DeepSleep divider update is required.
-        */
-               if (data->display_timing.min_clock_in_sr != min_clocks.engineClockInSR &&
-                       (min_clocks.engineClockInSR >= POLARIS10_MINIMUM_ENGINE_CLOCK ||
-                               data->display_timing.min_clock_in_sr >= POLARIS10_MINIMUM_ENGINE_CLOCK))
-                       data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
-       }
-
-       for (i = 0; i < mclk_table->count; i++) {
-               if (mclk == mclk_table->dpm_levels[i].value)
-                       break;
-       }
-
-       if (i >= mclk_table->count)
-               data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       if (data->display_timing.num_existing_displays != info.display_count)
-               data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
-
-       return 0;
-}
-
-static uint16_t polaris10_get_maximum_link_speed(struct pp_hwmgr *hwmgr,
-               const struct polaris10_power_state *polaris10_ps)
-{
-       uint32_t i;
-       uint32_t sclk, max_sclk = 0;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_dpm_table *dpm_table = &data->dpm_table;
-
-       for (i = 0; i < polaris10_ps->performance_level_count; i++) {
-               sclk = polaris10_ps->performance_levels[i].engine_clock;
-               if (max_sclk < sclk)
-                       max_sclk = sclk;
-       }
-
-       for (i = 0; i < dpm_table->sclk_table.count; i++) {
-               if (dpm_table->sclk_table.dpm_levels[i].value == max_sclk)
-                       return (uint16_t) ((i >= dpm_table->pcie_speed_table.count) ?
-                                       dpm_table->pcie_speed_table.dpm_levels
-                                       [dpm_table->pcie_speed_table.count - 1].value :
-                                       dpm_table->pcie_speed_table.dpm_levels[i].value);
-       }
-
-       return 0;
-}
-
-static int polaris10_request_link_speed_change_before_state_change(
-               struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       const struct polaris10_power_state *polaris10_nps =
-                       cast_const_phw_polaris10_power_state(states->pnew_state);
-       const struct polaris10_power_state *polaris10_cps =
-                       cast_const_phw_polaris10_power_state(states->pcurrent_state);
-
-       uint16_t target_link_speed = polaris10_get_maximum_link_speed(hwmgr, polaris10_nps);
-       uint16_t current_link_speed;
-
-       if (data->force_pcie_gen == PP_PCIEGenInvalid)
-               current_link_speed = polaris10_get_maximum_link_speed(hwmgr, polaris10_cps);
-       else
-               current_link_speed = data->force_pcie_gen;
-
-       data->force_pcie_gen = PP_PCIEGenInvalid;
-       data->pspp_notify_required = false;
-
-       if (target_link_speed > current_link_speed) {
-               switch (target_link_speed) {
-               case PP_PCIEGen3:
-                       if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
-                               break;
-                       data->force_pcie_gen = PP_PCIEGen2;
-                       if (current_link_speed == PP_PCIEGen2)
-                               break;
-               case PP_PCIEGen2:
-                       if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
-                               break;
-               default:
-                       data->force_pcie_gen = phm_get_current_pcie_speed(hwmgr);
-                       break;
-               }
-       } else {
-               if (target_link_speed < current_link_speed)
-                       data->pspp_notify_required = true;
-       }
-
-       return 0;
-}
-
-static int polaris10_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (0 == data->need_update_smu7_dpm_table)
-               return 0;
-
-       if ((0 == data->sclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table &
-                       (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
-               PP_ASSERT_WITH_CODE(polaris10_is_dpm_running(hwmgr),
-                                   "Trying to freeze SCLK DPM when DPM is disabled",
-                               );
-               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_SCLKDPM_FreezeLevel),
-                               "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
-                               return -1);
-       }
-
-       if ((0 == data->mclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table &
-                DPMTABLE_OD_UPDATE_MCLK)) {
-               PP_ASSERT_WITH_CODE(polaris10_is_dpm_running(hwmgr),
-                                   "Trying to freeze MCLK DPM when DPM is disabled",
-                               );
-               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_MCLKDPM_FreezeLevel),
-                               "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
-                               return -1);
-       }
-
-       return 0;
-}
-
-static int polaris10_populate_and_upload_sclk_mclk_dpm_levels(
-               struct pp_hwmgr *hwmgr, const void *input)
-{
-       int result = 0;
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       const struct polaris10_power_state *polaris10_ps =
-                       cast_const_phw_polaris10_power_state(states->pnew_state);
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t sclk = polaris10_ps->performance_levels
-                       [polaris10_ps->performance_level_count - 1].engine_clock;
-       uint32_t mclk = polaris10_ps->performance_levels
-                       [polaris10_ps->performance_level_count - 1].memory_clock;
-       struct polaris10_dpm_table *dpm_table = &data->dpm_table;
-
-       struct polaris10_dpm_table *golden_dpm_table = &data->golden_dpm_table;
-       uint32_t dpm_count, clock_percent;
-       uint32_t i;
-
-       if (0 == data->need_update_smu7_dpm_table)
-               return 0;
-
-       if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
-               dpm_table->sclk_table.dpm_levels
-               [dpm_table->sclk_table.count - 1].value = sclk;
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
-                   phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
-               /* Need to do calculation based on the golden DPM table
-                * as the Heatmap GPU Clock axis is also based on the default values
-                */
-                       PP_ASSERT_WITH_CODE(
-                               (golden_dpm_table->sclk_table.dpm_levels
-                                               [golden_dpm_table->sclk_table.count - 1].value != 0),
-                               "Divide by 0!",
-                               return -1);
-                       dpm_count = dpm_table->sclk_table.count < 2 ? 0 : dpm_table->sclk_table.count - 2;
-
-                       for (i = dpm_count; i > 1; i--) {
-                               if (sclk > golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value) {
-                                       clock_percent =
-                                             ((sclk
-                                               - golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value
-                                               ) * 100)
-                                               / golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value;
-
-                                       dpm_table->sclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->sclk_table.dpm_levels[i].value +
-                                                       (golden_dpm_table->sclk_table.dpm_levels[i].value *
-                                                               clock_percent)/100;
-
-                               } else if (golden_dpm_table->sclk_table.dpm_levels[dpm_table->sclk_table.count-1].value > sclk) {
-                                       clock_percent =
-                                               ((golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count - 1].value
-                                               - sclk) * 100)
-                                               / golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value;
-
-                                       dpm_table->sclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->sclk_table.dpm_levels[i].value -
-                                                       (golden_dpm_table->sclk_table.dpm_levels[i].value *
-                                                                       clock_percent) / 100;
-                               } else
-                                       dpm_table->sclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->sclk_table.dpm_levels[i].value;
-                       }
-               }
-       }
-
-       if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
-               dpm_table->mclk_table.dpm_levels
-                       [dpm_table->mclk_table.count - 1].value = mclk;
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
-                   phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
-
-                       PP_ASSERT_WITH_CODE(
-                                       (golden_dpm_table->mclk_table.dpm_levels
-                                               [golden_dpm_table->mclk_table.count-1].value != 0),
-                                       "Divide by 0!",
-                                       return -1);
-                       dpm_count = dpm_table->mclk_table.count < 2 ? 0 : dpm_table->mclk_table.count - 2;
-                       for (i = dpm_count; i > 1; i--) {
-                               if (golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value < mclk) {
-                                       clock_percent = ((mclk -
-                                       golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value) * 100)
-                                       / golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value;
-
-                                       dpm_table->mclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->mclk_table.dpm_levels[i].value +
-                                                       (golden_dpm_table->mclk_table.dpm_levels[i].value *
-                                                       clock_percent) / 100;
-
-                               } else if (golden_dpm_table->mclk_table.dpm_levels[dpm_table->mclk_table.count-1].value > mclk) {
-                                       clock_percent = (
-                                        (golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value - mclk)
-                                       * 100)
-                                       / golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value;
-
-                                       dpm_table->mclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->mclk_table.dpm_levels[i].value -
-                                                       (golden_dpm_table->mclk_table.dpm_levels[i].value *
-                                                                       clock_percent) / 100;
-                               } else
-                                       dpm_table->mclk_table.dpm_levels[i].value =
-                                                       golden_dpm_table->mclk_table.dpm_levels[i].value;
-                       }
-               }
-       }
-
-       if (data->need_update_smu7_dpm_table &
-                       (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
-               result = polaris10_populate_all_graphic_levels(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
-                               return result);
-       }
-
-       if (data->need_update_smu7_dpm_table &
-                       (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
-               /*populate MCLK dpm table to SMU7 */
-               result = polaris10_populate_all_memory_levels(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
-                               return result);
-       }
-
-       return result;
-}
-
-static int polaris10_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
-                         struct polaris10_single_dpm_table *dpm_table,
-                       uint32_t low_limit, uint32_t high_limit)
-{
-       uint32_t i;
-
-       for (i = 0; i < dpm_table->count; i++) {
-               if ((dpm_table->dpm_levels[i].value < low_limit)
-               || (dpm_table->dpm_levels[i].value > high_limit))
-                       dpm_table->dpm_levels[i].enabled = false;
-               else
-                       dpm_table->dpm_levels[i].enabled = true;
-       }
-
-       return 0;
-}
-
-static int polaris10_trim_dpm_states(struct pp_hwmgr *hwmgr,
-               const struct polaris10_power_state *polaris10_ps)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t high_limit_count;
-
-       PP_ASSERT_WITH_CODE((polaris10_ps->performance_level_count >= 1),
-                       "power state did not have any performance level",
-                       return -1);
-
-       high_limit_count = (1 == polaris10_ps->performance_level_count) ? 0 : 1;
-
-       polaris10_trim_single_dpm_states(hwmgr,
-                       &(data->dpm_table.sclk_table),
-                       polaris10_ps->performance_levels[0].engine_clock,
-                       polaris10_ps->performance_levels[high_limit_count].engine_clock);
-
-       polaris10_trim_single_dpm_states(hwmgr,
-                       &(data->dpm_table.mclk_table),
-                       polaris10_ps->performance_levels[0].memory_clock,
-                       polaris10_ps->performance_levels[high_limit_count].memory_clock);
-
-       return 0;
-}
-
-static int polaris10_generate_dpm_level_enable_mask(
-               struct pp_hwmgr *hwmgr, const void *input)
-{
-       int result;
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       const struct polaris10_power_state *polaris10_ps =
-                       cast_const_phw_polaris10_power_state(states->pnew_state);
-
-       result = polaris10_trim_dpm_states(hwmgr, polaris10_ps);
-       if (result)
-               return result;
-
-       data->dpm_level_enable_mask.sclk_dpm_enable_mask =
-                       phm_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
-       data->dpm_level_enable_mask.mclk_dpm_enable_mask =
-                       phm_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
-       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
-                       phm_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
-
-       return 0;
-}
-
-int polaris10_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
-                       PPSMC_MSG_UVDDPM_Enable :
-                       PPSMC_MSG_UVDDPM_Disable);
-}
-
-int polaris10_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, enable?
-                       PPSMC_MSG_VCEDPM_Enable :
-                       PPSMC_MSG_VCEDPM_Disable);
-}
-
-int polaris10_enable_disable_samu_dpm(struct pp_hwmgr *hwmgr, bool enable)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, enable?
-                       PPSMC_MSG_SAMUDPM_Enable :
-                       PPSMC_MSG_SAMUDPM_Disable);
-}
-
-int polaris10_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t mm_boot_level_offset, mm_boot_level_value;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (!bgate) {
-               data->smc_state_table.UvdBootLevel = 0;
-               if (table_info->mm_dep_table->count > 0)
-                       data->smc_state_table.UvdBootLevel =
-                                       (uint8_t) (table_info->mm_dep_table->count - 1);
-               mm_boot_level_offset = data->dpm_table_start +
-                               offsetof(SMU74_Discrete_DpmTable, UvdBootLevel);
-               mm_boot_level_offset /= 4;
-               mm_boot_level_offset *= 4;
-               mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset);
-               mm_boot_level_value &= 0x00FFFFFF;
-               mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
-               cgs_write_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
-
-               if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_UVDDPM) ||
-                       phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_StablePState))
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_UVDDPM_SetEnabledMask,
-                                       (uint32_t)(1 << data->smc_state_table.UvdBootLevel));
-       }
-
-       return polaris10_enable_disable_uvd_dpm(hwmgr, !bgate);
-}
-
-int polaris10_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t mm_boot_level_offset, mm_boot_level_value;
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (!bgate) {
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                               PHM_PlatformCaps_StablePState))
-                       data->smc_state_table.VceBootLevel =
-                               (uint8_t) (table_info->mm_dep_table->count - 1);
-               else
-                       data->smc_state_table.VceBootLevel = 0;
-
-               mm_boot_level_offset = data->dpm_table_start +
-                               offsetof(SMU74_Discrete_DpmTable, VceBootLevel);
-               mm_boot_level_offset /= 4;
-               mm_boot_level_offset *= 4;
-               mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset);
-               mm_boot_level_value &= 0xFF00FFFF;
-               mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
-               cgs_write_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_VCEDPM_SetEnabledMask,
-                                       (uint32_t)1 << data->smc_state_table.VceBootLevel);
-       }
-
-       polaris10_enable_disable_vce_dpm(hwmgr, !bgate);
-
-       return 0;
-}
-
-int polaris10_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t mm_boot_level_offset, mm_boot_level_value;
-
-       if (!bgate) {
-               data->smc_state_table.SamuBootLevel = 0;
-               mm_boot_level_offset = data->dpm_table_start +
-                               offsetof(SMU74_Discrete_DpmTable, SamuBootLevel);
-               mm_boot_level_offset /= 4;
-               mm_boot_level_offset *= 4;
-               mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset);
-               mm_boot_level_value &= 0xFFFFFF00;
-               mm_boot_level_value |= data->smc_state_table.SamuBootLevel << 0;
-               cgs_write_ind_register(hwmgr->device,
-                               CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_StablePState))
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_SAMUDPM_SetEnabledMask,
-                                       (uint32_t)(1 << data->smc_state_table.SamuBootLevel));
-       }
-
-       return polaris10_enable_disable_samu_dpm(hwmgr, !bgate);
-}
-
-static int polaris10_update_sclk_threshold(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       int result = 0;
-       uint32_t low_sclk_interrupt_threshold = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkThrottleLowNotification)
-               && (hwmgr->gfx_arbiter.sclk_threshold !=
-                               data->low_sclk_interrupt_threshold)) {
-               data->low_sclk_interrupt_threshold =
-                               hwmgr->gfx_arbiter.sclk_threshold;
-               low_sclk_interrupt_threshold =
-                               data->low_sclk_interrupt_threshold;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
-
-               result = polaris10_copy_bytes_to_smc(
-                               hwmgr->smumgr,
-                               data->dpm_table_start +
-                               offsetof(SMU74_Discrete_DpmTable,
-                                       LowSclkInterruptThreshold),
-                               (uint8_t *)&low_sclk_interrupt_threshold,
-                               sizeof(uint32_t),
-                               data->sram_end);
-       }
-
-       return result;
-}
-
-static int polaris10_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (data->need_update_smu7_dpm_table &
-               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
-               return polaris10_program_memory_timing_parameters(hwmgr);
-
-       return 0;
-}
-
-static int polaris10_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (0 == data->need_update_smu7_dpm_table)
-               return 0;
-
-       if ((0 == data->sclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table &
-               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
-
-               PP_ASSERT_WITH_CODE(polaris10_is_dpm_running(hwmgr),
-                                   "Trying to Unfreeze SCLK DPM when DPM is disabled",
-                               );
-               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_SCLKDPM_UnfreezeLevel),
-                       "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
-                       return -1);
-       }
-
-       if ((0 == data->mclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
-
-               PP_ASSERT_WITH_CODE(polaris10_is_dpm_running(hwmgr),
-                                   "Trying to Unfreeze MCLK DPM when DPM is disabled",
-                               );
-               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                               PPSMC_MSG_SCLKDPM_UnfreezeLevel),
-                   "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
-                   return -1);
-       }
-
-       data->need_update_smu7_dpm_table = 0;
-
-       return 0;
-}
-
-static int polaris10_notify_link_speed_change_after_state_change(
-               struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states =
-                       (const struct phm_set_power_state_input *)input;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       const struct polaris10_power_state *polaris10_ps =
-                       cast_const_phw_polaris10_power_state(states->pnew_state);
-       uint16_t target_link_speed = polaris10_get_maximum_link_speed(hwmgr, polaris10_ps);
-       uint8_t  request;
-
-       if (data->pspp_notify_required) {
-               if (target_link_speed == PP_PCIEGen3)
-                       request = PCIE_PERF_REQ_GEN3;
-               else if (target_link_speed == PP_PCIEGen2)
-                       request = PCIE_PERF_REQ_GEN2;
-               else
-                       request = PCIE_PERF_REQ_GEN1;
-
-               if (request == PCIE_PERF_REQ_GEN1 &&
-                               phm_get_current_pcie_speed(hwmgr) > 0)
-                       return 0;
-
-               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!");
-                       else
-                               printk("PSPP request to switch to Gen1 from Gen2 Failed!");
-               }
-       }
-
-       return 0;
-}
-
-static int polaris10_notify_smc_display(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-               (PPSMC_Msg)PPSMC_MSG_SetVBITimeout, data->frame_time_x2);
-       return (smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_HasDisplay) == 0) ?  0 : -EINVAL;
-}
-
-
-
-static int polaris10_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
-{
-       int tmp_result, result = 0;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       tmp_result = polaris10_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to find DPM states clocks in DPM table!",
-                       result = tmp_result);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PCIEPerformanceRequest)) {
-               tmp_result =
-                       polaris10_request_link_speed_change_before_state_change(hwmgr, input);
-               PP_ASSERT_WITH_CODE((0 == tmp_result),
-                               "Failed to request link speed change before state change!",
-                               result = tmp_result);
-       }
-
-       tmp_result = polaris10_freeze_sclk_mclk_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
-
-       tmp_result = polaris10_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to populate and upload SCLK MCLK DPM levels!",
-                       result = tmp_result);
-
-       tmp_result = polaris10_generate_dpm_level_enable_mask(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to generate DPM level enabled mask!",
-                       result = tmp_result);
-
-       tmp_result = polaris10_update_sclk_threshold(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to update SCLK threshold!",
-                       result = tmp_result);
-
-       tmp_result = polaris10_program_mem_timing_parameters(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to program memory timing parameters!",
-                       result = tmp_result);
-
-       tmp_result = polaris10_notify_smc_display(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to notify smc display settings!",
-                       result = tmp_result);
-
-       tmp_result = polaris10_unfreeze_sclk_mclk_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to unfreeze SCLK MCLK DPM!",
-                       result = tmp_result);
-
-       tmp_result = polaris10_upload_dpm_level_enable_mask(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to upload DPM level enabled mask!",
-                       result = tmp_result);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PCIEPerformanceRequest)) {
-               tmp_result =
-                       polaris10_notify_link_speed_change_after_state_change(hwmgr, input);
-               PP_ASSERT_WITH_CODE((0 == tmp_result),
-                               "Failed to notify link speed change after state change!",
-                               result = tmp_result);
-       }
-       data->apply_optimized_settings = false;
-       return result;
-}
-
-static int polaris10_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
-{
-       hwmgr->thermal_controller.
-       advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
-
-       if (phm_is_hw_access_blocked(hwmgr))
-               return 0;
-
-       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                       PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
-}
-
-
-int polaris10_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display)
-{
-       PPSMC_Msg msg = has_display ? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
-
-       return (smum_send_msg_to_smc(hwmgr->smumgr, msg) == 0) ?  0 : -1;
-}
-
-int polaris10_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
-{
-       uint32_t num_active_displays = 0;
-       struct cgs_display_info info = {0};
-       info.mode_info = NULL;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       num_active_displays = info.display_count;
-
-       if (num_active_displays > 1)  /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */
-               polaris10_notify_smc_display_change(hwmgr, false);
-
-
-       return 0;
-}
-
-/**
-* Programs the display gap
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always OK
-*/
-int polaris10_program_display_gap(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t num_active_displays = 0;
-       uint32_t display_gap = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
-       uint32_t display_gap2;
-       uint32_t pre_vbi_time_in_us;
-       uint32_t frame_time_in_us;
-       uint32_t ref_clock;
-       uint32_t refresh_rate = 0;
-       struct cgs_display_info info = {0};
-       struct cgs_mode_info mode_info;
-
-       info.mode_info = &mode_info;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-       num_active_displays = info.display_count;
-
-       display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL, DISP_GAP, (num_active_displays > 0) ? DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL, display_gap);
-
-       ref_clock = mode_info.ref_clock;
-       refresh_rate = mode_info.refresh_rate;
-
-       if (0 == refresh_rate)
-               refresh_rate = 60;
-
-       frame_time_in_us = 1000000 / refresh_rate;
-
-       pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
-       data->frame_time_x2 = frame_time_in_us * 2 / 100;
-
-       display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU74_SoftRegisters, PreVBlankGap), 0x64);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU74_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us));
-
-
-       return 0;
-}
-
-
-int polaris10_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
-{
-       return polaris10_program_display_gap(hwmgr);
-}
-
-/**
-*  Set maximum target operating fan output RPM
-*
-* @param    hwmgr:  the address of the powerplay hardware manager.
-* @param    usMaxFanRpm:  max operating fan RPM value.
-* @return   The response that came from the SMC.
-*/
-static int polaris10_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_rpm)
-{
-       hwmgr->thermal_controller.
-       advanceFanControlParameters.usMaxFanRPM = us_max_fan_rpm;
-
-       if (phm_is_hw_access_blocked(hwmgr))
-               return 0;
-
-       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                       PPSMC_MSG_SetFanRpmMax, us_max_fan_rpm);
-}
-
-int polaris10_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
-                                       const void *thermal_interrupt_info)
-{
-       return 0;
-}
-
-bool polaris10_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       bool is_update_required = false;
-       struct cgs_display_info info = {0, 0, NULL};
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       if (data->display_timing.num_existing_displays != info.display_count)
-               is_update_required = true;
-/* TO DO NEED TO GET DEEP SLEEP CLOCK FROM DAL
-       if (phm_cap_enabled(hwmgr->hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
-               cgs_get_min_clock_settings(hwmgr->device, &min_clocks);
-               if (min_clocks.engineClockInSR != data->display_timing.minClockInSR &&
-                       (min_clocks.engineClockInSR >= POLARIS10_MINIMUM_ENGINE_CLOCK ||
-                               data->display_timing.minClockInSR >= POLARIS10_MINIMUM_ENGINE_CLOCK))
-                       is_update_required = true;
-*/
-       return is_update_required;
-}
-
-static inline bool polaris10_are_power_levels_equal(const struct polaris10_performance_level *pl1,
-                                                          const struct polaris10_performance_level *pl2)
-{
-       return ((pl1->memory_clock == pl2->memory_clock) &&
-                 (pl1->engine_clock == pl2->engine_clock) &&
-                 (pl1->pcie_gen == pl2->pcie_gen) &&
-                 (pl1->pcie_lane == pl2->pcie_lane));
-}
-
-int polaris10_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal)
-{
-       const struct polaris10_power_state *psa = cast_const_phw_polaris10_power_state(pstate1);
-       const struct polaris10_power_state *psb = cast_const_phw_polaris10_power_state(pstate2);
-       int i;
-
-       if (pstate1 == NULL || pstate2 == NULL || equal == NULL)
-               return -EINVAL;
-
-       /* If the two states don't even have the same number of performance levels they cannot be the same state. */
-       if (psa->performance_level_count != psb->performance_level_count) {
-               *equal = false;
-               return 0;
-       }
-
-       for (i = 0; i < psa->performance_level_count; i++) {
-               if (!polaris10_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
-                       /* If we have found even one performance level pair that is different the states are different. */
-                       *equal = false;
-                       return 0;
-               }
-       }
-
-       /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
-       *equal = ((psa->uvd_clks.vclk == psb->uvd_clks.vclk) && (psa->uvd_clks.dclk == psb->uvd_clks.dclk));
-       *equal &= ((psa->vce_clks.evclk == psb->vce_clks.evclk) && (psa->vce_clks.ecclk == psb->vce_clks.ecclk));
-       *equal &= (psa->sclk_threshold == psb->sclk_threshold);
-
-       return 0;
-}
-
-int polaris10_upload_mc_firmware(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       uint32_t vbios_version;
-
-       /*  Read MC indirect register offset 0x9F bits [3:0] to see if VBIOS has already loaded a full version of MC ucode or not.*/
-
-       phm_get_mc_microcode_version(hwmgr);
-       vbios_version = hwmgr->microcode_version_info.MC & 0xf;
-       /*  Full version of MC ucode has already been loaded. */
-       if (vbios_version == 0) {
-               data->need_long_memory_training = false;
-               return 0;
-       }
-
-       data->need_long_memory_training = false;
-
-/*
- *     PPMCME_FirmwareDescriptorEntry *pfd = NULL;
-       pfd = &tonga_mcmeFirmware;
-       if (0 == PHM_READ_FIELD(hwmgr->device, MC_SEQ_SUP_CNTL, RUN))
-               polaris10_load_mc_microcode(hwmgr, pfd->dpmThreshold,
-                                       pfd->cfgArray, pfd->cfgSize, pfd->ioDebugArray,
-                                       pfd->ioDebugSize, pfd->ucodeArray, pfd->ucodeSize);
-*/
-       return 0;
-}
-
-/**
- * Read clock related registers.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-static int polaris10_read_clock_registers(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       data->clock_registers.vCG_SPLL_FUNC_CNTL = cgs_read_ind_register(hwmgr->device,
-                                               CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL)
-                                               & CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN_MASK;
-
-       data->clock_registers.vCG_SPLL_FUNC_CNTL_2 = cgs_read_ind_register(hwmgr->device,
-                                               CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_2)
-                                               & CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL_MASK;
-
-       data->clock_registers.vCG_SPLL_FUNC_CNTL_4 = cgs_read_ind_register(hwmgr->device,
-                                               CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_4)
-                                               & CG_SPLL_FUNC_CNTL_4__SPLL_SPARE_MASK;
-
-       return 0;
-}
-
-/**
- * Find out if memory is GDDR5.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-static int polaris10_get_memory_type(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t temp;
-
-       temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
-
-       data->is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
-                       ((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
-                        MC_SEQ_MISC0_GDDR5_SHIFT));
-
-       return 0;
-}
-
-/**
- * Enables Dynamic Power Management by SMC
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-static int polaris10_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
-{
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       GENERAL_PWRMGT, STATIC_PM_EN, 1);
-
-       return 0;
-}
-
-/**
- * Initialize PowerGating States for different engines
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-static int polaris10_init_power_gate_state(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       data->uvd_power_gated = false;
-       data->vce_power_gated = false;
-       data->samu_power_gated = false;
-
-       return 0;
-}
-
-static int polaris10_init_sclk_threshold(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       data->low_sclk_interrupt_threshold = 0;
-
-       return 0;
-}
-
-int polaris10_setup_asic_task(struct pp_hwmgr *hwmgr)
-{
-       int tmp_result, result = 0;
-
-       polaris10_upload_mc_firmware(hwmgr);
-
-       tmp_result = polaris10_read_clock_registers(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to read clock registers!", result = tmp_result);
-
-       tmp_result = polaris10_get_memory_type(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to get memory type!", result = tmp_result);
-
-       tmp_result = polaris10_enable_acpi_power_management(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable ACPI power management!", result = tmp_result);
-
-       tmp_result = polaris10_init_power_gate_state(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to init power gate state!", result = tmp_result);
-
-       tmp_result = phm_get_mc_microcode_version(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to get MC microcode version!", result = tmp_result);
-
-       tmp_result = polaris10_init_sclk_threshold(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to init sclk threshold!", result = tmp_result);
-
-       return result;
-}
-
-static int polaris10_force_clock_level(struct pp_hwmgr *hwmgr,
-               enum pp_clock_type type, uint32_t mask)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
-               return -EINVAL;
-
-       switch (type) {
-       case PP_SCLK:
-               if (!data->sclk_dpm_key_disabled)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
-               break;
-       case PP_MCLK:
-               if (!data->mclk_dpm_key_disabled)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
-               break;
-       case PP_PCIE:
-       {
-               uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
-               uint32_t level = 0;
-
-               while (tmp >>= 1)
-                       level++;
-
-               if (!data->pcie_dpm_key_disabled)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_PCIeDPM_ForceLevel,
-                                       level);
-               break;
-       }
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static uint16_t polaris10_get_current_pcie_speed(struct pp_hwmgr *hwmgr)
-{
-       uint32_t speedCntl = 0;
-
-       /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
-       speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE,
-                       ixPCIE_LC_SPEED_CNTL);
-       return((uint16_t)PHM_GET_FIELD(speedCntl,
-                       PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
-}
-
-static int polaris10_print_clock_levels(struct pp_hwmgr *hwmgr,
-               enum pp_clock_type type, char *buf)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
-       struct polaris10_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
-       struct polaris10_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table);
-       int i, now, size = 0;
-       uint32_t clock, pcie_speed;
-
-       switch (type) {
-       case PP_SCLK:
-               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
-               clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-
-               for (i = 0; i < sclk_table->count; i++) {
-                       if (clock > sclk_table->dpm_levels[i].value)
-                               continue;
-                       break;
-               }
-               now = i;
-
-               for (i = 0; i < sclk_table->count; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
-                                       i, sclk_table->dpm_levels[i].value / 100,
-                                       (i == now) ? "*" : "");
-               break;
-       case PP_MCLK:
-               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
-               clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-
-               for (i = 0; i < mclk_table->count; i++) {
-                       if (clock > mclk_table->dpm_levels[i].value)
-                               continue;
-                       break;
-               }
-               now = i;
-
-               for (i = 0; i < mclk_table->count; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
-                                       i, mclk_table->dpm_levels[i].value / 100,
-                                       (i == now) ? "*" : "");
-               break;
-       case PP_PCIE:
-               pcie_speed = polaris10_get_current_pcie_speed(hwmgr);
-               for (i = 0; i < pcie_table->count; i++) {
-                       if (pcie_speed != pcie_table->dpm_levels[i].value)
-                               continue;
-                       break;
-               }
-               now = i;
-
-               for (i = 0; i < pcie_table->count; i++)
-                       size += sprintf(buf + size, "%d: %s %s\n", i,
-                                       (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x8" :
-                                       (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" :
-                                       (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "",
-                                       (i == now) ? "*" : "");
-               break;
-       default:
-               break;
-       }
-       return size;
-}
-
-static int polaris10_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
-{
-       if (mode) {
-               /* stop auto-manage */
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_MicrocodeFanControl))
-                       polaris10_fan_ctrl_stop_smc_fan_control(hwmgr);
-               polaris10_fan_ctrl_set_static_mode(hwmgr, mode);
-       } else
-               /* restart auto-manage */
-               polaris10_fan_ctrl_reset_fan_speed_to_default(hwmgr);
-
-       return 0;
-}
-
-static int polaris10_get_fan_control_mode(struct pp_hwmgr *hwmgr)
-{
-       if (hwmgr->fan_ctrl_is_in_default_mode)
-               return hwmgr->fan_ctrl_default_mode;
-       else
-               return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_FDO_CTRL2, FDO_PWM_MODE);
-}
-
-static int polaris10_get_sclk_od(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
-       struct polaris10_single_dpm_table *golden_sclk_table =
-                       &(data->golden_dpm_table.sclk_table);
-       int value;
-
-       value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
-                       100 /
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
-
-       return value;
-}
-
-static int polaris10_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_single_dpm_table *golden_sclk_table =
-                       &(data->golden_dpm_table.sclk_table);
-       struct pp_power_state  *ps;
-       struct polaris10_power_state  *polaris10_ps;
-
-       if (value > 20)
-               value = 20;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       polaris10_ps = cast_phw_polaris10_power_state(&ps->hardware);
-
-       polaris10_ps->performance_levels[polaris10_ps->performance_level_count - 1].engine_clock =
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
-                       value / 100 +
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
-
-       return 0;
-}
-
-static int polaris10_get_mclk_od(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
-       struct polaris10_single_dpm_table *golden_mclk_table =
-                       &(data->golden_dpm_table.mclk_table);
-       int value;
-
-       value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
-                       100 /
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
-
-       return value;
-}
-
-static int polaris10_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct polaris10_single_dpm_table *golden_mclk_table =
-                       &(data->golden_dpm_table.mclk_table);
-       struct pp_power_state  *ps;
-       struct polaris10_power_state  *polaris10_ps;
-
-       if (value > 20)
-               value = 20;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       polaris10_ps = cast_phw_polaris10_power_state(&ps->hardware);
-
-       polaris10_ps->performance_levels[polaris10_ps->performance_level_count - 1].memory_clock =
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
-                       value / 100 +
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
-
-       return 0;
-}
-static const struct pp_hwmgr_func polaris10_hwmgr_funcs = {
-       .backend_init = &polaris10_hwmgr_backend_init,
-       .backend_fini = &polaris10_hwmgr_backend_fini,
-       .asic_setup = &polaris10_setup_asic_task,
-       .dynamic_state_management_enable = &polaris10_enable_dpm_tasks,
-       .apply_state_adjust_rules = polaris10_apply_state_adjust_rules,
-       .force_dpm_level = &polaris10_force_dpm_level,
-       .power_state_set = polaris10_set_power_state_tasks,
-       .get_power_state_size = polaris10_get_power_state_size,
-       .get_mclk = polaris10_dpm_get_mclk,
-       .get_sclk = polaris10_dpm_get_sclk,
-       .patch_boot_state = polaris10_dpm_patch_boot_state,
-       .get_pp_table_entry = polaris10_get_pp_table_entry,
-       .get_num_of_pp_table_entries = tonga_get_number_of_powerplay_table_entries,
-       .print_current_perforce_level = polaris10_print_current_perforce_level,
-       .powerdown_uvd = polaris10_phm_powerdown_uvd,
-       .powergate_uvd = polaris10_phm_powergate_uvd,
-       .powergate_vce = polaris10_phm_powergate_vce,
-       .disable_clock_power_gating = polaris10_phm_disable_clock_power_gating,
-       .update_clock_gatings = polaris10_phm_update_clock_gatings,
-       .notify_smc_display_config_after_ps_adjustment = polaris10_notify_smc_display_config_after_ps_adjustment,
-       .display_config_changed = polaris10_display_configuration_changed_task,
-       .set_max_fan_pwm_output = polaris10_set_max_fan_pwm_output,
-       .set_max_fan_rpm_output = polaris10_set_max_fan_rpm_output,
-       .get_temperature = polaris10_thermal_get_temperature,
-       .stop_thermal_controller = polaris10_thermal_stop_thermal_controller,
-       .get_fan_speed_info = polaris10_fan_ctrl_get_fan_speed_info,
-       .get_fan_speed_percent = polaris10_fan_ctrl_get_fan_speed_percent,
-       .set_fan_speed_percent = polaris10_fan_ctrl_set_fan_speed_percent,
-       .reset_fan_speed_to_default = polaris10_fan_ctrl_reset_fan_speed_to_default,
-       .get_fan_speed_rpm = polaris10_fan_ctrl_get_fan_speed_rpm,
-       .set_fan_speed_rpm = polaris10_fan_ctrl_set_fan_speed_rpm,
-       .uninitialize_thermal_controller = polaris10_thermal_ctrl_uninitialize_thermal_controller,
-       .register_internal_thermal_interrupt = polaris10_register_internal_thermal_interrupt,
-       .check_smc_update_required_for_display_configuration = polaris10_check_smc_update_required_for_display_configuration,
-       .check_states_equal = polaris10_check_states_equal,
-       .set_fan_control_mode = polaris10_set_fan_control_mode,
-       .get_fan_control_mode = polaris10_get_fan_control_mode,
-       .force_clock_level = polaris10_force_clock_level,
-       .print_clock_levels = polaris10_print_clock_levels,
-       .enable_per_cu_power_gating = polaris10_phm_enable_per_cu_power_gating,
-       .get_sclk_od = polaris10_get_sclk_od,
-       .set_sclk_od = polaris10_set_sclk_od,
-       .get_mclk_od = polaris10_get_mclk_od,
-       .set_mclk_od = polaris10_set_mclk_od,
-};
-
-int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr)
-{
-       hwmgr->hwmgr_func = &polaris10_hwmgr_funcs;
-       hwmgr->pptable_func = &tonga_pptable_funcs;
-       pp_polaris10_thermal_initialize(hwmgr);
-
-       return 0;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.h
deleted file mode 100644 (file)
index 33c3394..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright 2015 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 POLARIS10_HWMGR_H
-#define POLARIS10_HWMGR_H
-
-#include "hwmgr.h"
-#include "smu74.h"
-#include "smu74_discrete.h"
-#include "ppatomctrl.h"
-#include "polaris10_ppsmc.h"
-#include "polaris10_powertune.h"
-
-#define POLARIS10_MAX_HARDWARE_POWERLEVELS     2
-
-#define POLARIS10_VOLTAGE_CONTROL_NONE                   0x0
-#define POLARIS10_VOLTAGE_CONTROL_BY_GPIO                0x1
-#define POLARIS10_VOLTAGE_CONTROL_BY_SVID2               0x2
-#define POLARIS10_VOLTAGE_CONTROL_MERGED                 0x3
-
-#define DPMTABLE_OD_UPDATE_SCLK     0x00000001
-#define DPMTABLE_OD_UPDATE_MCLK     0x00000002
-#define DPMTABLE_UPDATE_SCLK        0x00000004
-#define DPMTABLE_UPDATE_MCLK        0x00000008
-
-struct polaris10_performance_level {
-       uint32_t  memory_clock;
-       uint32_t  engine_clock;
-       uint16_t  pcie_gen;
-       uint16_t  pcie_lane;
-};
-
-struct polaris10_uvd_clocks {
-       uint32_t  vclk;
-       uint32_t  dclk;
-};
-
-struct polaris10_vce_clocks {
-       uint32_t  evclk;
-       uint32_t  ecclk;
-};
-
-struct polaris10_power_state {
-       uint32_t                  magic;
-       struct polaris10_uvd_clocks    uvd_clks;
-       struct polaris10_vce_clocks    vce_clks;
-       uint32_t                  sam_clk;
-       uint16_t                  performance_level_count;
-       bool                      dc_compatible;
-       uint32_t                  sclk_threshold;
-       struct polaris10_performance_level  performance_levels[POLARIS10_MAX_HARDWARE_POWERLEVELS];
-};
-
-struct polaris10_dpm_level {
-       bool    enabled;
-       uint32_t        value;
-       uint32_t        param1;
-};
-
-#define POLARIS10_MAX_DEEPSLEEP_DIVIDER_ID 5
-#define MAX_REGULAR_DPM_NUMBER 8
-#define POLARIS10_MINIMUM_ENGINE_CLOCK 2500
-
-struct polaris10_single_dpm_table {
-       uint32_t                count;
-       struct polaris10_dpm_level      dpm_levels[MAX_REGULAR_DPM_NUMBER];
-};
-
-struct polaris10_dpm_table {
-       struct polaris10_single_dpm_table  sclk_table;
-       struct polaris10_single_dpm_table  mclk_table;
-       struct polaris10_single_dpm_table  pcie_speed_table;
-       struct polaris10_single_dpm_table  vddc_table;
-       struct polaris10_single_dpm_table  vddci_table;
-       struct polaris10_single_dpm_table  mvdd_table;
-};
-
-struct polaris10_clock_registers {
-       uint32_t  vCG_SPLL_FUNC_CNTL;
-       uint32_t  vCG_SPLL_FUNC_CNTL_2;
-       uint32_t  vCG_SPLL_FUNC_CNTL_3;
-       uint32_t  vCG_SPLL_FUNC_CNTL_4;
-       uint32_t  vCG_SPLL_SPREAD_SPECTRUM;
-       uint32_t  vCG_SPLL_SPREAD_SPECTRUM_2;
-       uint32_t  vDLL_CNTL;
-       uint32_t  vMCLK_PWRMGT_CNTL;
-       uint32_t  vMPLL_AD_FUNC_CNTL;
-       uint32_t  vMPLL_DQ_FUNC_CNTL;
-       uint32_t  vMPLL_FUNC_CNTL;
-       uint32_t  vMPLL_FUNC_CNTL_1;
-       uint32_t  vMPLL_FUNC_CNTL_2;
-       uint32_t  vMPLL_SS1;
-       uint32_t  vMPLL_SS2;
-};
-
-#define DISABLE_MC_LOADMICROCODE   1
-#define DISABLE_MC_CFGPROGRAMMING  2
-
-struct polaris10_voltage_smio_registers {
-       uint32_t vS0_VID_LOWER_SMIO_CNTL;
-};
-
-#define POLARIS10_MAX_LEAKAGE_COUNT  8
-
-struct polaris10_leakage_voltage {
-       uint16_t  count;
-       uint16_t  leakage_id[POLARIS10_MAX_LEAKAGE_COUNT];
-       uint16_t  actual_voltage[POLARIS10_MAX_LEAKAGE_COUNT];
-};
-
-struct polaris10_vbios_boot_state {
-       uint16_t    mvdd_bootup_value;
-       uint16_t    vddc_bootup_value;
-       uint16_t    vddci_bootup_value;
-       uint32_t    sclk_bootup_value;
-       uint32_t    mclk_bootup_value;
-       uint16_t    pcie_gen_bootup_value;
-       uint16_t    pcie_lane_bootup_value;
-};
-
-/* Ultra Low Voltage parameter structure */
-struct polaris10_ulv_parm {
-       bool                           ulv_supported;
-       uint32_t                       cg_ulv_parameter;
-       uint32_t                       ulv_volt_change_delay;
-       struct polaris10_performance_level  ulv_power_level;
-};
-
-struct polaris10_display_timing {
-       uint32_t  min_clock_in_sr;
-       uint32_t  num_existing_displays;
-};
-
-struct polaris10_dpmlevel_enable_mask {
-       uint32_t  uvd_dpm_enable_mask;
-       uint32_t  vce_dpm_enable_mask;
-       uint32_t  acp_dpm_enable_mask;
-       uint32_t  samu_dpm_enable_mask;
-       uint32_t  sclk_dpm_enable_mask;
-       uint32_t  mclk_dpm_enable_mask;
-       uint32_t  pcie_dpm_enable_mask;
-};
-
-struct polaris10_pcie_perf_range {
-       uint16_t  max;
-       uint16_t  min;
-};
-struct polaris10_range_table {
-       uint32_t trans_lower_frequency; /* in 10khz */
-       uint32_t trans_upper_frequency;
-};
-
-struct polaris10_hwmgr {
-       struct polaris10_dpm_table                      dpm_table;
-       struct polaris10_dpm_table                      golden_dpm_table;
-       SMU74_Discrete_DpmTable                         smc_state_table;
-       struct SMU74_Discrete_Ulv            ulv_setting;
-
-       struct polaris10_range_table                range_table[NUM_SCLK_RANGE];
-       uint32_t                                                voting_rights_clients0;
-       uint32_t                                                voting_rights_clients1;
-       uint32_t                                                voting_rights_clients2;
-       uint32_t                                                voting_rights_clients3;
-       uint32_t                                                voting_rights_clients4;
-       uint32_t                                                voting_rights_clients5;
-       uint32_t                                                voting_rights_clients6;
-       uint32_t                                                voting_rights_clients7;
-       uint32_t                                                static_screen_threshold_unit;
-       uint32_t                                                static_screen_threshold;
-       uint32_t                                                voltage_control;
-       uint32_t                                                vddc_vddci_delta;
-
-       uint32_t                                                active_auto_throttle_sources;
-
-       struct polaris10_clock_registers            clock_registers;
-       struct polaris10_voltage_smio_registers      voltage_smio_registers;
-
-       bool                           is_memory_gddr5;
-       uint16_t                       acpi_vddc;
-       bool                           pspp_notify_required;
-       uint16_t                       force_pcie_gen;
-       uint16_t                       acpi_pcie_gen;
-       uint32_t                       pcie_gen_cap;
-       uint32_t                       pcie_lane_cap;
-       uint32_t                       pcie_spc_cap;
-       struct polaris10_leakage_voltage          vddc_leakage;
-       struct polaris10_leakage_voltage          Vddci_leakage;
-
-       uint32_t                             mvdd_control;
-       uint32_t                             vddc_mask_low;
-       uint32_t                             mvdd_mask_low;
-       uint16_t                            max_vddc_in_pptable;
-       uint16_t                            min_vddc_in_pptable;
-       uint16_t                            max_vddci_in_pptable;
-       uint16_t                            min_vddci_in_pptable;
-       uint32_t                             mclk_strobe_mode_threshold;
-       uint32_t                             mclk_stutter_mode_threshold;
-       uint32_t                             mclk_edc_enable_threshold;
-       uint32_t                             mclk_edcwr_enable_threshold;
-       bool                                is_uvd_enabled;
-       struct polaris10_vbios_boot_state        vbios_boot_state;
-
-       bool                           pcie_performance_request;
-       bool                           battery_state;
-       bool                           is_tlu_enabled;
-
-       /* ---- SMC SRAM Address of firmware header tables ---- */
-       uint32_t                             sram_end;
-       uint32_t                             dpm_table_start;
-       uint32_t                             soft_regs_start;
-       uint32_t                             mc_reg_table_start;
-       uint32_t                             fan_table_start;
-       uint32_t                             arb_table_start;
-
-       /* ---- Stuff originally coming from Evergreen ---- */
-       uint32_t                             vddci_control;
-       struct pp_atomctrl_voltage_table     vddc_voltage_table;
-       struct pp_atomctrl_voltage_table     vddci_voltage_table;
-       struct pp_atomctrl_voltage_table     mvdd_voltage_table;
-
-       uint32_t                             mgcg_cgtt_local2;
-       uint32_t                             mgcg_cgtt_local3;
-       uint32_t                             gpio_debug;
-       uint32_t                             mc_micro_code_feature;
-       uint32_t                             highest_mclk;
-       uint16_t                             acpi_vddci;
-       uint8_t                              mvdd_high_index;
-       uint8_t                              mvdd_low_index;
-       bool                                 dll_default_on;
-       bool                                 performance_request_registered;
-
-       /* ---- Low Power Features ---- */
-       struct polaris10_ulv_parm                 ulv;
-
-       /* ---- CAC Stuff ---- */
-       uint32_t                       cac_table_start;
-       bool                           cac_configuration_required;
-       bool                           driver_calculate_cac_leakage;
-       bool                           cac_enabled;
-
-       /* ---- DPM2 Parameters ---- */
-       uint32_t                       power_containment_features;
-       bool                           enable_dte_feature;
-       bool                           enable_tdc_limit_feature;
-       bool                           enable_pkg_pwr_tracking_feature;
-       bool                           disable_uvd_power_tune_feature;
-       const struct polaris10_pt_defaults       *power_tune_defaults;
-       struct SMU74_Discrete_PmFuses  power_tune_table;
-       uint32_t                       dte_tj_offset;
-       uint32_t                       fast_watermark_threshold;
-
-       /* ---- Phase Shedding ---- */
-       bool                           vddc_phase_shed_control;
-
-       /* ---- DI/DT ---- */
-       struct polaris10_display_timing        display_timing;
-       uint32_t                      bif_sclk_table[SMU74_MAX_LEVELS_LINK];
-
-       /* ---- Thermal Temperature Setting ---- */
-       struct polaris10_dpmlevel_enable_mask     dpm_level_enable_mask;
-       uint32_t                                  need_update_smu7_dpm_table;
-       uint32_t                                  sclk_dpm_key_disabled;
-       uint32_t                                  mclk_dpm_key_disabled;
-       uint32_t                                  pcie_dpm_key_disabled;
-       uint32_t                                  min_engine_clocks;
-       struct polaris10_pcie_perf_range          pcie_gen_performance;
-       struct polaris10_pcie_perf_range          pcie_lane_performance;
-       struct polaris10_pcie_perf_range          pcie_gen_power_saving;
-       struct polaris10_pcie_perf_range          pcie_lane_power_saving;
-       bool                                      use_pcie_performance_levels;
-       bool                                      use_pcie_power_saving_levels;
-       uint32_t                                  activity_target[SMU74_MAX_LEVELS_GRAPHICS];
-       uint32_t                                  mclk_activity_target;
-       uint32_t                                  mclk_dpm0_activity_target;
-       uint32_t                                  low_sclk_interrupt_threshold;
-       uint32_t                                  last_mclk_dpm_enable_mask;
-       bool                                      uvd_enabled;
-
-       /* ---- Power Gating States ---- */
-       bool                           uvd_power_gated;
-       bool                           vce_power_gated;
-       bool                           samu_power_gated;
-       bool                           need_long_memory_training;
-
-       /* Application power optimization parameters */
-       bool                               update_up_hyst;
-       bool                               update_down_hyst;
-       uint32_t                           down_hyst;
-       uint32_t                           up_hyst;
-       uint32_t disable_dpm_mask;
-       bool apply_optimized_settings;
-       uint32_t                              avfs_vdroop_override_setting;
-       bool                                  apply_avfs_cks_off_voltage;
-       uint32_t                              frame_time_x2;
-};
-
-/* To convert to Q8.8 format for firmware */
-#define POLARIS10_Q88_FORMAT_CONVERSION_UNIT             256
-
-enum Polaris10_I2CLineID {
-       Polaris10_I2CLineID_DDC1 = 0x90,
-       Polaris10_I2CLineID_DDC2 = 0x91,
-       Polaris10_I2CLineID_DDC3 = 0x92,
-       Polaris10_I2CLineID_DDC4 = 0x93,
-       Polaris10_I2CLineID_DDC5 = 0x94,
-       Polaris10_I2CLineID_DDC6 = 0x95,
-       Polaris10_I2CLineID_SCLSDA = 0x96,
-       Polaris10_I2CLineID_DDCVGA = 0x97
-};
-
-#define POLARIS10_I2C_DDC1DATA          0
-#define POLARIS10_I2C_DDC1CLK           1
-#define POLARIS10_I2C_DDC2DATA          2
-#define POLARIS10_I2C_DDC2CLK           3
-#define POLARIS10_I2C_DDC3DATA          4
-#define POLARIS10_I2C_DDC3CLK           5
-#define POLARIS10_I2C_SDA               40
-#define POLARIS10_I2C_SCL               41
-#define POLARIS10_I2C_DDC4DATA          65
-#define POLARIS10_I2C_DDC4CLK           66
-#define POLARIS10_I2C_DDC5DATA          0x48
-#define POLARIS10_I2C_DDC5CLK           0x49
-#define POLARIS10_I2C_DDC6DATA          0x4a
-#define POLARIS10_I2C_DDC6CLK           0x4b
-#define POLARIS10_I2C_DDCVGADATA        0x4c
-#define POLARIS10_I2C_DDCVGACLK         0x4d
-
-#define POLARIS10_UNUSED_GPIO_PIN       0x7F
-
-int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr);
-
-int polaris10_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
-int polaris10_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate);
-int polaris10_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
-int polaris10_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate);
-#endif
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_powertune.c
deleted file mode 100644 (file)
index b9cb240..0000000
+++ /dev/null
@@ -1,988 +0,0 @@
-/*
- * Copyright 2015 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 "hwmgr.h"
-#include "smumgr.h"
-#include "polaris10_hwmgr.h"
-#include "polaris10_powertune.h"
-#include "polaris10_smumgr.h"
-#include "smu74_discrete.h"
-#include "pp_debug.h"
-#include "gca/gfx_8_0_d.h"
-#include "gca/gfx_8_0_sh_mask.h"
-#include "oss/oss_3_0_sh_mask.h"
-
-#define VOLTAGE_SCALE  4
-#define POWERTUNE_DEFAULT_SET_MAX    1
-
-uint32_t DIDTBlock_Info = SQ_IR_MASK | TCP_IR_MASK | TD_PCC_MASK;
-
-struct polaris10_pt_config_reg GCCACConfig_Polaris10[] = {
-/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- *      Offset                             Mask                                                Shift                                               Value       Type
- * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- */
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00060013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00860013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01060013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01860013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02060013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02860013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x03060013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x03860013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x04060013, POLARIS10_CONFIGREG_GC_CAC_IND },
-
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x000E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x008E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x010E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x018E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x020E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
-
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00100013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00900013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01100013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01900013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02100013, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02900013, POLARIS10_CONFIGREG_GC_CAC_IND },
-
-       {   0xFFFFFFFF  }
-};
-
-struct polaris10_pt_config_reg GCCACConfig_Polaris11[] = {
-/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- *      Offset                             Mask                                                Shift                                               Value       Type
- * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- */
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00060011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00860011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01060011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01860011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02060011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02860011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x03060011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x03860011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x04060011, POLARIS10_CONFIGREG_GC_CAC_IND },
-
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x000E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x008E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x010E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x018E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x020E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
-
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00100011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00900011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01100011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01900011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02100011, POLARIS10_CONFIGREG_GC_CAC_IND },
-       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02900011, POLARIS10_CONFIGREG_GC_CAC_IND },
-
-       {   0xFFFFFFFF  }
-};
-
-struct polaris10_pt_config_reg DIDTConfig_Polaris10[] = {
-/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- *      Offset                             Mask                                                Shift                                               Value       Type
- * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- */
-       {   ixDIDT_SQ_WEIGHT0_3,               DIDT_SQ_WEIGHT0_3__WEIGHT0_MASK,                    DIDT_SQ_WEIGHT0_3__WEIGHT0__SHIFT,                  0x0073,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT0_3,               DIDT_SQ_WEIGHT0_3__WEIGHT1_MASK,                    DIDT_SQ_WEIGHT0_3__WEIGHT1__SHIFT,                  0x00ab,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT0_3,               DIDT_SQ_WEIGHT0_3__WEIGHT2_MASK,                    DIDT_SQ_WEIGHT0_3__WEIGHT2__SHIFT,                  0x0084,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT0_3,               DIDT_SQ_WEIGHT0_3__WEIGHT3_MASK,                    DIDT_SQ_WEIGHT0_3__WEIGHT3__SHIFT,                  0x005a,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_WEIGHT4_7,               DIDT_SQ_WEIGHT4_7__WEIGHT4_MASK,                    DIDT_SQ_WEIGHT4_7__WEIGHT4__SHIFT,                  0x0067,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT4_7,               DIDT_SQ_WEIGHT4_7__WEIGHT5_MASK,                    DIDT_SQ_WEIGHT4_7__WEIGHT5__SHIFT,                  0x0084,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT4_7,               DIDT_SQ_WEIGHT4_7__WEIGHT6_MASK,                    DIDT_SQ_WEIGHT4_7__WEIGHT6__SHIFT,                  0x0027,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT4_7,               DIDT_SQ_WEIGHT4_7__WEIGHT7_MASK,                    DIDT_SQ_WEIGHT4_7__WEIGHT7__SHIFT,                  0x0046,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_WEIGHT8_11,              DIDT_SQ_WEIGHT8_11__WEIGHT8_MASK,                   DIDT_SQ_WEIGHT8_11__WEIGHT8__SHIFT,                 0x00aa,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT8_11,              DIDT_SQ_WEIGHT8_11__WEIGHT9_MASK,                   DIDT_SQ_WEIGHT8_11__WEIGHT9__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT8_11,              DIDT_SQ_WEIGHT8_11__WEIGHT10_MASK,                  DIDT_SQ_WEIGHT8_11__WEIGHT10__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT8_11,              DIDT_SQ_WEIGHT8_11__WEIGHT11_MASK,                  DIDT_SQ_WEIGHT8_11__WEIGHT11__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_CTRL1,                   DIDT_SQ_CTRL1__MIN_POWER_MASK,                      DIDT_SQ_CTRL1__MIN_POWER__SHIFT,                    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL1,                   DIDT_SQ_CTRL1__MAX_POWER_MASK,                      DIDT_SQ_CTRL1__MAX_POWER__SHIFT,                    0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_CTRL_OCP,                DIDT_SQ_CTRL_OCP__UNUSED_0_MASK,                    DIDT_SQ_CTRL_OCP__UNUSED_0__SHIFT,                  0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL_OCP,                DIDT_SQ_CTRL_OCP__OCP_MAX_POWER_MASK,               DIDT_SQ_CTRL_OCP__OCP_MAX_POWER__SHIFT,             0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__MAX_POWER_DELTA_MASK,                DIDT_SQ_CTRL2__MAX_POWER_DELTA__SHIFT,              0x3853,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__UNUSED_0_MASK,                       DIDT_SQ_CTRL2__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK,       DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT,     0x005a,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__UNUSED_1_MASK,                       DIDT_SQ_CTRL2__UNUSED_1__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK,       DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT,     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__UNUSED_2_MASK,                       DIDT_SQ_CTRL2__UNUSED_2__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_STALL_CTRL,              DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK,    DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT,  0x0001,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_STALL_CTRL,              DIDT_SQ_STALL_CTRL__UNUSED_0_MASK,                  DIDT_SQ_STALL_CTRL__UNUSED_0__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_TUNING_CTRL,             DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK,       DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT,     0x0001,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_TUNING_CTRL,             DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK,                 DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT,               0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK,                   DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT,                 0x0001,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__USE_REF_CLOCK_MASK,                  DIDT_SQ_CTRL0__USE_REF_CLOCK__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__PHASE_OFFSET_MASK,                   DIDT_SQ_CTRL0__PHASE_OFFSET__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__DIDT_CTRL_RST_MASK,                  DIDT_SQ_CTRL0__DIDT_CTRL_RST__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK,           DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT,         0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__UNUSED_0_MASK,                       DIDT_SQ_CTRL0__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT0_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT0__SHIFT,                  0x000a,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT1_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT1__SHIFT,                  0x0010,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT2_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT2__SHIFT,                  0x0017,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT3_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT3__SHIFT,                  0x002f,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT4_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT4__SHIFT,                  0x0046,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT5_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT5__SHIFT,                  0x005d,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT6_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT6__SHIFT,                  0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT7_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT7__SHIFT,                  0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_CTRL1,                   DIDT_TD_CTRL1__MIN_POWER_MASK,                      DIDT_TD_CTRL1__MIN_POWER__SHIFT,                    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL1,                   DIDT_TD_CTRL1__MAX_POWER_MASK,                      DIDT_TD_CTRL1__MAX_POWER__SHIFT,                    0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_CTRL_OCP,                DIDT_TD_CTRL_OCP__UNUSED_0_MASK,                    DIDT_TD_CTRL_OCP__UNUSED_0__SHIFT,                  0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL_OCP,                DIDT_TD_CTRL_OCP__OCP_MAX_POWER_MASK,               DIDT_TD_CTRL_OCP__OCP_MAX_POWER__SHIFT,             0x00ff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__MAX_POWER_DELTA_MASK,                DIDT_TD_CTRL2__MAX_POWER_DELTA__SHIFT,              0x3fff,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__UNUSED_0_MASK,                       DIDT_TD_CTRL2__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK,       DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT,     0x000f,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__UNUSED_1_MASK,                       DIDT_TD_CTRL2__UNUSED_1__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK,       DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT,     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__UNUSED_2_MASK,                       DIDT_TD_CTRL2__UNUSED_2__SHIFT,                     0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_STALL_CTRL,              DIDT_TD_STALL_CTRL__UNUSED_0_MASK,                  DIDT_TD_STALL_CTRL__UNUSED_0__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_TUNING_CTRL,             DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK,       DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT,     0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_TUNING_CTRL,             DIDT_TD_TUNING_CTRL__UNUSED_0_MASK,                 DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT,               0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK,                   DIDT_TD_CTRL0__DIDT_CTRL_EN__SHIFT,                 0x0001,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__USE_REF_CLOCK_MASK,                  DIDT_TD_CTRL0__USE_REF_CLOCK__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__PHASE_OFFSET_MASK,                   DIDT_TD_CTRL0__PHASE_OFFSET__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__DIDT_CTRL_RST_MASK,                  DIDT_TD_CTRL0__DIDT_CTRL_RST__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK,           DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT,         0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK,     DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT,   0x0009,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK,     DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT,   0x0009,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__UNUSED_0_MASK,                       DIDT_TD_CTRL0__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_WEIGHT0_3,              DIDT_TCP_WEIGHT0_3__WEIGHT0_MASK,                   DIDT_TCP_WEIGHT0_3__WEIGHT0__SHIFT,                 0x0004,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT0_3,              DIDT_TCP_WEIGHT0_3__WEIGHT1_MASK,                   DIDT_TCP_WEIGHT0_3__WEIGHT1__SHIFT,                 0x0037,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT0_3,              DIDT_TCP_WEIGHT0_3__WEIGHT2_MASK,                   DIDT_TCP_WEIGHT0_3__WEIGHT2__SHIFT,                 0x0001,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT0_3,              DIDT_TCP_WEIGHT0_3__WEIGHT3_MASK,                   DIDT_TCP_WEIGHT0_3__WEIGHT3__SHIFT,                 0x00ff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_WEIGHT4_7,              DIDT_TCP_WEIGHT4_7__WEIGHT4_MASK,                   DIDT_TCP_WEIGHT4_7__WEIGHT4__SHIFT,                 0x0054,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT4_7,              DIDT_TCP_WEIGHT4_7__WEIGHT5_MASK,                   DIDT_TCP_WEIGHT4_7__WEIGHT5__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT4_7,              DIDT_TCP_WEIGHT4_7__WEIGHT6_MASK,                   DIDT_TCP_WEIGHT4_7__WEIGHT6__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT4_7,              DIDT_TCP_WEIGHT4_7__WEIGHT7_MASK,                   DIDT_TCP_WEIGHT4_7__WEIGHT7__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_CTRL1,                  DIDT_TCP_CTRL1__MIN_POWER_MASK,                     DIDT_TCP_CTRL1__MIN_POWER__SHIFT,                   0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL1,                  DIDT_TCP_CTRL1__MAX_POWER_MASK,                     DIDT_TCP_CTRL1__MAX_POWER__SHIFT,                   0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_CTRL_OCP,               DIDT_TCP_CTRL_OCP__UNUSED_0_MASK,                   DIDT_TCP_CTRL_OCP__UNUSED_0__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL_OCP,               DIDT_TCP_CTRL_OCP__OCP_MAX_POWER_MASK,              DIDT_TCP_CTRL_OCP__OCP_MAX_POWER__SHIFT,            0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__MAX_POWER_DELTA_MASK,               DIDT_TCP_CTRL2__MAX_POWER_DELTA__SHIFT,             0x3dde,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__UNUSED_0_MASK,                      DIDT_TCP_CTRL2__UNUSED_0__SHIFT,                    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK,      DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT,    0x0032,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__UNUSED_1_MASK,                      DIDT_TCP_CTRL2__UNUSED_1__SHIFT,                    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK,      DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT,    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__UNUSED_2_MASK,                      DIDT_TCP_CTRL2__UNUSED_2__SHIFT,                    0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_STALL_CTRL,             DIDT_TCP_STALL_CTRL__UNUSED_0_MASK,                 DIDT_TCP_STALL_CTRL__UNUSED_0__SHIFT,               0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_TUNING_CTRL,            DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK,      DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT,    0x0001,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_TUNING_CTRL,            DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK,                DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT,              0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK,                   DIDT_TCP_CTRL0__DIDT_CTRL_EN__SHIFT,                 0x0001,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__USE_REF_CLOCK_MASK,                  DIDT_TCP_CTRL0__USE_REF_CLOCK__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__PHASE_OFFSET_MASK,                   DIDT_TCP_CTRL0__PHASE_OFFSET__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__DIDT_CTRL_RST_MASK,                  DIDT_TCP_CTRL0__DIDT_CTRL_RST__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK,           DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT,         0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__UNUSED_0_MASK,                       DIDT_TCP_CTRL0__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   0xFFFFFFFF  }
-};
-
-struct polaris10_pt_config_reg DIDTConfig_Polaris11[] = {
-/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- *      Offset                             Mask                                                Shift                                               Value       Type
- * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- */
-       {   ixDIDT_SQ_WEIGHT0_3,               DIDT_SQ_WEIGHT0_3__WEIGHT0_MASK,                    DIDT_SQ_WEIGHT0_3__WEIGHT0__SHIFT,                  0x0073,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT0_3,               DIDT_SQ_WEIGHT0_3__WEIGHT1_MASK,                    DIDT_SQ_WEIGHT0_3__WEIGHT1__SHIFT,                  0x00ab,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT0_3,               DIDT_SQ_WEIGHT0_3__WEIGHT2_MASK,                    DIDT_SQ_WEIGHT0_3__WEIGHT2__SHIFT,                  0x0084,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT0_3,               DIDT_SQ_WEIGHT0_3__WEIGHT3_MASK,                    DIDT_SQ_WEIGHT0_3__WEIGHT3__SHIFT,                  0x005a,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_WEIGHT4_7,               DIDT_SQ_WEIGHT4_7__WEIGHT4_MASK,                    DIDT_SQ_WEIGHT4_7__WEIGHT4__SHIFT,                  0x0067,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT4_7,               DIDT_SQ_WEIGHT4_7__WEIGHT5_MASK,                    DIDT_SQ_WEIGHT4_7__WEIGHT5__SHIFT,                  0x0084,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT4_7,               DIDT_SQ_WEIGHT4_7__WEIGHT6_MASK,                    DIDT_SQ_WEIGHT4_7__WEIGHT6__SHIFT,                  0x0027,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT4_7,               DIDT_SQ_WEIGHT4_7__WEIGHT7_MASK,                    DIDT_SQ_WEIGHT4_7__WEIGHT7__SHIFT,                  0x0046,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_WEIGHT8_11,              DIDT_SQ_WEIGHT8_11__WEIGHT8_MASK,                   DIDT_SQ_WEIGHT8_11__WEIGHT8__SHIFT,                 0x00aa,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT8_11,              DIDT_SQ_WEIGHT8_11__WEIGHT9_MASK,                   DIDT_SQ_WEIGHT8_11__WEIGHT9__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT8_11,              DIDT_SQ_WEIGHT8_11__WEIGHT10_MASK,                  DIDT_SQ_WEIGHT8_11__WEIGHT10__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_WEIGHT8_11,              DIDT_SQ_WEIGHT8_11__WEIGHT11_MASK,                  DIDT_SQ_WEIGHT8_11__WEIGHT11__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_CTRL1,                   DIDT_SQ_CTRL1__MIN_POWER_MASK,                      DIDT_SQ_CTRL1__MIN_POWER__SHIFT,                    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL1,                   DIDT_SQ_CTRL1__MAX_POWER_MASK,                      DIDT_SQ_CTRL1__MAX_POWER__SHIFT,                    0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_CTRL_OCP,                DIDT_SQ_CTRL_OCP__UNUSED_0_MASK,                    DIDT_SQ_CTRL_OCP__UNUSED_0__SHIFT,                  0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL_OCP,                DIDT_SQ_CTRL_OCP__OCP_MAX_POWER_MASK,               DIDT_SQ_CTRL_OCP__OCP_MAX_POWER__SHIFT,             0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__MAX_POWER_DELTA_MASK,                DIDT_SQ_CTRL2__MAX_POWER_DELTA__SHIFT,              0x3853,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__UNUSED_0_MASK,                       DIDT_SQ_CTRL2__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK,       DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT,     0x005a,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__UNUSED_1_MASK,                       DIDT_SQ_CTRL2__UNUSED_1__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK,       DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT,     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL2,                   DIDT_SQ_CTRL2__UNUSED_2_MASK,                       DIDT_SQ_CTRL2__UNUSED_2__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_STALL_CTRL,              DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK,    DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT,  0x0001,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_STALL_CTRL,              DIDT_SQ_STALL_CTRL__UNUSED_0_MASK,                  DIDT_SQ_STALL_CTRL__UNUSED_0__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_TUNING_CTRL,             DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK,       DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT,     0x0001,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_TUNING_CTRL,             DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK,                 DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT,               0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK,                   DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT,                 0x0001,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__USE_REF_CLOCK_MASK,                  DIDT_SQ_CTRL0__USE_REF_CLOCK__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__PHASE_OFFSET_MASK,                   DIDT_SQ_CTRL0__PHASE_OFFSET__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__DIDT_CTRL_RST_MASK,                  DIDT_SQ_CTRL0__DIDT_CTRL_RST__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK,           DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT,         0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__UNUSED_0_MASK,                       DIDT_SQ_CTRL0__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT0_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT0__SHIFT,                  0x000a,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT1_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT1__SHIFT,                  0x0010,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT2_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT2__SHIFT,                  0x0017,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT3_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT3__SHIFT,                  0x002f,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT4_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT4__SHIFT,                  0x0046,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT5_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT5__SHIFT,                  0x005d,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT6_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT6__SHIFT,                  0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT7_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT7__SHIFT,                  0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_CTRL1,                   DIDT_TD_CTRL1__MIN_POWER_MASK,                      DIDT_TD_CTRL1__MIN_POWER__SHIFT,                    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL1,                   DIDT_TD_CTRL1__MAX_POWER_MASK,                      DIDT_TD_CTRL1__MAX_POWER__SHIFT,                    0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_CTRL_OCP,                DIDT_TD_CTRL_OCP__UNUSED_0_MASK,                    DIDT_TD_CTRL_OCP__UNUSED_0__SHIFT,                  0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL_OCP,                DIDT_TD_CTRL_OCP__OCP_MAX_POWER_MASK,               DIDT_TD_CTRL_OCP__OCP_MAX_POWER__SHIFT,             0x00ff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__MAX_POWER_DELTA_MASK,                DIDT_TD_CTRL2__MAX_POWER_DELTA__SHIFT,              0x3fff,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__UNUSED_0_MASK,                       DIDT_TD_CTRL2__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK,       DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT,     0x000f,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__UNUSED_1_MASK,                       DIDT_TD_CTRL2__UNUSED_1__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK,       DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT,     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL2,                   DIDT_TD_CTRL2__UNUSED_2_MASK,                       DIDT_TD_CTRL2__UNUSED_2__SHIFT,                     0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_STALL_CTRL,              DIDT_TD_STALL_CTRL__UNUSED_0_MASK,                  DIDT_TD_STALL_CTRL__UNUSED_0__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_TUNING_CTRL,             DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK,       DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT,     0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_TUNING_CTRL,             DIDT_TD_TUNING_CTRL__UNUSED_0_MASK,                 DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT,               0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK,                   DIDT_TD_CTRL0__DIDT_CTRL_EN__SHIFT,                 0x0001,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__USE_REF_CLOCK_MASK,                  DIDT_TD_CTRL0__USE_REF_CLOCK__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__PHASE_OFFSET_MASK,                   DIDT_TD_CTRL0__PHASE_OFFSET__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__DIDT_CTRL_RST_MASK,                  DIDT_TD_CTRL0__DIDT_CTRL_RST__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK,           DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT,         0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TD_CTRL0,                   DIDT_TD_CTRL0__UNUSED_0_MASK,                       DIDT_TD_CTRL0__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_WEIGHT0_3,              DIDT_TCP_WEIGHT0_3__WEIGHT0_MASK,                   DIDT_TCP_WEIGHT0_3__WEIGHT0__SHIFT,                 0x0004,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT0_3,              DIDT_TCP_WEIGHT0_3__WEIGHT1_MASK,                   DIDT_TCP_WEIGHT0_3__WEIGHT1__SHIFT,                 0x0037,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT0_3,              DIDT_TCP_WEIGHT0_3__WEIGHT2_MASK,                   DIDT_TCP_WEIGHT0_3__WEIGHT2__SHIFT,                 0x0001,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT0_3,              DIDT_TCP_WEIGHT0_3__WEIGHT3_MASK,                   DIDT_TCP_WEIGHT0_3__WEIGHT3__SHIFT,                 0x00ff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_WEIGHT4_7,              DIDT_TCP_WEIGHT4_7__WEIGHT4_MASK,                   DIDT_TCP_WEIGHT4_7__WEIGHT4__SHIFT,                 0x0054,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT4_7,              DIDT_TCP_WEIGHT4_7__WEIGHT5_MASK,                   DIDT_TCP_WEIGHT4_7__WEIGHT5__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT4_7,              DIDT_TCP_WEIGHT4_7__WEIGHT6_MASK,                   DIDT_TCP_WEIGHT4_7__WEIGHT6__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_WEIGHT4_7,              DIDT_TCP_WEIGHT4_7__WEIGHT7_MASK,                   DIDT_TCP_WEIGHT4_7__WEIGHT7__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_CTRL1,                  DIDT_TCP_CTRL1__MIN_POWER_MASK,                     DIDT_TCP_CTRL1__MIN_POWER__SHIFT,                   0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL1,                  DIDT_TCP_CTRL1__MAX_POWER_MASK,                     DIDT_TCP_CTRL1__MAX_POWER__SHIFT,                   0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_CTRL_OCP,               DIDT_TCP_CTRL_OCP__UNUSED_0_MASK,                   DIDT_TCP_CTRL_OCP__UNUSED_0__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL_OCP,               DIDT_TCP_CTRL_OCP__OCP_MAX_POWER_MASK,              DIDT_TCP_CTRL_OCP__OCP_MAX_POWER__SHIFT,            0xffff,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__MAX_POWER_DELTA_MASK,               DIDT_TCP_CTRL2__MAX_POWER_DELTA__SHIFT,             0x3dde,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__UNUSED_0_MASK,                      DIDT_TCP_CTRL2__UNUSED_0__SHIFT,                    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK,      DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT,    0x0032,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__UNUSED_1_MASK,                      DIDT_TCP_CTRL2__UNUSED_1__SHIFT,                    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK,      DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT,    0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL2,                  DIDT_TCP_CTRL2__UNUSED_2_MASK,                      DIDT_TCP_CTRL2__UNUSED_2__SHIFT,                    0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_STALL_CTRL,             DIDT_TCP_STALL_CTRL__UNUSED_0_MASK,                 DIDT_TCP_STALL_CTRL__UNUSED_0__SHIFT,               0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_TUNING_CTRL,            DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK,      DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT,    0x0001,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_TUNING_CTRL,            DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK,                DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT,              0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK,                   DIDT_TCP_CTRL0__DIDT_CTRL_EN__SHIFT,                 0x0001,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__USE_REF_CLOCK_MASK,                  DIDT_TCP_CTRL0__USE_REF_CLOCK__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__PHASE_OFFSET_MASK,                   DIDT_TCP_CTRL0__PHASE_OFFSET__SHIFT,                 0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__DIDT_CTRL_RST_MASK,                  DIDT_TCP_CTRL0__DIDT_CTRL_RST__SHIFT,                0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK,           DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT,         0x0000,     POLARIS10_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,     POLARIS10_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,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   ixDIDT_TCP_CTRL0,                   DIDT_TCP_CTRL0__UNUSED_0_MASK,                       DIDT_TCP_CTRL0__UNUSED_0__SHIFT,                     0x0000,     POLARIS10_CONFIGREG_DIDT_IND },
-       {   0xFFFFFFFF  }
-};
-
-static const struct polaris10_pt_defaults polaris10_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
-       /* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
-        * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT */
-       { 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
-       { 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61},
-       { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 } },
-};
-
-void polaris10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *polaris10_hwmgr = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct  phm_ppt_v1_information *table_info =
-                       (struct  phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (table_info &&
-                       table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
-                       table_info->cac_dtp_table->usPowerTuneDataSetID)
-               polaris10_hwmgr->power_tune_defaults =
-                               &polaris10_power_tune_data_set_array
-                               [table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
-       else
-               polaris10_hwmgr->power_tune_defaults = &polaris10_power_tune_data_set_array[0];
-
-}
-
-static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
-{
-       uint32_t tmp;
-       tmp = raw_setting * 4096 / 100;
-       return (uint16_t)tmp;
-}
-
-int polaris10_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       const struct polaris10_pt_defaults *defaults = data->power_tune_defaults;
-       SMU74_Discrete_DpmTable  *dpm_table = &(data->smc_state_table);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
-       struct pp_advance_fan_control_parameters *fan_table=
-                       &hwmgr->thermal_controller.advanceFanControlParameters;
-       int i, j, k;
-       const uint16_t *pdef1;
-       const uint16_t *pdef2;
-
-       dpm_table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 128));
-       dpm_table->TargetTdp  = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 128));
-
-       PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
-                               "Target Operating Temp is out of Range!",
-                               );
-
-       dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
-                       cac_dtp_table->usTargetOperatingTemp * 256);
-       dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
-                       cac_dtp_table->usTemperatureLimitHotspot * 256);
-       dpm_table->FanGainEdge = PP_HOST_TO_SMC_US(
-                       scale_fan_gain_settings(fan_table->usFanGainEdge));
-       dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US(
-                       scale_fan_gain_settings(fan_table->usFanGainHotspot));
-
-       pdef1 = defaults->BAPMTI_R;
-       pdef2 = defaults->BAPMTI_RC;
-
-       for (i = 0; i < SMU74_DTE_ITERATIONS; i++) {
-               for (j = 0; j < SMU74_DTE_SOURCES; j++) {
-                       for (k = 0; k < SMU74_DTE_SINKS; k++) {
-                               dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*pdef1);
-                               dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*pdef2);
-                               pdef1++;
-                               pdef2++;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int polaris10_populate_svi_load_line(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       const struct polaris10_pt_defaults *defaults = data->power_tune_defaults;
-
-       data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
-       data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
-       data->power_tune_table.SviLoadLineTrimVddC = 3;
-       data->power_tune_table.SviLoadLineOffsetVddC = 0;
-
-       return 0;
-}
-
-static int polaris10_populate_tdc_limit(struct pp_hwmgr *hwmgr)
-{
-       uint16_t tdc_limit;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       const struct polaris10_pt_defaults *defaults = data->power_tune_defaults;
-
-       tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
-       data->power_tune_table.TDC_VDDC_PkgLimit =
-                       CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
-       data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
-                       defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
-       data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
-
-       return 0;
-}
-
-static int polaris10_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       const struct polaris10_pt_defaults *defaults = data->power_tune_defaults;
-       uint32_t temp;
-
-       if (polaris10_read_smc_sram_dword(hwmgr->smumgr,
-                       fuse_table_offset +
-                       offsetof(SMU74_Discrete_PmFuses, TdcWaterfallCtl),
-                       (uint32_t *)&temp, data->sram_end))
-               PP_ASSERT_WITH_CODE(false,
-                               "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
-                               return -EINVAL);
-       else {
-               data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
-               data->power_tune_table.LPMLTemperatureMin =
-                               (uint8_t)((temp >> 16) & 0xff);
-               data->power_tune_table.LPMLTemperatureMax =
-                               (uint8_t)((temp >> 8) & 0xff);
-               data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
-       }
-       return 0;
-}
-
-static int polaris10_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
-{
-       int i;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       /* Currently not used. Set all to zero. */
-       for (i = 0; i < 16; i++)
-               data->power_tune_table.LPMLTemperatureScaler[i] = 0;
-
-       return 0;
-}
-
-static int polaris10_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if ((hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity & (1 << 15))
-               || 0 == hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity)
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity =
-                       hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity;
-
-       data->power_tune_table.FuzzyFan_PwmSetDelta = PP_HOST_TO_SMC_US(
-                               hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity);
-       return 0;
-}
-
-static int polaris10_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
-{
-       int i;
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       /* Currently not used. Set all to zero. */
-       for (i = 0; i < 16; i++)
-               data->power_tune_table.GnbLPML[i] = 0;
-
-       return 0;
-}
-
-static int polaris10_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
-{
-       return 0;
-}
-
-static int polaris10_enable_didt(struct pp_hwmgr *hwmgr, const bool enable)
-{
-
-       uint32_t en = enable ? 1 : 0;
-       int32_t result = 0;
-       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 (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;
-       }
-
-       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;
-       }
-
-       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);
-
-       return result;
-}
-
-static int polaris10_program_pt_config_registers(struct pp_hwmgr *hwmgr,
-                               struct polaris10_pt_config_reg *cac_config_regs)
-{
-       struct polaris10_pt_config_reg *config_regs = cac_config_regs;
-       uint32_t cache = 0;
-       uint32_t data = 0;
-
-       PP_ASSERT_WITH_CODE((config_regs != NULL), "Invalid config register table.", return -EINVAL);
-
-       while (config_regs->offset != 0xFFFFFFFF) {
-               if (config_regs->type == POLARIS10_CONFIGREG_CACHE)
-                       cache |= ((config_regs->value << config_regs->shift) & config_regs->mask);
-               else {
-                       switch (config_regs->type) {
-                       case POLARIS10_CONFIGREG_SMC_IND:
-                               data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, config_regs->offset);
-                               break;
-
-                       case POLARIS10_CONFIGREG_DIDT_IND:
-                               data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, config_regs->offset);
-                               break;
-
-                       case POLARIS10_CONFIGREG_GC_CAC_IND:
-                               data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG_GC_CAC, config_regs->offset);
-                               break;
-
-                       default:
-                               data = cgs_read_register(hwmgr->device, config_regs->offset);
-                               break;
-                       }
-
-                       data &= ~config_regs->mask;
-                       data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
-                       data |= cache;
-
-                       switch (config_regs->type) {
-                       case POLARIS10_CONFIGREG_SMC_IND:
-                               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, config_regs->offset, data);
-                               break;
-
-                       case POLARIS10_CONFIGREG_DIDT_IND:
-                               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, config_regs->offset, data);
-                               break;
-
-                       case POLARIS10_CONFIGREG_GC_CAC_IND:
-                               cgs_write_ind_register(hwmgr->device, CGS_IND_REG_GC_CAC, config_regs->offset, data);
-                               break;
-
-                       default:
-                               cgs_write_register(hwmgr->device, config_regs->offset, data);
-                               break;
-                       }
-                       cache = 0;
-               }
-
-               config_regs++;
-       }
-
-       return 0;
-}
-
-int polaris10_enable_didt_config(struct pp_hwmgr *hwmgr)
-{
-       int result;
-       uint32_t num_se = 0;
-       uint32_t count, value, value2;
-       struct cgs_system_info sys_info = {0};
-
-       sys_info.size = sizeof(struct cgs_system_info);
-       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;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping) ||
-               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 */
-               value = 0;
-               value2 = cgs_read_register(hwmgr->device, mmGRBM_GFX_INDEX);
-               for (count = 0; count < num_se; count++) {
-                       value = SYS_GRBM_GFX_INDEX_DATA__INSTANCE_BROADCAST_WRITES_MASK
-                               | SYS_GRBM_GFX_INDEX_DATA__SH_BROADCAST_WRITES_MASK
-                               | (count << SYS_GRBM_GFX_INDEX_DATA__SE_INDEX__SHIFT);
-                       cgs_write_register(hwmgr->device, mmGRBM_GFX_INDEX, value);
-
-                       if (hwmgr->chip_id == CHIP_POLARIS10) {
-                               result = polaris10_program_pt_config_registers(hwmgr, GCCACConfig_Polaris10);
-                               PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
-                               result = polaris10_program_pt_config_registers(hwmgr, DIDTConfig_Polaris10);
-                               PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
-                       } else if (hwmgr->chip_id == CHIP_POLARIS11) {
-                               result = polaris10_program_pt_config_registers(hwmgr, GCCACConfig_Polaris11);
-                               PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
-                               result = polaris10_program_pt_config_registers(hwmgr, DIDTConfig_Polaris11);
-                               PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
-                       }
-               }
-               cgs_write_register(hwmgr->device, mmGRBM_GFX_INDEX, value2);
-
-               result = polaris10_enable_didt(hwmgr, true);
-               PP_ASSERT_WITH_CODE((result == 0), "EnableDiDt failed.", return result);
-
-               /* TO DO Post DIDT enable clock gating */
-       }
-
-       return 0;
-}
-
-int polaris10_disable_didt_config(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping) ||
-               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 */
-
-               result = polaris10_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 */
-       }
-
-       return 0;
-}
-
-
-static int polaris10_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint16_t hi_sidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
-       uint16_t lo_sidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
-       struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
-
-       hi_sidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
-       lo_sidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
-
-       data->power_tune_table.BapmVddCBaseLeakageHiSidd =
-                       CONVERT_FROM_HOST_TO_SMC_US(hi_sidd);
-       data->power_tune_table.BapmVddCBaseLeakageLoSidd =
-                       CONVERT_FROM_HOST_TO_SMC_US(lo_sidd);
-
-       return 0;
-}
-
-int polaris10_populate_pm_fuses(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint32_t pm_fuse_table_offset;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerContainment)) {
-               if (polaris10_read_smc_sram_dword(hwmgr->smumgr,
-                               SMU7_FIRMWARE_HEADER_LOCATION +
-                               offsetof(SMU74_Firmware_Header, PmFuseTable),
-                               &pm_fuse_table_offset, data->sram_end))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to get pm_fuse_table_offset Failed!",
-                                       return -EINVAL);
-
-               if (polaris10_populate_svi_load_line(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate SviLoadLine Failed!",
-                                       return -EINVAL);
-
-               if (polaris10_populate_tdc_limit(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate TDCLimit Failed!", return -EINVAL);
-
-               if (polaris10_populate_dw8(hwmgr, pm_fuse_table_offset))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate TdcWaterfallCtl, "
-                                       "LPMLTemperature Min and Max Failed!",
-                                       return -EINVAL);
-
-               if (0 != polaris10_populate_temperature_scaler(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate LPMLTemperatureScaler Failed!",
-                                       return -EINVAL);
-
-               if (polaris10_populate_fuzzy_fan(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate Fuzzy Fan Control parameters Failed!",
-                                       return -EINVAL);
-
-               if (polaris10_populate_gnb_lpml(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate GnbLPML Failed!",
-                                       return -EINVAL);
-
-               if (polaris10_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate GnbLPML Min and Max Vid Failed!",
-                                       return -EINVAL);
-
-               if (polaris10_populate_bapm_vddc_base_leakage_sidd(hwmgr))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to populate BapmVddCBaseLeakage Hi and Lo "
-                                       "Sidd Failed!", return -EINVAL);
-
-               if (polaris10_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
-                               (uint8_t *)&data->power_tune_table,
-                               (sizeof(struct SMU74_Discrete_PmFuses) - 92), data->sram_end))
-                       PP_ASSERT_WITH_CODE(false,
-                                       "Attempt to download PmFuseTable Failed!",
-                                       return -EINVAL);
-       }
-       return 0;
-}
-
-int polaris10_enable_smc_cac(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       int result = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_CAC)) {
-               int smc_result;
-               smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                               (uint16_t)(PPSMC_MSG_EnableCac));
-               PP_ASSERT_WITH_CODE((0 == smc_result),
-                               "Failed to enable CAC in SMC.", result = -1);
-
-               data->cac_enabled = (0 == smc_result) ? true : false;
-       }
-       return result;
-}
-
-int polaris10_disable_smc_cac(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       int result = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_CAC) && data->cac_enabled) {
-               int smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                               (uint16_t)(PPSMC_MSG_DisableCac));
-               PP_ASSERT_WITH_CODE((smc_result == 0),
-                               "Failed to disable CAC in SMC.", result = -1);
-
-               data->cac_enabled = false;
-       }
-       return result;
-}
-
-int polaris10_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (data->power_containment_features &
-                       POWERCONTAINMENT_FEATURE_PkgPwrLimit)
-               return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_PkgPwrSetLimit, n);
-       return 0;
-}
-
-static int polaris10_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
-{
-       return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
-                       PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
-}
-
-int polaris10_enable_power_containment(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       int smc_result;
-       int result = 0;
-
-       data->power_containment_features = 0;
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerContainment)) {
-
-               if (data->enable_tdc_limit_feature) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_TDCLimitEnable));
-                       PP_ASSERT_WITH_CODE((0 == smc_result),
-                                       "Failed to enable TDCLimit in SMC.", result = -1;);
-                       if (0 == smc_result)
-                               data->power_containment_features |=
-                                               POWERCONTAINMENT_FEATURE_TDCLimit;
-               }
-
-               if (data->enable_pkg_pwr_tracking_feature) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
-                       PP_ASSERT_WITH_CODE((0 == smc_result),
-                                       "Failed to enable PkgPwrTracking in SMC.", result = -1;);
-                       if (0 == smc_result) {
-                               struct phm_cac_tdp_table *cac_table =
-                                               table_info->cac_dtp_table;
-                               uint32_t default_limit =
-                                       (uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
-
-                               data->power_containment_features |=
-                                               POWERCONTAINMENT_FEATURE_PkgPwrLimit;
-
-                               if (polaris10_set_power_limit(hwmgr, default_limit))
-                                       printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
-                       }
-               }
-       }
-       return result;
-}
-
-int polaris10_disable_power_containment(struct pp_hwmgr *hwmgr)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       int result = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerContainment) &&
-                       data->power_containment_features) {
-               int smc_result;
-
-               if (data->power_containment_features &
-                               POWERCONTAINMENT_FEATURE_TDCLimit) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_TDCLimitDisable));
-                       PP_ASSERT_WITH_CODE((smc_result == 0),
-                                       "Failed to disable TDCLimit in SMC.",
-                                       result = smc_result);
-               }
-
-               if (data->power_containment_features &
-                               POWERCONTAINMENT_FEATURE_DTE) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_DisableDTE));
-                       PP_ASSERT_WITH_CODE((smc_result == 0),
-                                       "Failed to disable DTE in SMC.",
-                                       result = smc_result);
-               }
-
-               if (data->power_containment_features &
-                               POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
-                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
-                                       (uint16_t)(PPSMC_MSG_PkgPwrLimitDisable));
-                       PP_ASSERT_WITH_CODE((smc_result == 0),
-                                       "Failed to disable PkgPwrTracking in SMC.",
-                                       result = smc_result);
-               }
-               data->power_containment_features = 0;
-       }
-
-       return result;
-}
-
-int polaris10_power_control_set_level(struct pp_hwmgr *hwmgr)
-{
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
-       int adjust_percent, target_tdp;
-       int result = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerContainment)) {
-               /* adjustment percentage has already been validated */
-               adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
-                               hwmgr->platform_descriptor.TDPAdjustment :
-                               (-1 * hwmgr->platform_descriptor.TDPAdjustment);
-               /* SMC requested that target_tdp to be 7 bit fraction in DPM table
-                * but message to be 8 bit fraction for messages
-                */
-               target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
-               result = polaris10_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
-       }
-
-       return result;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_powertune.h b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_powertune.h
deleted file mode 100644 (file)
index bc78e28..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2015 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 POLARIS10_POWERTUNE_H
-#define POLARIS10_POWERTUNE_H
-
-enum polaris10_pt_config_reg_type {
-       POLARIS10_CONFIGREG_MMR = 0,
-       POLARIS10_CONFIGREG_SMC_IND,
-       POLARIS10_CONFIGREG_DIDT_IND,
-       POLARIS10_CONFIGREG_GC_CAC_IND,
-       POLARIS10_CONFIGREG_CACHE,
-       POLARIS10_CONFIGREG_MAX
-};
-
-#define DIDT_SQ_CTRL0__UNUSED_0_MASK    0xfffc0000
-#define DIDT_SQ_CTRL0__UNUSED_0__SHIFT  0x12
-#define DIDT_TD_CTRL0__UNUSED_0_MASK    0xfffc0000
-#define DIDT_TD_CTRL0__UNUSED_0__SHIFT  0x12
-#define DIDT_TCP_CTRL0__UNUSED_0_MASK   0xfffc0000
-#define DIDT_TCP_CTRL0__UNUSED_0__SHIFT 0x12
-#define DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK                 0xc0000000
-#define DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT               0x0000001e
-#define DIDT_TD_TUNING_CTRL__UNUSED_0_MASK                 0xc0000000
-#define DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT               0x0000001e
-#define DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK                0xc0000000
-#define DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT              0x0000001e
-
-/* PowerContainment Features */
-#define POWERCONTAINMENT_FEATURE_DTE             0x00000001
-#define POWERCONTAINMENT_FEATURE_TDCLimit        0x00000002
-#define POWERCONTAINMENT_FEATURE_PkgPwrLimit     0x00000004
-
-#define ixGC_CAC_CNTL 0x0000
-#define ixDIDT_SQ_STALL_CTRL 0x0004
-#define  ixDIDT_SQ_TUNING_CTRL 0x0005
-#define ixDIDT_TD_STALL_CTRL 0x0044
-#define ixDIDT_TD_TUNING_CTRL 0x0045
-#define ixDIDT_TCP_STALL_CTRL 0x0064
-#define ixDIDT_TCP_TUNING_CTRL 0x0065
-
-struct polaris10_pt_config_reg {
-       uint32_t                           offset;
-       uint32_t                           mask;
-       uint32_t                           shift;
-       uint32_t                           value;
-       enum polaris10_pt_config_reg_type       type;
-};
-
-struct polaris10_pt_defaults {
-       uint8_t   SviLoadLineEn;
-       uint8_t   SviLoadLineVddC;
-       uint8_t   TDC_VDDC_ThrottleReleaseLimitPerc;
-       uint8_t   TDC_MAWt;
-       uint8_t   TdcWaterfallCtl;
-       uint8_t   DTEAmbientTempBase;
-
-       uint32_t  DisplayCac;
-       uint32_t  BAPM_TEMP_GRADIENT;
-       uint16_t  BAPMTI_R[SMU74_DTE_ITERATIONS * SMU74_DTE_SOURCES * SMU74_DTE_SINKS];
-       uint16_t  BAPMTI_RC[SMU74_DTE_ITERATIONS * SMU74_DTE_SOURCES * SMU74_DTE_SINKS];
-};
-
-void polaris10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
-int polaris10_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
-int polaris10_populate_pm_fuses(struct pp_hwmgr *hwmgr);
-int polaris10_enable_smc_cac(struct pp_hwmgr *hwmgr);
-int polaris10_disable_smc_cac(struct pp_hwmgr *hwmgr);
-int polaris10_enable_power_containment(struct pp_hwmgr *hwmgr);
-int polaris10_disable_power_containment(struct pp_hwmgr *hwmgr);
-int polaris10_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
-int polaris10_power_control_set_level(struct pp_hwmgr *hwmgr);
-int polaris10_enable_didt_config(struct pp_hwmgr *hwmgr);
-#endif  /* POLARIS10_POWERTUNE_H */
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_thermal.c
deleted file mode 100644 (file)
index b206632..0000000
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * 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 <asm/div64.h>
-#include "polaris10_thermal.h"
-#include "polaris10_hwmgr.h"
-#include "polaris10_smumgr.h"
-#include "polaris10_ppsmc.h"
-#include "smu/smu_7_1_3_d.h"
-#include "smu/smu_7_1_3_sh_mask.h"
-
-int polaris10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
-               struct phm_fan_speed_info *fan_speed_info)
-{
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       fan_speed_info->supports_percent_read = true;
-       fan_speed_info->supports_percent_write = true;
-       fan_speed_info->min_percent = 0;
-       fan_speed_info->max_percent = 100;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
-               hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
-               fan_speed_info->supports_rpm_read = true;
-               fan_speed_info->supports_rpm_write = true;
-               fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
-               fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
-       } else {
-               fan_speed_info->min_rpm = 0;
-               fan_speed_info->max_rpm = 0;
-       }
-
-       return 0;
-}
-
-int polaris10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
-               uint32_t *speed)
-{
-       uint32_t duty100;
-       uint32_t duty;
-       uint64_t tmp64;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL1, FMAX_DUTY100);
-       duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_STATUS, FDO_PWM_DUTY);
-
-       if (duty100 == 0)
-               return -EINVAL;
-
-
-       tmp64 = (uint64_t)duty * 100;
-       do_div(tmp64, duty100);
-       *speed = (uint32_t)tmp64;
-
-       if (*speed > 100)
-               *speed = 100;
-
-       return 0;
-}
-
-int polaris10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
-{
-       uint32_t tach_period;
-       uint32_t crystal_clock_freq;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan ||
-                       (hwmgr->thermal_controller.fanInfo.
-                               ucTachometerPulsesPerRevolution == 0))
-               return 0;
-
-       tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_TACH_STATUS, TACH_PERIOD);
-
-       if (tach_period == 0)
-               return -EINVAL;
-
-       crystal_clock_freq = tonga_get_xclk(hwmgr);
-
-       *speed = 60 * crystal_clock_freq * 10000 / tach_period;
-
-       return 0;
-}
-
-/**
-* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
-* @param    hwmgr  the address of the powerplay hardware manager.
-*           mode    the fan control mode, 0 default, 1 by percent, 5, by RPM
-* @exception Should always succeed.
-*/
-int polaris10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
-{
-
-       if (hwmgr->fan_ctrl_is_in_default_mode) {
-               hwmgr->fan_ctrl_default_mode =
-                               PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,     CGS_IND_REG__SMC,
-                                               CG_FDO_CTRL2, FDO_PWM_MODE);
-               hwmgr->tmin =
-                               PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                                               CG_FDO_CTRL2, TMIN);
-               hwmgr->fan_ctrl_is_in_default_mode = false;
-       }
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL2, TMIN, 0);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL2, FDO_PWM_MODE, mode);
-
-       return 0;
-}
-
-/**
-* Reset Fan Speed Control to default mode.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @exception Should always succeed.
-*/
-int polaris10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
-{
-       if (!hwmgr->fan_ctrl_is_in_default_mode) {
-               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
-               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_FDO_CTRL2, TMIN, hwmgr->tmin);
-               hwmgr->fan_ctrl_is_in_default_mode = true;
-       }
-
-       return 0;
-}
-
-int polaris10_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
-               cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
-               result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_FanSpeedInTableIsRPM))
-                       hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
-                                       hwmgr->thermal_controller.
-                                       advanceFanControlParameters.usMaxFanRPM);
-               else
-                       hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
-                                       hwmgr->thermal_controller.
-                                       advanceFanControlParameters.usMaxFanPWM);
-
-       } else {
-               cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
-               result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
-       }
-
-       if (!result && hwmgr->thermal_controller.
-                       advanceFanControlParameters.ucTargetTemperature)
-               result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_SetFanTemperatureTarget,
-                               hwmgr->thermal_controller.
-                               advanceFanControlParameters.ucTargetTemperature);
-
-       return result;
-}
-
-
-int polaris10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
-}
-
-/**
-* Set Fan Speed in percent.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    speed is the percentage value (0% - 100%) to be set.
-* @exception Fails is the 100% setting appears to be 0.
-*/
-int polaris10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
-               uint32_t speed)
-{
-       uint32_t duty100;
-       uint32_t duty;
-       uint64_t tmp64;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       if (speed > 100)
-               speed = 100;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_MicrocodeFanControl))
-               polaris10_fan_ctrl_stop_smc_fan_control(hwmgr);
-
-       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL1, FMAX_DUTY100);
-
-       if (duty100 == 0)
-               return -EINVAL;
-
-       tmp64 = (uint64_t)speed * duty100;
-       do_div(tmp64, 100);
-       duty = (uint32_t)tmp64;
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
-
-       return polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-}
-
-/**
-* Reset Fan Speed to default.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @exception Always succeeds.
-*/
-int polaris10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_MicrocodeFanControl)) {
-               result = polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-               if (!result)
-                       result = polaris10_fan_ctrl_start_smc_fan_control(hwmgr);
-       } else
-               result = polaris10_fan_ctrl_set_default_mode(hwmgr);
-
-       return result;
-}
-
-/**
-* Set Fan Speed in RPM.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    speed is the percentage value (min - max) to be set.
-* @exception Fails is the speed not lie between min and max.
-*/
-int polaris10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
-{
-       uint32_t tach_period;
-       uint32_t crystal_clock_freq;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan ||
-                       (hwmgr->thermal_controller.fanInfo.
-                       ucTachometerPulsesPerRevolution == 0) ||
-                       (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
-                       (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
-               return 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_MicrocodeFanControl))
-               polaris10_fan_ctrl_stop_smc_fan_control(hwmgr);
-
-       crystal_clock_freq = tonga_get_xclk(hwmgr);
-
-       tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_TACH_STATUS, TACH_PERIOD, tach_period);
-
-       return polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-}
-
-/**
-* Reads the remote temperature from the SIslands thermal controller.
-*
-* @param    hwmgr The address of the hardware manager.
-*/
-int polaris10_thermal_get_temperature(struct pp_hwmgr *hwmgr)
-{
-       int temp;
-
-       temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_MULT_THERMAL_STATUS, CTF_TEMP);
-
-       /* Bit 9 means the reading is lower than the lowest usable value. */
-       if (temp & 0x200)
-               temp = POLARIS10_THERMAL_MAXIMUM_TEMP_READING;
-       else
-               temp = temp & 0x1ff;
-
-       temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-
-       return temp;
-}
-
-/**
-* Set the requested temperature range for high and low alert signals
-*
-* @param    hwmgr The address of the hardware manager.
-* @param    range Temperature range to be programmed for high and low alert signals
-* @exception PP_Result_BadInput if the input data is not valid.
-*/
-static int polaris10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
-               uint32_t low_temp, uint32_t high_temp)
-{
-       uint32_t low = POLARIS10_THERMAL_MINIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-       uint32_t high = POLARIS10_THERMAL_MAXIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-
-       if (low < low_temp)
-               low = low_temp;
-       if (high > high_temp)
-               high = high_temp;
-
-       if (low > high)
-               return -EINVAL;
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, DIG_THERM_INTH,
-                       (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, DIG_THERM_INTL,
-                       (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_CTRL, DIG_THERM_DPM,
-                       (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-
-       return 0;
-}
-
-/**
-* Programs thermal controller one-time setting registers
-*
-* @param    hwmgr The address of the hardware manager.
-*/
-static int polaris10_thermal_initialize(struct pp_hwmgr *hwmgr)
-{
-       if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
-               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_TACH_CTRL, EDGE_PER_REV,
-                               hwmgr->thermal_controller.fanInfo.
-                               ucTachometerPulsesPerRevolution - 1);
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
-
-       return 0;
-}
-
-/**
-* Enable thermal alerts on the RV770 thermal controller.
-*
-* @param    hwmgr The address of the hardware manager.
-*/
-static int polaris10_thermal_enable_alert(struct pp_hwmgr *hwmgr)
-{
-       uint32_t alert;
-
-       alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, THERM_INT_MASK);
-       alert &= ~(POLARIS10_THERMAL_HIGH_ALERT_MASK | POLARIS10_THERMAL_LOW_ALERT_MASK);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, THERM_INT_MASK, alert);
-
-       /* send message to SMU to enable internal thermal interrupts */
-       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable);
-}
-
-/**
-* Disable thermal alerts on the RV770 thermal controller.
-* @param    hwmgr The address of the hardware manager.
-*/
-static int polaris10_thermal_disable_alert(struct pp_hwmgr *hwmgr)
-{
-       uint32_t alert;
-
-       alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, THERM_INT_MASK);
-       alert |= (POLARIS10_THERMAL_HIGH_ALERT_MASK | POLARIS10_THERMAL_LOW_ALERT_MASK);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_THERMAL_INT, THERM_INT_MASK, alert);
-
-       /* send message to SMU to disable internal thermal interrupts */
-       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable);
-}
-
-/**
-* Uninitialize the thermal controller.
-* Currently just disables alerts.
-* @param    hwmgr The address of the hardware manager.
-*/
-int polaris10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
-{
-       int result = polaris10_thermal_disable_alert(hwmgr);
-
-       if (!hwmgr->thermal_controller.fanInfo.bNoFan)
-               polaris10_fan_ctrl_set_default_mode(hwmgr);
-
-       return result;
-}
-
-/**
-* Set up the fan table to control the fan using the SMC.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from set temperature range routine
-*/
-int tf_polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       SMU74_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
-       uint32_t duty100;
-       uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
-       uint16_t fdo_min, slope1, slope2;
-       uint32_t reference_clock;
-       int res;
-       uint64_t tmp64;
-
-       if (data->fan_table_start == 0) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_MicrocodeFanControl);
-               return 0;
-       }
-
-       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                       CG_FDO_CTRL1, FMAX_DUTY100);
-
-       if (duty100 == 0) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_MicrocodeFanControl);
-               return 0;
-       }
-
-       tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
-                       usPWMMin * duty100;
-       do_div(tmp64, 10000);
-       fdo_min = (uint16_t)tmp64;
-
-       t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
-                       hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
-       t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
-                       hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
-
-       pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
-                       hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
-       pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
-                       hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
-
-       slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
-       slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
-
-       fan_table.TempMin = cpu_to_be16((50 + hwmgr->
-                       thermal_controller.advanceFanControlParameters.usTMin) / 100);
-       fan_table.TempMed = cpu_to_be16((50 + hwmgr->
-                       thermal_controller.advanceFanControlParameters.usTMed) / 100);
-       fan_table.TempMax = cpu_to_be16((50 + hwmgr->
-                       thermal_controller.advanceFanControlParameters.usTMax) / 100);
-
-       fan_table.Slope1 = cpu_to_be16(slope1);
-       fan_table.Slope2 = cpu_to_be16(slope2);
-
-       fan_table.FdoMin = cpu_to_be16(fdo_min);
-
-       fan_table.HystDown = cpu_to_be16(hwmgr->
-                       thermal_controller.advanceFanControlParameters.ucTHyst);
-
-       fan_table.HystUp = cpu_to_be16(1);
-
-       fan_table.HystSlope = cpu_to_be16(1);
-
-       fan_table.TempRespLim = cpu_to_be16(5);
-
-       reference_clock = tonga_get_xclk(hwmgr);
-
-       fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
-                       thermal_controller.advanceFanControlParameters.ulCycleDelay *
-                       reference_clock) / 1600);
-
-       fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
-
-       fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
-                       hwmgr->device, CGS_IND_REG__SMC,
-                       CG_MULT_THERMAL_CTRL, TEMP_SEL);
-
-       res = polaris10_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start,
-                       (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
-                       data->sram_end);
-
-       if (!res && hwmgr->thermal_controller.
-                       advanceFanControlParameters.ucMinimumPWMLimit)
-               res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_SetFanMinPwm,
-                               hwmgr->thermal_controller.
-                               advanceFanControlParameters.ucMinimumPWMLimit);
-
-       if (!res && hwmgr->thermal_controller.
-                       advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
-               res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                               PPSMC_MSG_SetFanSclkTarget,
-                               hwmgr->thermal_controller.
-                               advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
-
-       if (res)
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_MicrocodeFanControl);
-
-       return 0;
-}
-
-/**
-* Start the fan control on the SMC.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from set temperature range routine
-*/
-int tf_polaris10_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-/* If the fantable setup has failed we could have disabled
- * PHM_PlatformCaps_MicrocodeFanControl even after
- * this function was included in the table.
- * Make sure that we still think controlling the fan is OK.
-*/
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_MicrocodeFanControl)) {
-               polaris10_fan_ctrl_start_smc_fan_control(hwmgr);
-               polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-       }
-
-       return 0;
-}
-
-/**
-* Set temperature range for high and low alerts
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from set temperature range routine
-*/
-int tf_polaris10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-       struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
-
-       if (range == NULL)
-               return -EINVAL;
-
-       return polaris10_thermal_set_temperature_range(hwmgr, range->min, range->max);
-}
-
-/**
-* Programs one-time setting registers
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from initialize thermal controller routine
-*/
-int tf_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-    return polaris10_thermal_initialize(hwmgr);
-}
-
-/**
-* Enable high and low alerts
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from enable alert routine
-*/
-int tf_polaris10_thermal_enable_alert(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-       return polaris10_thermal_enable_alert(hwmgr);
-}
-
-/**
-* Disable high and low alerts
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from disable alert routine
-*/
-static int tf_polaris10_thermal_disable_alert(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-       return polaris10_thermal_disable_alert(hwmgr);
-}
-
-static int tf_polaris10_thermal_avfs_enable(struct pp_hwmgr *hwmgr,
-               void *input, void *output, void *storage, int result)
-{
-       int ret;
-       struct pp_smumgr *smumgr = (struct pp_smumgr *)(hwmgr->smumgr);
-       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED)
-               return 0;
-
-       ret = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                       PPSMC_MSG_SetGBDroopSettings, data->avfs_vdroop_override_setting);
-
-       ret = (smum_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs) == 0) ?
-                       0 : -1;
-
-       if (!ret)
-               /* If this param is not changed, this function could fire unnecessarily */
-               smu_data->avfs.avfs_btc_status = AVFS_BTC_COMPLETED_PREVIOUSLY;
-
-       return ret;
-}
-
-static const struct phm_master_table_item
-polaris10_thermal_start_thermal_controller_master_list[] = {
-       {NULL, tf_polaris10_thermal_initialize},
-       {NULL, tf_polaris10_thermal_set_temperature_range},
-       {NULL, tf_polaris10_thermal_enable_alert},
-       {NULL, tf_polaris10_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, tf_polaris10_thermal_setup_fan_table},
-       {NULL, tf_polaris10_thermal_start_smc_fan_control},
-       {NULL, NULL}
-};
-
-static const struct phm_master_table_header
-polaris10_thermal_start_thermal_controller_master = {
-       0,
-       PHM_MasterTableFlag_None,
-       polaris10_thermal_start_thermal_controller_master_list
-};
-
-static const struct phm_master_table_item
-polaris10_thermal_set_temperature_range_master_list[] = {
-       {NULL, tf_polaris10_thermal_disable_alert},
-       {NULL, tf_polaris10_thermal_set_temperature_range},
-       {NULL, tf_polaris10_thermal_enable_alert},
-       {NULL, NULL}
-};
-
-static const struct phm_master_table_header
-polaris10_thermal_set_temperature_range_master = {
-       0,
-       PHM_MasterTableFlag_None,
-       polaris10_thermal_set_temperature_range_master_list
-};
-
-int polaris10_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
-{
-       if (!hwmgr->thermal_controller.fanInfo.bNoFan)
-               polaris10_fan_ctrl_set_default_mode(hwmgr);
-       return 0;
-}
-
-/**
-* Initializes the thermal controller related functions in the Hardware Manager structure.
-* @param    hwmgr The address of the hardware manager.
-* @exception Any error code from the low-level communication.
-*/
-int pp_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       result = phm_construct_table(hwmgr,
-                       &polaris10_thermal_set_temperature_range_master,
-                       &(hwmgr->set_temperature_range));
-
-       if (!result) {
-               result = phm_construct_table(hwmgr,
-                               &polaris10_thermal_start_thermal_controller_master,
-                               &(hwmgr->start_thermal_controller));
-               if (result)
-                       phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
-       }
-
-       if (!result)
-               hwmgr->fan_ctrl_is_in_default_mode = true;
-       return result;
-}
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_thermal.h
deleted file mode 100644 (file)
index 62f8cbc..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.
- *
- */
-
-#ifndef _POLARIS10_THERMAL_H_
-#define _POLARIS10_THERMAL_H_
-
-#include "hwmgr.h"
-
-#define POLARIS10_THERMAL_HIGH_ALERT_MASK         0x1
-#define POLARIS10_THERMAL_LOW_ALERT_MASK          0x2
-
-#define POLARIS10_THERMAL_MINIMUM_TEMP_READING    -256
-#define POLARIS10_THERMAL_MAXIMUM_TEMP_READING    255
-
-#define POLARIS10_THERMAL_MINIMUM_ALERT_TEMP      0
-#define POLARIS10_THERMAL_MAXIMUM_ALERT_TEMP      255
-
-#define FDO_PWM_MODE_STATIC  1
-#define FDO_PWM_MODE_STATIC_RPM 5
-
-
-extern int tf_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
-extern int tf_polaris10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
-extern int tf_polaris10_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
-
-extern int polaris10_thermal_get_temperature(struct pp_hwmgr *hwmgr);
-extern int polaris10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
-extern int polaris10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
-extern int polaris10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
-extern int polaris10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
-extern int polaris10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
-extern int polaris10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
-extern int polaris10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
-extern int pp_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr);
-extern int polaris10_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
-extern int polaris10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
-extern int polaris10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
-extern int polaris10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
-extern uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
-
-#endif
-
index 26f3e30..1126bd4 100644 (file)
@@ -22,7 +22,6 @@
  */
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/fb.h>
 
 #include "ppatomctrl.h"
 #include "atombios.h"
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pptable_v1_0.h b/drivers/gpu/drm/amd/powerplay/hwmgr/pptable_v1_0.h
new file mode 100644 (file)
index 0000000..1e870f5
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2015 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 TONGA_PPTABLE_H
+#define TONGA_PPTABLE_H
+
+/** \file
+ * This is a PowerPlay table header file
+ */
+#pragma pack(push, 1)
+
+#include "hwmgr.h"
+
+#define ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f
+#define ATOM_TONGA_PP_FANPARAMETERS_NOFAN                                 0x80    /* No fan is connected to this controller. */
+
+#define ATOM_TONGA_PP_THERMALCONTROLLER_NONE      0
+#define ATOM_TONGA_PP_THERMALCONTROLLER_LM96163   17
+#define ATOM_TONGA_PP_THERMALCONTROLLER_TONGA     21
+#define ATOM_TONGA_PP_THERMALCONTROLLER_FIJI      22
+
+/*
+ * Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
+ * We probably should reserve the bit 0x80 for this use.
+ * To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here).
+ * The driver can pick the correct internal controller based on the ASIC.
+ */
+
+#define ATOM_TONGA_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL   0x89    /* ADT7473 Fan Control + Internal Thermal Controller */
+#define ATOM_TONGA_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL   0x8D    /* EMC2103 Fan Control + Internal Thermal Controller */
+
+/*/* ATOM_TONGA_POWERPLAYTABLE::ulPlatformCaps */
+#define ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL              0x1            /* This cap indicates whether vddgfx will be a separated power rail. */
+#define ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY                   0x2            /* This cap indicates whether this is a mobile part and CCC need to show Powerplay page. */
+#define ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE            0x4            /* This cap indicates whether power source notificaiton is done by SBIOS directly. */
+#define ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND      0x8            /* Enable the option to overwrite voltage island feature to be disabled, regardless of VddGfx power rail support. */
+#define ____RETIRE16____                                0x10
+#define ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC                 0x20            /* This cap indicates whether power source notificaiton is done by GPIO directly. */
+#define ____RETIRE64____                                0x40
+#define ____RETIRE128____                               0x80
+#define ____RETIRE256____                              0x100
+#define ____RETIRE512____                              0x200
+#define ____RETIRE1024____                             0x400
+#define ____RETIRE2048____                             0x800
+#define ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL             0x1000            /* This cap indicates dynamic MVDD is required. Uncheck to disable it. */
+#define ____RETIRE2000____                            0x2000
+#define ____RETIRE4000____                            0x4000
+#define ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL            0x8000            /* This cap indicates dynamic VDDCI is required. Uncheck to disable it. */
+#define ____RETIRE10000____                          0x10000
+#define ATOM_TONGA_PP_PLATFORM_CAP_BACO                    0x20000            /* Enable to indicate the driver supports BACO state. */
+
+#define ATOM_TONGA_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17         0x100000     /* Enable to indicate the driver supports thermal2GPIO17. */
+#define ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL  0x1000000     /* Enable to indicate if thermal and PCC are sharing the same GPIO */
+#define ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE       0x2000000
+
+/* ATOM_PPLIB_NONCLOCK_INFO::usClassification */
+#define ATOM_PPLIB_CLASSIFICATION_UI_MASK               0x0007
+#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT              0
+#define ATOM_PPLIB_CLASSIFICATION_UI_NONE               0
+#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY            1
+#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED           3
+#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE        5
+/* 2, 4, 6, 7 are reserved */
+
+#define ATOM_PPLIB_CLASSIFICATION_BOOT                  0x0008
+#define ATOM_PPLIB_CLASSIFICATION_THERMAL               0x0010
+#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE    0x0020
+#define ATOM_PPLIB_CLASSIFICATION_REST                  0x0040
+#define ATOM_PPLIB_CLASSIFICATION_FORCED                0x0080
+#define ATOM_PPLIB_CLASSIFICATION_ACPI                  0x1000
+
+/* ATOM_PPLIB_NONCLOCK_INFO::usClassification2 */
+#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001
+
+#define ATOM_Tonga_DISALLOW_ON_DC                       0x00004000
+#define ATOM_Tonga_ENABLE_VARIBRIGHT                    0x00008000
+
+#define ATOM_Tonga_TABLE_REVISION_TONGA                 7
+
+typedef struct _ATOM_Tonga_POWERPLAYTABLE {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+
+       UCHAR  ucTableRevision;
+       USHORT usTableSize;                                             /*the size of header structure */
+
+       ULONG   ulGoldenPPID;
+       ULONG   ulGoldenRevision;
+       USHORT  usFormatID;
+
+       USHORT  usVoltageTime;                                   /*in microseconds */
+       ULONG   ulPlatformCaps;                                   /*See ATOM_Tonga_CAPS_* */
+
+       ULONG   ulMaxODEngineClock;                        /*For Overdrive.  */
+       ULONG   ulMaxODMemoryClock;                        /*For Overdrive. */
+
+       USHORT  usPowerControlLimit;
+       USHORT  usUlvVoltageOffset;                               /*in mv units */
+
+       USHORT  usStateArrayOffset;                               /*points to ATOM_Tonga_State_Array */
+       USHORT  usFanTableOffset;                                 /*points to ATOM_Tonga_Fan_Table */
+       USHORT  usThermalControllerOffset;                 /*points to ATOM_Tonga_Thermal_Controller */
+       USHORT  usReserv;                                                  /*CustomThermalPolicy removed for Tonga. Keep this filed as reserved. */
+
+       USHORT  usMclkDependencyTableOffset;       /*points to ATOM_Tonga_MCLK_Dependency_Table */
+       USHORT  usSclkDependencyTableOffset;       /*points to ATOM_Tonga_SCLK_Dependency_Table */
+       USHORT  usVddcLookupTableOffset;                   /*points to ATOM_Tonga_Voltage_Lookup_Table */
+       USHORT  usVddgfxLookupTableOffset;              /*points to ATOM_Tonga_Voltage_Lookup_Table */
+
+       USHORT  usMMDependencyTableOffset;                /*points to ATOM_Tonga_MM_Dependency_Table */
+
+       USHORT  usVCEStateTableOffset;                     /*points to ATOM_Tonga_VCE_State_Table; */
+
+       USHORT  usPPMTableOffset;                                 /*points to ATOM_Tonga_PPM_Table */
+       USHORT  usPowerTuneTableOffset;                   /*points to ATOM_PowerTune_Table */
+
+       USHORT  usHardLimitTableOffset;                    /*points to ATOM_Tonga_Hard_Limit_Table */
+
+       USHORT  usPCIETableOffset;                                /*points to ATOM_Tonga_PCIE_Table */
+
+       USHORT  usGPIOTableOffset;                                /*points to ATOM_Tonga_GPIO_Table */
+
+       USHORT  usReserved[6];                                     /*TODO: modify reserved size to fit structure aligning */
+} ATOM_Tonga_POWERPLAYTABLE;
+
+typedef struct _ATOM_Tonga_State {
+       UCHAR  ucEngineClockIndexHigh;
+       UCHAR  ucEngineClockIndexLow;
+
+       UCHAR  ucMemoryClockIndexHigh;
+       UCHAR  ucMemoryClockIndexLow;
+
+       UCHAR  ucPCIEGenLow;
+       UCHAR  ucPCIEGenHigh;
+
+       UCHAR  ucPCIELaneLow;
+       UCHAR  ucPCIELaneHigh;
+
+       USHORT usClassification;
+       ULONG ulCapsAndSettings;
+       USHORT usClassification2;
+       UCHAR  ucUnused[4];
+} ATOM_Tonga_State;
+
+typedef struct _ATOM_Tonga_State_Array {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;             /* Number of entries. */
+       ATOM_Tonga_State entries[1];    /* Dynamically allocate entries. */
+} ATOM_Tonga_State_Array;
+
+typedef struct _ATOM_Tonga_MCLK_Dependency_Record {
+       UCHAR  ucVddcInd;       /* Vddc voltage */
+       USHORT usVddci;
+       USHORT usVddgfxOffset;  /* Offset relative to Vddc voltage */
+       USHORT usMvdd;
+       ULONG ulMclk;
+       USHORT usReserved;
+} ATOM_Tonga_MCLK_Dependency_Record;
+
+typedef struct _ATOM_Tonga_MCLK_Dependency_Table {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;                                                                             /* Number of entries. */
+       ATOM_Tonga_MCLK_Dependency_Record entries[1];                           /* Dynamically allocate entries. */
+} ATOM_Tonga_MCLK_Dependency_Table;
+
+typedef struct _ATOM_Tonga_SCLK_Dependency_Record {
+       UCHAR  ucVddInd;                                                                                        /* Base voltage */
+       USHORT usVddcOffset;                                                                            /* Offset relative to base voltage */
+       ULONG ulSclk;
+       USHORT usEdcCurrent;
+       UCHAR  ucReliabilityTemperature;
+       UCHAR  ucCKSVOffsetandDisable;                                                    /* Bits 0~6: Voltage offset for CKS, Bit 7: Disable/enable for the SCLK level. */
+} ATOM_Tonga_SCLK_Dependency_Record;
+
+typedef struct _ATOM_Tonga_SCLK_Dependency_Table {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;                                                                             /* Number of entries. */
+       ATOM_Tonga_SCLK_Dependency_Record entries[1];                            /* Dynamically allocate entries. */
+} ATOM_Tonga_SCLK_Dependency_Table;
+
+typedef struct _ATOM_Polaris_SCLK_Dependency_Record {
+       UCHAR  ucVddInd;                                                                                        /* Base voltage */
+       USHORT usVddcOffset;                                                                            /* Offset relative to base voltage */
+       ULONG ulSclk;
+       USHORT usEdcCurrent;
+       UCHAR  ucReliabilityTemperature;
+       UCHAR  ucCKSVOffsetandDisable;                  /* Bits 0~6: Voltage offset for CKS, Bit 7: Disable/enable for the SCLK level. */
+       ULONG  ulSclkOffset;
+} ATOM_Polaris_SCLK_Dependency_Record;
+
+typedef struct _ATOM_Polaris_SCLK_Dependency_Table {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;                                                     /* Number of entries. */
+       ATOM_Polaris_SCLK_Dependency_Record entries[1];                          /* Dynamically allocate entries. */
+} ATOM_Polaris_SCLK_Dependency_Table;
+
+typedef struct _ATOM_Tonga_PCIE_Record {
+       UCHAR ucPCIEGenSpeed;
+       UCHAR usPCIELaneWidth;
+       UCHAR ucReserved[2];
+} ATOM_Tonga_PCIE_Record;
+
+typedef struct _ATOM_Tonga_PCIE_Table {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;                                                                             /* Number of entries. */
+       ATOM_Tonga_PCIE_Record entries[1];                                                      /* Dynamically allocate entries. */
+} ATOM_Tonga_PCIE_Table;
+
+typedef struct _ATOM_Polaris10_PCIE_Record {
+       UCHAR ucPCIEGenSpeed;
+       UCHAR usPCIELaneWidth;
+       UCHAR ucReserved[2];
+       ULONG ulPCIE_Sclk;
+} ATOM_Polaris10_PCIE_Record;
+
+typedef struct _ATOM_Polaris10_PCIE_Table {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;                                         /* Number of entries. */
+       ATOM_Polaris10_PCIE_Record entries[1];                      /* Dynamically allocate entries. */
+} ATOM_Polaris10_PCIE_Table;
+
+
+typedef struct _ATOM_Tonga_MM_Dependency_Record {
+       UCHAR   ucVddcInd;                                                                                       /* VDDC voltage */
+       USHORT  usVddgfxOffset;                                                                   /* Offset relative to VDDC voltage */
+       ULONG  ulDClk;                                                                                          /* UVD D-clock */
+       ULONG  ulVClk;                                                                                          /* UVD V-clock */
+       ULONG  ulEClk;                                                                                          /* VCE clock */
+       ULONG  ulAClk;                                                                                          /* ACP clock */
+       ULONG  ulSAMUClk;                                                                                       /* SAMU clock */
+} ATOM_Tonga_MM_Dependency_Record;
+
+typedef struct _ATOM_Tonga_MM_Dependency_Table {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;                                                                             /* Number of entries. */
+       ATOM_Tonga_MM_Dependency_Record entries[1];                        /* Dynamically allocate entries. */
+} ATOM_Tonga_MM_Dependency_Table;
+
+typedef struct _ATOM_Tonga_Voltage_Lookup_Record {
+       USHORT usVdd;                                                                                      /* Base voltage */
+       USHORT usCACLow;
+       USHORT usCACMid;
+       USHORT usCACHigh;
+} ATOM_Tonga_Voltage_Lookup_Record;
+
+typedef struct _ATOM_Tonga_Voltage_Lookup_Table {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;                                                                             /* Number of entries. */
+       ATOM_Tonga_Voltage_Lookup_Record entries[1];                            /* Dynamically allocate entries. */
+} ATOM_Tonga_Voltage_Lookup_Table;
+
+typedef struct _ATOM_Tonga_Fan_Table {
+       UCHAR   ucRevId;                                                 /* Change this if the table format changes or version changes so that the other fields are not the same. */
+       UCHAR   ucTHyst;                                                 /* Temperature hysteresis. Integer. */
+       USHORT  usTMin;                                                  /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
+       USHORT  usTMed;                                                  /* The middle temperature where we change slopes. */
+       USHORT  usTHigh;                                                 /* The high point above TMed for adjusting the second slope. */
+       USHORT  usPWMMin;                                                /* The minimum PWM value in percent (0.01% increments). */
+       USHORT  usPWMMed;                                                /* The PWM value (in percent) at TMed. */
+       USHORT  usPWMHigh;                                               /* The PWM value at THigh. */
+       USHORT  usTMax;                                                  /* The max temperature */
+       UCHAR   ucFanControlMode;                                 /* Legacy or Fuzzy Fan mode */
+       USHORT  usFanPWMMax;                                      /* Maximum allowed fan power in percent */
+       USHORT  usFanOutputSensitivity;           /* Sensitivity of fan reaction to temepature changes */
+       USHORT  usFanRPMMax;                                      /* The default value in RPM */
+       ULONG  ulMinFanSCLKAcousticLimit;          /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
+       UCHAR   ucTargetTemperature;                     /* Advanced fan controller target temperature. */
+       UCHAR   ucMinimumPWMLimit;                        /* The minimum PWM that the advanced fan controller can set.  This should be set to the highest PWM that will run the fan at its lowest RPM. */
+       USHORT  usReserved;
+} ATOM_Tonga_Fan_Table;
+
+typedef struct _ATOM_Fiji_Fan_Table {
+       UCHAR   ucRevId;                                                 /* Change this if the table format changes or version changes so that the other fields are not the same. */
+       UCHAR   ucTHyst;                                                 /* Temperature hysteresis. Integer. */
+       USHORT  usTMin;                                                  /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
+       USHORT  usTMed;                                                  /* The middle temperature where we change slopes. */
+       USHORT  usTHigh;                                                 /* The high point above TMed for adjusting the second slope. */
+       USHORT  usPWMMin;                                                /* The minimum PWM value in percent (0.01% increments). */
+       USHORT  usPWMMed;                                                /* The PWM value (in percent) at TMed. */
+       USHORT  usPWMHigh;                                               /* The PWM value at THigh. */
+       USHORT  usTMax;                                                  /* The max temperature */
+       UCHAR   ucFanControlMode;                                 /* Legacy or Fuzzy Fan mode */
+       USHORT  usFanPWMMax;                                      /* Maximum allowed fan power in percent */
+       USHORT  usFanOutputSensitivity;           /* Sensitivity of fan reaction to temepature changes */
+       USHORT  usFanRPMMax;                                      /* The default value in RPM */
+       ULONG  ulMinFanSCLKAcousticLimit;               /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
+       UCHAR   ucTargetTemperature;                     /* Advanced fan controller target temperature. */
+       UCHAR   ucMinimumPWMLimit;                        /* The minimum PWM that the advanced fan controller can set.  This should be set to the highest PWM that will run the fan at its lowest RPM. */
+       USHORT  usFanGainEdge;
+       USHORT  usFanGainHotspot;
+       USHORT  usFanGainLiquid;
+       USHORT  usFanGainVrVddc;
+       USHORT  usFanGainVrMvdd;
+       USHORT  usFanGainPlx;
+       USHORT  usFanGainHbm;
+       USHORT  usReserved;
+} ATOM_Fiji_Fan_Table;
+
+typedef struct _ATOM_Tonga_Thermal_Controller {
+       UCHAR ucRevId;
+       UCHAR ucType;              /* one of ATOM_TONGA_PP_THERMALCONTROLLER_* */
+       UCHAR ucI2cLine;                /* as interpreted by DAL I2C */
+       UCHAR ucI2cAddress;
+       UCHAR ucFanParameters;  /* Fan Control Parameters. */
+       UCHAR ucFanMinRPM;       /* Fan Minimum RPM (hundreds) -- for display purposes only. */
+       UCHAR ucFanMaxRPM;       /* Fan Maximum RPM (hundreds) -- for display purposes only. */
+       UCHAR ucReserved;
+       UCHAR ucFlags;             /* to be defined */
+} ATOM_Tonga_Thermal_Controller;
+
+typedef struct _ATOM_Tonga_VCE_State_Record {
+       UCHAR  ucVCEClockIndex; /*index into usVCEDependencyTableOffset of 'ATOM_Tonga_MM_Dependency_Table' type */
+       UCHAR  ucFlag;          /* 2 bits indicates memory p-states */
+       UCHAR  ucSCLKIndex;             /*index into ATOM_Tonga_SCLK_Dependency_Table */
+       UCHAR  ucMCLKIndex;             /*index into ATOM_Tonga_MCLK_Dependency_Table */
+} ATOM_Tonga_VCE_State_Record;
+
+typedef struct _ATOM_Tonga_VCE_State_Table {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;
+       ATOM_Tonga_VCE_State_Record entries[1];
+} ATOM_Tonga_VCE_State_Table;
+
+typedef struct _ATOM_Tonga_PowerTune_Table {
+       UCHAR  ucRevId;
+       USHORT usTDP;
+       USHORT usConfigurableTDP;
+       USHORT usTDC;
+       USHORT usBatteryPowerLimit;
+       USHORT usSmallPowerLimit;
+       USHORT usLowCACLeakage;
+       USHORT usHighCACLeakage;
+       USHORT usMaximumPowerDeliveryLimit;
+       USHORT usTjMax;
+       USHORT usPowerTuneDataSetID;
+       USHORT usEDCLimit;
+       USHORT usSoftwareShutdownTemp;
+       USHORT usClockStretchAmount;
+       USHORT usReserve[2];
+} ATOM_Tonga_PowerTune_Table;
+
+typedef struct _ATOM_Fiji_PowerTune_Table {
+       UCHAR  ucRevId;
+       USHORT usTDP;
+       USHORT usConfigurableTDP;
+       USHORT usTDC;
+       USHORT usBatteryPowerLimit;
+       USHORT usSmallPowerLimit;
+       USHORT usLowCACLeakage;
+       USHORT usHighCACLeakage;
+       USHORT usMaximumPowerDeliveryLimit;
+       USHORT usTjMax;  /* For Fiji, this is also usTemperatureLimitEdge; */
+       USHORT usPowerTuneDataSetID;
+       USHORT usEDCLimit;
+       USHORT usSoftwareShutdownTemp;
+       USHORT usClockStretchAmount;
+       USHORT usTemperatureLimitHotspot;  /*The following are added for Fiji */
+       USHORT usTemperatureLimitLiquid1;
+       USHORT usTemperatureLimitLiquid2;
+       USHORT usTemperatureLimitVrVddc;
+       USHORT usTemperatureLimitVrMvdd;
+       USHORT usTemperatureLimitPlx;
+       UCHAR  ucLiquid1_I2C_address;  /*Liquid */
+       UCHAR  ucLiquid2_I2C_address;
+       UCHAR  ucLiquid_I2C_Line;
+       UCHAR  ucVr_I2C_address;        /*VR */
+       UCHAR  ucVr_I2C_Line;
+       UCHAR  ucPlx_I2C_address;  /*PLX */
+       UCHAR  ucPlx_I2C_Line;
+       USHORT usReserved;
+} ATOM_Fiji_PowerTune_Table;
+
+#define ATOM_PPM_A_A    1
+#define ATOM_PPM_A_I    2
+typedef struct _ATOM_Tonga_PPM_Table {
+       UCHAR   ucRevId;
+       UCHAR   ucPpmDesign;              /*A+I or A+A */
+       USHORT  usCpuCoreNumber;
+       ULONG  ulPlatformTDP;
+       ULONG  ulSmallACPlatformTDP;
+       ULONG  ulPlatformTDC;
+       ULONG  ulSmallACPlatformTDC;
+       ULONG  ulApuTDP;
+       ULONG  ulDGpuTDP;
+       ULONG  ulDGpuUlvPower;
+       ULONG  ulTjmax;
+} ATOM_Tonga_PPM_Table;
+
+typedef struct _ATOM_Tonga_Hard_Limit_Record {
+       ULONG  ulSCLKLimit;
+       ULONG  ulMCLKLimit;
+       USHORT  usVddcLimit;
+       USHORT  usVddciLimit;
+       USHORT  usVddgfxLimit;
+} ATOM_Tonga_Hard_Limit_Record;
+
+typedef struct _ATOM_Tonga_Hard_Limit_Table {
+       UCHAR ucRevId;
+       UCHAR ucNumEntries;
+       ATOM_Tonga_Hard_Limit_Record entries[1];
+} ATOM_Tonga_Hard_Limit_Table;
+
+typedef struct _ATOM_Tonga_GPIO_Table {
+       UCHAR  ucRevId;
+       UCHAR  ucVRHotTriggeredSclkDpmIndex;            /* If VRHot signal is triggered SCLK will be limited to this DPM level */
+       UCHAR  ucReserve[5];
+} ATOM_Tonga_GPIO_Table;
+
+typedef struct _PPTable_Generic_SubTable_Header {
+       UCHAR  ucRevId;
+} PPTable_Generic_SubTable_Header;
+
+
+#pragma pack(pop)
+
+
+#endif
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
new file mode 100644 (file)
index 0000000..7de701d
--- /dev/null
@@ -0,0 +1,1325 @@
+/*
+ * Copyright 2015 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/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"
+
+/**
+ * Private Function used during initialization.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param setIt A flag indication if the capability should be set (TRUE) or reset (FALSE).
+ * @param cap Which capability to set/reset.
+ */
+static void set_hw_cap(struct pp_hwmgr *hwmgr, bool setIt, enum phm_platform_caps cap)
+{
+       if (setIt)
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
+       else
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
+}
+
+
+/**
+ * Private Function used during initialization.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_caps the bit array (from BIOS) of capability bits.
+ * @exception the current implementation always returns 1.
+ */
+static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps)
+{
+       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE16____),
+               "ATOM_PP_PLATFORM_CAP_ASPM_L1 is not supported!", continue);
+       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE64____),
+               "ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY is not supported!", continue);
+       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE512____),
+               "ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL is not supported!", continue);
+       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE1024____),
+               "ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 is not supported!", continue);
+       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE2048____),
+               "ATOM_PP_PLATFORM_CAP_HTLINKCONTROL is not supported!", continue);
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY),
+                       PHM_PlatformCaps_PowerPlaySupport
+                 );
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
+                       PHM_PlatformCaps_BiosPowerSourceControl
+                 );
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC),
+                       PHM_PlatformCaps_AutomaticDCTransition
+                 );
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL),
+                       PHM_PlatformCaps_EnableMVDDControl
+                 );
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL),
+                       PHM_PlatformCaps_ControlVDDCI
+                 );
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL),
+                       PHM_PlatformCaps_ControlVDDGFX
+                 );
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_BACO),
+                       PHM_PlatformCaps_BACO
+                 );
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND),
+                       PHM_PlatformCaps_DisableVoltageIsland
+                 );
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
+                       PHM_PlatformCaps_CombinePCCWithThermalSignal
+                 );
+
+       set_hw_cap(
+                       hwmgr,
+                       0 != (powerplay_caps & ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
+                       PHM_PlatformCaps_LoadPostProductionFirmware
+                 );
+
+       return 0;
+}
+
+/**
+ * Private Function to get the PowerPlay Table Address.
+ */
+const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
+{
+       int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+
+       u16 size;
+       u8 frev, crev;
+       void *table_address = (void *)hwmgr->soft_pp_table;
+
+       if (!table_address) {
+               table_address = (ATOM_Tonga_POWERPLAYTABLE *)
+                               cgs_atom_get_data_table(hwmgr->device,
+                                               index, &size, &frev, &crev);
+               hwmgr->soft_pp_table = table_address;   /*Cache the result in RAM.*/
+               hwmgr->soft_pp_table_size = size;
+       }
+
+       return table_address;
+}
+
+static int get_vddc_lookup_table(
+               struct pp_hwmgr *hwmgr,
+               phm_ppt_v1_voltage_lookup_table **lookup_table,
+               const ATOM_Tonga_Voltage_Lookup_Table *vddc_lookup_pp_tables,
+               uint32_t max_levels
+               )
+{
+       uint32_t table_size, i;
+       phm_ppt_v1_voltage_lookup_table *table;
+       phm_ppt_v1_voltage_lookup_record *record;
+       ATOM_Tonga_Voltage_Lookup_Record *atom_record;
+
+       PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries),
+               "Invalid CAC Leakage PowerPlay Table!", return 1);
+
+       table_size = sizeof(uint32_t) +
+               sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels;
+
+       table = kzalloc(table_size, GFP_KERNEL);
+
+       if (NULL == table)
+               return -ENOMEM;
+
+       memset(table, 0x00, table_size);
+
+       table->count = vddc_lookup_pp_tables->ucNumEntries;
+
+       for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) {
+               record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       phm_ppt_v1_voltage_lookup_record,
+                                       entries, table, i);
+               atom_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       ATOM_Tonga_Voltage_Lookup_Record,
+                                       entries, vddc_lookup_pp_tables, i);
+               record->us_calculated = 0;
+               record->us_vdd = atom_record->usVdd;
+               record->us_cac_low = atom_record->usCACLow;
+               record->us_cac_mid = atom_record->usCACMid;
+               record->us_cac_high = atom_record->usCACHigh;
+       }
+
+       *lookup_table = table;
+
+       return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Initialize Platform Power Management Parameter table
+ * @param hwmgr Pointer to the hardware manager.
+ * @param atom_ppm_table Pointer to PPM table in VBIOS
+ */
+static int get_platform_power_management_table(
+               struct pp_hwmgr *hwmgr,
+               ATOM_Tonga_PPM_Table *atom_ppm_table)
+{
+       struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL);
+       struct phm_ppt_v1_information *pp_table_information =
+               (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       if (NULL == ptr)
+               return -ENOMEM;
+
+       ptr->ppm_design
+               = atom_ppm_table->ucPpmDesign;
+       ptr->cpu_core_number
+               = atom_ppm_table->usCpuCoreNumber;
+       ptr->platform_tdp
+               = atom_ppm_table->ulPlatformTDP;
+       ptr->small_ac_platform_tdp
+               = atom_ppm_table->ulSmallACPlatformTDP;
+       ptr->platform_tdc
+               = atom_ppm_table->ulPlatformTDC;
+       ptr->small_ac_platform_tdc
+               = atom_ppm_table->ulSmallACPlatformTDC;
+       ptr->apu_tdp
+               = atom_ppm_table->ulApuTDP;
+       ptr->dgpu_tdp
+               = atom_ppm_table->ulDGpuTDP;
+       ptr->dgpu_ulv_power
+               = atom_ppm_table->ulDGpuUlvPower;
+       ptr->tj_max
+               = atom_ppm_table->ulTjmax;
+
+       pp_table_information->ppm_parameter_table = ptr;
+
+       return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Initialize TDP limits for DPM2
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ */
+static int init_dpm_2_parameters(
+               struct pp_hwmgr *hwmgr,
+               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+               )
+{
+       int result = 0;
+       struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       ATOM_Tonga_PPM_Table *atom_ppm_table;
+       uint32_t disable_ppm = 0;
+       uint32_t disable_power_control = 0;
+
+       pp_table_information->us_ulv_voltage_offset =
+               le16_to_cpu(powerplay_table->usUlvVoltageOffset);
+
+       pp_table_information->ppm_parameter_table = NULL;
+       pp_table_information->vddc_lookup_table = NULL;
+       pp_table_information->vddgfx_lookup_table = NULL;
+       /* TDP limits */
+       hwmgr->platform_descriptor.TDPODLimit =
+               le16_to_cpu(powerplay_table->usPowerControlLimit);
+       hwmgr->platform_descriptor.TDPAdjustment = 0;
+       hwmgr->platform_descriptor.VidAdjustment = 0;
+       hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
+       hwmgr->platform_descriptor.VidMinLimit = 0;
+       hwmgr->platform_descriptor.VidMaxLimit = 1500000;
+       hwmgr->platform_descriptor.VidStep = 6250;
+
+       disable_power_control = 0;
+       if (0 == disable_power_control) {
+               /* enable TDP overdrive (PowerControl) feature as well if supported */
+               if (hwmgr->platform_descriptor.TDPODLimit != 0)
+                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PowerControl);
+       }
+
+       if (0 != powerplay_table->usVddcLookupTableOffset) {
+               const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable =
+                       (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
+                       le16_to_cpu(powerplay_table->usVddcLookupTableOffset));
+
+               result = get_vddc_lookup_table(hwmgr,
+                       &pp_table_information->vddc_lookup_table, pVddcCACTable, 16);
+       }
+
+       if (0 != powerplay_table->usVddgfxLookupTableOffset) {
+               const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable =
+                       (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
+                       le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset));
+
+               result = get_vddc_lookup_table(hwmgr,
+                       &pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16);
+       }
+
+       disable_ppm = 0;
+       if (0 == disable_ppm) {
+               atom_ppm_table = (ATOM_Tonga_PPM_Table *)
+                       (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset));
+
+               if (0 != powerplay_table->usPPMTableOffset) {
+                       if (get_platform_power_management_table(hwmgr, atom_ppm_table) == 0) {
+                               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_EnablePlatformPowerManagement);
+                       }
+               }
+       }
+
+       return result;
+}
+
+static int get_valid_clk(
+               struct pp_hwmgr *hwmgr,
+               struct phm_clock_array **clk_table,
+               phm_ppt_v1_clock_voltage_dependency_table const *clk_volt_pp_table
+               )
+{
+       uint32_t table_size, i;
+       struct phm_clock_array *table;
+       phm_ppt_v1_clock_voltage_dependency_record *dep_record;
+
+       PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count),
+               "Invalid PowerPlay Table!", return -1);
+
+       table_size = sizeof(uint32_t) +
+               sizeof(uint32_t) * clk_volt_pp_table->count;
+
+       table = kzalloc(table_size, GFP_KERNEL);
+
+       if (NULL == table)
+               return -ENOMEM;
+
+       memset(table, 0x00, table_size);
+
+       table->count = (uint32_t)clk_volt_pp_table->count;
+
+       for (i = 0; i < table->count; i++) {
+               dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                               phm_ppt_v1_clock_voltage_dependency_record,
+                               entries, clk_volt_pp_table, i);
+               table->values[i] = (uint32_t)dep_record->clk;
+       }
+       *clk_table = table;
+
+       return 0;
+}
+
+static int get_hard_limits(
+               struct pp_hwmgr *hwmgr,
+               struct phm_clock_and_voltage_limits *limits,
+               ATOM_Tonga_Hard_Limit_Table const *limitable
+               )
+{
+       PP_ASSERT_WITH_CODE((0 != limitable->ucNumEntries), "Invalid PowerPlay Table!", return -1);
+
+       /* currently we always take entries[0] parameters */
+       limits->sclk = (uint32_t)limitable->entries[0].ulSCLKLimit;
+       limits->mclk = (uint32_t)limitable->entries[0].ulMCLKLimit;
+       limits->vddc = (uint16_t)limitable->entries[0].usVddcLimit;
+       limits->vddci = (uint16_t)limitable->entries[0].usVddciLimit;
+       limits->vddgfx = (uint16_t)limitable->entries[0].usVddgfxLimit;
+
+       return 0;
+}
+
+static int get_mclk_voltage_dependency_table(
+               struct pp_hwmgr *hwmgr,
+               phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_mclk_dep_table,
+               ATOM_Tonga_MCLK_Dependency_Table const *mclk_dep_table
+               )
+{
+       uint32_t table_size, i;
+       phm_ppt_v1_clock_voltage_dependency_table *mclk_table;
+       phm_ppt_v1_clock_voltage_dependency_record *mclk_table_record;
+       ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record;
+
+       PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries),
+               "Invalid PowerPlay Table!", return -1);
+
+       table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
+               * mclk_dep_table->ucNumEntries;
+
+       mclk_table = kzalloc(table_size, GFP_KERNEL);
+
+       if (NULL == mclk_table)
+               return -ENOMEM;
+
+       memset(mclk_table, 0x00, table_size);
+
+       mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries;
+
+       for (i = 0; i < mclk_dep_table->ucNumEntries; i++) {
+               mclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       phm_ppt_v1_clock_voltage_dependency_record,
+                                               entries, mclk_table, i);
+               mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       ATOM_Tonga_MCLK_Dependency_Record,
+                                               entries, mclk_dep_table, i);
+               mclk_table_record->vddInd = mclk_dep_record->ucVddcInd;
+               mclk_table_record->vdd_offset = mclk_dep_record->usVddgfxOffset;
+               mclk_table_record->vddci = mclk_dep_record->usVddci;
+               mclk_table_record->mvdd = mclk_dep_record->usMvdd;
+               mclk_table_record->clk = mclk_dep_record->ulMclk;
+       }
+
+       *pp_tonga_mclk_dep_table = mclk_table;
+
+       return 0;
+}
+
+static int get_sclk_voltage_dependency_table(
+               struct pp_hwmgr *hwmgr,
+               phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_sclk_dep_table,
+               PPTable_Generic_SubTable_Header const  *sclk_dep_table
+               )
+{
+       uint32_t table_size, i;
+       phm_ppt_v1_clock_voltage_dependency_table *sclk_table;
+       phm_ppt_v1_clock_voltage_dependency_record *sclk_table_record;
+
+       if (sclk_dep_table->ucRevId < 1) {
+               const ATOM_Tonga_SCLK_Dependency_Table *tonga_table =
+                           (ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table;
+               ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record;
+
+               PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries),
+                       "Invalid PowerPlay Table!", return -1);
+
+               table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
+                       * tonga_table->ucNumEntries;
+
+               sclk_table = kzalloc(table_size, GFP_KERNEL);
+
+               if (NULL == sclk_table)
+                       return -ENOMEM;
+
+               memset(sclk_table, 0x00, table_size);
+
+               sclk_table->count = (uint32_t)tonga_table->ucNumEntries;
+
+               for (i = 0; i < tonga_table->ucNumEntries; i++) {
+                       sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               ATOM_Tonga_SCLK_Dependency_Record,
+                                               entries, tonga_table, i);
+                       sclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               phm_ppt_v1_clock_voltage_dependency_record,
+                                               entries, sclk_table, i);
+                       sclk_table_record->vddInd = sclk_dep_record->ucVddInd;
+                       sclk_table_record->vdd_offset = sclk_dep_record->usVddcOffset;
+                       sclk_table_record->clk = sclk_dep_record->ulSclk;
+                       sclk_table_record->cks_enable =
+                               (((sclk_dep_record->ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0;
+                       sclk_table_record->cks_voffset = (sclk_dep_record->ucCKSVOffsetandDisable & 0x7F);
+               }
+       } else {
+               const ATOM_Polaris_SCLK_Dependency_Table *polaris_table =
+                           (ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table;
+               ATOM_Polaris_SCLK_Dependency_Record *sclk_dep_record;
+
+               PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries),
+                       "Invalid PowerPlay Table!", return -1);
+
+               table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
+                       * polaris_table->ucNumEntries;
+
+               sclk_table = kzalloc(table_size, GFP_KERNEL);
+
+               if (NULL == sclk_table)
+                       return -ENOMEM;
+
+               memset(sclk_table, 0x00, table_size);
+
+               sclk_table->count = (uint32_t)polaris_table->ucNumEntries;
+
+               for (i = 0; i < polaris_table->ucNumEntries; i++) {
+                       sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               ATOM_Polaris_SCLK_Dependency_Record,
+                                               entries, polaris_table, i);
+                       sclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               phm_ppt_v1_clock_voltage_dependency_record,
+                                               entries, sclk_table, i);
+                       sclk_table_record->vddInd = sclk_dep_record->ucVddInd;
+                       sclk_table_record->vdd_offset = sclk_dep_record->usVddcOffset;
+                       sclk_table_record->clk = sclk_dep_record->ulSclk;
+                       sclk_table_record->cks_enable =
+                               (((sclk_dep_record->ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0;
+                       sclk_table_record->cks_voffset = (sclk_dep_record->ucCKSVOffsetandDisable & 0x7F);
+                       sclk_table_record->sclk_offset = sclk_dep_record->ulSclkOffset;
+               }
+       }
+       *pp_tonga_sclk_dep_table = sclk_table;
+
+       return 0;
+}
+
+static int get_pcie_table(
+               struct pp_hwmgr *hwmgr,
+               phm_ppt_v1_pcie_table **pp_tonga_pcie_table,
+               PPTable_Generic_SubTable_Header const *ptable
+               )
+{
+       uint32_t table_size, i, pcie_count;
+       phm_ppt_v1_pcie_table *pcie_table;
+       struct phm_ppt_v1_information *pp_table_information =
+               (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       phm_ppt_v1_pcie_record *pcie_record;
+
+       if (ptable->ucRevId < 1) {
+               const ATOM_Tonga_PCIE_Table *atom_pcie_table = (ATOM_Tonga_PCIE_Table *)ptable;
+               ATOM_Tonga_PCIE_Record *atom_pcie_record;
+
+               PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0),
+                       "Invalid PowerPlay Table!", return -1);
+
+               table_size = sizeof(uint32_t) +
+                       sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries;
+
+               pcie_table = kzalloc(table_size, GFP_KERNEL);
+
+               if (pcie_table == NULL)
+                       return -ENOMEM;
+
+               memset(pcie_table, 0x00, table_size);
+
+               /*
+               * Make sure the number of pcie entries are less than or equal to sclk dpm levels.
+               * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1.
+               */
+               pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1;
+               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! \
+                       Disregarding the excess entries... \n");
+
+               pcie_table->count = pcie_count;
+               for (i = 0; i < pcie_count; i++) {
+                       pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               phm_ppt_v1_pcie_record,
+                                               entries, pcie_table, i);
+                       atom_pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               ATOM_Tonga_PCIE_Record,
+                                               entries, atom_pcie_table, i);
+                       pcie_record->gen_speed = atom_pcie_record->ucPCIEGenSpeed;
+                       pcie_record->lane_width = atom_pcie_record->usPCIELaneWidth;
+               }
+
+               *pp_tonga_pcie_table = pcie_table;
+       } else {
+               /* Polaris10/Polaris11 and newer. */
+               const ATOM_Polaris10_PCIE_Table *atom_pcie_table = (ATOM_Polaris10_PCIE_Table *)ptable;
+               ATOM_Polaris10_PCIE_Record *atom_pcie_record;
+
+               PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0),
+                       "Invalid PowerPlay Table!", return -1);
+
+               table_size = sizeof(uint32_t) +
+                       sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries;
+
+               pcie_table = kzalloc(table_size, GFP_KERNEL);
+
+               if (pcie_table == NULL)
+                       return -ENOMEM;
+
+               memset(pcie_table, 0x00, table_size);
+
+               /*
+               * Make sure the number of pcie entries are less than or equal to sclk dpm levels.
+               * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1.
+               */
+               pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1;
+               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! \
+                       Disregarding the excess entries... \n");
+
+               pcie_table->count = pcie_count;
+
+               for (i = 0; i < pcie_count; i++) {
+                       pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               phm_ppt_v1_pcie_record,
+                                               entries, pcie_table, i);
+                       atom_pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               ATOM_Polaris10_PCIE_Record,
+                                               entries, atom_pcie_table, i);
+                       pcie_record->gen_speed = atom_pcie_record->ucPCIEGenSpeed;
+                       pcie_record->lane_width = atom_pcie_record->usPCIELaneWidth;
+                       pcie_record->pcie_sclk = atom_pcie_record->ulPCIE_Sclk;
+               }
+
+               *pp_tonga_pcie_table = pcie_table;
+       }
+
+       return 0;
+}
+
+static int get_cac_tdp_table(
+               struct pp_hwmgr *hwmgr,
+               struct phm_cac_tdp_table **cac_tdp_table,
+               const PPTable_Generic_SubTable_Header * table
+               )
+{
+       uint32_t table_size;
+       struct phm_cac_tdp_table *tdp_table;
+
+       table_size = sizeof(uint32_t) + sizeof(struct phm_cac_tdp_table);
+       tdp_table = kzalloc(table_size, GFP_KERNEL);
+
+       if (NULL == tdp_table)
+               return -ENOMEM;
+
+       memset(tdp_table, 0x00, table_size);
+
+       hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL);
+
+       if (NULL == hwmgr->dyn_state.cac_dtp_table) {
+               kfree(tdp_table);
+               return -ENOMEM;
+       }
+
+       memset(hwmgr->dyn_state.cac_dtp_table, 0x00, table_size);
+
+       if (table->ucRevId < 3) {
+               const ATOM_Tonga_PowerTune_Table *tonga_table =
+                       (ATOM_Tonga_PowerTune_Table *)table;
+               tdp_table->usTDP = tonga_table->usTDP;
+               tdp_table->usConfigurableTDP =
+                       tonga_table->usConfigurableTDP;
+               tdp_table->usTDC = tonga_table->usTDC;
+               tdp_table->usBatteryPowerLimit =
+                       tonga_table->usBatteryPowerLimit;
+               tdp_table->usSmallPowerLimit =
+                       tonga_table->usSmallPowerLimit;
+               tdp_table->usLowCACLeakage =
+                       tonga_table->usLowCACLeakage;
+               tdp_table->usHighCACLeakage =
+                       tonga_table->usHighCACLeakage;
+               tdp_table->usMaximumPowerDeliveryLimit =
+                       tonga_table->usMaximumPowerDeliveryLimit;
+               tdp_table->usDefaultTargetOperatingTemp =
+                       tonga_table->usTjMax;
+               tdp_table->usTargetOperatingTemp =
+                       tonga_table->usTjMax; /*Set the initial temp to the same as default */
+               tdp_table->usPowerTuneDataSetID =
+                       tonga_table->usPowerTuneDataSetID;
+               tdp_table->usSoftwareShutdownTemp =
+                       tonga_table->usSoftwareShutdownTemp;
+               tdp_table->usClockStretchAmount =
+                       tonga_table->usClockStretchAmount;
+       } else {   /* Fiji and newer */
+               const ATOM_Fiji_PowerTune_Table *fijitable =
+                       (ATOM_Fiji_PowerTune_Table *)table;
+               tdp_table->usTDP = fijitable->usTDP;
+               tdp_table->usConfigurableTDP = fijitable->usConfigurableTDP;
+               tdp_table->usTDC = fijitable->usTDC;
+               tdp_table->usBatteryPowerLimit = fijitable->usBatteryPowerLimit;
+               tdp_table->usSmallPowerLimit = fijitable->usSmallPowerLimit;
+               tdp_table->usLowCACLeakage = fijitable->usLowCACLeakage;
+               tdp_table->usHighCACLeakage = fijitable->usHighCACLeakage;
+               tdp_table->usMaximumPowerDeliveryLimit =
+                       fijitable->usMaximumPowerDeliveryLimit;
+               tdp_table->usDefaultTargetOperatingTemp =
+                       fijitable->usTjMax;
+               tdp_table->usTargetOperatingTemp =
+                       fijitable->usTjMax; /*Set the initial temp to the same as default */
+               tdp_table->usPowerTuneDataSetID =
+                       fijitable->usPowerTuneDataSetID;
+               tdp_table->usSoftwareShutdownTemp =
+                       fijitable->usSoftwareShutdownTemp;
+               tdp_table->usClockStretchAmount =
+                       fijitable->usClockStretchAmount;
+               tdp_table->usTemperatureLimitHotspot =
+                       fijitable->usTemperatureLimitHotspot;
+               tdp_table->usTemperatureLimitLiquid1 =
+                       fijitable->usTemperatureLimitLiquid1;
+               tdp_table->usTemperatureLimitLiquid2 =
+                       fijitable->usTemperatureLimitLiquid2;
+               tdp_table->usTemperatureLimitVrVddc =
+                       fijitable->usTemperatureLimitVrVddc;
+               tdp_table->usTemperatureLimitVrMvdd =
+                       fijitable->usTemperatureLimitVrMvdd;
+               tdp_table->usTemperatureLimitPlx =
+                       fijitable->usTemperatureLimitPlx;
+               tdp_table->ucLiquid1_I2C_address =
+                       fijitable->ucLiquid1_I2C_address;
+               tdp_table->ucLiquid2_I2C_address =
+                       fijitable->ucLiquid2_I2C_address;
+               tdp_table->ucLiquid_I2C_Line =
+                       fijitable->ucLiquid_I2C_Line;
+               tdp_table->ucVr_I2C_address = fijitable->ucVr_I2C_address;
+               tdp_table->ucVr_I2C_Line = fijitable->ucVr_I2C_Line;
+               tdp_table->ucPlx_I2C_address = fijitable->ucPlx_I2C_address;
+               tdp_table->ucPlx_I2C_Line = fijitable->ucPlx_I2C_Line;
+       }
+
+       *cac_tdp_table = tdp_table;
+
+       return 0;
+}
+
+static int get_mm_clock_voltage_table(
+               struct pp_hwmgr *hwmgr,
+               phm_ppt_v1_mm_clock_voltage_dependency_table **tonga_mm_table,
+               const ATOM_Tonga_MM_Dependency_Table * mm_dependency_table
+               )
+{
+       uint32_t table_size, i;
+       const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record;
+       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table;
+       phm_ppt_v1_mm_clock_voltage_dependency_record *mm_table_record;
+
+       PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries),
+               "Invalid PowerPlay Table!", return -1);
+       table_size = sizeof(uint32_t) +
+               sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record)
+               * mm_dependency_table->ucNumEntries;
+       mm_table = kzalloc(table_size, GFP_KERNEL);
+
+       if (NULL == mm_table)
+               return -ENOMEM;
+
+       memset(mm_table, 0x00, table_size);
+
+       mm_table->count = mm_dependency_table->ucNumEntries;
+
+       for (i = 0; i < mm_dependency_table->ucNumEntries; i++) {
+               mm_dependency_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               ATOM_Tonga_MM_Dependency_Record,
+                                               entries, mm_dependency_table, i);
+               mm_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       phm_ppt_v1_mm_clock_voltage_dependency_record,
+                                       entries, mm_table, i);
+               mm_table_record->vddcInd = mm_dependency_record->ucVddcInd;
+               mm_table_record->vddgfx_offset = mm_dependency_record->usVddgfxOffset;
+               mm_table_record->aclk = mm_dependency_record->ulAClk;
+               mm_table_record->samclock = mm_dependency_record->ulSAMUClk;
+               mm_table_record->eclk = mm_dependency_record->ulEClk;
+               mm_table_record->vclk = mm_dependency_record->ulVClk;
+               mm_table_record->dclk = mm_dependency_record->ulDClk;
+       }
+
+       *tonga_mm_table = mm_table;
+
+       return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Initialize clock voltage dependency
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ */
+static int init_clock_voltage_dependency(
+               struct pp_hwmgr *hwmgr,
+               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+               )
+{
+       int result = 0;
+       struct phm_ppt_v1_information *pp_table_information =
+               (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table =
+               (const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) +
+               le16_to_cpu(powerplay_table->usMMDependencyTableOffset));
+       const PPTable_Generic_SubTable_Header *pPowerTuneTable =
+               (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
+               le16_to_cpu(powerplay_table->usPowerTuneTableOffset));
+       const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
+               (const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
+               le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
+       const PPTable_Generic_SubTable_Header *sclk_dep_table =
+               (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
+               le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
+       const ATOM_Tonga_Hard_Limit_Table *pHardLimits =
+               (const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) +
+               le16_to_cpu(powerplay_table->usHardLimitTableOffset));
+       const PPTable_Generic_SubTable_Header *pcie_table =
+               (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
+               le16_to_cpu(powerplay_table->usPCIETableOffset));
+
+       pp_table_information->vdd_dep_on_sclk = NULL;
+       pp_table_information->vdd_dep_on_mclk = NULL;
+       pp_table_information->mm_dep_table = NULL;
+       pp_table_information->pcie_table = NULL;
+
+       if (powerplay_table->usMMDependencyTableOffset != 0)
+               result = get_mm_clock_voltage_table(hwmgr,
+               &pp_table_information->mm_dep_table, mm_dependency_table);
+
+       if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0)
+               result = get_cac_tdp_table(hwmgr,
+               &pp_table_information->cac_dtp_table, pPowerTuneTable);
+
+       if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0)
+               result = get_sclk_voltage_dependency_table(hwmgr,
+               &pp_table_information->vdd_dep_on_sclk, sclk_dep_table);
+
+       if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0)
+               result = get_mclk_voltage_dependency_table(hwmgr,
+               &pp_table_information->vdd_dep_on_mclk, mclk_dep_table);
+
+       if (result == 0 && powerplay_table->usPCIETableOffset != 0)
+               result = get_pcie_table(hwmgr,
+               &pp_table_information->pcie_table, pcie_table);
+
+       if (result == 0 && powerplay_table->usHardLimitTableOffset != 0)
+               result = get_hard_limits(hwmgr,
+               &pp_table_information->max_clock_voltage_on_dc, pHardLimits);
+
+       hwmgr->dyn_state.max_clock_voltage_on_dc.sclk =
+               pp_table_information->max_clock_voltage_on_dc.sclk;
+       hwmgr->dyn_state.max_clock_voltage_on_dc.mclk =
+               pp_table_information->max_clock_voltage_on_dc.mclk;
+       hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
+               pp_table_information->max_clock_voltage_on_dc.vddc;
+       hwmgr->dyn_state.max_clock_voltage_on_dc.vddci =
+               pp_table_information->max_clock_voltage_on_dc.vddci;
+
+       if (result == 0 && (NULL != pp_table_information->vdd_dep_on_mclk)
+               && (0 != pp_table_information->vdd_dep_on_mclk->count))
+               result = get_valid_clk(hwmgr, &pp_table_information->valid_mclk_values,
+               pp_table_information->vdd_dep_on_mclk);
+
+       if (result == 0 && (NULL != pp_table_information->vdd_dep_on_sclk)
+               && (0 != pp_table_information->vdd_dep_on_sclk->count))
+               result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values,
+               pp_table_information->vdd_dep_on_sclk);
+
+       return result;
+}
+
+/** Retrieves the (signed) Overdrive limits from VBIOS.
+ * The max engine clock, memory clock and max temperature come from the firmware info table.
+ *
+ * The information is placed into the platform descriptor.
+ *
+ * @param hwmgr source of the VBIOS table and owner of the platform descriptor to be updated.
+ * @param powerplay_table the address of the PowerPlay table.
+ *
+ * @return 1 as long as the firmware info table was present and of a supported version.
+ */
+static int init_over_drive_limits(
+               struct pp_hwmgr *hwmgr,
+               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table)
+{
+       hwmgr->platform_descriptor.overdriveLimit.engineClock =
+               le16_to_cpu(powerplay_table->ulMaxODEngineClock);
+       hwmgr->platform_descriptor.overdriveLimit.memoryClock =
+               le16_to_cpu(powerplay_table->ulMaxODMemoryClock);
+
+       hwmgr->platform_descriptor.minOverdriveVDDC = 0;
+       hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
+       hwmgr->platform_descriptor.overdriveVDDCStep = 0;
+
+       if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 \
+               && hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) {
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ACOverdriveSupport);
+       }
+
+       return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Inspect the PowerPlay table for obvious signs of corruption.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ * @exception This implementation always returns 1.
+ */
+static int init_thermal_controller(
+               struct pp_hwmgr *hwmgr,
+               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+               )
+{
+       const PPTable_Generic_SubTable_Header *fan_table;
+       ATOM_Tonga_Thermal_Controller *thermal_controller;
+
+       thermal_controller = (ATOM_Tonga_Thermal_Controller *)
+               (((unsigned long)powerplay_table) +
+               le16_to_cpu(powerplay_table->usThermalControllerOffset));
+       PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset),
+               "Thermal controller table not set!", return -1);
+
+       hwmgr->thermal_controller.ucType = thermal_controller->ucType;
+       hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine;
+       hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress;
+
+       hwmgr->thermal_controller.fanInfo.bNoFan =
+               (0 != (thermal_controller->ucFanParameters & ATOM_TONGA_PP_FANPARAMETERS_NOFAN));
+
+       hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
+               thermal_controller->ucFanParameters &
+               ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
+
+       hwmgr->thermal_controller.fanInfo.ulMinRPM
+               = thermal_controller->ucFanMinRPM * 100UL;
+       hwmgr->thermal_controller.fanInfo.ulMaxRPM
+               = thermal_controller->ucFanMaxRPM * 100UL;
+
+       set_hw_cap(
+                       hwmgr,
+                       ATOM_TONGA_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
+                       PHM_PlatformCaps_ThermalController
+                 );
+
+       if (0 == powerplay_table->usFanTableOffset)
+               return 0;
+
+       fan_table = (const PPTable_Generic_SubTable_Header *)
+               (((unsigned long)powerplay_table) +
+               le16_to_cpu(powerplay_table->usFanTableOffset));
+
+       PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset),
+               "Fan table not set!", return -1);
+       PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId),
+               "Unsupported fan table format!", return -1);
+
+       hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay
+               = 100000;
+       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+               PHM_PlatformCaps_MicrocodeFanControl);
+
+       if (fan_table->ucRevId < 8) {
+               const ATOM_Tonga_Fan_Table *tonga_fan_table =
+                       (ATOM_Tonga_Fan_Table *)fan_table;
+               hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
+                       = tonga_fan_table->ucTHyst;
+               hwmgr->thermal_controller.advanceFanControlParameters.usTMin
+                       = tonga_fan_table->usTMin;
+               hwmgr->thermal_controller.advanceFanControlParameters.usTMed
+                       = tonga_fan_table->usTMed;
+               hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
+                       = tonga_fan_table->usTHigh;
+               hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
+                       = tonga_fan_table->usPWMMin;
+               hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
+                       = tonga_fan_table->usPWMMed;
+               hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
+                       = tonga_fan_table->usPWMHigh;
+               hwmgr->thermal_controller.advanceFanControlParameters.usTMax
+                       = 10900;                  /* hard coded */
+               hwmgr->thermal_controller.advanceFanControlParameters.usTMax
+                       = tonga_fan_table->usTMax;
+               hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
+                       = tonga_fan_table->ucFanControlMode;
+               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
+                       = tonga_fan_table->usFanPWMMax;
+               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
+                       = 4836;
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
+                       = tonga_fan_table->usFanOutputSensitivity;
+               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
+                       = tonga_fan_table->usFanRPMMax;
+               hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
+                       = (tonga_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places.  SMC wants MHz. */
+               hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
+                       = tonga_fan_table->ucTargetTemperature;
+               hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
+                       = tonga_fan_table->ucMinimumPWMLimit;
+       } else {
+               const ATOM_Fiji_Fan_Table *fiji_fan_table =
+                       (ATOM_Fiji_Fan_Table *)fan_table;
+               hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
+                       = fiji_fan_table->ucTHyst;
+               hwmgr->thermal_controller.advanceFanControlParameters.usTMin
+                       = fiji_fan_table->usTMin;
+               hwmgr->thermal_controller.advanceFanControlParameters.usTMed
+                       = fiji_fan_table->usTMed;
+               hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
+                       = fiji_fan_table->usTHigh;
+               hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
+                       = fiji_fan_table->usPWMMin;
+               hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
+                       = fiji_fan_table->usPWMMed;
+               hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
+                       = fiji_fan_table->usPWMHigh;
+               hwmgr->thermal_controller.advanceFanControlParameters.usTMax
+                       = fiji_fan_table->usTMax;
+               hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
+                       = fiji_fan_table->ucFanControlMode;
+               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
+                       = fiji_fan_table->usFanPWMMax;
+               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
+                       = 4836;
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
+                       = fiji_fan_table->usFanOutputSensitivity;
+               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
+                       = fiji_fan_table->usFanRPMMax;
+               hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
+                       = (fiji_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places.  SMC wants MHz. */
+               hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
+                       = fiji_fan_table->ucTargetTemperature;
+               hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
+                       = fiji_fan_table->ucMinimumPWMLimit;
+
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge
+                       = fiji_fan_table->usFanGainEdge;
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot
+                       = fiji_fan_table->usFanGainHotspot;
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid
+                       = fiji_fan_table->usFanGainLiquid;
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc
+                       = fiji_fan_table->usFanGainVrVddc;
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd
+                       = fiji_fan_table->usFanGainVrMvdd;
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx
+                       = fiji_fan_table->usFanGainPlx;
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm
+                       = fiji_fan_table->usFanGainHbm;
+       }
+
+       return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Inspect the PowerPlay table for obvious signs of corruption.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ * @exception 2 if the powerplay table is incorrect.
+ */
+static int check_powerplay_tables(
+               struct pp_hwmgr *hwmgr,
+               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+               )
+{
+       const ATOM_Tonga_State_Array *state_arrays;
+
+       state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) +
+               le16_to_cpu(powerplay_table->usStateArrayOffset));
+
+       PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <=
+               powerplay_table->sHeader.ucTableFormatRevision),
+               "Unsupported PPTable format!", return -1);
+       PP_ASSERT_WITH_CODE((0 != powerplay_table->usStateArrayOffset),
+               "State table is not set!", return -1);
+       PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize),
+               "Invalid PowerPlay Table!", return -1);
+       PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
+               "Invalid PowerPlay Table!", return -1);
+
+       return 0;
+}
+
+int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr)
+{
+       int result = 0;
+       const ATOM_Tonga_POWERPLAYTABLE *powerplay_table;
+
+       hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL);
+
+       PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable),
+                           "Failed to allocate hwmgr->pptable!", return -ENOMEM);
+
+       memset(hwmgr->pptable, 0x00, sizeof(struct phm_ppt_v1_information));
+
+       powerplay_table = get_powerplay_table(hwmgr);
+
+       PP_ASSERT_WITH_CODE((NULL != powerplay_table),
+               "Missing PowerPlay Table!", return -1);
+
+       result = check_powerplay_tables(hwmgr, powerplay_table);
+
+       PP_ASSERT_WITH_CODE((result == 0),
+                           "check_powerplay_tables failed", return result);
+
+       result = set_platform_caps(hwmgr,
+                                  le32_to_cpu(powerplay_table->ulPlatformCaps));
+
+       PP_ASSERT_WITH_CODE((result == 0),
+                           "set_platform_caps failed", return result);
+
+       result = init_thermal_controller(hwmgr, powerplay_table);
+
+       PP_ASSERT_WITH_CODE((result == 0),
+                           "init_thermal_controller failed", return result);
+
+       result = init_over_drive_limits(hwmgr, powerplay_table);
+
+       PP_ASSERT_WITH_CODE((result == 0),
+                           "init_over_drive_limits failed", return result);
+
+       result = init_clock_voltage_dependency(hwmgr, powerplay_table);
+
+       PP_ASSERT_WITH_CODE((result == 0),
+                           "init_clock_voltage_dependency failed", return result);
+
+       result = init_dpm_2_parameters(hwmgr, powerplay_table);
+
+       PP_ASSERT_WITH_CODE((result == 0),
+                           "init_dpm_2_parameters failed", return result);
+
+       return result;
+}
+
+int pp_tables_v1_0_uninitialize(struct pp_hwmgr *hwmgr)
+{
+       struct phm_ppt_v1_information *pp_table_information =
+               (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       kfree(pp_table_information->vdd_dep_on_sclk);
+       pp_table_information->vdd_dep_on_sclk = NULL;
+
+       kfree(pp_table_information->vdd_dep_on_mclk);
+       pp_table_information->vdd_dep_on_mclk = NULL;
+
+       kfree(pp_table_information->valid_mclk_values);
+       pp_table_information->valid_mclk_values = NULL;
+
+       kfree(pp_table_information->valid_sclk_values);
+       pp_table_information->valid_sclk_values = NULL;
+
+       kfree(pp_table_information->vddc_lookup_table);
+       pp_table_information->vddc_lookup_table = NULL;
+
+       kfree(pp_table_information->vddgfx_lookup_table);
+       pp_table_information->vddgfx_lookup_table = NULL;
+
+       kfree(pp_table_information->mm_dep_table);
+       pp_table_information->mm_dep_table = NULL;
+
+       kfree(pp_table_information->cac_dtp_table);
+       pp_table_information->cac_dtp_table = NULL;
+
+       kfree(hwmgr->dyn_state.cac_dtp_table);
+       hwmgr->dyn_state.cac_dtp_table = NULL;
+
+       kfree(pp_table_information->ppm_parameter_table);
+       pp_table_information->ppm_parameter_table = NULL;
+
+       kfree(pp_table_information->pcie_table);
+       pp_table_information->pcie_table = NULL;
+
+       kfree(hwmgr->pptable);
+       hwmgr->pptable = NULL;
+
+       return 0;
+}
+
+const struct pp_table_func pptable_v1_0_funcs = {
+       .pptable_init = pp_tables_v1_0_initialize,
+       .pptable_fini = pp_tables_v1_0_uninitialize,
+};
+
+int get_number_of_powerplay_table_entries_v1_0(struct pp_hwmgr *hwmgr)
+{
+       ATOM_Tonga_State_Array const *state_arrays;
+       const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
+
+       PP_ASSERT_WITH_CODE((NULL != pp_table),
+                       "Missing PowerPlay Table!", return -1);
+       PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >=
+                       ATOM_Tonga_TABLE_REVISION_TONGA),
+                       "Incorrect PowerPlay table revision!", return -1);
+
+       state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
+                       le16_to_cpu(pp_table->usStateArrayOffset));
+
+       return (uint32_t)(state_arrays->ucNumEntries);
+}
+
+/**
+* Private function to convert flags stored in the BIOS to software flags in PowerPlay.
+*/
+static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr,
+               uint16_t classification, uint16_t classification2)
+{
+       uint32_t result = 0;
+
+       if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
+               result |= PP_StateClassificationFlag_Boot;
+
+       if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+               result |= PP_StateClassificationFlag_Thermal;
+
+       if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
+               result |= PP_StateClassificationFlag_LimitedPowerSource;
+
+       if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
+               result |= PP_StateClassificationFlag_Rest;
+
+       if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
+               result |= PP_StateClassificationFlag_Forced;
+
+       if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
+               result |= PP_StateClassificationFlag_ACPI;
+
+       if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
+               result |= PP_StateClassificationFlag_LimitedPowerSource_2;
+
+       return result;
+}
+
+static int ppt_get_num_of_vce_state_table_entries_v1_0(struct pp_hwmgr *hwmgr)
+{
+       const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
+       const ATOM_Tonga_VCE_State_Table *vce_state_table =
+                               (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pp_table) + le16_to_cpu(pp_table->usVCEStateTableOffset));
+
+       if (vce_state_table == NULL)
+               return 0;
+
+       return vce_state_table->ucNumEntries;
+}
+
+static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i,
+               struct pp_vce_state *vce_state, void **clock_info, uint32_t *flag)
+{
+       const ATOM_Tonga_VCE_State_Record *vce_state_record;
+       ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record;
+       ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record;
+       ATOM_Tonga_MM_Dependency_Record *mm_dep_record;
+       const ATOM_Tonga_POWERPLAYTABLE *pptable = get_powerplay_table(hwmgr);
+       const ATOM_Tonga_VCE_State_Table *vce_state_table = (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pptable)
+                                                         + le16_to_cpu(pptable->usVCEStateTableOffset));
+       const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table = (ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long)pptable)
+                                                         + le16_to_cpu(pptable->usSclkDependencyTableOffset));
+       const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = (ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long)pptable)
+                                                         + le16_to_cpu(pptable->usMclkDependencyTableOffset));
+       const ATOM_Tonga_MM_Dependency_Table *mm_dep_table = (ATOM_Tonga_MM_Dependency_Table *)(((unsigned long)pptable)
+                                                         + le16_to_cpu(pptable->usMMDependencyTableOffset));
+
+       PP_ASSERT_WITH_CODE((i < vce_state_table->ucNumEntries),
+                        "Requested state entry ID is out of range!",
+                        return -EINVAL);
+
+       vce_state_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       ATOM_Tonga_VCE_State_Record,
+                                       entries, vce_state_table, i);
+       sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       ATOM_Tonga_SCLK_Dependency_Record,
+                                       entries, sclk_dep_table,
+                                       vce_state_record->ucSCLKIndex);
+       mm_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       ATOM_Tonga_MM_Dependency_Record,
+                                       entries, mm_dep_table,
+                                       vce_state_record->ucVCEClockIndex);
+       *flag = vce_state_record->ucFlag;
+
+       vce_state->evclk = mm_dep_record->ulEClk;
+       vce_state->ecclk = mm_dep_record->ulEClk;
+       vce_state->sclk = sclk_dep_record->ulSclk;
+
+       if (vce_state_record->ucMCLKIndex >= mclk_dep_table->ucNumEntries)
+               mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       ATOM_Tonga_MCLK_Dependency_Record,
+                                       entries, mclk_dep_table,
+                                       mclk_dep_table->ucNumEntries - 1);
+       else
+               mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                       ATOM_Tonga_MCLK_Dependency_Record,
+                                       entries, mclk_dep_table,
+                                       vce_state_record->ucMCLKIndex);
+
+       vce_state->mclk = mclk_dep_record->ulMclk;
+       return 0;
+}
+
+/**
+* Create a Power State out of an entry in the PowerPlay table.
+* This function is called by the hardware back-end.
+* @param hwmgr Pointer to the hardware manager.
+* @param entry_index The index of the entry to be extracted from the table.
+* @param power_state The address of the PowerState instance being created.
+* @return -1 if the entry cannot be retrieved.
+*/
+int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr,
+               uint32_t entry_index, struct pp_power_state *power_state,
+               int (*call_back_func)(struct pp_hwmgr *, void *,
+                               struct pp_power_state *, void *, uint32_t))
+{
+       int result = 0;
+       const ATOM_Tonga_State_Array *state_arrays;
+       const ATOM_Tonga_State *state_entry;
+       const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
+       int i, j;
+       uint32_t flags = 0;
+
+       PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1;);
+       power_state->classification.bios_index = entry_index;
+
+       if (pp_table->sHeader.ucTableFormatRevision >=
+                       ATOM_Tonga_TABLE_REVISION_TONGA) {
+               state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
+                               le16_to_cpu(pp_table->usStateArrayOffset));
+
+               PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset),
+                               "Invalid PowerPlay Table State Array Offset.", return -1);
+               PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
+                               "Invalid PowerPlay Table State Array.", return -1);
+               PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
+                               "Invalid PowerPlay Table State Array Entry.", return -1);
+
+               state_entry = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+                                               ATOM_Tonga_State, entries,
+                                               state_arrays, entry_index);
+
+               result = call_back_func(hwmgr, (void *)state_entry, power_state,
+                               (void *)pp_table,
+                               make_classification_flags(hwmgr,
+                                       le16_to_cpu(state_entry->usClassification),
+                                       le16_to_cpu(state_entry->usClassification2)));
+       }
+
+       if (!result && (power_state->classification.flags &
+                       PP_StateClassificationFlag_Boot))
+               result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware));
+
+       hwmgr->num_vce_state_tables = i = ppt_get_num_of_vce_state_table_entries_v1_0(hwmgr);
+
+       if ((i != 0) && (i <= PP_MAX_VCE_LEVELS)) {
+               for (j = 0; j < i; j++)
+                       ppt_get_vce_state_table_entry_v1_0(hwmgr, j, &(hwmgr->vce_states[j]), NULL, &flags);
+       }
+
+       return result;
+}
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.h b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.h
new file mode 100644 (file)
index 0000000..b9710ab
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 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 _PROCESSPPTABLES_V1_0_H
+#define _PROCESSPPTABLES_V1_0_H
+
+#include "hwmgr.h"
+
+extern const struct pp_table_func pptable_v1_0_funcs;
+extern int get_number_of_powerplay_table_entries_v1_0(struct pp_hwmgr *hwmgr);
+extern int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t entry_index,
+               struct pp_power_state *power_state, int (*call_back_func)(struct pp_hwmgr *, void *,
+                               struct pp_power_state *, void *, uint32_t));
+
+#endif
+
index 6c321b0..ccf7ebe 100644 (file)
@@ -1523,7 +1523,7 @@ int get_number_of_vce_state_table_entries(
 
 int get_vce_state_table_entry(struct pp_hwmgr *hwmgr,
                                                        unsigned long i,
-                                                       struct PP_VCEState *vce_state,
+                                                       struct pp_vce_state *vce_state,
                                                        void **clock_info,
                                                        unsigned long *flag)
 {
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c
new file mode 100644 (file)
index 0000000..6eb6db1
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * 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 "smu7_hwmgr.h"
+#include "smu7_clockpowergating.h"
+#include "smu7_common.h"
+
+static int smu7_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+       return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
+                       PPSMC_MSG_UVDDPM_Enable :
+                       PPSMC_MSG_UVDDPM_Disable);
+}
+
+static int smu7_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+       return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
+                       PPSMC_MSG_VCEDPM_Enable :
+                       PPSMC_MSG_VCEDPM_Disable);
+}
+
+static int smu7_enable_disable_samu_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+       return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
+                       PPSMC_MSG_SAMUDPM_Enable :
+                       PPSMC_MSG_SAMUDPM_Disable);
+}
+
+static int smu7_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+       if (!bgate)
+               smum_update_smc_table(hwmgr, SMU_UVD_TABLE);
+       return smu7_enable_disable_uvd_dpm(hwmgr, !bgate);
+}
+
+static int smu7_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+       if (!bgate)
+               smum_update_smc_table(hwmgr, SMU_VCE_TABLE);
+       return smu7_enable_disable_vce_dpm(hwmgr, !bgate);
+}
+
+static int smu7_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+       if (!bgate)
+               smum_update_smc_table(hwmgr, SMU_SAMU_TABLE);
+       return smu7_enable_disable_samu_dpm(hwmgr, !bgate);
+}
+
+int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr)
+{
+       if (phm_cf_want_uvd_power_gating(hwmgr))
+               return smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_UVDPowerOFF);
+       return 0;
+}
+
+int smu7_powerup_uvd(struct pp_hwmgr *hwmgr)
+{
+       if (phm_cf_want_uvd_power_gating(hwmgr)) {
+               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                 PHM_PlatformCaps_UVDDynamicPowerGating)) {
+                       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                       PPSMC_MSG_UVDPowerON, 1);
+               } else {
+                       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                       PPSMC_MSG_UVDPowerON, 0);
+               }
+       }
+
+       return 0;
+}
+
+int smu7_powerdown_vce(struct pp_hwmgr *hwmgr)
+{
+       if (phm_cf_want_vce_power_gating(hwmgr))
+               return smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_VCEPowerOFF);
+       return 0;
+}
+
+int smu7_powerup_vce(struct pp_hwmgr *hwmgr)
+{
+       if (phm_cf_want_vce_power_gating(hwmgr))
+               return smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_VCEPowerON);
+       return 0;
+}
+
+int smu7_powerdown_samu(struct pp_hwmgr *hwmgr)
+{
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SamuPowerGating))
+               return smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_SAMPowerOFF);
+       return 0;
+}
+
+int smu7_powerup_samu(struct pp_hwmgr *hwmgr)
+{
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SamuPowerGating))
+               return smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_SAMPowerON);
+       return 0;
+}
+
+int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       data->uvd_power_gated = false;
+       data->vce_power_gated = false;
+       data->samu_power_gated = false;
+
+       smu7_powerup_uvd(hwmgr);
+       smu7_powerup_vce(hwmgr);
+       smu7_powerup_samu(hwmgr);
+
+       return 0;
+}
+
+int smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       data->uvd_power_gated = bgate;
+
+       if (bgate) {
+               cgs_set_clockgating_state(hwmgr->device,
+                               AMD_IP_BLOCK_TYPE_UVD,
+                               AMD_CG_STATE_GATE);
+               smu7_update_uvd_dpm(hwmgr, true);
+               smu7_powerdown_uvd(hwmgr);
+       } else {
+               smu7_powerup_uvd(hwmgr);
+               smu7_update_uvd_dpm(hwmgr, false);
+               cgs_set_clockgating_state(hwmgr->device,
+                               AMD_IP_BLOCK_TYPE_UVD,
+                               AMD_CG_STATE_UNGATE);
+       }
+
+       return 0;
+}
+
+int smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->vce_power_gated == bgate)
+               return 0;
+
+       data->vce_power_gated = bgate;
+
+       if (bgate) {
+               cgs_set_clockgating_state(hwmgr->device,
+                               AMD_IP_BLOCK_TYPE_VCE,
+                               AMD_CG_STATE_GATE);
+               smu7_update_vce_dpm(hwmgr, true);
+               smu7_powerdown_vce(hwmgr);
+       } else {
+               smu7_powerup_vce(hwmgr);
+               smu7_update_vce_dpm(hwmgr, false);
+               cgs_set_clockgating_state(hwmgr->device,
+                               AMD_IP_BLOCK_TYPE_VCE,
+                               AMD_CG_STATE_UNGATE);
+       }
+       return 0;
+}
+
+int smu7_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->samu_power_gated == bgate)
+               return 0;
+
+       data->samu_power_gated = bgate;
+
+       if (bgate) {
+               smu7_update_samu_dpm(hwmgr, true);
+               smu7_powerdown_samu(hwmgr);
+       } else {
+               smu7_powerup_samu(hwmgr);
+               smu7_update_samu_dpm(hwmgr, false);
+       }
+
+       return 0;
+}
+
+int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr,
+                                       const uint32_t *msg_id)
+{
+       PPSMC_Msg msg;
+       uint32_t value;
+
+       if (!(hwmgr->feature_mask & PP_ENABLE_GFX_CG_THRU_SMU))
+               return 0;
+
+       switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
+       case PP_GROUP_GFX:
+               switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
+               case PP_BLOCK_GFX_CG:
+                       if (PP_STATE_SUPPORT_CG & *msg_id) {
+                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_GFX_CGCG_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       if (PP_STATE_SUPPORT_LS & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+                                       ? PPSMC_MSG_EnableClockGatingFeature
+                                       : PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_GFX_CGLS_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               case PP_BLOCK_GFX_3D:
+                       if (PP_STATE_SUPPORT_CG & *msg_id) {
+                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_GFX_3DCG_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+
+                       if  (PP_STATE_SUPPORT_LS & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_GFX_3DLS_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               case PP_BLOCK_GFX_RLC:
+                       if (PP_STATE_SUPPORT_LS & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_GFX_RLC_LS_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               case PP_BLOCK_GFX_CP:
+                       if (PP_STATE_SUPPORT_LS & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_GFX_CP_LS_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               case PP_BLOCK_GFX_MG:
+                       if (PP_STATE_SUPPORT_CG & *msg_id) {
+                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = (CG_CPF_MGCG_MASK | CG_RLC_MGCG_MASK |
+                                               CG_GFX_OTHERS_MGCG_MASK);
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case PP_GROUP_SYS:
+               switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
+               case PP_BLOCK_SYS_BIF:
+                       if (PP_STATE_SUPPORT_CG & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_BIF_MGCG_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       if  (PP_STATE_SUPPORT_LS & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_BIF_MGLS_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               case PP_BLOCK_SYS_MC:
+                       if (PP_STATE_SUPPORT_CG & *msg_id) {
+                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_MC_MGCG_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+
+                       if (PP_STATE_SUPPORT_LS & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_MC_MGLS_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               case PP_BLOCK_SYS_DRM:
+                       if (PP_STATE_SUPPORT_CG & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_DRM_MGCG_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       if (PP_STATE_SUPPORT_LS & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_DRM_MGLS_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               case PP_BLOCK_SYS_HDP:
+                       if (PP_STATE_SUPPORT_CG & *msg_id) {
+                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_HDP_MGCG_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+
+                       if (PP_STATE_SUPPORT_LS & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_HDP_MGLS_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               case PP_BLOCK_SYS_SDMA:
+                       if (PP_STATE_SUPPORT_CG & *msg_id) {
+                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_SDMA_MGCG_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+
+                       if (PP_STATE_SUPPORT_LS & *msg_id) {
+                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_SDMA_MGLS_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               case PP_BLOCK_SYS_ROM:
+                       if (PP_STATE_SUPPORT_CG & *msg_id) {
+                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
+                                               PPSMC_MSG_EnableClockGatingFeature :
+                                               PPSMC_MSG_DisableClockGatingFeature;
+                               value = CG_SYS_ROM_MASK;
+
+                               if (smum_send_msg_to_smc_with_parameter(
+                                               hwmgr->smumgr, msg, value))
+                                       return -EINVAL;
+                       }
+                       break;
+
+               default:
+                       return -EINVAL;
+
+               }
+               break;
+
+       default:
+               return -EINVAL;
+
+       }
+
+       return 0;
+}
+
+/* This function is for Polaris11 only for now,
+ * Powerplay will only control the static per CU Power Gating.
+ * Dynamic per CU Power Gating will be done in gfx.
+ */
+int smu7_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable)
+{
+       struct cgs_system_info sys_info = {0};
+       uint32_t active_cus;
+       int result;
+
+       sys_info.size = sizeof(struct cgs_system_info);
+       sys_info.info_id = CGS_SYSTEM_INFO_GFX_CU_INFO;
+
+       result = cgs_query_system_info(hwmgr->device, &sys_info);
+
+       if (result)
+               return -EINVAL;
+
+       active_cus = sys_info.value;
+
+       if (enable)
+               return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_GFX_CU_PG_ENABLE, active_cus);
+       else
+               return smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_GFX_CU_PG_DISABLE);
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h
new file mode 100644 (file)
index 0000000..d52a28c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _SMU7_CLOCK_POWER_GATING_H_
+#define _SMU7_CLOCK__POWER_GATING_H_
+
+#include "smu7_hwmgr.h"
+#include "pp_asicblocks.h"
+
+int smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
+int smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
+int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr);
+int smu7_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
+int smu7_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
+int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
+int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr,
+                                       const uint32_t *msg_id);
+int smu7_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable);
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_dyn_defaults.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_dyn_defaults.h
new file mode 100644 (file)
index 0000000..f967613
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 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 _SMU7_DYN_DEFAULTS_H
+#define _SMU7_DYN_DEFAULTS_H
+
+
+/*  We need to fill in the default values */
+
+
+#define SMU7_VOTINGRIGHTSCLIENTS_DFLT0              0x3FFFC102
+#define SMU7_VOTINGRIGHTSCLIENTS_DFLT1              0x000400
+#define SMU7_VOTINGRIGHTSCLIENTS_DFLT2              0xC00080
+#define SMU7_VOTINGRIGHTSCLIENTS_DFLT3              0xC00200
+#define SMU7_VOTINGRIGHTSCLIENTS_DFLT4              0xC01680
+#define SMU7_VOTINGRIGHTSCLIENTS_DFLT5              0xC00033
+#define SMU7_VOTINGRIGHTSCLIENTS_DFLT6              0xC00033
+#define SMU7_VOTINGRIGHTSCLIENTS_DFLT7              0x3FFFC000
+
+
+#define SMU7_THERMALPROTECTCOUNTER_DFLT            0x200
+#define SMU7_STATICSCREENTHRESHOLDUNIT_DFLT        0
+#define SMU7_STATICSCREENTHRESHOLD_DFLT            0x00C8
+#define SMU7_GFXIDLECLOCKSTOPTHRESHOLD_DFLT        0x200
+#define SMU7_REFERENCEDIVIDER_DFLT                  4
+
+#define SMU7_ULVVOLTAGECHANGEDELAY_DFLT             1687
+
+#define SMU7_CGULVPARAMETER_DFLT                    0x00040035
+#define SMU7_CGULVCONTROL_DFLT                      0x00007450
+#define SMU7_TARGETACTIVITY_DFLT                     50
+#define SMU7_MCLK_TARGETACTIVITY_DFLT                10
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
new file mode 100644 (file)
index 0000000..508245d
--- /dev/null
@@ -0,0 +1,4359 @@
+/*
+ * Copyright 2015 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/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"
+#include "pppcielanes.h"
+#include "amd_pcie_helpers.h"
+#include "hardwaremanager.h"
+#include "process_pptables_v1_0.h"
+#include "cgs_common.h"
+
+#include "smu7_common.h"
+
+#include "hwmgr.h"
+#include "smu7_hwmgr.h"
+#include "smu7_powertune.h"
+#include "smu7_dyn_defaults.h"
+#include "smu7_thermal.h"
+#include "smu7_clockpowergating.h"
+#include "processpptables.h"
+
+#define MC_CG_ARB_FREQ_F0           0x0a
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define MC_CG_ARB_FREQ_F2           0x0c
+#define MC_CG_ARB_FREQ_F3           0x0d
+
+#define MC_CG_SEQ_DRAMCONF_S0       0x05
+#define MC_CG_SEQ_DRAMCONF_S1       0x06
+#define MC_CG_SEQ_YCLK_SUSPEND      0x04
+#define MC_CG_SEQ_YCLK_RESUME       0x0a
+
+#define SMC_CG_IND_START            0xc0030000
+#define SMC_CG_IND_END              0xc0040000
+
+#define VOLTAGE_SCALE               4
+#define VOLTAGE_VID_OFFSET_SCALE1   625
+#define VOLTAGE_VID_OFFSET_SCALE2   100
+
+#define MEM_FREQ_LOW_LATENCY        25000
+#define MEM_FREQ_HIGH_LATENCY       80000
+
+#define MEM_LATENCY_HIGH            45
+#define MEM_LATENCY_LOW             35
+#define MEM_LATENCY_ERR             0xFFFF
+
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+
+#define PCIE_BUS_CLK                10000
+#define TCLK                        (PCIE_BUS_CLK / 10)
+
+
+/** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
+enum DPM_EVENT_SRC {
+       DPM_EVENT_SRC_ANALOG = 0,
+       DPM_EVENT_SRC_EXTERNAL = 1,
+       DPM_EVENT_SRC_DIGITAL = 2,
+       DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,
+       DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4
+};
+
+static const unsigned long PhwVIslands_Magic = (unsigned long)(PHM_VIslands_Magic);
+
+struct smu7_power_state *cast_phw_smu7_power_state(
+                                 struct pp_hw_power_state *hw_ps)
+{
+       PP_ASSERT_WITH_CODE((PhwVIslands_Magic == hw_ps->magic),
+                               "Invalid Powerstate Type!",
+                                return NULL);
+
+       return (struct smu7_power_state *)hw_ps;
+}
+
+const struct smu7_power_state *cast_const_phw_smu7_power_state(
+                                const struct pp_hw_power_state *hw_ps)
+{
+       PP_ASSERT_WITH_CODE((PhwVIslands_Magic == hw_ps->magic),
+                               "Invalid Powerstate Type!",
+                                return NULL);
+
+       return (const struct smu7_power_state *)hw_ps;
+}
+
+/**
+ * Find the MC microcode version and store it in the HwMgr struct
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int smu7_get_mc_microcode_version (struct pp_hwmgr *hwmgr)
+{
+       cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX, 0x9F);
+
+       hwmgr->microcode_version_info.MC = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA);
+
+       return 0;
+}
+
+uint16_t smu7_get_current_pcie_speed(struct pp_hwmgr *hwmgr)
+{
+       uint32_t speedCntl = 0;
+
+       /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
+       speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE,
+                       ixPCIE_LC_SPEED_CNTL);
+       return((uint16_t)PHM_GET_FIELD(speedCntl,
+                       PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
+}
+
+int smu7_get_current_pcie_lane_number(struct pp_hwmgr *hwmgr)
+{
+       uint32_t link_width;
+
+       /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
+       link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
+                       PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD);
+
+       PP_ASSERT_WITH_CODE((7 >= link_width),
+                       "Invalid PCIe lane width!", return 0);
+
+       return decode_pcie_lane_width(link_width);
+}
+
+/**
+* Enable voltage control
+*
+* @param    pHwMgr  the address of the powerplay hardware manager.
+* @return   always PP_Result_OK
+*/
+int smu7_enable_smc_voltage_controller(struct pp_hwmgr *hwmgr)
+{
+       if (hwmgr->feature_mask & PP_SMC_VOLTAGE_CONTROL_MASK)
+               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Voltage_Cntl_Enable);
+
+       return 0;
+}
+
+/**
+* Checks if we want to support voltage control
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+*/
+static bool smu7_voltage_control(const struct pp_hwmgr *hwmgr)
+{
+       const struct smu7_hwmgr *data =
+                       (const struct smu7_hwmgr *)(hwmgr->backend);
+
+       return (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control);
+}
+
+/**
+* Enable voltage control
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int smu7_enable_voltage_control(struct pp_hwmgr *hwmgr)
+{
+       /* enable voltage control */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
+
+       return 0;
+}
+
+static int phm_get_svi2_voltage_table_v0(pp_atomctrl_voltage_table *voltage_table,
+               struct phm_clock_voltage_dependency_table *voltage_dependency_table
+               )
+{
+       uint32_t i;
+
+       PP_ASSERT_WITH_CODE((NULL != voltage_table),
+                       "Voltage Dependency Table empty.", return -EINVAL;);
+
+       voltage_table->mask_low = 0;
+       voltage_table->phase_delay = 0;
+       voltage_table->count = voltage_dependency_table->count;
+
+       for (i = 0; i < voltage_dependency_table->count; i++) {
+               voltage_table->entries[i].value =
+                       voltage_dependency_table->entries[i].v;
+               voltage_table->entries[i].smio_low = 0;
+       }
+
+       return 0;
+}
+
+
+/**
+* Create Voltage Tables.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int smu7_construct_voltage_tables(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)hwmgr->pptable;
+       int result = 0;
+       uint32_t tmp;
+
+       if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+               result = atomctrl_get_voltage_table_v3(hwmgr,
+                               VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT,
+                               &(data->mvdd_voltage_table));
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "Failed to retrieve MVDD table.",
+                               return result);
+       } else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
+               if (hwmgr->pp_table_version == PP_TABLE_V1)
+                       result = phm_get_svi2_mvdd_voltage_table(&(data->mvdd_voltage_table),
+                                       table_info->vdd_dep_on_mclk);
+               else if (hwmgr->pp_table_version == PP_TABLE_V0)
+                       result = phm_get_svi2_voltage_table_v0(&(data->mvdd_voltage_table),
+                                       hwmgr->dyn_state.mvdd_dependency_on_mclk);
+
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "Failed to retrieve SVI2 MVDD table from dependancy table.",
+                               return result;);
+       }
+
+       if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+               result = atomctrl_get_voltage_table_v3(hwmgr,
+                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT,
+                               &(data->vddci_voltage_table));
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "Failed to retrieve VDDCI table.",
+                               return result);
+       } else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
+               if (hwmgr->pp_table_version == PP_TABLE_V1)
+                       result = phm_get_svi2_vddci_voltage_table(&(data->vddci_voltage_table),
+                                       table_info->vdd_dep_on_mclk);
+               else if (hwmgr->pp_table_version == PP_TABLE_V0)
+                       result = phm_get_svi2_voltage_table_v0(&(data->vddci_voltage_table),
+                                       hwmgr->dyn_state.vddci_dependency_on_mclk);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "Failed to retrieve SVI2 VDDCI table from dependancy table.",
+                               return result);
+       }
+
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
+               /* VDDGFX has only SVI2 voltage control */
+               result = phm_get_svi2_vdd_voltage_table(&(data->vddgfx_voltage_table),
+                                       table_info->vddgfx_lookup_table);
+               PP_ASSERT_WITH_CODE((0 == result),
+                       "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result;);
+       }
+
+
+       if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) {
+               result = atomctrl_get_voltage_table_v3(hwmgr,
+                                       VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT,
+                                       &data->vddc_voltage_table);
+               PP_ASSERT_WITH_CODE((0 == result),
+                       "Failed to retrieve VDDC table.", return result;);
+       } else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+
+               if (hwmgr->pp_table_version == PP_TABLE_V0)
+                       result = phm_get_svi2_voltage_table_v0(&data->vddc_voltage_table,
+                                       hwmgr->dyn_state.vddc_dependency_on_mclk);
+               else if (hwmgr->pp_table_version == PP_TABLE_V1)
+                       result = phm_get_svi2_vdd_voltage_table(&(data->vddc_voltage_table),
+                               table_info->vddc_lookup_table);
+
+               PP_ASSERT_WITH_CODE((0 == result),
+                       "Failed to retrieve SVI2 VDDC table from dependancy table.", return result;);
+       }
+
+       tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_VDDC);
+       PP_ASSERT_WITH_CODE(
+                       (data->vddc_voltage_table.count <= tmp),
+               "Too many voltage values for VDDC. Trimming to fit state table.",
+                       phm_trim_voltage_table_to_fit_state_table(tmp,
+                                               &(data->vddc_voltage_table)));
+
+       tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_VDDGFX);
+       PP_ASSERT_WITH_CODE(
+                       (data->vddgfx_voltage_table.count <= tmp),
+               "Too many voltage values for VDDC. Trimming to fit state table.",
+                       phm_trim_voltage_table_to_fit_state_table(tmp,
+                                               &(data->vddgfx_voltage_table)));
+
+       tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_VDDCI);
+       PP_ASSERT_WITH_CODE(
+                       (data->vddci_voltage_table.count <= tmp),
+               "Too many voltage values for VDDCI. Trimming to fit state table.",
+                       phm_trim_voltage_table_to_fit_state_table(tmp,
+                                       &(data->vddci_voltage_table)));
+
+       tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_MVDD);
+       PP_ASSERT_WITH_CODE(
+                       (data->mvdd_voltage_table.count <= tmp),
+               "Too many voltage values for MVDD. Trimming to fit state table.",
+                       phm_trim_voltage_table_to_fit_state_table(tmp,
+                                               &(data->mvdd_voltage_table)));
+
+       return 0;
+}
+
+/**
+* Programs static screed detection parameters
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int smu7_program_static_screen_threshold_parameters(
+                                                       struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       /* Set static screen threshold unit */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
+                       data->static_screen_threshold_unit);
+       /* Set static screen threshold */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
+                       data->static_screen_threshold);
+
+       return 0;
+}
+
+/**
+* Setup display gap for glitch free memory clock switching.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always  0
+*/
+static int smu7_enable_display_gap(struct pp_hwmgr *hwmgr)
+{
+       uint32_t display_gap =
+                       cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                                       ixCG_DISPLAY_GAP_CNTL);
+
+       display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
+                       DISP_GAP, DISPLAY_GAP_IGNORE);
+
+       display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
+                       DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_DISPLAY_GAP_CNTL, display_gap);
+
+       return 0;
+}
+
+/**
+* Programs activity state transition voting clients
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always  0
+*/
+static int smu7_program_voting_clients(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       /* Clear reset for voting clients before enabling DPM */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
+
+       return 0;
+}
+
+static int smu7_clear_voting_clients(struct pp_hwmgr *hwmgr)
+{
+       /* Reset voting clients before disabling DPM */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 1);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 1);
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_0, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_1, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_2, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_3, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_4, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_5, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_6, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_7, 0);
+
+       return 0;
+}
+
+/* Copy one arb setting to another and then switch the active set.
+ * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
+ */
+static int smu7_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
+               uint32_t arb_src, uint32_t arb_dest)
+{
+       uint32_t mc_arb_dram_timing;
+       uint32_t mc_arb_dram_timing2;
+       uint32_t burst_time;
+       uint32_t mc_cg_config;
+
+       switch (arb_src) {
+       case MC_CG_ARB_FREQ_F0:
+               mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+               mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+               burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+               break;
+       case MC_CG_ARB_FREQ_F1:
+               mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
+               mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
+               burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (arb_dest) {
+       case MC_CG_ARB_FREQ_F0:
+               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
+               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
+               PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
+               break;
+       case MC_CG_ARB_FREQ_F1:
+               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
+               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
+               PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
+       mc_cg_config |= 0x0000000F;
+       cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
+       PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arb_dest);
+
+       return 0;
+}
+
+static int smu7_reset_to_default(struct pp_hwmgr *hwmgr)
+{
+       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults);
+}
+
+/**
+* Initial switch from ARB F0->F1
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+* This function is to be called from the SetPowerState table.
+*/
+static int smu7_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr)
+{
+       return smu7_copy_and_switch_arb_sets(hwmgr,
+                       MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+static int smu7_force_switch_to_arbf0(struct pp_hwmgr *hwmgr)
+{
+       uint32_t tmp;
+
+       tmp = (cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, ixSMC_SCRATCH9) &
+                       0x0000ff00) >> 8;
+
+       if (tmp == MC_CG_ARB_FREQ_F0)
+               return 0;
+
+       return smu7_copy_and_switch_arb_sets(hwmgr,
+                       tmp, MC_CG_ARB_FREQ_F0);
+}
+
+static int smu7_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_pcie_table *pcie_table = NULL;
+
+       uint32_t i, max_entry;
+       uint32_t tmp;
+
+       PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels ||
+                       data->use_pcie_power_saving_levels), "No pcie performance levels!",
+                       return -EINVAL);
+
+       if (table_info != NULL)
+               pcie_table = table_info->pcie_table;
+
+       if (data->use_pcie_performance_levels &&
+                       !data->use_pcie_power_saving_levels) {
+               data->pcie_gen_power_saving = data->pcie_gen_performance;
+               data->pcie_lane_power_saving = data->pcie_lane_performance;
+       } else if (!data->use_pcie_performance_levels &&
+                       data->use_pcie_power_saving_levels) {
+               data->pcie_gen_performance = data->pcie_gen_power_saving;
+               data->pcie_lane_performance = data->pcie_lane_power_saving;
+       }
+       tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_LINK);
+       phm_reset_single_dpm_table(&data->dpm_table.pcie_speed_table,
+                                       tmp,
+                                       MAX_REGULAR_DPM_NUMBER);
+
+       if (pcie_table != NULL) {
+               /* max_entry is used to make sure we reserve one PCIE level
+                * for boot level (fix for A+A PSPP issue).
+                * If PCIE table from PPTable have ULV entry + 8 entries,
+                * then ignore the last entry.*/
+               max_entry = (tmp < pcie_table->count) ? tmp : pcie_table->count;
+               for (i = 1; i < max_entry; i++) {
+                       phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i - 1,
+                                       get_pcie_gen_support(data->pcie_gen_cap,
+                                                       pcie_table->entries[i].gen_speed),
+                                       get_pcie_lane_support(data->pcie_lane_cap,
+                                                       pcie_table->entries[i].lane_width));
+               }
+               data->dpm_table.pcie_speed_table.count = max_entry - 1;
+               smum_update_smc_table(hwmgr, SMU_BIF_TABLE);
+       } else {
+               /* Hardcode Pcie Table */
+               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
+                               get_pcie_gen_support(data->pcie_gen_cap,
+                                               PP_Min_PCIEGen),
+                               get_pcie_lane_support(data->pcie_lane_cap,
+                                               PP_Max_PCIELane));
+               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
+                               get_pcie_gen_support(data->pcie_gen_cap,
+                                               PP_Min_PCIEGen),
+                               get_pcie_lane_support(data->pcie_lane_cap,
+                                               PP_Max_PCIELane));
+               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
+                               get_pcie_gen_support(data->pcie_gen_cap,
+                                               PP_Max_PCIEGen),
+                               get_pcie_lane_support(data->pcie_lane_cap,
+                                               PP_Max_PCIELane));
+               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
+                               get_pcie_gen_support(data->pcie_gen_cap,
+                                               PP_Max_PCIEGen),
+                               get_pcie_lane_support(data->pcie_lane_cap,
+                                               PP_Max_PCIELane));
+               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
+                               get_pcie_gen_support(data->pcie_gen_cap,
+                                               PP_Max_PCIEGen),
+                               get_pcie_lane_support(data->pcie_lane_cap,
+                                               PP_Max_PCIELane));
+               phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
+                               get_pcie_gen_support(data->pcie_gen_cap,
+                                               PP_Max_PCIEGen),
+                               get_pcie_lane_support(data->pcie_lane_cap,
+                                               PP_Max_PCIELane));
+
+               data->dpm_table.pcie_speed_table.count = 6;
+       }
+       /* Populate last level for boot PCIE level, but do not increment count. */
+       phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
+                       data->dpm_table.pcie_speed_table.count,
+                       get_pcie_gen_support(data->pcie_gen_cap,
+                                       PP_Min_PCIEGen),
+                       get_pcie_lane_support(data->pcie_lane_cap,
+                                       PP_Max_PCIELane));
+
+       return 0;
+}
+
+static int smu7_reset_dpm_tables(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       memset(&(data->dpm_table), 0x00, sizeof(data->dpm_table));
+
+       phm_reset_single_dpm_table(
+                       &data->dpm_table.sclk_table,
+                               smum_get_mac_definition(hwmgr->smumgr,
+                                       SMU_MAX_LEVELS_GRAPHICS),
+                                       MAX_REGULAR_DPM_NUMBER);
+       phm_reset_single_dpm_table(
+                       &data->dpm_table.mclk_table,
+                       smum_get_mac_definition(hwmgr->smumgr,
+                               SMU_MAX_LEVELS_MEMORY), MAX_REGULAR_DPM_NUMBER);
+
+       phm_reset_single_dpm_table(
+                       &data->dpm_table.vddc_table,
+                               smum_get_mac_definition(hwmgr->smumgr,
+                                       SMU_MAX_LEVELS_VDDC),
+                                       MAX_REGULAR_DPM_NUMBER);
+       phm_reset_single_dpm_table(
+                       &data->dpm_table.vddci_table,
+                       smum_get_mac_definition(hwmgr->smumgr,
+                               SMU_MAX_LEVELS_VDDCI), MAX_REGULAR_DPM_NUMBER);
+
+       phm_reset_single_dpm_table(
+                       &data->dpm_table.mvdd_table,
+                               smum_get_mac_definition(hwmgr->smumgr,
+                                       SMU_MAX_LEVELS_MVDD),
+                                       MAX_REGULAR_DPM_NUMBER);
+       return 0;
+}
+/*
+ * This function is to initialize all DPM state tables
+ * for SMU7 based on the dependency table.
+ * Dynamic state patching function will then trim these
+ * state tables to the allowed range based
+ * on the power policy or external client requests,
+ * such as UVD request, etc.
+ */
+
+static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_clock_voltage_dependency_table *allowed_vdd_sclk_table =
+               hwmgr->dyn_state.vddc_dependency_on_sclk;
+       struct phm_clock_voltage_dependency_table *allowed_vdd_mclk_table =
+               hwmgr->dyn_state.vddc_dependency_on_mclk;
+       struct phm_cac_leakage_table *std_voltage_table =
+               hwmgr->dyn_state.cac_leakage_table;
+       uint32_t i;
+
+       PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
+               "SCLK dependency table is missing. This table is mandatory", return -EINVAL);
+       PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table->count >= 1,
+               "SCLK dependency table has to have is missing. This table is mandatory", return -EINVAL);
+
+       PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
+               "MCLK dependency table is missing. This table is mandatory", return -EINVAL);
+       PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table->count >= 1,
+               "VMCLK dependency table has to have is missing. This table is mandatory", return -EINVAL);
+
+
+       /* Initialize Sclk DPM table based on allow Sclk values*/
+       data->dpm_table.sclk_table.count = 0;
+
+       for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
+               if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value !=
+                               allowed_vdd_sclk_table->entries[i].clk) {
+                       data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
+                               allowed_vdd_sclk_table->entries[i].clk;
+                       data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; to do */
+                       data->dpm_table.sclk_table.count++;
+               }
+       }
+
+       PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
+               "MCLK dependency table is missing. This table is mandatory", return -EINVAL);
+       /* Initialize Mclk DPM table based on allow Mclk values */
+       data->dpm_table.mclk_table.count = 0;
+       for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
+               if (i == 0 || data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count-1].value !=
+                       allowed_vdd_mclk_table->entries[i].clk) {
+                       data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
+                               allowed_vdd_mclk_table->entries[i].clk;
+                       data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; */
+                       data->dpm_table.mclk_table.count++;
+               }
+       }
+
+       /* Initialize Vddc DPM table based on allow Vddc values.  And populate corresponding std values. */
+       for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
+               data->dpm_table.vddc_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v;
+               data->dpm_table.vddc_table.dpm_levels[i].param1 = std_voltage_table->entries[i].Leakage;
+               /* param1 is for corresponding std voltage */
+               data->dpm_table.vddc_table.dpm_levels[i].enabled = 1;
+       }
+
+       data->dpm_table.vddc_table.count = allowed_vdd_sclk_table->count;
+       allowed_vdd_mclk_table = hwmgr->dyn_state.vddci_dependency_on_mclk;
+
+       if (NULL != allowed_vdd_mclk_table) {
+               /* Initialize Vddci DPM table based on allow Mclk values */
+               for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
+                       data->dpm_table.vddci_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v;
+                       data->dpm_table.vddci_table.dpm_levels[i].enabled = 1;
+               }
+               data->dpm_table.vddci_table.count = allowed_vdd_mclk_table->count;
+       }
+
+       allowed_vdd_mclk_table = hwmgr->dyn_state.mvdd_dependency_on_mclk;
+
+       if (NULL != allowed_vdd_mclk_table) {
+               /*
+                * Initialize MVDD DPM table based on allow Mclk
+                * values
+                */
+               for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
+                       data->dpm_table.mvdd_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v;
+                       data->dpm_table.mvdd_table.dpm_levels[i].enabled = 1;
+               }
+               data->dpm_table.mvdd_table.count = allowed_vdd_mclk_table->count;
+       }
+
+       return 0;
+}
+
+static int smu7_setup_dpm_tables_v1(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       uint32_t i;
+
+       struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table;
+       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table;
+
+       if (table_info == NULL)
+               return -EINVAL;
+
+       dep_sclk_table = table_info->vdd_dep_on_sclk;
+       dep_mclk_table = table_info->vdd_dep_on_mclk;
+
+       PP_ASSERT_WITH_CODE(dep_sclk_table != NULL,
+                       "SCLK dependency table is missing.",
+                       return -EINVAL);
+       PP_ASSERT_WITH_CODE(dep_sclk_table->count >= 1,
+                       "SCLK dependency table count is 0.",
+                       return -EINVAL);
+
+       PP_ASSERT_WITH_CODE(dep_mclk_table != NULL,
+                       "MCLK dependency table is missing.",
+                       return -EINVAL);
+       PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
+                       "MCLK dependency table count is 0",
+                       return -EINVAL);
+
+       /* Initialize Sclk DPM table based on allow Sclk values */
+       data->dpm_table.sclk_table.count = 0;
+       for (i = 0; i < dep_sclk_table->count; i++) {
+               if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count - 1].value !=
+                                               dep_sclk_table->entries[i].clk) {
+
+                       data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
+                                       dep_sclk_table->entries[i].clk;
+
+                       data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled =
+                                       (i == 0) ? true : false;
+                       data->dpm_table.sclk_table.count++;
+               }
+       }
+
+       /* Initialize Mclk DPM table based on allow Mclk values */
+       data->dpm_table.mclk_table.count = 0;
+       for (i = 0; i < dep_mclk_table->count; i++) {
+               if (i == 0 || data->dpm_table.mclk_table.dpm_levels
+                               [data->dpm_table.mclk_table.count - 1].value !=
+                                               dep_mclk_table->entries[i].clk) {
+                       data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
+                                                       dep_mclk_table->entries[i].clk;
+                       data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled =
+                                                       (i == 0) ? true : false;
+                       data->dpm_table.mclk_table.count++;
+               }
+       }
+
+       return 0;
+}
+
+int smu7_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       smu7_reset_dpm_tables(hwmgr);
+
+       if (hwmgr->pp_table_version == PP_TABLE_V1)
+               smu7_setup_dpm_tables_v1(hwmgr);
+       else if (hwmgr->pp_table_version == PP_TABLE_V0)
+               smu7_setup_dpm_tables_v0(hwmgr);
+
+       smu7_setup_default_pcie_table(hwmgr);
+
+       /* save a copy of the default DPM table */
+       memcpy(&(data->golden_dpm_table), &(data->dpm_table),
+                       sizeof(struct smu7_dpm_table));
+       return 0;
+}
+
+uint32_t smu7_get_xclk(struct pp_hwmgr *hwmgr)
+{
+       uint32_t reference_clock, tmp;
+       struct cgs_display_info info = {0};
+       struct cgs_mode_info mode_info;
+
+       info.mode_info = &mode_info;
+
+       tmp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK);
+
+       if (tmp)
+               return TCLK;
+
+       cgs_get_active_displays_info(hwmgr->device, &info);
+       reference_clock = mode_info.ref_clock;
+
+       tmp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL, XTALIN_DIVIDE);
+
+       if (0 != tmp)
+               return reference_clock / 4;
+
+       return reference_clock;
+}
+
+static int smu7_enable_vrhot_gpio_interrupt(struct pp_hwmgr *hwmgr)
+{
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_RegulatorHot))
+               return smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_EnableVRHotGPIOInterrupt);
+
+       return 0;
+}
+
+static int smu7_enable_sclk_control(struct pp_hwmgr *hwmgr)
+{
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
+                       SCLK_PWRMGT_OFF, 0);
+       return 0;
+}
+
+static int smu7_enable_ulv(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->ulv_supported)
+               return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_EnableULV);
+
+       return 0;
+}
+
+static int smu7_disable_ulv(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->ulv_supported)
+               return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableULV);
+
+       return 0;
+}
+
+static int smu7_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
+{
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkDeepSleep)) {
+               if (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MASTER_DeepSleep_ON))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to enable Master Deep Sleep switch failed!",
+                                       return -EINVAL);
+       } else {
+               if (smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_MASTER_DeepSleep_OFF)) {
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to disable Master Deep Sleep switch failed!",
+                                       return -EINVAL);
+               }
+       }
+
+       return 0;
+}
+
+static int smu7_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
+{
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkDeepSleep)) {
+               if (smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_MASTER_DeepSleep_OFF)) {
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to disable Master Deep Sleep switch failed!",
+                                       return -EINVAL);
+               }
+       }
+
+       return 0;
+}
+
+static int smu7_disable_handshake_uvd(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t soft_register_value = 0;
+       uint32_t handshake_disables_offset = data->soft_regs_start
+                               + smum_get_offsetof(hwmgr->smumgr,
+                                       SMU_SoftRegisters, HandshakeDisables);
+
+       soft_register_value = cgs_read_ind_register(hwmgr->device,
+                               CGS_IND_REG__SMC, handshake_disables_offset);
+       soft_register_value |= smum_get_mac_definition(hwmgr->smumgr,
+                                       SMU_UVD_MCLK_HANDSHAKE_DISABLE);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       handshake_disables_offset, soft_register_value);
+       return 0;
+}
+
+static int smu7_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       /* enable SCLK dpm */
+       if (!data->sclk_dpm_key_disabled)
+               PP_ASSERT_WITH_CODE(
+               (0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Enable)),
+               "Failed to enable SCLK DPM during DPM Start Function!",
+               return -EINVAL);
+
+       /* enable MCLK dpm */
+       if (0 == data->mclk_dpm_key_disabled) {
+               if (!(hwmgr->feature_mask & PP_UVD_HANDSHAKE_MASK))
+                       smu7_disable_handshake_uvd(hwmgr);
+               PP_ASSERT_WITH_CODE(
+                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+                                               PPSMC_MSG_MCLKDPM_Enable)),
+                               "Failed to enable MCLK DPM during DPM Start Function!",
+                               return -EINVAL);
+
+               PHM_WRITE_FIELD(hwmgr->device, MC_SEQ_CNTL_3, CAC_EN, 0x1);
+
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x5);
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x5);
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x100005);
+               udelay(10);
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x400005);
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x400005);
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x500005);
+       }
+
+       return 0;
+}
+
+static int smu7_start_dpm(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       /*enable general power management */
+
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+                       GLOBAL_PWRMGT_EN, 1);
+
+       /* enable sclk deep sleep */
+
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
+                       DYNAMIC_PM_EN, 1);
+
+       /* prepare for PCIE DPM */
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       data->soft_regs_start +
+                       smum_get_offsetof(hwmgr->smumgr, SMU_SoftRegisters,
+                                               VoltageChangeTimeout), 0x1000);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
+                       SWRST_COMMAND_1, RESETLC, 0x0);
+
+       PP_ASSERT_WITH_CODE(
+                       (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+                                       PPSMC_MSG_Voltage_Cntl_Enable)),
+                       "Failed to enable voltage DPM during DPM Start Function!",
+                       return -EINVAL);
+
+
+       if (smu7_enable_sclk_mclk_dpm(hwmgr)) {
+               printk(KERN_ERR "Failed to enable Sclk DPM and Mclk DPM!");
+               return -EINVAL;
+       }
+
+       /* enable PCIE dpm */
+       if (0 == data->pcie_dpm_key_disabled) {
+               PP_ASSERT_WITH_CODE(
+                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+                                               PPSMC_MSG_PCIeDPM_Enable)),
+                               "Failed to enable pcie DPM during DPM Start Function!",
+                               return -EINVAL);
+       }
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_Falcon_QuickTransition)) {
+               PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_EnableACDCGPIOInterrupt)),
+                               "Failed to enable AC DC GPIO Interrupt!",
+                               );
+       }
+
+       return 0;
+}
+
+static int smu7_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       /* disable SCLK dpm */
+       if (!data->sclk_dpm_key_disabled)
+               PP_ASSERT_WITH_CODE(
+                               (smum_send_msg_to_smc(hwmgr->smumgr,
+                                               PPSMC_MSG_DPM_Disable) == 0),
+                               "Failed to disable SCLK DPM!",
+                               return -EINVAL);
+
+       /* disable MCLK dpm */
+       if (!data->mclk_dpm_key_disabled) {
+               PP_ASSERT_WITH_CODE(
+                               (smum_send_msg_to_smc(hwmgr->smumgr,
+                                               PPSMC_MSG_MCLKDPM_Disable) == 0),
+                               "Failed to disable MCLK DPM!",
+                               return -EINVAL);
+       }
+
+       return 0;
+}
+
+static int smu7_stop_dpm(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       /* disable general power management */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+                       GLOBAL_PWRMGT_EN, 0);
+       /* disable sclk deep sleep */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
+                       DYNAMIC_PM_EN, 0);
+
+       /* disable PCIE dpm */
+       if (!data->pcie_dpm_key_disabled) {
+               PP_ASSERT_WITH_CODE(
+                               (smum_send_msg_to_smc(hwmgr->smumgr,
+                                               PPSMC_MSG_PCIeDPM_Disable) == 0),
+                               "Failed to disable pcie DPM during DPM Stop Function!",
+                               return -EINVAL);
+       }
+
+       if (smu7_disable_sclk_mclk_dpm(hwmgr)) {
+               printk(KERN_ERR "Failed to disable Sclk DPM and Mclk DPM!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void smu7_set_dpm_event_sources(struct pp_hwmgr *hwmgr, uint32_t sources)
+{
+       bool protection;
+       enum DPM_EVENT_SRC src;
+
+       switch (sources) {
+       default:
+               printk(KERN_ERR "Unknown throttling event sources.");
+               /* fall through */
+       case 0:
+               protection = false;
+               /* src is unused */
+               break;
+       case (1 << PHM_AutoThrottleSource_Thermal):
+               protection = true;
+               src = DPM_EVENT_SRC_DIGITAL;
+               break;
+       case (1 << PHM_AutoThrottleSource_External):
+               protection = true;
+               src = DPM_EVENT_SRC_EXTERNAL;
+               break;
+       case (1 << PHM_AutoThrottleSource_External) |
+                       (1 << PHM_AutoThrottleSource_Thermal):
+               protection = true;
+               src = DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL;
+               break;
+       }
+       /* Order matters - don't enable thermal protection for the wrong source. */
+       if (protection) {
+               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL,
+                               DPM_EVENT_SRC, src);
+               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+                               THERMAL_PROTECTION_DIS,
+                               !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                               PHM_PlatformCaps_ThermalController));
+       } else
+               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+                               THERMAL_PROTECTION_DIS, 1);
+}
+
+static int smu7_enable_auto_throttle_source(struct pp_hwmgr *hwmgr,
+               PHM_AutoThrottleSource source)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (!(data->active_auto_throttle_sources & (1 << source))) {
+               data->active_auto_throttle_sources |= 1 << source;
+               smu7_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
+       }
+       return 0;
+}
+
+static int smu7_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
+{
+       return smu7_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
+}
+
+static int smu7_disable_auto_throttle_source(struct pp_hwmgr *hwmgr,
+               PHM_AutoThrottleSource source)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->active_auto_throttle_sources & (1 << source)) {
+               data->active_auto_throttle_sources &= ~(1 << source);
+               smu7_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
+       }
+       return 0;
+}
+
+static int smu7_disable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
+{
+       return smu7_disable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
+}
+
+int smu7_pcie_performance_request(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       data->pcie_performance_request = true;
+
+       return 0;
+}
+
+int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
+{
+       int tmp_result = 0;
+       int result = 0;
+
+       tmp_result = (!smum_is_dpm_running(hwmgr)) ? 0 : -1;
+       PP_ASSERT_WITH_CODE(tmp_result == 0,
+                       "DPM is already running right now, no need to enable DPM!",
+                       return 0);
+
+       if (smu7_voltage_control(hwmgr)) {
+               tmp_result = smu7_enable_voltage_control(hwmgr);
+               PP_ASSERT_WITH_CODE(tmp_result == 0,
+                               "Failed to enable voltage control!",
+                               result = tmp_result);
+
+               tmp_result = smu7_construct_voltage_tables(hwmgr);
+               PP_ASSERT_WITH_CODE((0 == tmp_result),
+                               "Failed to contruct voltage tables!",
+                               result = tmp_result);
+       }
+       smum_initialize_mc_reg_table(hwmgr);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_EngineSpreadSpectrumSupport))
+               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                               GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 1);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ThermalController))
+               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                               GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 0);
+
+       tmp_result = smu7_program_static_screen_threshold_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to program static screen threshold parameters!",
+                       result = tmp_result);
+
+       tmp_result = smu7_enable_display_gap(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable display gap!", result = tmp_result);
+
+       tmp_result = smu7_program_voting_clients(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to program voting clients!", result = tmp_result);
+
+       tmp_result = smum_process_firmware_header(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to process firmware header!", result = tmp_result);
+
+       tmp_result = smu7_initial_switch_from_arbf0_to_f1(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to initialize switch from ArbF0 to F1!",
+                       result = tmp_result);
+
+       result = smu7_setup_default_dpm_tables(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to setup default DPM tables!", return result);
+
+       tmp_result = smum_init_smc_table(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to initialize SMC table!", result = tmp_result);
+
+       tmp_result = smu7_enable_vrhot_gpio_interrupt(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable VR hot GPIO interrupt!", result = tmp_result);
+
+       smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_HasDisplay);
+
+       tmp_result = smu7_enable_sclk_control(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable SCLK control!", result = tmp_result);
+
+       tmp_result = smu7_enable_smc_voltage_controller(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable voltage control!", result = tmp_result);
+
+       tmp_result = smu7_enable_ulv(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable ULV!", result = tmp_result);
+
+       tmp_result = smu7_enable_deep_sleep_master_switch(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable deep sleep master switch!", result = tmp_result);
+
+       tmp_result = smu7_enable_didt_config(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to enable deep sleep master switch!", result = tmp_result);
+
+       tmp_result = smu7_start_dpm(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to start DPM!", result = tmp_result);
+
+       tmp_result = smu7_enable_smc_cac(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable SMC CAC!", result = tmp_result);
+
+       tmp_result = smu7_enable_power_containment(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable power containment!", result = tmp_result);
+
+       tmp_result = smu7_power_control_set_level(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to power control set level!", result = tmp_result);
+
+       tmp_result = smu7_enable_thermal_auto_throttle(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable thermal auto throttle!", result = tmp_result);
+
+       tmp_result = smu7_pcie_performance_request(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "pcie performance request failed!", result = tmp_result);
+
+       return 0;
+}
+
+int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
+{
+       int tmp_result, result = 0;
+
+       tmp_result = (smum_is_dpm_running(hwmgr)) ? 0 : -1;
+       PP_ASSERT_WITH_CODE(tmp_result == 0,
+                       "DPM is not running right now, no need to disable DPM!",
+                       return 0);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ThermalController))
+               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                               GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 1);
+
+       tmp_result = smu7_disable_power_containment(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable power containment!", result = tmp_result);
+
+       tmp_result = smu7_disable_smc_cac(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable SMC CAC!", 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,
+                       GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 0);
+
+       tmp_result = smu7_disable_thermal_auto_throttle(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable thermal auto throttle!", result = tmp_result);
+
+       tmp_result = smu7_stop_dpm(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to stop DPM!", result = tmp_result);
+
+       tmp_result = smu7_disable_deep_sleep_master_switch(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable deep sleep master switch!", result = tmp_result);
+
+       tmp_result = smu7_disable_ulv(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable ULV!", result = tmp_result);
+
+       tmp_result = smu7_clear_voting_clients(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to clear voting clients!", result = tmp_result);
+
+       tmp_result = smu7_reset_to_default(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to reset to default!", result = tmp_result);
+
+       tmp_result = smu7_force_switch_to_arbf0(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to force to switch arbf0!", result = tmp_result);
+
+       return result;
+}
+
+int smu7_reset_asic_tasks(struct pp_hwmgr *hwmgr)
+{
+
+       return 0;
+}
+
+static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       data->dll_default_on = false;
+       data->mclk_dpm0_activity_target = 0xa;
+       data->mclk_activity_target = SMU7_MCLK_TARGETACTIVITY_DFLT;
+       data->vddc_vddgfx_delta = 300;
+       data->static_screen_threshold = SMU7_STATICSCREENTHRESHOLD_DFLT;
+       data->static_screen_threshold_unit = SMU7_STATICSCREENTHRESHOLDUNIT_DFLT;
+       data->voting_rights_clients0 = SMU7_VOTINGRIGHTSCLIENTS_DFLT0;
+       data->voting_rights_clients1 = SMU7_VOTINGRIGHTSCLIENTS_DFLT1;
+       data->voting_rights_clients2 = SMU7_VOTINGRIGHTSCLIENTS_DFLT2;
+       data->voting_rights_clients3 = SMU7_VOTINGRIGHTSCLIENTS_DFLT3;
+       data->voting_rights_clients4 = SMU7_VOTINGRIGHTSCLIENTS_DFLT4;
+       data->voting_rights_clients5 = SMU7_VOTINGRIGHTSCLIENTS_DFLT5;
+       data->voting_rights_clients6 = SMU7_VOTINGRIGHTSCLIENTS_DFLT6;
+       data->voting_rights_clients7 = SMU7_VOTINGRIGHTSCLIENTS_DFLT7;
+
+       data->mclk_dpm_key_disabled = hwmgr->feature_mask & PP_MCLK_DPM_MASK ? false : true;
+       data->sclk_dpm_key_disabled = hwmgr->feature_mask & PP_SCLK_DPM_MASK ? false : true;
+       data->pcie_dpm_key_disabled = hwmgr->feature_mask & PP_PCIE_DPM_MASK ? false : true;
+       /* need to set voltage control types before EVV patching */
+       data->voltage_control = SMU7_VOLTAGE_CONTROL_NONE;
+       data->vddci_control = SMU7_VOLTAGE_CONTROL_NONE;
+       data->mvdd_control = SMU7_VOLTAGE_CONTROL_NONE;
+       data->enable_tdc_limit_feature = true;
+       data->enable_pkg_pwr_tracking_feature = true;
+       data->force_pcie_gen = PP_PCIEGenInvalid;
+       data->ulv_supported = hwmgr->feature_mask & PP_ULV_MASK ? true : false;
+
+       data->fast_watermark_threshold = 100;
+       if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+                       VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
+               data->voltage_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ControlVDDGFX)) {
+               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+                       VOLTAGE_TYPE_VDDGFX, VOLTAGE_OBJ_SVID2)) {
+                       data->vdd_gfx_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
+               }
+       }
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_EnableMVDDControl)) {
+               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+                               VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
+                       data->mvdd_control = SMU7_VOLTAGE_CONTROL_BY_GPIO;
+               else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+                               VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2))
+                       data->mvdd_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
+       }
+
+       if (SMU7_VOLTAGE_CONTROL_NONE == data->vdd_gfx_control) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ControlVDDGFX);
+       }
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ControlVDDCI)) {
+               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
+                       data->vddci_control = SMU7_VOLTAGE_CONTROL_BY_GPIO;
+               else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
+                       data->vddci_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
+       }
+
+       if (data->mvdd_control == SMU7_VOLTAGE_CONTROL_NONE)
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_EnableMVDDControl);
+
+       if (data->vddci_control == SMU7_VOLTAGE_CONTROL_NONE)
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_ControlVDDCI);
+
+       if ((hwmgr->pp_table_version != PP_TABLE_V0)
+               && (table_info->cac_dtp_table->usClockStretchAmount != 0))
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_ClockStretcher);
+
+       data->pcie_gen_performance.max = PP_PCIEGen1;
+       data->pcie_gen_performance.min = PP_PCIEGen3;
+       data->pcie_gen_power_saving.max = PP_PCIEGen1;
+       data->pcie_gen_power_saving.min = PP_PCIEGen3;
+       data->pcie_lane_performance.max = 0;
+       data->pcie_lane_performance.min = 16;
+       data->pcie_lane_power_saving.max = 0;
+       data->pcie_lane_power_saving.min = 16;
+}
+
+/**
+* Get Leakage VDDC based on leakage ID.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int smu7_get_evv_voltages(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint16_t vv_id;
+       uint16_t vddc = 0;
+       uint16_t vddgfx = 0;
+       uint16_t i, j;
+       uint32_t sclk = 0;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)hwmgr->pptable;
+       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = NULL;
+
+
+       if (table_info != NULL)
+               sclk_table = table_info->vdd_dep_on_sclk;
+
+       for (i = 0; i < SMU7_MAX_LEAKAGE_COUNT; i++) {
+               vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
+
+               if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
+                       if (0 == phm_get_sclk_for_voltage_evv(hwmgr,
+                                               table_info->vddgfx_lookup_table, vv_id, &sclk)) {
+                               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                                       PHM_PlatformCaps_ClockStretcher)) {
+                                       for (j = 1; j < sclk_table->count; j++) {
+                                               if (sclk_table->entries[j].clk == sclk &&
+                                                               sclk_table->entries[j].cks_enable == 0) {
+                                                       sclk += 5000;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if (0 == atomctrl_get_voltage_evv_on_sclk
+                                   (hwmgr, VOLTAGE_TYPE_VDDGFX, sclk,
+                                    vv_id, &vddgfx)) {
+                                       /* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
+                                       PP_ASSERT_WITH_CODE((vddgfx < 2000 && vddgfx != 0), "Invalid VDDGFX value!", return -EINVAL);
+
+                                       /* the voltage should not be zero nor equal to leakage ID */
+                                       if (vddgfx != 0 && vddgfx != vv_id) {
+                                               data->vddcgfx_leakage.actual_voltage[data->vddcgfx_leakage.count] = vddgfx;
+                                               data->vddcgfx_leakage.leakage_id[data->vddcgfx_leakage.count] = vv_id;
+                                               data->vddcgfx_leakage.count++;
+                                       }
+                               } else {
+                                       printk("Error retrieving EVV voltage value!\n");
+                               }
+                       }
+               } else {
+
+                       if ((hwmgr->pp_table_version == PP_TABLE_V0)
+                               || !phm_get_sclk_for_voltage_evv(hwmgr,
+                                       table_info->vddc_lookup_table, vv_id, &sclk)) {
+                               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                               PHM_PlatformCaps_ClockStretcher)) {
+                                       for (j = 1; j < sclk_table->count; j++) {
+                                               if (sclk_table->entries[j].clk == sclk &&
+                                                               sclk_table->entries[j].cks_enable == 0) {
+                                                       sclk += 5000;
+                                                       break;
+                                               }
+                                       }
+                               }
+
+                               if (phm_get_voltage_evv_on_sclk(hwmgr,
+                                                       VOLTAGE_TYPE_VDDC,
+                                                       sclk, vv_id, &vddc) == 0) {
+                                       if (vddc >= 2000 || vddc == 0)
+                                               return -EINVAL;
+                               } else {
+                                       printk(KERN_WARNING "failed to retrieving EVV voltage!\n");
+                                       continue;
+                               }
+
+                               /* the voltage should not be zero nor equal to leakage ID */
+                               if (vddc != 0 && vddc != vv_id) {
+                                       data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = (uint16_t)(vddc);
+                                       data->vddc_leakage.leakage_id[data->vddc_leakage.count] = vv_id;
+                                       data->vddc_leakage.count++;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * Change virtual leakage voltage to actual value.
+ *
+ * @param     hwmgr  the address of the powerplay hardware manager.
+ * @param     pointer to changing voltage
+ * @param     pointer to leakage table
+ */
+static void smu7_patch_ppt_v1_with_vdd_leakage(struct pp_hwmgr *hwmgr,
+               uint16_t *voltage, struct smu7_leakage_voltage *leakage_table)
+{
+       uint32_t index;
+
+       /* search for leakage voltage ID 0xff01 ~ 0xff08 */
+       for (index = 0; index < leakage_table->count; index++) {
+               /* if this voltage matches a leakage voltage ID */
+               /* patch with actual leakage voltage */
+               if (leakage_table->leakage_id[index] == *voltage) {
+                       *voltage = leakage_table->actual_voltage[index];
+                       break;
+               }
+       }
+
+       if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
+               printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
+}
+
+/**
+* Patch voltage lookup table by EVV leakages.
+*
+* @param     hwmgr  the address of the powerplay hardware manager.
+* @param     pointer to voltage lookup table
+* @param     pointer to leakage table
+* @return     always 0
+*/
+static int smu7_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
+               phm_ppt_v1_voltage_lookup_table *lookup_table,
+               struct smu7_leakage_voltage *leakage_table)
+{
+       uint32_t i;
+
+       for (i = 0; i < lookup_table->count; i++)
+               smu7_patch_ppt_v1_with_vdd_leakage(hwmgr,
+                               &lookup_table->entries[i].us_vdd, leakage_table);
+
+       return 0;
+}
+
+static int smu7_patch_clock_voltage_limits_with_vddc_leakage(
+               struct pp_hwmgr *hwmgr, struct smu7_leakage_voltage *leakage_table,
+               uint16_t *vddc)
+{
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       smu7_patch_ppt_v1_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
+       hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
+                       table_info->max_clock_voltage_on_dc.vddc;
+       return 0;
+}
+
+static int smu7_patch_voltage_dependency_tables_with_lookup_table(
+               struct pp_hwmgr *hwmgr)
+{
+       uint8_t entry_id;
+       uint8_t voltage_id;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+                       table_info->vdd_dep_on_sclk;
+       struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
+                       table_info->vdd_dep_on_mclk;
+       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                       table_info->mm_dep_table;
+
+       if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
+               for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) {
+                       voltage_id = sclk_table->entries[entry_id].vddInd;
+                       sclk_table->entries[entry_id].vddgfx =
+                               table_info->vddgfx_lookup_table->entries[voltage_id].us_vdd;
+               }
+       } else {
+               for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) {
+                       voltage_id = sclk_table->entries[entry_id].vddInd;
+                       sclk_table->entries[entry_id].vddc =
+                               table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
+               }
+       }
+
+       for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) {
+               voltage_id = mclk_table->entries[entry_id].vddInd;
+               mclk_table->entries[entry_id].vddc =
+                       table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
+       }
+
+       for (entry_id = 0; entry_id < mm_table->count; ++entry_id) {
+               voltage_id = mm_table->entries[entry_id].vddcInd;
+               mm_table->entries[entry_id].vddc =
+                       table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
+       }
+
+       return 0;
+
+}
+
+static int phm_add_voltage(struct pp_hwmgr *hwmgr,
+                       phm_ppt_v1_voltage_lookup_table *look_up_table,
+                       phm_ppt_v1_voltage_lookup_record *record)
+{
+       uint32_t i;
+
+       PP_ASSERT_WITH_CODE((NULL != look_up_table),
+               "Lookup Table empty.", return -EINVAL);
+       PP_ASSERT_WITH_CODE((0 != look_up_table->count),
+               "Lookup Table empty.", return -EINVAL);
+
+       i = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_VDDGFX);
+       PP_ASSERT_WITH_CODE((i >= look_up_table->count),
+               "Lookup Table is full.", return -EINVAL);
+
+       /* This is to avoid entering duplicate calculated records. */
+       for (i = 0; i < look_up_table->count; i++) {
+               if (look_up_table->entries[i].us_vdd == record->us_vdd) {
+                       if (look_up_table->entries[i].us_calculated == 1)
+                               return 0;
+                       break;
+               }
+       }
+
+       look_up_table->entries[i].us_calculated = 1;
+       look_up_table->entries[i].us_vdd = record->us_vdd;
+       look_up_table->entries[i].us_cac_low = record->us_cac_low;
+       look_up_table->entries[i].us_cac_mid = record->us_cac_mid;
+       look_up_table->entries[i].us_cac_high = record->us_cac_high;
+       /* Only increment the count when we're appending, not replacing duplicate entry. */
+       if (i == look_up_table->count)
+               look_up_table->count++;
+
+       return 0;
+}
+
+
+static int smu7_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+       uint8_t entry_id;
+       struct phm_ppt_v1_voltage_lookup_record v_record;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
+       phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
+
+       if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
+               for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) {
+                       if (sclk_table->entries[entry_id].vdd_offset & (1 << 15))
+                               v_record.us_vdd = sclk_table->entries[entry_id].vddgfx +
+                                       sclk_table->entries[entry_id].vdd_offset - 0xFFFF;
+                       else
+                               v_record.us_vdd = sclk_table->entries[entry_id].vddgfx +
+                                       sclk_table->entries[entry_id].vdd_offset;
+
+                       sclk_table->entries[entry_id].vddc =
+                               v_record.us_cac_low = v_record.us_cac_mid =
+                               v_record.us_cac_high = v_record.us_vdd;
+
+                       phm_add_voltage(hwmgr, pptable_info->vddc_lookup_table, &v_record);
+               }
+
+               for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) {
+                       if (mclk_table->entries[entry_id].vdd_offset & (1 << 15))
+                               v_record.us_vdd = mclk_table->entries[entry_id].vddc +
+                                       mclk_table->entries[entry_id].vdd_offset - 0xFFFF;
+                       else
+                               v_record.us_vdd = mclk_table->entries[entry_id].vddc +
+                                       mclk_table->entries[entry_id].vdd_offset;
+
+                       mclk_table->entries[entry_id].vddgfx = v_record.us_cac_low =
+                               v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
+                       phm_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
+               }
+       }
+       return 0;
+}
+
+static int smu7_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
+{
+       uint8_t entry_id;
+       struct phm_ppt_v1_voltage_lookup_record v_record;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+       if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
+               for (entry_id = 0; entry_id < mm_table->count; entry_id++) {
+                       if (mm_table->entries[entry_id].vddgfx_offset & (1 << 15))
+                               v_record.us_vdd = mm_table->entries[entry_id].vddc +
+                                       mm_table->entries[entry_id].vddgfx_offset - 0xFFFF;
+                       else
+                               v_record.us_vdd = mm_table->entries[entry_id].vddc +
+                                       mm_table->entries[entry_id].vddgfx_offset;
+
+                       /* Add the calculated VDDGFX to the VDDGFX lookup table */
+                       mm_table->entries[entry_id].vddgfx = v_record.us_cac_low =
+                               v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
+                       phm_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
+               }
+       }
+       return 0;
+}
+
+static int smu7_sort_lookup_table(struct pp_hwmgr *hwmgr,
+               struct phm_ppt_v1_voltage_lookup_table *lookup_table)
+{
+       uint32_t table_size, i, j;
+       struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
+       table_size = lookup_table->count;
+
+       PP_ASSERT_WITH_CODE(0 != lookup_table->count,
+               "Lookup table is empty", return -EINVAL);
+
+       /* Sorting voltages */
+       for (i = 0; i < table_size - 1; i++) {
+               for (j = i + 1; j > 0; j--) {
+                       if (lookup_table->entries[j].us_vdd <
+                                       lookup_table->entries[j - 1].us_vdd) {
+                               tmp_voltage_lookup_record = lookup_table->entries[j - 1];
+                               lookup_table->entries[j - 1] = lookup_table->entries[j];
+                               lookup_table->entries[j] = tmp_voltage_lookup_record;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int smu7_complete_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+       int result = 0;
+       int tmp_result;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
+               tmp_result = smu7_patch_lookup_table_with_leakage(hwmgr,
+                       table_info->vddgfx_lookup_table, &(data->vddcgfx_leakage));
+               if (tmp_result != 0)
+                       result = tmp_result;
+
+               smu7_patch_ppt_v1_with_vdd_leakage(hwmgr,
+                       &table_info->max_clock_voltage_on_dc.vddgfx, &(data->vddcgfx_leakage));
+       } else {
+
+               tmp_result = smu7_patch_lookup_table_with_leakage(hwmgr,
+                               table_info->vddc_lookup_table, &(data->vddc_leakage));
+               if (tmp_result)
+                       result = tmp_result;
+
+               tmp_result = smu7_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
+                               &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
+               if (tmp_result)
+                       result = tmp_result;
+       }
+
+       tmp_result = smu7_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
+       if (tmp_result)
+               result = tmp_result;
+
+       tmp_result = smu7_calc_voltage_dependency_tables(hwmgr);
+       if (tmp_result)
+               result = tmp_result;
+
+       tmp_result = smu7_calc_mm_voltage_dependency_table(hwmgr);
+       if (tmp_result)
+               result = tmp_result;
+
+       tmp_result = smu7_sort_lookup_table(hwmgr, table_info->vddgfx_lookup_table);
+       if (tmp_result)
+               result = tmp_result;
+
+       tmp_result = smu7_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
+       if (tmp_result)
+               result = tmp_result;
+
+       return result;
+}
+
+static int smu7_set_private_data_based_on_pptable_v1(struct pp_hwmgr *hwmgr)
+{
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
+                                               table_info->vdd_dep_on_sclk;
+       struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
+                                               table_info->vdd_dep_on_mclk;
+
+       PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
+               "VDD dependency on SCLK table is missing.",
+               return -EINVAL);
+       PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
+               "VDD dependency on SCLK table has to have is missing.",
+               return -EINVAL);
+
+       PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
+               "VDD dependency on MCLK table is missing",
+               return -EINVAL);
+       PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
+               "VDD dependency on MCLK table has to have is missing.",
+               return -EINVAL);
+
+       table_info->max_clock_voltage_on_ac.sclk =
+               allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
+       table_info->max_clock_voltage_on_ac.mclk =
+               allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
+       table_info->max_clock_voltage_on_ac.vddc =
+               allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
+       table_info->max_clock_voltage_on_ac.vddci =
+               allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
+
+       hwmgr->dyn_state.max_clock_voltage_on_ac.sclk = table_info->max_clock_voltage_on_ac.sclk;
+       hwmgr->dyn_state.max_clock_voltage_on_ac.mclk = table_info->max_clock_voltage_on_ac.mclk;
+       hwmgr->dyn_state.max_clock_voltage_on_ac.vddc = table_info->max_clock_voltage_on_ac.vddc;
+       hwmgr->dyn_state.max_clock_voltage_on_ac.vddci = table_info->max_clock_voltage_on_ac.vddci;
+
+       return 0;
+}
+
+int smu7_patch_voltage_workaround(struct pp_hwmgr *hwmgr)
+{
+       struct phm_ppt_v1_information *table_info =
+                      (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table;
+       struct phm_ppt_v1_voltage_lookup_table *lookup_table;
+       uint32_t i;
+       uint32_t hw_revision, sub_vendor_id, sub_sys_id;
+       struct cgs_system_info sys_info = {0};
+
+       if (table_info != NULL) {
+               dep_mclk_table = table_info->vdd_dep_on_mclk;
+               lookup_table = table_info->vddc_lookup_table;
+       } else
+               return 0;
+
+       sys_info.size = sizeof(struct cgs_system_info);
+
+       sys_info.info_id = CGS_SYSTEM_INFO_PCIE_REV;
+       cgs_query_system_info(hwmgr->device, &sys_info);
+       hw_revision = (uint32_t)sys_info.value;
+
+       sys_info.info_id = CGS_SYSTEM_INFO_PCIE_SUB_SYS_ID;
+       cgs_query_system_info(hwmgr->device, &sys_info);
+       sub_sys_id = (uint32_t)sys_info.value;
+
+       sys_info.info_id = CGS_SYSTEM_INFO_PCIE_SUB_SYS_VENDOR_ID;
+       cgs_query_system_info(hwmgr->device, &sys_info);
+       sub_vendor_id = (uint32_t)sys_info.value;
+
+       if (hwmgr->chip_id == CHIP_POLARIS10 && hw_revision == 0xC7 &&
+                       ((sub_sys_id == 0xb37 && sub_vendor_id == 0x1002) ||
+                   (sub_sys_id == 0x4a8 && sub_vendor_id == 0x1043) ||
+                   (sub_sys_id == 0x9480 && sub_vendor_id == 0x1682))) {
+               if (lookup_table->entries[dep_mclk_table->entries[dep_mclk_table->count-1].vddInd].us_vdd >= 1000)
+                       return 0;
+
+               for (i = 0; i < lookup_table->count; i++) {
+                       if (lookup_table->entries[i].us_vdd < 0xff01 && lookup_table->entries[i].us_vdd >= 1000) {
+                               dep_mclk_table->entries[dep_mclk_table->count-1].vddInd = (uint8_t) i;
+                               return 0;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int smu7_thermal_parameter_init(struct pp_hwmgr *hwmgr)
+{
+       struct pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
+       uint32_t temp_reg;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+
+       if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_PCC_GPIO_PINID, &gpio_pin_assignment)) {
+               temp_reg = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL);
+               switch (gpio_pin_assignment.uc_gpio_pin_bit_shift) {
+               case 0:
+                       temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x1);
+                       break;
+               case 1:
+                       temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x2);
+                       break;
+               case 2:
+                       temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, GNB_SLOW, 0x1);
+                       break;
+               case 3:
+                       temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, FORCE_NB_PS1, 0x1);
+                       break;
+               case 4:
+                       temp_reg = PHM_SET_FIELD(temp_reg, CNB_PWRMGT_CNTL, DPM_ENABLED, 0x1);
+                       break;
+               default:
+                       PP_ASSERT_WITH_CODE(0,
+                       "Failed to setup PCC HW register! Wrong GPIO assigned for VDDC_PCC_GPIO_PINID!",
+                       );
+                       break;
+               }
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL, temp_reg);
+       }
+
+       if (table_info == NULL)
+               return 0;
+
+       if (table_info->cac_dtp_table->usDefaultTargetOperatingTemp != 0 &&
+               hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode) {
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMMinLimit =
+                       (uint16_t)hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit;
+
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMMaxLimit =
+                       (uint16_t)hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
+
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMStep = 1;
+
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMaxLimit = 100;
+
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMMinLimit =
+                       (uint16_t)hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit;
+
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMStep = 1;
+
+               table_info->cac_dtp_table->usDefaultTargetOperatingTemp = (table_info->cac_dtp_table->usDefaultTargetOperatingTemp >= 50) ?
+                                                               (table_info->cac_dtp_table->usDefaultTargetOperatingTemp - 50) : 0;
+
+               table_info->cac_dtp_table->usOperatingTempMaxLimit = table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
+               table_info->cac_dtp_table->usOperatingTempStep = 1;
+               table_info->cac_dtp_table->usOperatingTempHyst = 1;
+
+               hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM =
+                              hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
+
+               hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM =
+                              hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM;
+
+               hwmgr->dyn_state.cac_dtp_table->usOperatingTempMinLimit =
+                              table_info->cac_dtp_table->usOperatingTempMinLimit;
+
+               hwmgr->dyn_state.cac_dtp_table->usOperatingTempMaxLimit =
+                              table_info->cac_dtp_table->usOperatingTempMaxLimit;
+
+               hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
+                              table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
+
+               hwmgr->dyn_state.cac_dtp_table->usOperatingTempStep =
+                              table_info->cac_dtp_table->usOperatingTempStep;
+
+               hwmgr->dyn_state.cac_dtp_table->usTargetOperatingTemp =
+                              table_info->cac_dtp_table->usTargetOperatingTemp;
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                               PHM_PlatformCaps_ODFuzzyFanControlSupport);
+       }
+
+       return 0;
+}
+
+/**
+ * Change virtual leakage voltage to actual value.
+ *
+ * @param     hwmgr  the address of the powerplay hardware manager.
+ * @param     pointer to changing voltage
+ * @param     pointer to leakage table
+ */
+static void smu7_patch_ppt_v0_with_vdd_leakage(struct pp_hwmgr *hwmgr,
+               uint32_t *voltage, struct smu7_leakage_voltage *leakage_table)
+{
+       uint32_t index;
+
+       /* search for leakage voltage ID 0xff01 ~ 0xff08 */
+       for (index = 0; index < leakage_table->count; index++) {
+               /* if this voltage matches a leakage voltage ID */
+               /* patch with actual leakage voltage */
+               if (leakage_table->leakage_id[index] == *voltage) {
+                       *voltage = leakage_table->actual_voltage[index];
+                       break;
+               }
+       }
+
+       if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
+               printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
+}
+
+
+static int smu7_patch_vddc(struct pp_hwmgr *hwmgr,
+                             struct phm_clock_voltage_dependency_table *tab)
+{
+       uint16_t i;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (tab)
+               for (i = 0; i < tab->count; i++)
+                       smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
+                                               &data->vddc_leakage);
+
+       return 0;
+}
+
+static int smu7_patch_vddci(struct pp_hwmgr *hwmgr,
+                              struct phm_clock_voltage_dependency_table *tab)
+{
+       uint16_t i;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (tab)
+               for (i = 0; i < tab->count; i++)
+                       smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
+                                                       &data->vddci_leakage);
+
+       return 0;
+}
+
+static int smu7_patch_vce_vddc(struct pp_hwmgr *hwmgr,
+                                 struct phm_vce_clock_voltage_dependency_table *tab)
+{
+       uint16_t i;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (tab)
+               for (i = 0; i < tab->count; i++)
+                       smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
+                                                       &data->vddc_leakage);
+
+       return 0;
+}
+
+
+static int smu7_patch_uvd_vddc(struct pp_hwmgr *hwmgr,
+                                 struct phm_uvd_clock_voltage_dependency_table *tab)
+{
+       uint16_t i;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (tab)
+               for (i = 0; i < tab->count; i++)
+                       smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
+                                                       &data->vddc_leakage);
+
+       return 0;
+}
+
+static int smu7_patch_vddc_shed_limit(struct pp_hwmgr *hwmgr,
+                                        struct phm_phase_shedding_limits_table *tab)
+{
+       uint16_t i;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (tab)
+               for (i = 0; i < tab->count; i++)
+                       smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].Voltage,
+                                                       &data->vddc_leakage);
+
+       return 0;
+}
+
+static int smu7_patch_samu_vddc(struct pp_hwmgr *hwmgr,
+                                  struct phm_samu_clock_voltage_dependency_table *tab)
+{
+       uint16_t i;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (tab)
+               for (i = 0; i < tab->count; i++)
+                       smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
+                                                       &data->vddc_leakage);
+
+       return 0;
+}
+
+static int smu7_patch_acp_vddc(struct pp_hwmgr *hwmgr,
+                                 struct phm_acp_clock_voltage_dependency_table *tab)
+{
+       uint16_t i;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (tab)
+               for (i = 0; i < tab->count; i++)
+                       smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &tab->entries[i].v,
+                                       &data->vddc_leakage);
+
+       return 0;
+}
+
+static int smu7_patch_limits_vddc(struct pp_hwmgr *hwmgr,
+                                    struct phm_clock_and_voltage_limits *tab)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (tab) {
+               smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, (uint32_t *)&tab->vddc,
+                                                       &data->vddc_leakage);
+               smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, (uint32_t *)&tab->vddci,
+                                                       &data->vddci_leakage);
+       }
+
+       return 0;
+}
+
+static int smu7_patch_cac_vddc(struct pp_hwmgr *hwmgr, struct phm_cac_leakage_table *tab)
+{
+       uint32_t i;
+       uint32_t vddc;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (tab) {
+               for (i = 0; i < tab->count; i++) {
+                       vddc = (uint32_t)(tab->entries[i].Vddc);
+                       smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &vddc, &data->vddc_leakage);
+                       tab->entries[i].Vddc = (uint16_t)vddc;
+               }
+       }
+
+       return 0;
+}
+
+static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr)
+{
+       int tmp;
+
+       tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_sclk);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_mclk);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_vddci(hwmgr, hwmgr->dyn_state.vddci_dependency_on_mclk);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_uvd_vddc(hwmgr, hwmgr->dyn_state.uvd_clock_voltage_dependency_table);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_samu_vddc(hwmgr, hwmgr->dyn_state.samu_clock_voltage_dependency_table);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_acp_vddc(hwmgr, hwmgr->dyn_state.acp_clock_voltage_dependency_table);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_vddc_shed_limit(hwmgr, hwmgr->dyn_state.vddc_phase_shed_limits_table);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_limits_vddc(hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_ac);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_limits_vddc(hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_dc);
+       if (tmp)
+               return -EINVAL;
+
+       tmp = smu7_patch_cac_vddc(hwmgr, hwmgr->dyn_state.cac_leakage_table);
+       if (tmp)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int smu7_set_private_data_based_on_pptable_v0(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       struct phm_clock_voltage_dependency_table *allowed_sclk_vddc_table = hwmgr->dyn_state.vddc_dependency_on_sclk;
+       struct phm_clock_voltage_dependency_table *allowed_mclk_vddc_table = hwmgr->dyn_state.vddc_dependency_on_mclk;
+       struct phm_clock_voltage_dependency_table *allowed_mclk_vddci_table = hwmgr->dyn_state.vddci_dependency_on_mclk;
+
+       PP_ASSERT_WITH_CODE(allowed_sclk_vddc_table != NULL,
+               "VDDC dependency on SCLK table is missing. This table is mandatory\n", return -EINVAL);
+       PP_ASSERT_WITH_CODE(allowed_sclk_vddc_table->count >= 1,
+               "VDDC dependency on SCLK table has to have is missing. This table is mandatory\n", return -EINVAL);
+
+       PP_ASSERT_WITH_CODE(allowed_mclk_vddc_table != NULL,
+               "VDDC dependency on MCLK table is missing. This table is mandatory\n", return -EINVAL);
+       PP_ASSERT_WITH_CODE(allowed_mclk_vddc_table->count >= 1,
+               "VDD dependency on MCLK table has to have is missing. This table is mandatory\n", return -EINVAL);
+
+       data->min_vddc_in_pptable = (uint16_t)allowed_sclk_vddc_table->entries[0].v;
+       data->max_vddc_in_pptable = (uint16_t)allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
+
+       hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
+               allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
+       hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
+               allowed_mclk_vddc_table->entries[allowed_mclk_vddc_table->count - 1].clk;
+       hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
+               allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
+
+       if (allowed_mclk_vddci_table != NULL && allowed_mclk_vddci_table->count >= 1) {
+               data->min_vddci_in_pptable = (uint16_t)allowed_mclk_vddci_table->entries[0].v;
+               data->max_vddci_in_pptable = (uint16_t)allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
+       }
+
+       if (hwmgr->dyn_state.vddci_dependency_on_mclk != NULL && hwmgr->dyn_state.vddci_dependency_on_mclk->count > 1)
+               hwmgr->dyn_state.max_clock_voltage_on_ac.vddci = hwmgr->dyn_state.vddci_dependency_on_mclk->entries[hwmgr->dyn_state.vddci_dependency_on_mclk->count - 1].v;
+
+       return 0;
+}
+
+int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data;
+       int result;
+
+       data = kzalloc(sizeof(struct smu7_hwmgr), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+
+       hwmgr->backend = data;
+
+       smu7_patch_voltage_workaround(hwmgr);
+       smu7_init_dpm_defaults(hwmgr);
+
+       /* Get leakage voltage based on leakage ID. */
+       result = smu7_get_evv_voltages(hwmgr);
+
+       if (result) {
+               printk("Get EVV Voltage Failed.  Abort Driver loading!\n");
+               return -EINVAL;
+       }
+
+       if (hwmgr->pp_table_version == PP_TABLE_V1) {
+               smu7_complete_dependency_tables(hwmgr);
+               smu7_set_private_data_based_on_pptable_v1(hwmgr);
+       } else if (hwmgr->pp_table_version == PP_TABLE_V0) {
+               smu7_patch_dependency_tables_with_leakage(hwmgr);
+               smu7_set_private_data_based_on_pptable_v0(hwmgr);
+       }
+
+       /* Initalize Dynamic State Adjustment Rule Settings */
+       result = phm_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
+
+       if (0 == result) {
+               struct cgs_system_info sys_info = {0};
+
+               data->is_tlu_enabled = false;
+
+               hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
+                                                       SMU7_MAX_HARDWARE_POWERLEVELS;
+               hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
+               hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
+
+               sys_info.size = sizeof(struct cgs_system_info);
+               sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
+               result = cgs_query_system_info(hwmgr->device, &sys_info);
+               if (result)
+                       data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK;
+               else
+                       data->pcie_gen_cap = (uint32_t)sys_info.value;
+               if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+                       data->pcie_spc_cap = 20;
+               sys_info.size = sizeof(struct cgs_system_info);
+               sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
+               result = cgs_query_system_info(hwmgr->device, &sys_info);
+               if (result)
+                       data->pcie_lane_cap = AMDGPU_DEFAULT_PCIE_MLW_MASK;
+               else
+                       data->pcie_lane_cap = (uint32_t)sys_info.value;
+
+               hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */
+/* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */
+               hwmgr->platform_descriptor.clockStep.engineClock = 500;
+               hwmgr->platform_descriptor.clockStep.memoryClock = 500;
+               smu7_thermal_parameter_init(hwmgr);
+       } else {
+               /* Ignore return value in here, we are cleaning up a mess. */
+               phm_hwmgr_backend_fini(hwmgr);
+       }
+
+       return 0;
+}
+
+static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t level, tmp;
+
+       if (!data->pcie_dpm_key_disabled) {
+               if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+                       level = 0;
+                       tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
+                       while (tmp >>= 1)
+                               level++;
+
+                       if (level)
+                               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                               PPSMC_MSG_PCIeDPM_ForceLevel, level);
+               }
+       }
+
+       if (!data->sclk_dpm_key_disabled) {
+               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+                       level = 0;
+                       tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
+                       while (tmp >>= 1)
+                               level++;
+
+                       if (level)
+                               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                               PPSMC_MSG_SCLKDPM_SetEnabledMask,
+                                               (1 << level));
+               }
+       }
+
+       if (!data->mclk_dpm_key_disabled) {
+               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+                       level = 0;
+                       tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
+                       while (tmp >>= 1)
+                               level++;
+
+                       if (level)
+                               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                               PPSMC_MSG_MCLKDPM_SetEnabledMask,
+                                               (1 << level));
+               }
+       }
+
+       return 0;
+}
+
+static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (hwmgr->pp_table_version == PP_TABLE_V1)
+               phm_apply_dal_min_voltage_request(hwmgr);
+/* TO DO  for v0 iceland and Ci*/
+
+       if (!data->sclk_dpm_key_disabled) {
+               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
+                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                       PPSMC_MSG_SCLKDPM_SetEnabledMask,
+                                       data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+       }
+
+       if (!data->mclk_dpm_key_disabled) {
+               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask)
+                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                       PPSMC_MSG_MCLKDPM_SetEnabledMask,
+                                       data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+       }
+
+       return 0;
+}
+
+static int smu7_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (!smum_is_dpm_running(hwmgr))
+               return -EINVAL;
+
+       if (!data->pcie_dpm_key_disabled) {
+               smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_PCIeDPM_UnForceLevel);
+       }
+
+       return smu7_upload_dpm_level_enable_mask(hwmgr);
+}
+
+static int smu7_force_dpm_lowest(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data =
+                       (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t level;
+
+       if (!data->sclk_dpm_key_disabled)
+               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+                       level = phm_get_lowest_enabled_level(hwmgr,
+                                                             data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                                           PPSMC_MSG_SCLKDPM_SetEnabledMask,
+                                                           (1 << level));
+
+       }
+
+       if (!data->mclk_dpm_key_disabled) {
+               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+                       level = phm_get_lowest_enabled_level(hwmgr,
+                                                             data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                                           PPSMC_MSG_MCLKDPM_SetEnabledMask,
+                                                           (1 << level));
+               }
+       }
+
+       if (!data->pcie_dpm_key_disabled) {
+               if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+                       level = phm_get_lowest_enabled_level(hwmgr,
+                                                             data->dpm_level_enable_mask.pcie_dpm_enable_mask);
+                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                                           PPSMC_MSG_PCIeDPM_ForceLevel,
+                                                           (level));
+               }
+       }
+
+       return 0;
+
+}
+static int smu7_force_dpm_level(struct pp_hwmgr *hwmgr,
+                               enum amd_dpm_forced_level level)
+{
+       int ret = 0;
+
+       switch (level) {
+       case AMD_DPM_FORCED_LEVEL_HIGH:
+               ret = smu7_force_dpm_highest(hwmgr);
+               if (ret)
+                       return ret;
+               break;
+       case AMD_DPM_FORCED_LEVEL_LOW:
+               ret = smu7_force_dpm_lowest(hwmgr);
+               if (ret)
+                       return ret;
+               break;
+       case AMD_DPM_FORCED_LEVEL_AUTO:
+               ret = smu7_unforce_dpm_levels(hwmgr);
+               if (ret)
+                       return ret;
+               break;
+       default:
+               break;
+       }
+
+       hwmgr->dpm_level = level;
+
+       return ret;
+}
+
+static int smu7_get_power_state_size(struct pp_hwmgr *hwmgr)
+{
+       return sizeof(struct smu7_power_state);
+}
+
+
+static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+                               struct pp_power_state *request_ps,
+                       const struct pp_power_state *current_ps)
+{
+
+       struct smu7_power_state *smu7_ps =
+                               cast_phw_smu7_power_state(&request_ps->hardware);
+       uint32_t sclk;
+       uint32_t mclk;
+       struct PP_Clocks minimum_clocks = {0};
+       bool disable_mclk_switching;
+       bool disable_mclk_switching_for_frame_lock;
+       struct cgs_display_info info = {0};
+       const struct phm_clock_and_voltage_limits *max_limits;
+       uint32_t i;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       int32_t count;
+       int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
+
+       data->battery_state = (PP_StateUILabel_Battery ==
+                       request_ps->classification.ui_label);
+
+       PP_ASSERT_WITH_CODE(smu7_ps->performance_level_count == 2,
+                                "VI should always have 2 performance levels",
+                               );
+
+       max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
+                       &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
+                       &(hwmgr->dyn_state.max_clock_voltage_on_dc);
+
+       /* Cap clock DPM tables at DC MAX if it is in DC. */
+       if (PP_PowerSource_DC == hwmgr->power_source) {
+               for (i = 0; i < smu7_ps->performance_level_count; i++) {
+                       if (smu7_ps->performance_levels[i].memory_clock > max_limits->mclk)
+                               smu7_ps->performance_levels[i].memory_clock = max_limits->mclk;
+                       if (smu7_ps->performance_levels[i].engine_clock > max_limits->sclk)
+                               smu7_ps->performance_levels[i].engine_clock = max_limits->sclk;
+               }
+       }
+
+       smu7_ps->vce_clks.evclk = hwmgr->vce_arbiter.evclk;
+       smu7_ps->vce_clks.ecclk = hwmgr->vce_arbiter.ecclk;
+
+       cgs_get_active_displays_info(hwmgr->device, &info);
+
+       /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
+
+       minimum_clocks.engineClock = hwmgr->display_config.min_core_set_clock;
+       minimum_clocks.memoryClock = hwmgr->display_config.min_mem_set_clock;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StablePState)) {
+               max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
+               stable_pstate_sclk = (max_limits->sclk * 75) / 100;
+
+               for (count = table_info->vdd_dep_on_sclk->count - 1;
+                               count >= 0; count--) {
+                       if (stable_pstate_sclk >=
+                                       table_info->vdd_dep_on_sclk->entries[count].clk) {
+                               stable_pstate_sclk =
+                                               table_info->vdd_dep_on_sclk->entries[count].clk;
+                               break;
+                       }
+               }
+
+               if (count < 0)
+                       stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
+
+               stable_pstate_mclk = max_limits->mclk;
+
+               minimum_clocks.engineClock = stable_pstate_sclk;
+               minimum_clocks.memoryClock = stable_pstate_mclk;
+       }
+
+       if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
+               minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
+
+       if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
+               minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
+
+       smu7_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
+
+       if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
+               PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <=
+                               hwmgr->platform_descriptor.overdriveLimit.engineClock),
+                               "Overdrive sclk exceeds limit",
+                               hwmgr->gfx_arbiter.sclk_over_drive =
+                                               hwmgr->platform_descriptor.overdriveLimit.engineClock);
+
+               if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
+                       smu7_ps->performance_levels[1].engine_clock =
+                                       hwmgr->gfx_arbiter.sclk_over_drive;
+       }
+
+       if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
+               PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <=
+                               hwmgr->platform_descriptor.overdriveLimit.memoryClock),
+                               "Overdrive mclk exceeds limit",
+                               hwmgr->gfx_arbiter.mclk_over_drive =
+                                               hwmgr->platform_descriptor.overdriveLimit.memoryClock);
+
+               if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
+                       smu7_ps->performance_levels[1].memory_clock =
+                                       hwmgr->gfx_arbiter.mclk_over_drive;
+       }
+
+       disable_mclk_switching_for_frame_lock = phm_cap_enabled(
+                                   hwmgr->platform_descriptor.platformCaps,
+                                   PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
+
+
+       disable_mclk_switching = (1 < info.display_count) ||
+                                   disable_mclk_switching_for_frame_lock;
+
+       sclk = smu7_ps->performance_levels[0].engine_clock;
+       mclk = smu7_ps->performance_levels[0].memory_clock;
+
+       if (disable_mclk_switching)
+               mclk = smu7_ps->performance_levels
+               [smu7_ps->performance_level_count - 1].memory_clock;
+
+       if (sclk < minimum_clocks.engineClock)
+               sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
+                               max_limits->sclk : minimum_clocks.engineClock;
+
+       if (mclk < minimum_clocks.memoryClock)
+               mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
+                               max_limits->mclk : minimum_clocks.memoryClock;
+
+       smu7_ps->performance_levels[0].engine_clock = sclk;
+       smu7_ps->performance_levels[0].memory_clock = mclk;
+
+       smu7_ps->performance_levels[1].engine_clock =
+               (smu7_ps->performance_levels[1].engine_clock >=
+                               smu7_ps->performance_levels[0].engine_clock) ?
+                                               smu7_ps->performance_levels[1].engine_clock :
+                                               smu7_ps->performance_levels[0].engine_clock;
+
+       if (disable_mclk_switching) {
+               if (mclk < smu7_ps->performance_levels[1].memory_clock)
+                       mclk = smu7_ps->performance_levels[1].memory_clock;
+
+               smu7_ps->performance_levels[0].memory_clock = mclk;
+               smu7_ps->performance_levels[1].memory_clock = mclk;
+       } else {
+               if (smu7_ps->performance_levels[1].memory_clock <
+                               smu7_ps->performance_levels[0].memory_clock)
+                       smu7_ps->performance_levels[1].memory_clock =
+                                       smu7_ps->performance_levels[0].memory_clock;
+       }
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StablePState)) {
+               for (i = 0; i < smu7_ps->performance_level_count; i++) {
+                       smu7_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
+                       smu7_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
+                       smu7_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
+                       smu7_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
+               }
+       }
+       return 0;
+}
+
+
+static int smu7_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
+{
+       struct pp_power_state  *ps;
+       struct smu7_power_state  *smu7_ps;
+
+       if (hwmgr == NULL)
+               return -EINVAL;
+
+       ps = hwmgr->request_ps;
+
+       if (ps == NULL)
+               return -EINVAL;
+
+       smu7_ps = cast_phw_smu7_power_state(&ps->hardware);
+
+       if (low)
+               return smu7_ps->performance_levels[0].memory_clock;
+       else
+               return smu7_ps->performance_levels
+                               [smu7_ps->performance_level_count-1].memory_clock;
+}
+
+static int smu7_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
+{
+       struct pp_power_state  *ps;
+       struct smu7_power_state  *smu7_ps;
+
+       if (hwmgr == NULL)
+               return -EINVAL;
+
+       ps = hwmgr->request_ps;
+
+       if (ps == NULL)
+               return -EINVAL;
+
+       smu7_ps = cast_phw_smu7_power_state(&ps->hardware);
+
+       if (low)
+               return smu7_ps->performance_levels[0].engine_clock;
+       else
+               return smu7_ps->performance_levels
+                               [smu7_ps->performance_level_count-1].engine_clock;
+}
+
+static int smu7_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
+                                       struct pp_hw_power_state *hw_ps)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_power_state *ps = (struct smu7_power_state *)hw_ps;
+       ATOM_FIRMWARE_INFO_V2_2 *fw_info;
+       uint16_t size;
+       uint8_t frev, crev;
+       int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+
+       /* First retrieve the Boot clocks and VDDC from the firmware info table.
+        * We assume here that fw_info is unchanged if this call fails.
+        */
+       fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
+                       hwmgr->device, index,
+                       &size, &frev, &crev);
+       if (!fw_info)
+               /* During a test, there is no firmware info table. */
+               return 0;
+
+       /* Patch the state. */
+       data->vbios_boot_state.sclk_bootup_value =
+                       le32_to_cpu(fw_info->ulDefaultEngineClock);
+       data->vbios_boot_state.mclk_bootup_value =
+                       le32_to_cpu(fw_info->ulDefaultMemoryClock);
+       data->vbios_boot_state.mvdd_bootup_value =
+                       le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
+       data->vbios_boot_state.vddc_bootup_value =
+                       le16_to_cpu(fw_info->usBootUpVDDCVoltage);
+       data->vbios_boot_state.vddci_bootup_value =
+                       le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
+       data->vbios_boot_state.pcie_gen_bootup_value =
+                       smu7_get_current_pcie_speed(hwmgr);
+
+       data->vbios_boot_state.pcie_lane_bootup_value =
+                       (uint16_t)smu7_get_current_pcie_lane_number(hwmgr);
+
+       /* set boot power state */
+       ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
+       ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
+       ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
+       ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
+
+       return 0;
+}
+
+static int smu7_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       unsigned long ret = 0;
+
+       if (hwmgr->pp_table_version == PP_TABLE_V0) {
+               result = pp_tables_get_num_of_entries(hwmgr, &ret);
+               return result ? 0 : ret;
+       } else if (hwmgr->pp_table_version == PP_TABLE_V1) {
+               result = get_number_of_powerplay_table_entries_v1_0(hwmgr);
+               return result;
+       }
+       return 0;
+}
+
+static int smu7_get_pp_table_entry_callback_func_v1(struct pp_hwmgr *hwmgr,
+               void *state, struct pp_power_state *power_state,
+               void *pp_table, uint32_t classification_flag)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_power_state  *smu7_power_state =
+                       (struct smu7_power_state *)(&(power_state->hardware));
+       struct smu7_performance_level *performance_level;
+       ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
+       ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
+                       (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
+       PPTable_Generic_SubTable_Header *sclk_dep_table =
+                       (PPTable_Generic_SubTable_Header *)
+                       (((unsigned long)powerplay_table) +
+                               le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
+
+       ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
+                       (ATOM_Tonga_MCLK_Dependency_Table *)
+                       (((unsigned long)powerplay_table) +
+                               le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
+
+       /* The following fields are not initialized here: id orderedList allStatesList */
+       power_state->classification.ui_label =
+                       (le16_to_cpu(state_entry->usClassification) &
+                       ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
+                       ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
+       power_state->classification.flags = classification_flag;
+       /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
+
+       power_state->classification.temporary_state = false;
+       power_state->classification.to_be_deleted = false;
+
+       power_state->validation.disallowOnDC =
+                       (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
+                                       ATOM_Tonga_DISALLOW_ON_DC));
+
+       power_state->pcie.lanes = 0;
+
+       power_state->display.disableFrameModulation = false;
+       power_state->display.limitRefreshrate = false;
+       power_state->display.enableVariBright =
+                       (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
+                                       ATOM_Tonga_ENABLE_VARIBRIGHT));
+
+       power_state->validation.supportedPowerLevels = 0;
+       power_state->uvd_clocks.VCLK = 0;
+       power_state->uvd_clocks.DCLK = 0;
+       power_state->temperatures.min = 0;
+       power_state->temperatures.max = 0;
+
+       performance_level = &(smu7_power_state->performance_levels
+                       [smu7_power_state->performance_level_count++]);
+
+       PP_ASSERT_WITH_CODE(
+                       (smu7_power_state->performance_level_count < smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_GRAPHICS)),
+                       "Performance levels exceeds SMC limit!",
+                       return -EINVAL);
+
+       PP_ASSERT_WITH_CODE(
+                       (smu7_power_state->performance_level_count <=
+                                       hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
+                       "Performance levels exceeds Driver limit!",
+                       return -EINVAL);
+
+       /* Performance levels are arranged from low to high. */
+       performance_level->memory_clock = mclk_dep_table->entries
+                       [state_entry->ucMemoryClockIndexLow].ulMclk;
+       if (sclk_dep_table->ucRevId == 0)
+               performance_level->engine_clock = ((ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table)->entries
+                       [state_entry->ucEngineClockIndexLow].ulSclk;
+       else if (sclk_dep_table->ucRevId == 1)
+               performance_level->engine_clock = ((ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table)->entries
+                       [state_entry->ucEngineClockIndexLow].ulSclk;
+       performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
+                       state_entry->ucPCIEGenLow);
+       performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
+                       state_entry->ucPCIELaneHigh);
+
+       performance_level = &(smu7_power_state->performance_levels
+                       [smu7_power_state->performance_level_count++]);
+       performance_level->memory_clock = mclk_dep_table->entries
+                       [state_entry->ucMemoryClockIndexHigh].ulMclk;
+
+       if (sclk_dep_table->ucRevId == 0)
+               performance_level->engine_clock = ((ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table)->entries
+                       [state_entry->ucEngineClockIndexHigh].ulSclk;
+       else if (sclk_dep_table->ucRevId == 1)
+               performance_level->engine_clock = ((ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table)->entries
+                       [state_entry->ucEngineClockIndexHigh].ulSclk;
+
+       performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
+                       state_entry->ucPCIEGenHigh);
+       performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
+                       state_entry->ucPCIELaneHigh);
+
+       return 0;
+}
+
+static int smu7_get_pp_table_entry_v1(struct pp_hwmgr *hwmgr,
+               unsigned long entry_index, struct pp_power_state *state)
+{
+       int result;
+       struct smu7_power_state *ps;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
+                       table_info->vdd_dep_on_mclk;
+
+       state->hardware.magic = PHM_VIslands_Magic;
+
+       ps = (struct smu7_power_state *)(&state->hardware);
+
+       result = get_powerplay_table_entry_v1_0(hwmgr, entry_index, state,
+                       smu7_get_pp_table_entry_callback_func_v1);
+
+       /* This is the earliest time we have all the dependency table and the VBIOS boot state
+        * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
+        * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
+        */
+       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 "
+                                       "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 "
+                                       "does not match VBIOS boot VDDCI level");
+       }
+
+       /* set DC compatible flag if this state supports DC */
+       if (!state->validation.disallowOnDC)
+               ps->dc_compatible = true;
+
+       if (state->classification.flags & PP_StateClassificationFlag_ACPI)
+               data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
+
+       ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
+       ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
+
+       if (!result) {
+               uint32_t i;
+
+               switch (state->classification.ui_label) {
+               case PP_StateUILabel_Performance:
+                       data->use_pcie_performance_levels = true;
+                       for (i = 0; i < ps->performance_level_count; i++) {
+                               if (data->pcie_gen_performance.max <
+                                               ps->performance_levels[i].pcie_gen)
+                                       data->pcie_gen_performance.max =
+                                                       ps->performance_levels[i].pcie_gen;
+
+                               if (data->pcie_gen_performance.min >
+                                               ps->performance_levels[i].pcie_gen)
+                                       data->pcie_gen_performance.min =
+                                                       ps->performance_levels[i].pcie_gen;
+
+                               if (data->pcie_lane_performance.max <
+                                               ps->performance_levels[i].pcie_lane)
+                                       data->pcie_lane_performance.max =
+                                                       ps->performance_levels[i].pcie_lane;
+                               if (data->pcie_lane_performance.min >
+                                               ps->performance_levels[i].pcie_lane)
+                                       data->pcie_lane_performance.min =
+                                                       ps->performance_levels[i].pcie_lane;
+                       }
+                       break;
+               case PP_StateUILabel_Battery:
+                       data->use_pcie_power_saving_levels = true;
+
+                       for (i = 0; i < ps->performance_level_count; i++) {
+                               if (data->pcie_gen_power_saving.max <
+                                               ps->performance_levels[i].pcie_gen)
+                                       data->pcie_gen_power_saving.max =
+                                                       ps->performance_levels[i].pcie_gen;
+
+                               if (data->pcie_gen_power_saving.min >
+                                               ps->performance_levels[i].pcie_gen)
+                                       data->pcie_gen_power_saving.min =
+                                                       ps->performance_levels[i].pcie_gen;
+
+                               if (data->pcie_lane_power_saving.max <
+                                               ps->performance_levels[i].pcie_lane)
+                                       data->pcie_lane_power_saving.max =
+                                                       ps->performance_levels[i].pcie_lane;
+
+                               if (data->pcie_lane_power_saving.min >
+                                               ps->performance_levels[i].pcie_lane)
+                                       data->pcie_lane_power_saving.min =
+                                                       ps->performance_levels[i].pcie_lane;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr,
+                                       struct pp_hw_power_state *power_state,
+                                       unsigned int index, const void *clock_info)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_power_state  *ps = cast_phw_smu7_power_state(power_state);
+       const ATOM_PPLIB_CI_CLOCK_INFO *visland_clk_info = clock_info;
+       struct smu7_performance_level *performance_level;
+       uint32_t engine_clock, memory_clock;
+       uint16_t pcie_gen_from_bios;
+
+       engine_clock = visland_clk_info->ucEngineClockHigh << 16 | visland_clk_info->usEngineClockLow;
+       memory_clock = visland_clk_info->ucMemoryClockHigh << 16 | visland_clk_info->usMemoryClockLow;
+
+       if (!(data->mc_micro_code_feature & DISABLE_MC_LOADMICROCODE) && memory_clock > data->highest_mclk)
+               data->highest_mclk = memory_clock;
+
+       performance_level = &(ps->performance_levels
+                       [ps->performance_level_count++]);
+
+       PP_ASSERT_WITH_CODE(
+                       (ps->performance_level_count < smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_GRAPHICS)),
+                       "Performance levels exceeds SMC limit!",
+                       return -EINVAL);
+
+       PP_ASSERT_WITH_CODE(
+                       (ps->performance_level_count <=
+                                       hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
+                       "Performance levels exceeds Driver limit!",
+                       return -EINVAL);
+
+       /* Performance levels are arranged from low to high. */
+       performance_level->memory_clock = memory_clock;
+       performance_level->engine_clock = engine_clock;
+
+       pcie_gen_from_bios = visland_clk_info->ucPCIEGen;
+
+       performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap, pcie_gen_from_bios);
+       performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap, visland_clk_info->usPCIELane);
+
+       return 0;
+}
+
+static int smu7_get_pp_table_entry_v0(struct pp_hwmgr *hwmgr,
+               unsigned long entry_index, struct pp_power_state *state)
+{
+       int result;
+       struct smu7_power_state *ps;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_clock_voltage_dependency_table *dep_mclk_table =
+                       hwmgr->dyn_state.vddci_dependency_on_mclk;
+
+       memset(&state->hardware, 0x00, sizeof(struct pp_hw_power_state));
+
+       state->hardware.magic = PHM_VIslands_Magic;
+
+       ps = (struct smu7_power_state *)(&state->hardware);
+
+       result = pp_tables_get_entry(hwmgr, entry_index, state,
+                       smu7_get_pp_table_entry_callback_func_v0);
+
+       /*
+        * This is the earliest time we have all the dependency table
+        * and the VBIOS boot state as
+        * PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot
+        * state if there is only one VDDCI/MCLK level, check if it's
+        * the same as VBIOS boot state
+        */
+       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 "
+                                       "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 "
+                                       "does not match VBIOS boot VDDCI level");
+       }
+
+       /* set DC compatible flag if this state supports DC */
+       if (!state->validation.disallowOnDC)
+               ps->dc_compatible = true;
+
+       if (state->classification.flags & PP_StateClassificationFlag_ACPI)
+               data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
+
+       ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
+       ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
+
+       if (!result) {
+               uint32_t i;
+
+               switch (state->classification.ui_label) {
+               case PP_StateUILabel_Performance:
+                       data->use_pcie_performance_levels = true;
+
+                       for (i = 0; i < ps->performance_level_count; i++) {
+                               if (data->pcie_gen_performance.max <
+                                               ps->performance_levels[i].pcie_gen)
+                                       data->pcie_gen_performance.max =
+                                                       ps->performance_levels[i].pcie_gen;
+
+                               if (data->pcie_gen_performance.min >
+                                               ps->performance_levels[i].pcie_gen)
+                                       data->pcie_gen_performance.min =
+                                                       ps->performance_levels[i].pcie_gen;
+
+                               if (data->pcie_lane_performance.max <
+                                               ps->performance_levels[i].pcie_lane)
+                                       data->pcie_lane_performance.max =
+                                                       ps->performance_levels[i].pcie_lane;
+
+                               if (data->pcie_lane_performance.min >
+                                               ps->performance_levels[i].pcie_lane)
+                                       data->pcie_lane_performance.min =
+                                                       ps->performance_levels[i].pcie_lane;
+                       }
+                       break;
+               case PP_StateUILabel_Battery:
+                       data->use_pcie_power_saving_levels = true;
+
+                       for (i = 0; i < ps->performance_level_count; i++) {
+                               if (data->pcie_gen_power_saving.max <
+                                               ps->performance_levels[i].pcie_gen)
+                                       data->pcie_gen_power_saving.max =
+                                                       ps->performance_levels[i].pcie_gen;
+
+                               if (data->pcie_gen_power_saving.min >
+                                               ps->performance_levels[i].pcie_gen)
+                                       data->pcie_gen_power_saving.min =
+                                                       ps->performance_levels[i].pcie_gen;
+
+                               if (data->pcie_lane_power_saving.max <
+                                               ps->performance_levels[i].pcie_lane)
+                                       data->pcie_lane_power_saving.max =
+                                                       ps->performance_levels[i].pcie_lane;
+
+                               if (data->pcie_lane_power_saving.min >
+                                               ps->performance_levels[i].pcie_lane)
+                                       data->pcie_lane_power_saving.min =
+                                                       ps->performance_levels[i].pcie_lane;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int smu7_get_pp_table_entry(struct pp_hwmgr *hwmgr,
+               unsigned long entry_index, struct pp_power_state *state)
+{
+       if (hwmgr->pp_table_version == PP_TABLE_V0)
+               return smu7_get_pp_table_entry_v0(hwmgr, entry_index, state);
+       else if (hwmgr->pp_table_version == PP_TABLE_V1)
+               return smu7_get_pp_table_entry_v1(hwmgr, entry_index, state);
+
+       return 0;
+}
+
+static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value)
+{
+       uint32_t sclk, mclk, activity_percent;
+       uint32_t offset;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       switch (idx) {
+       case AMDGPU_PP_SENSOR_GFX_SCLK:
+               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
+               sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+               *value = sclk;
+               return 0;
+       case AMDGPU_PP_SENSOR_GFX_MCLK:
+               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
+               mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+               *value = mclk;
+               return 0;
+       case AMDGPU_PP_SENSOR_GPU_LOAD:
+               offset = data->soft_regs_start + smum_get_offsetof(hwmgr->smumgr,
+                                                               SMU_SoftRegisters,
+                                                               AverageGraphicsActivity);
+
+               activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
+               activity_percent += 0x80;
+               activity_percent >>= 8;
+               *value = activity_percent > 100 ? 100 : activity_percent;
+               return 0;
+       case AMDGPU_PP_SENSOR_GPU_TEMP:
+               *value = smu7_thermal_get_temperature(hwmgr);
+               return 0;
+       case AMDGPU_PP_SENSOR_UVD_POWER:
+               *value = data->uvd_power_gated ? 0 : 1;
+               return 0;
+       case AMDGPU_PP_SENSOR_VCE_POWER:
+               *value = data->vce_power_gated ? 0 : 1;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int smu7_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
+{
+       const struct phm_set_power_state_input *states =
+                       (const struct phm_set_power_state_input *)input;
+       const struct smu7_power_state *smu7_ps =
+                       cast_const_phw_smu7_power_state(states->pnew_state);
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
+       uint32_t sclk = smu7_ps->performance_levels
+                       [smu7_ps->performance_level_count - 1].engine_clock;
+       struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
+       uint32_t mclk = smu7_ps->performance_levels
+                       [smu7_ps->performance_level_count - 1].memory_clock;
+       struct PP_Clocks min_clocks = {0};
+       uint32_t i;
+       struct cgs_display_info info = {0};
+
+       data->need_update_smu7_dpm_table = 0;
+
+       for (i = 0; i < sclk_table->count; i++) {
+               if (sclk == sclk_table->dpm_levels[i].value)
+                       break;
+       }
+
+       if (i >= sclk_table->count)
+               data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
+       else {
+       /* TODO: Check SCLK in DAL's minimum clocks
+        * in case DeepSleep divider update is required.
+        */
+               if (data->display_timing.min_clock_in_sr != min_clocks.engineClockInSR &&
+                       (min_clocks.engineClockInSR >= SMU7_MINIMUM_ENGINE_CLOCK ||
+                               data->display_timing.min_clock_in_sr >= SMU7_MINIMUM_ENGINE_CLOCK))
+                       data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
+       }
+
+       for (i = 0; i < mclk_table->count; i++) {
+               if (mclk == mclk_table->dpm_levels[i].value)
+                       break;
+       }
+
+       if (i >= mclk_table->count)
+               data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
+
+       cgs_get_active_displays_info(hwmgr->device, &info);
+
+       if (data->display_timing.num_existing_displays != info.display_count)
+               data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
+
+       return 0;
+}
+
+static uint16_t smu7_get_maximum_link_speed(struct pp_hwmgr *hwmgr,
+               const struct smu7_power_state *smu7_ps)
+{
+       uint32_t i;
+       uint32_t sclk, max_sclk = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+
+       for (i = 0; i < smu7_ps->performance_level_count; i++) {
+               sclk = smu7_ps->performance_levels[i].engine_clock;
+               if (max_sclk < sclk)
+                       max_sclk = sclk;
+       }
+
+       for (i = 0; i < dpm_table->sclk_table.count; i++) {
+               if (dpm_table->sclk_table.dpm_levels[i].value == max_sclk)
+                       return (uint16_t) ((i >= dpm_table->pcie_speed_table.count) ?
+                                       dpm_table->pcie_speed_table.dpm_levels
+                                       [dpm_table->pcie_speed_table.count - 1].value :
+                                       dpm_table->pcie_speed_table.dpm_levels[i].value);
+       }
+
+       return 0;
+}
+
+static int smu7_request_link_speed_change_before_state_change(
+               struct pp_hwmgr *hwmgr, const void *input)
+{
+       const struct phm_set_power_state_input *states =
+                       (const struct phm_set_power_state_input *)input;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       const struct smu7_power_state *smu7_nps =
+                       cast_const_phw_smu7_power_state(states->pnew_state);
+       const struct smu7_power_state *polaris10_cps =
+                       cast_const_phw_smu7_power_state(states->pcurrent_state);
+
+       uint16_t target_link_speed = smu7_get_maximum_link_speed(hwmgr, smu7_nps);
+       uint16_t current_link_speed;
+
+       if (data->force_pcie_gen == PP_PCIEGenInvalid)
+               current_link_speed = smu7_get_maximum_link_speed(hwmgr, polaris10_cps);
+       else
+               current_link_speed = data->force_pcie_gen;
+
+       data->force_pcie_gen = PP_PCIEGenInvalid;
+       data->pspp_notify_required = false;
+
+       if (target_link_speed > current_link_speed) {
+               switch (target_link_speed) {
+               case PP_PCIEGen3:
+                       if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
+                               break;
+                       data->force_pcie_gen = PP_PCIEGen2;
+                       if (current_link_speed == PP_PCIEGen2)
+                               break;
+               case PP_PCIEGen2:
+                       if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
+                               break;
+               default:
+                       data->force_pcie_gen = smu7_get_current_pcie_speed(hwmgr);
+                       break;
+               }
+       } else {
+               if (target_link_speed < current_link_speed)
+                       data->pspp_notify_required = true;
+       }
+
+       return 0;
+}
+
+static int smu7_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (0 == data->need_update_smu7_dpm_table)
+               return 0;
+
+       if ((0 == data->sclk_dpm_key_disabled) &&
+               (data->need_update_smu7_dpm_table &
+                       (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+               PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
+                               "Trying to freeze SCLK DPM when DPM is disabled",
+                               );
+               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_SCLKDPM_FreezeLevel),
+                               "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
+                               return -EINVAL);
+       }
+
+       if ((0 == data->mclk_dpm_key_disabled) &&
+               (data->need_update_smu7_dpm_table &
+                DPMTABLE_OD_UPDATE_MCLK)) {
+               PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
+                               "Trying to freeze MCLK DPM when DPM is disabled",
+                               );
+               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_MCLKDPM_FreezeLevel),
+                               "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
+                               return -EINVAL);
+       }
+
+       return 0;
+}
+
+static int smu7_populate_and_upload_sclk_mclk_dpm_levels(
+               struct pp_hwmgr *hwmgr, const void *input)
+{
+       int result = 0;
+       const struct phm_set_power_state_input *states =
+                       (const struct phm_set_power_state_input *)input;
+       const struct smu7_power_state *smu7_ps =
+                       cast_const_phw_smu7_power_state(states->pnew_state);
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t sclk = smu7_ps->performance_levels
+                       [smu7_ps->performance_level_count - 1].engine_clock;
+       uint32_t mclk = smu7_ps->performance_levels
+                       [smu7_ps->performance_level_count - 1].memory_clock;
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+
+       struct smu7_dpm_table *golden_dpm_table = &data->golden_dpm_table;
+       uint32_t dpm_count, clock_percent;
+       uint32_t i;
+
+       if (0 == data->need_update_smu7_dpm_table)
+               return 0;
+
+       if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
+               dpm_table->sclk_table.dpm_levels
+               [dpm_table->sclk_table.count - 1].value = sclk;
+
+               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
+                   phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
+               /* Need to do calculation based on the golden DPM table
+                * as the Heatmap GPU Clock axis is also based on the default values
+                */
+                       PP_ASSERT_WITH_CODE(
+                               (golden_dpm_table->sclk_table.dpm_levels
+                                               [golden_dpm_table->sclk_table.count - 1].value != 0),
+                               "Divide by 0!",
+                               return -EINVAL);
+                       dpm_count = dpm_table->sclk_table.count < 2 ? 0 : dpm_table->sclk_table.count - 2;
+
+                       for (i = dpm_count; i > 1; i--) {
+                               if (sclk > golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value) {
+                                       clock_percent =
+                                             ((sclk
+                                               - golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value
+                                               ) * 100)
+                                               / golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value;
+
+                                       dpm_table->sclk_table.dpm_levels[i].value =
+                                                       golden_dpm_table->sclk_table.dpm_levels[i].value +
+                                                       (golden_dpm_table->sclk_table.dpm_levels[i].value *
+                                                               clock_percent)/100;
+
+                               } else if (golden_dpm_table->sclk_table.dpm_levels[dpm_table->sclk_table.count-1].value > sclk) {
+                                       clock_percent =
+                                               ((golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count - 1].value
+                                               - sclk) * 100)
+                                               / golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value;
+
+                                       dpm_table->sclk_table.dpm_levels[i].value =
+                                                       golden_dpm_table->sclk_table.dpm_levels[i].value -
+                                                       (golden_dpm_table->sclk_table.dpm_levels[i].value *
+                                                                       clock_percent) / 100;
+                               } else
+                                       dpm_table->sclk_table.dpm_levels[i].value =
+                                                       golden_dpm_table->sclk_table.dpm_levels[i].value;
+                       }
+               }
+       }
+
+       if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
+               dpm_table->mclk_table.dpm_levels
+                       [dpm_table->mclk_table.count - 1].value = mclk;
+
+               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
+                   phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
+
+                       PP_ASSERT_WITH_CODE(
+                                       (golden_dpm_table->mclk_table.dpm_levels
+                                               [golden_dpm_table->mclk_table.count-1].value != 0),
+                                       "Divide by 0!",
+                                       return -EINVAL);
+                       dpm_count = dpm_table->mclk_table.count < 2 ? 0 : dpm_table->mclk_table.count - 2;
+                       for (i = dpm_count; i > 1; i--) {
+                               if (golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value < mclk) {
+                                       clock_percent = ((mclk -
+                                       golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value) * 100)
+                                       / golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value;
+
+                                       dpm_table->mclk_table.dpm_levels[i].value =
+                                                       golden_dpm_table->mclk_table.dpm_levels[i].value +
+                                                       (golden_dpm_table->mclk_table.dpm_levels[i].value *
+                                                       clock_percent) / 100;
+
+                               } else if (golden_dpm_table->mclk_table.dpm_levels[dpm_table->mclk_table.count-1].value > mclk) {
+                                       clock_percent = (
+                                        (golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value - mclk)
+                                       * 100)
+                                       / golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value;
+
+                                       dpm_table->mclk_table.dpm_levels[i].value =
+                                                       golden_dpm_table->mclk_table.dpm_levels[i].value -
+                                                       (golden_dpm_table->mclk_table.dpm_levels[i].value *
+                                                                       clock_percent) / 100;
+                               } else
+                                       dpm_table->mclk_table.dpm_levels[i].value =
+                                                       golden_dpm_table->mclk_table.dpm_levels[i].value;
+                       }
+               }
+       }
+
+       if (data->need_update_smu7_dpm_table &
+                       (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
+               result = smum_populate_all_graphic_levels(hwmgr);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
+                               return result);
+       }
+
+       if (data->need_update_smu7_dpm_table &
+                       (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
+               /*populate MCLK dpm table to SMU7 */
+               result = smum_populate_all_memory_levels(hwmgr);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
+                               return result);
+       }
+
+       return result;
+}
+
+static int smu7_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
+                         struct smu7_single_dpm_table *dpm_table,
+                       uint32_t low_limit, uint32_t high_limit)
+{
+       uint32_t i;
+
+       for (i = 0; i < dpm_table->count; i++) {
+               if ((dpm_table->dpm_levels[i].value < low_limit)
+               || (dpm_table->dpm_levels[i].value > high_limit))
+                       dpm_table->dpm_levels[i].enabled = false;
+               else
+                       dpm_table->dpm_levels[i].enabled = true;
+       }
+
+       return 0;
+}
+
+static int smu7_trim_dpm_states(struct pp_hwmgr *hwmgr,
+               const struct smu7_power_state *smu7_ps)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t high_limit_count;
+
+       PP_ASSERT_WITH_CODE((smu7_ps->performance_level_count >= 1),
+                       "power state did not have any performance level",
+                       return -EINVAL);
+
+       high_limit_count = (1 == smu7_ps->performance_level_count) ? 0 : 1;
+
+       smu7_trim_single_dpm_states(hwmgr,
+                       &(data->dpm_table.sclk_table),
+                       smu7_ps->performance_levels[0].engine_clock,
+                       smu7_ps->performance_levels[high_limit_count].engine_clock);
+
+       smu7_trim_single_dpm_states(hwmgr,
+                       &(data->dpm_table.mclk_table),
+                       smu7_ps->performance_levels[0].memory_clock,
+                       smu7_ps->performance_levels[high_limit_count].memory_clock);
+
+       return 0;
+}
+
+static int smu7_generate_dpm_level_enable_mask(
+               struct pp_hwmgr *hwmgr, const void *input)
+{
+       int result;
+       const struct phm_set_power_state_input *states =
+                       (const struct phm_set_power_state_input *)input;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       const struct smu7_power_state *smu7_ps =
+                       cast_const_phw_smu7_power_state(states->pnew_state);
+
+       result = smu7_trim_dpm_states(hwmgr, smu7_ps);
+       if (result)
+               return result;
+
+       data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+                       phm_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
+       data->dpm_level_enable_mask.mclk_dpm_enable_mask =
+                       phm_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
+       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+                       phm_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
+
+       return 0;
+}
+
+static int smu7_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (0 == data->need_update_smu7_dpm_table)
+               return 0;
+
+       if ((0 == data->sclk_dpm_key_disabled) &&
+               (data->need_update_smu7_dpm_table &
+               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+
+               PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
+                               "Trying to Unfreeze SCLK DPM when DPM is disabled",
+                               );
+               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+                       "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
+                       return -EINVAL);
+       }
+
+       if ((0 == data->mclk_dpm_key_disabled) &&
+               (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
+
+               PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
+                               "Trying to Unfreeze MCLK DPM when DPM is disabled",
+                               );
+               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+                   "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
+                   return -EINVAL);
+       }
+
+       data->need_update_smu7_dpm_table = 0;
+
+       return 0;
+}
+
+static int smu7_notify_link_speed_change_after_state_change(
+               struct pp_hwmgr *hwmgr, const void *input)
+{
+       const struct phm_set_power_state_input *states =
+                       (const struct phm_set_power_state_input *)input;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       const struct smu7_power_state *smu7_ps =
+                       cast_const_phw_smu7_power_state(states->pnew_state);
+       uint16_t target_link_speed = smu7_get_maximum_link_speed(hwmgr, smu7_ps);
+       uint8_t  request;
+
+       if (data->pspp_notify_required) {
+               if (target_link_speed == PP_PCIEGen3)
+                       request = PCIE_PERF_REQ_GEN3;
+               else if (target_link_speed == PP_PCIEGen2)
+                       request = PCIE_PERF_REQ_GEN2;
+               else
+                       request = PCIE_PERF_REQ_GEN1;
+
+               if (request == PCIE_PERF_REQ_GEN1 &&
+                               smu7_get_current_pcie_speed(hwmgr) > 0)
+                       return 0;
+
+               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!");
+                       else
+                               printk("PSPP request to switch to Gen1 from Gen2 Failed!");
+               }
+       }
+
+       return 0;
+}
+
+static int smu7_notify_smc_display(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (hwmgr->feature_mask & PP_VBI_TIME_SUPPORT_MASK)
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                       (PPSMC_Msg)PPSMC_MSG_SetVBITimeout, data->frame_time_x2);
+       return (smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_HasDisplay) == 0) ?  0 : -EINVAL;
+}
+
+static int smu7_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
+{
+       int tmp_result, result = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       tmp_result = smu7_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to find DPM states clocks in DPM table!",
+                       result = tmp_result);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PCIEPerformanceRequest)) {
+               tmp_result =
+                       smu7_request_link_speed_change_before_state_change(hwmgr, input);
+               PP_ASSERT_WITH_CODE((0 == tmp_result),
+                               "Failed to request link speed change before state change!",
+                               result = tmp_result);
+       }
+
+       tmp_result = smu7_freeze_sclk_mclk_dpm(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
+
+       tmp_result = smu7_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to populate and upload SCLK MCLK DPM levels!",
+                       result = tmp_result);
+
+       tmp_result = smu7_generate_dpm_level_enable_mask(hwmgr, input);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to generate DPM level enabled mask!",
+                       result = tmp_result);
+
+       tmp_result = smum_update_sclk_threshold(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to update SCLK threshold!",
+                       result = tmp_result);
+
+       tmp_result = smu7_notify_smc_display(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to notify smc display settings!",
+                       result = tmp_result);
+
+       tmp_result = smu7_unfreeze_sclk_mclk_dpm(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to unfreeze SCLK MCLK DPM!",
+                       result = tmp_result);
+
+       tmp_result = smu7_upload_dpm_level_enable_mask(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to upload DPM level enabled mask!",
+                       result = tmp_result);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PCIEPerformanceRequest)) {
+               tmp_result =
+                       smu7_notify_link_speed_change_after_state_change(hwmgr, input);
+               PP_ASSERT_WITH_CODE((0 == tmp_result),
+                               "Failed to notify link speed change after state change!",
+                               result = tmp_result);
+       }
+       data->apply_optimized_settings = false;
+       return result;
+}
+
+static int smu7_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
+{
+       hwmgr->thermal_controller.
+       advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
+
+       if (phm_is_hw_access_blocked(hwmgr))
+               return 0;
+
+       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                       PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
+}
+
+int smu7_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display)
+{
+       PPSMC_Msg msg = has_display ? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
+
+       return (smum_send_msg_to_smc(hwmgr->smumgr, msg) == 0) ?  0 : -1;
+}
+
+int smu7_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
+{
+       uint32_t num_active_displays = 0;
+       struct cgs_display_info info = {0};
+
+       info.mode_info = NULL;
+       cgs_get_active_displays_info(hwmgr->device, &info);
+
+       num_active_displays = info.display_count;
+
+       if (num_active_displays > 1 && hwmgr->display_config.multi_monitor_in_sync != true)
+               smu7_notify_smc_display_change(hwmgr, false);
+
+       return 0;
+}
+
+/**
+* Programs the display gap
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always OK
+*/
+int smu7_program_display_gap(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t num_active_displays = 0;
+       uint32_t display_gap = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
+       uint32_t display_gap2;
+       uint32_t pre_vbi_time_in_us;
+       uint32_t frame_time_in_us;
+       uint32_t ref_clock;
+       uint32_t refresh_rate = 0;
+       struct cgs_display_info info = {0};
+       struct cgs_mode_info mode_info;
+
+       info.mode_info = &mode_info;
+
+       cgs_get_active_displays_info(hwmgr->device, &info);
+       num_active_displays = info.display_count;
+
+       display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL, DISP_GAP, (num_active_displays > 0) ? DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL, display_gap);
+
+       ref_clock = mode_info.ref_clock;
+       refresh_rate = mode_info.refresh_rate;
+
+       if (0 == refresh_rate)
+               refresh_rate = 60;
+
+       frame_time_in_us = 1000000 / refresh_rate;
+
+       pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
+       data->frame_time_x2 = frame_time_in_us * 2 / 100;
+
+       display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2);
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       data->soft_regs_start + smum_get_offsetof(hwmgr->smumgr,
+                                                       SMU_SoftRegisters,
+                                                       PreVBlankGap), 0x64);
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       data->soft_regs_start + smum_get_offsetof(hwmgr->smumgr,
+                                                       SMU_SoftRegisters,
+                                                       VBlankTimeout),
+                                       (frame_time_in_us - pre_vbi_time_in_us));
+
+       return 0;
+}
+
+int smu7_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
+{
+       return smu7_program_display_gap(hwmgr);
+}
+
+/**
+*  Set maximum target operating fan output RPM
+*
+* @param    hwmgr:  the address of the powerplay hardware manager.
+* @param    usMaxFanRpm:  max operating fan RPM value.
+* @return   The response that came from the SMC.
+*/
+static int smu7_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_rpm)
+{
+       hwmgr->thermal_controller.
+       advanceFanControlParameters.usMaxFanRPM = us_max_fan_rpm;
+
+       if (phm_is_hw_access_blocked(hwmgr))
+               return 0;
+
+       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                       PPSMC_MSG_SetFanRpmMax, us_max_fan_rpm);
+}
+
+int smu7_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
+                                       const void *thermal_interrupt_info)
+{
+       return 0;
+}
+
+bool smu7_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       bool is_update_required = false;
+       struct cgs_display_info info = {0, 0, NULL};
+
+       cgs_get_active_displays_info(hwmgr->device, &info);
+
+       if (data->display_timing.num_existing_displays != info.display_count)
+               is_update_required = true;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
+               if (data->display_timing.min_clock_in_sr != hwmgr->display_config.min_core_set_clock_in_sr &&
+                       (data->display_timing.min_clock_in_sr >= SMU7_MINIMUM_ENGINE_CLOCK ||
+                       hwmgr->display_config.min_core_set_clock_in_sr >= SMU7_MINIMUM_ENGINE_CLOCK))
+                       is_update_required = true;
+       }
+       return is_update_required;
+}
+
+static inline bool smu7_are_power_levels_equal(const struct smu7_performance_level *pl1,
+                                                          const struct smu7_performance_level *pl2)
+{
+       return ((pl1->memory_clock == pl2->memory_clock) &&
+                 (pl1->engine_clock == pl2->engine_clock) &&
+                 (pl1->pcie_gen == pl2->pcie_gen) &&
+                 (pl1->pcie_lane == pl2->pcie_lane));
+}
+
+int smu7_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal)
+{
+       const struct smu7_power_state *psa = cast_const_phw_smu7_power_state(pstate1);
+       const struct smu7_power_state *psb = cast_const_phw_smu7_power_state(pstate2);
+       int i;
+
+       if (pstate1 == NULL || pstate2 == NULL || equal == NULL)
+               return -EINVAL;
+
+       /* If the two states don't even have the same number of performance levels they cannot be the same state. */
+       if (psa->performance_level_count != psb->performance_level_count) {
+               *equal = false;
+               return 0;
+       }
+
+       for (i = 0; i < psa->performance_level_count; i++) {
+               if (!smu7_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
+                       /* If we have found even one performance level pair that is different the states are different. */
+                       *equal = false;
+                       return 0;
+               }
+       }
+
+       /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
+       *equal = ((psa->uvd_clks.vclk == psb->uvd_clks.vclk) && (psa->uvd_clks.dclk == psb->uvd_clks.dclk));
+       *equal &= ((psa->vce_clks.evclk == psb->vce_clks.evclk) && (psa->vce_clks.ecclk == psb->vce_clks.ecclk));
+       *equal &= (psa->sclk_threshold == psb->sclk_threshold);
+
+       return 0;
+}
+
+int smu7_upload_mc_firmware(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       uint32_t vbios_version;
+       uint32_t tmp;
+
+       /* Read MC indirect register offset 0x9F bits [3:0] to see
+        * if VBIOS has already loaded a full version of MC ucode
+        * or not.
+        */
+
+       smu7_get_mc_microcode_version(hwmgr);
+       vbios_version = hwmgr->microcode_version_info.MC & 0xf;
+
+       data->need_long_memory_training = false;
+
+       cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX,
+                                                       ixMC_IO_DEBUG_UP_13);
+       tmp = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA);
+
+       if (tmp & (1 << 23)) {
+               data->mem_latency_high = MEM_LATENCY_HIGH;
+               data->mem_latency_low = MEM_LATENCY_LOW;
+       } else {
+               data->mem_latency_high = 330;
+               data->mem_latency_low = 330;
+       }
+
+       return 0;
+}
+
+static int smu7_read_clock_registers(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       data->clock_registers.vCG_SPLL_FUNC_CNTL         =
+               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL);
+       data->clock_registers.vCG_SPLL_FUNC_CNTL_2       =
+               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_2);
+       data->clock_registers.vCG_SPLL_FUNC_CNTL_3       =
+               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_3);
+       data->clock_registers.vCG_SPLL_FUNC_CNTL_4       =
+               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_4);
+       data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM   =
+               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM);
+       data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
+               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM_2);
+       data->clock_registers.vDLL_CNTL                  =
+               cgs_read_register(hwmgr->device, mmDLL_CNTL);
+       data->clock_registers.vMCLK_PWRMGT_CNTL          =
+               cgs_read_register(hwmgr->device, mmMCLK_PWRMGT_CNTL);
+       data->clock_registers.vMPLL_AD_FUNC_CNTL         =
+               cgs_read_register(hwmgr->device, mmMPLL_AD_FUNC_CNTL);
+       data->clock_registers.vMPLL_DQ_FUNC_CNTL         =
+               cgs_read_register(hwmgr->device, mmMPLL_DQ_FUNC_CNTL);
+       data->clock_registers.vMPLL_FUNC_CNTL            =
+               cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL);
+       data->clock_registers.vMPLL_FUNC_CNTL_1          =
+               cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_1);
+       data->clock_registers.vMPLL_FUNC_CNTL_2          =
+               cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_2);
+       data->clock_registers.vMPLL_SS1                  =
+               cgs_read_register(hwmgr->device, mmMPLL_SS1);
+       data->clock_registers.vMPLL_SS2                  =
+               cgs_read_register(hwmgr->device, mmMPLL_SS2);
+       return 0;
+
+}
+
+/**
+ * Find out if memory is GDDR5.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+static int smu7_get_memory_type(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t temp;
+
+       temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
+
+       data->is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
+                       ((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
+                        MC_SEQ_MISC0_GDDR5_SHIFT));
+
+       return 0;
+}
+
+/**
+ * Enables Dynamic Power Management by SMC
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+static int smu7_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
+{
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       GENERAL_PWRMGT, STATIC_PM_EN, 1);
+
+       return 0;
+}
+
+/**
+ * Initialize PowerGating States for different engines
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+static int smu7_init_power_gate_state(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       data->uvd_power_gated = false;
+       data->vce_power_gated = false;
+       data->samu_power_gated = false;
+
+       return 0;
+}
+
+static int smu7_init_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       data->low_sclk_interrupt_threshold = 0;
+       return 0;
+}
+
+int smu7_setup_asic_task(struct pp_hwmgr *hwmgr)
+{
+       int tmp_result, result = 0;
+
+       smu7_upload_mc_firmware(hwmgr);
+
+       tmp_result = smu7_read_clock_registers(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to read clock registers!", result = tmp_result);
+
+       tmp_result = smu7_get_memory_type(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to get memory type!", result = tmp_result);
+
+       tmp_result = smu7_enable_acpi_power_management(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to enable ACPI power management!", result = tmp_result);
+
+       tmp_result = smu7_init_power_gate_state(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to init power gate state!", result = tmp_result);
+
+       tmp_result = smu7_get_mc_microcode_version(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to get MC microcode version!", result = tmp_result);
+
+       tmp_result = smu7_init_sclk_threshold(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == tmp_result),
+                       "Failed to init sclk threshold!", result = tmp_result);
+
+       return result;
+}
+
+static int smu7_force_clock_level(struct pp_hwmgr *hwmgr,
+               enum pp_clock_type type, uint32_t mask)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
+               return -EINVAL;
+
+       switch (type) {
+       case PP_SCLK:
+               if (!data->sclk_dpm_key_disabled)
+                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                       PPSMC_MSG_SCLKDPM_SetEnabledMask,
+                                       data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
+               break;
+       case PP_MCLK:
+               if (!data->mclk_dpm_key_disabled)
+                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                       PPSMC_MSG_MCLKDPM_SetEnabledMask,
+                                       data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
+               break;
+       case PP_PCIE:
+       {
+               uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
+               uint32_t level = 0;
+
+               while (tmp >>= 1)
+                       level++;
+
+               if (!data->pcie_dpm_key_disabled)
+                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                                       PPSMC_MSG_PCIeDPM_ForceLevel,
+                                       level);
+               break;
+       }
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
+               enum pp_clock_type type, char *buf)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
+       struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
+       struct smu7_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table);
+       int i, now, size = 0;
+       uint32_t clock, pcie_speed;
+
+       switch (type) {
+       case PP_SCLK:
+               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
+               clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+
+               for (i = 0; i < sclk_table->count; i++) {
+                       if (clock > sclk_table->dpm_levels[i].value)
+                               continue;
+                       break;
+               }
+               now = i;
+
+               for (i = 0; i < sclk_table->count; i++)
+                       size += sprintf(buf + size, "%d: %uMhz %s\n",
+                                       i, sclk_table->dpm_levels[i].value / 100,
+                                       (i == now) ? "*" : "");
+               break;
+       case PP_MCLK:
+               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
+               clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+
+               for (i = 0; i < mclk_table->count; i++) {
+                       if (clock > mclk_table->dpm_levels[i].value)
+                               continue;
+                       break;
+               }
+               now = i;
+
+               for (i = 0; i < mclk_table->count; i++)
+                       size += sprintf(buf + size, "%d: %uMhz %s\n",
+                                       i, mclk_table->dpm_levels[i].value / 100,
+                                       (i == now) ? "*" : "");
+               break;
+       case PP_PCIE:
+               pcie_speed = smu7_get_current_pcie_speed(hwmgr);
+               for (i = 0; i < pcie_table->count; i++) {
+                       if (pcie_speed != pcie_table->dpm_levels[i].value)
+                               continue;
+                       break;
+               }
+               now = i;
+
+               for (i = 0; i < pcie_table->count; i++)
+                       size += sprintf(buf + size, "%d: %s %s\n", i,
+                                       (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x8" :
+                                       (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" :
+                                       (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "",
+                                       (i == now) ? "*" : "");
+               break;
+       default:
+               break;
+       }
+       return size;
+}
+
+static int smu7_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+       if (mode) {
+               /* stop auto-manage */
+               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_MicrocodeFanControl))
+                       smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
+               smu7_fan_ctrl_set_static_mode(hwmgr, mode);
+       } else
+               /* restart auto-manage */
+               smu7_fan_ctrl_reset_fan_speed_to_default(hwmgr);
+
+       return 0;
+}
+
+static int smu7_get_fan_control_mode(struct pp_hwmgr *hwmgr)
+{
+       if (hwmgr->fan_ctrl_is_in_default_mode)
+               return hwmgr->fan_ctrl_default_mode;
+       else
+               return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                               CG_FDO_CTRL2, FDO_PWM_MODE);
+}
+
+static int smu7_get_sclk_od(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
+       struct smu7_single_dpm_table *golden_sclk_table =
+                       &(data->golden_dpm_table.sclk_table);
+       int value;
+
+       value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
+                       100 /
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
+
+       return value;
+}
+
+static int smu7_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_single_dpm_table *golden_sclk_table =
+                       &(data->golden_dpm_table.sclk_table);
+       struct pp_power_state  *ps;
+       struct smu7_power_state  *smu7_ps;
+
+       if (value > 20)
+               value = 20;
+
+       ps = hwmgr->request_ps;
+
+       if (ps == NULL)
+               return -EINVAL;
+
+       smu7_ps = cast_phw_smu7_power_state(&ps->hardware);
+
+       smu7_ps->performance_levels[smu7_ps->performance_level_count - 1].engine_clock =
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
+                       value / 100 +
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
+
+       return 0;
+}
+
+static int smu7_get_mclk_od(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
+       struct smu7_single_dpm_table *golden_mclk_table =
+                       &(data->golden_dpm_table.mclk_table);
+       int value;
+
+       value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
+                       100 /
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
+
+       return value;
+}
+
+static int smu7_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_single_dpm_table *golden_mclk_table =
+                       &(data->golden_dpm_table.mclk_table);
+       struct pp_power_state  *ps;
+       struct smu7_power_state  *smu7_ps;
+
+       if (value > 20)
+               value = 20;
+
+       ps = hwmgr->request_ps;
+
+       if (ps == NULL)
+               return -EINVAL;
+
+       smu7_ps = cast_phw_smu7_power_state(&ps->hardware);
+
+       smu7_ps->performance_levels[smu7_ps->performance_level_count - 1].memory_clock =
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
+                       value / 100 +
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
+
+       return 0;
+}
+
+
+static int smu7_get_sclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks)
+{
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)hwmgr->pptable;
+       struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table;
+       int i;
+
+       if (table_info == NULL)
+               return -EINVAL;
+
+       dep_sclk_table = table_info->vdd_dep_on_sclk;
+
+       for (i = 0; i < dep_sclk_table->count; i++) {
+               clocks->clock[i] = dep_sclk_table->entries[i].clk;
+               clocks->count++;
+       }
+       return 0;
+}
+
+static uint32_t smu7_get_mem_latency(struct pp_hwmgr *hwmgr, uint32_t clk)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (clk >= MEM_FREQ_LOW_LATENCY && clk < MEM_FREQ_HIGH_LATENCY)
+               return data->mem_latency_high;
+       else if (clk >= MEM_FREQ_HIGH_LATENCY)
+               return data->mem_latency_low;
+       else
+               return MEM_LATENCY_ERR;
+}
+
+static int smu7_get_mclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks)
+{
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)hwmgr->pptable;
+       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table;
+       int i;
+
+       if (table_info == NULL)
+               return -EINVAL;
+
+       dep_mclk_table = table_info->vdd_dep_on_mclk;
+
+       for (i = 0; i < dep_mclk_table->count; i++) {
+               clocks->clock[i] = dep_mclk_table->entries[i].clk;
+               clocks->latency[i] = smu7_get_mem_latency(hwmgr,
+                                               dep_mclk_table->entries[i].clk);
+               clocks->count++;
+       }
+       return 0;
+}
+
+static int smu7_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type,
+                                               struct amd_pp_clocks *clocks)
+{
+       switch (type) {
+       case amd_pp_sys_clock:
+               smu7_get_sclks(hwmgr, clocks);
+               break;
+       case amd_pp_mem_clock:
+               smu7_get_mclks(hwmgr, clocks);
+               break;
+       default:
+               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,
+       .asic_setup = &smu7_setup_asic_task,
+       .dynamic_state_management_enable = &smu7_enable_dpm_tasks,
+       .apply_state_adjust_rules = smu7_apply_state_adjust_rules,
+       .force_dpm_level = &smu7_force_dpm_level,
+       .power_state_set = smu7_set_power_state_tasks,
+       .get_power_state_size = smu7_get_power_state_size,
+       .get_mclk = smu7_dpm_get_mclk,
+       .get_sclk = smu7_dpm_get_sclk,
+       .patch_boot_state = smu7_dpm_patch_boot_state,
+       .get_pp_table_entry = smu7_get_pp_table_entry,
+       .get_num_of_pp_table_entries = smu7_get_number_of_powerplay_table_entries,
+       .powerdown_uvd = smu7_powerdown_uvd,
+       .powergate_uvd = smu7_powergate_uvd,
+       .powergate_vce = smu7_powergate_vce,
+       .disable_clock_power_gating = smu7_disable_clock_power_gating,
+       .update_clock_gatings = smu7_update_clock_gatings,
+       .notify_smc_display_config_after_ps_adjustment = smu7_notify_smc_display_config_after_ps_adjustment,
+       .display_config_changed = smu7_display_configuration_changed_task,
+       .set_max_fan_pwm_output = smu7_set_max_fan_pwm_output,
+       .set_max_fan_rpm_output = smu7_set_max_fan_rpm_output,
+       .get_temperature = smu7_thermal_get_temperature,
+       .stop_thermal_controller = smu7_thermal_stop_thermal_controller,
+       .get_fan_speed_info = smu7_fan_ctrl_get_fan_speed_info,
+       .get_fan_speed_percent = smu7_fan_ctrl_get_fan_speed_percent,
+       .set_fan_speed_percent = smu7_fan_ctrl_set_fan_speed_percent,
+       .reset_fan_speed_to_default = smu7_fan_ctrl_reset_fan_speed_to_default,
+       .get_fan_speed_rpm = smu7_fan_ctrl_get_fan_speed_rpm,
+       .set_fan_speed_rpm = smu7_fan_ctrl_set_fan_speed_rpm,
+       .uninitialize_thermal_controller = smu7_thermal_ctrl_uninitialize_thermal_controller,
+       .register_internal_thermal_interrupt = smu7_register_internal_thermal_interrupt,
+       .check_smc_update_required_for_display_configuration = smu7_check_smc_update_required_for_display_configuration,
+       .check_states_equal = smu7_check_states_equal,
+       .set_fan_control_mode = smu7_set_fan_control_mode,
+       .get_fan_control_mode = smu7_get_fan_control_mode,
+       .force_clock_level = smu7_force_clock_level,
+       .print_clock_levels = smu7_print_clock_levels,
+       .enable_per_cu_power_gating = smu7_enable_per_cu_power_gating,
+       .get_sclk_od = smu7_get_sclk_od,
+       .set_sclk_od = smu7_set_sclk_od,
+       .get_mclk_od = smu7_get_mclk_od,
+       .set_mclk_od = smu7_set_mclk_od,
+       .get_clock_by_type = smu7_get_clock_by_type,
+       .read_sensor = smu7_read_sensor,
+};
+
+uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
+               uint32_t clock_insr)
+{
+       uint8_t i;
+       uint32_t temp;
+       uint32_t min = max(clock_insr, (uint32_t)SMU7_MINIMUM_ENGINE_CLOCK);
+
+       PP_ASSERT_WITH_CODE((clock >= min), "Engine clock can't satisfy stutter requirement!", return 0);
+       for (i = SMU7_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
+               temp = clock >> i;
+
+               if (temp >= min || i == 0)
+                       break;
+       }
+       return i;
+}
+
+int smu7_hwmgr_init(struct pp_hwmgr *hwmgr)
+{
+       int ret = 0;
+
+       hwmgr->hwmgr_func = &smu7_hwmgr_funcs;
+       if (hwmgr->pp_table_version == PP_TABLE_V0)
+               hwmgr->pptable_func = &pptable_funcs;
+       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_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h
new file mode 100644 (file)
index 0000000..27e7f76
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright 2015 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 _SMU7_HWMGR_H
+#define _SMU7_HWMGR_H
+
+#include "hwmgr.h"
+#include "ppatomctrl.h"
+
+#define SMU7_MAX_HARDWARE_POWERLEVELS   2
+
+#define SMU7_VOLTAGE_CONTROL_NONE                   0x0
+#define SMU7_VOLTAGE_CONTROL_BY_GPIO                0x1
+#define SMU7_VOLTAGE_CONTROL_BY_SVID2               0x2
+#define SMU7_VOLTAGE_CONTROL_MERGED                 0x3
+
+#define DPMTABLE_OD_UPDATE_SCLK     0x00000001
+#define DPMTABLE_OD_UPDATE_MCLK     0x00000002
+#define DPMTABLE_UPDATE_SCLK        0x00000004
+#define DPMTABLE_UPDATE_MCLK        0x00000008
+
+enum gpu_pt_config_reg_type {
+       GPU_CONFIGREG_MMR = 0,
+       GPU_CONFIGREG_SMC_IND,
+       GPU_CONFIGREG_DIDT_IND,
+       GPU_CONFIGREG_GC_CAC_IND,
+       GPU_CONFIGREG_CACHE,
+       GPU_CONFIGREG_MAX
+};
+
+struct gpu_pt_config_reg {
+       uint32_t                           offset;
+       uint32_t                           mask;
+       uint32_t                           shift;
+       uint32_t                           value;
+       enum gpu_pt_config_reg_type       type;
+};
+
+struct smu7_performance_level {
+       uint32_t  memory_clock;
+       uint32_t  engine_clock;
+       uint16_t  pcie_gen;
+       uint16_t  pcie_lane;
+};
+
+struct smu7_thermal_temperature_setting {
+       long temperature_low;
+       long temperature_high;
+       long temperature_shutdown;
+};
+
+struct smu7_uvd_clocks {
+       uint32_t  vclk;
+       uint32_t  dclk;
+};
+
+struct smu7_vce_clocks {
+       uint32_t  evclk;
+       uint32_t  ecclk;
+};
+
+struct smu7_power_state {
+       uint32_t                  magic;
+       struct smu7_uvd_clocks    uvd_clks;
+       struct smu7_vce_clocks    vce_clks;
+       uint32_t                  sam_clk;
+       uint16_t                  performance_level_count;
+       bool                      dc_compatible;
+       uint32_t                  sclk_threshold;
+       struct smu7_performance_level  performance_levels[SMU7_MAX_HARDWARE_POWERLEVELS];
+};
+
+struct smu7_dpm_level {
+       bool    enabled;
+       uint32_t        value;
+       uint32_t        param1;
+};
+
+#define SMU7_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define MAX_REGULAR_DPM_NUMBER 8
+#define SMU7_MINIMUM_ENGINE_CLOCK 2500
+
+struct smu7_single_dpm_table {
+       uint32_t                count;
+       struct smu7_dpm_level   dpm_levels[MAX_REGULAR_DPM_NUMBER];
+};
+
+struct smu7_dpm_table {
+       struct smu7_single_dpm_table  sclk_table;
+       struct smu7_single_dpm_table  mclk_table;
+       struct smu7_single_dpm_table  pcie_speed_table;
+       struct smu7_single_dpm_table  vddc_table;
+       struct smu7_single_dpm_table  vddci_table;
+       struct smu7_single_dpm_table  mvdd_table;
+};
+
+struct smu7_clock_registers {
+       uint32_t  vCG_SPLL_FUNC_CNTL;
+       uint32_t  vCG_SPLL_FUNC_CNTL_2;
+       uint32_t  vCG_SPLL_FUNC_CNTL_3;
+       uint32_t  vCG_SPLL_FUNC_CNTL_4;
+       uint32_t  vCG_SPLL_SPREAD_SPECTRUM;
+       uint32_t  vCG_SPLL_SPREAD_SPECTRUM_2;
+       uint32_t  vDLL_CNTL;
+       uint32_t  vMCLK_PWRMGT_CNTL;
+       uint32_t  vMPLL_AD_FUNC_CNTL;
+       uint32_t  vMPLL_DQ_FUNC_CNTL;
+       uint32_t  vMPLL_FUNC_CNTL;
+       uint32_t  vMPLL_FUNC_CNTL_1;
+       uint32_t  vMPLL_FUNC_CNTL_2;
+       uint32_t  vMPLL_SS1;
+       uint32_t  vMPLL_SS2;
+};
+
+#define DISABLE_MC_LOADMICROCODE   1
+#define DISABLE_MC_CFGPROGRAMMING  2
+
+struct smu7_voltage_smio_registers {
+       uint32_t vS0_VID_LOWER_SMIO_CNTL;
+};
+
+#define SMU7_MAX_LEAKAGE_COUNT  8
+
+struct smu7_leakage_voltage {
+       uint16_t  count;
+       uint16_t  leakage_id[SMU7_MAX_LEAKAGE_COUNT];
+       uint16_t  actual_voltage[SMU7_MAX_LEAKAGE_COUNT];
+};
+
+struct smu7_vbios_boot_state {
+       uint16_t    mvdd_bootup_value;
+       uint16_t    vddc_bootup_value;
+       uint16_t    vddci_bootup_value;
+       uint16_t    vddgfx_bootup_value;
+       uint32_t    sclk_bootup_value;
+       uint32_t    mclk_bootup_value;
+       uint16_t    pcie_gen_bootup_value;
+       uint16_t    pcie_lane_bootup_value;
+};
+
+struct smu7_display_timing {
+       uint32_t  min_clock_in_sr;
+       uint32_t  num_existing_displays;
+};
+
+struct smu7_dpmlevel_enable_mask {
+       uint32_t  uvd_dpm_enable_mask;
+       uint32_t  vce_dpm_enable_mask;
+       uint32_t  acp_dpm_enable_mask;
+       uint32_t  samu_dpm_enable_mask;
+       uint32_t  sclk_dpm_enable_mask;
+       uint32_t  mclk_dpm_enable_mask;
+       uint32_t  pcie_dpm_enable_mask;
+};
+
+struct smu7_pcie_perf_range {
+       uint16_t  max;
+       uint16_t  min;
+};
+
+struct smu7_hwmgr {
+       struct smu7_dpm_table                   dpm_table;
+       struct smu7_dpm_table                   golden_dpm_table;
+
+       uint32_t                                                voting_rights_clients0;
+       uint32_t                                                voting_rights_clients1;
+       uint32_t                                                voting_rights_clients2;
+       uint32_t                                                voting_rights_clients3;
+       uint32_t                                                voting_rights_clients4;
+       uint32_t                                                voting_rights_clients5;
+       uint32_t                                                voting_rights_clients6;
+       uint32_t                                                voting_rights_clients7;
+       uint32_t                                                static_screen_threshold_unit;
+       uint32_t                                                static_screen_threshold;
+       uint32_t                                                voltage_control;
+       uint32_t                                                vdd_gfx_control;
+       uint32_t                                                vddc_vddgfx_delta;
+       uint32_t                                                active_auto_throttle_sources;
+
+       struct smu7_clock_registers            clock_registers;
+
+       bool                           is_memory_gddr5;
+       uint16_t                       acpi_vddc;
+       bool                           pspp_notify_required;
+       uint16_t                       force_pcie_gen;
+       uint16_t                       acpi_pcie_gen;
+       uint32_t                       pcie_gen_cap;
+       uint32_t                       pcie_lane_cap;
+       uint32_t                       pcie_spc_cap;
+       struct smu7_leakage_voltage          vddc_leakage;
+       struct smu7_leakage_voltage          vddci_leakage;
+       struct smu7_leakage_voltage          vddcgfx_leakage;
+
+       uint32_t                             mvdd_control;
+       uint32_t                             vddc_mask_low;
+       uint32_t                             mvdd_mask_low;
+       uint16_t                            max_vddc_in_pptable;
+       uint16_t                            min_vddc_in_pptable;
+       uint16_t                            max_vddci_in_pptable;
+       uint16_t                            min_vddci_in_pptable;
+       bool                                is_uvd_enabled;
+       struct smu7_vbios_boot_state        vbios_boot_state;
+
+       bool                           pcie_performance_request;
+       bool                           battery_state;
+       bool                           is_tlu_enabled;
+       bool                           disable_handshake;
+       bool                           smc_voltage_control_enabled;
+       bool                           vbi_time_out_support;
+
+       uint32_t                       soft_regs_start;
+       /* ---- Stuff originally coming from Evergreen ---- */
+       uint32_t                             vddci_control;
+       struct pp_atomctrl_voltage_table     vddc_voltage_table;
+       struct pp_atomctrl_voltage_table     vddci_voltage_table;
+       struct pp_atomctrl_voltage_table     mvdd_voltage_table;
+       struct pp_atomctrl_voltage_table     vddgfx_voltage_table;
+
+       uint32_t                             mgcg_cgtt_local2;
+       uint32_t                             mgcg_cgtt_local3;
+       uint32_t                             gpio_debug;
+       uint32_t                             mc_micro_code_feature;
+       uint32_t                             highest_mclk;
+       uint16_t                             acpi_vddci;
+       uint8_t                              mvdd_high_index;
+       uint8_t                              mvdd_low_index;
+       bool                                 dll_default_on;
+       bool                                 performance_request_registered;
+
+       /* ---- Low Power Features ---- */
+       bool                           ulv_supported;
+
+       /* ---- CAC Stuff ---- */
+       uint32_t                       cac_table_start;
+       bool                           cac_configuration_required;
+       bool                           driver_calculate_cac_leakage;
+       bool                           cac_enabled;
+
+       /* ---- DPM2 Parameters ---- */
+       uint32_t                       power_containment_features;
+       bool                           enable_dte_feature;
+       bool                           enable_tdc_limit_feature;
+       bool                           enable_pkg_pwr_tracking_feature;
+       bool                           disable_uvd_power_tune_feature;
+
+
+       uint32_t                       dte_tj_offset;
+       uint32_t                       fast_watermark_threshold;
+
+       /* ---- Phase Shedding ---- */
+       bool                           vddc_phase_shed_control;
+
+       /* ---- DI/DT ---- */
+       struct smu7_display_timing        display_timing;
+
+       /* ---- Thermal Temperature Setting ---- */
+       struct smu7_thermal_temperature_setting  thermal_temp_setting;
+       struct smu7_dpmlevel_enable_mask     dpm_level_enable_mask;
+       uint32_t                                  need_update_smu7_dpm_table;
+       uint32_t                                  sclk_dpm_key_disabled;
+       uint32_t                                  mclk_dpm_key_disabled;
+       uint32_t                                  pcie_dpm_key_disabled;
+       uint32_t                                  min_engine_clocks;
+       struct smu7_pcie_perf_range          pcie_gen_performance;
+       struct smu7_pcie_perf_range          pcie_lane_performance;
+       struct smu7_pcie_perf_range          pcie_gen_power_saving;
+       struct smu7_pcie_perf_range          pcie_lane_power_saving;
+       bool                                      use_pcie_performance_levels;
+       bool                                      use_pcie_power_saving_levels;
+       uint32_t                                  mclk_activity_target;
+       uint32_t                                  mclk_dpm0_activity_target;
+       uint32_t                                  low_sclk_interrupt_threshold;
+       uint32_t                                  last_mclk_dpm_enable_mask;
+       bool                                      uvd_enabled;
+
+       /* ---- Power Gating States ---- */
+       bool                           uvd_power_gated;
+       bool                           vce_power_gated;
+       bool                           samu_power_gated;
+       bool                           need_long_memory_training;
+
+       /* Application power optimization parameters */
+       bool                               update_up_hyst;
+       bool                               update_down_hyst;
+       uint32_t                           down_hyst;
+       uint32_t                           up_hyst;
+       uint32_t disable_dpm_mask;
+       bool apply_optimized_settings;
+
+       uint32_t                              avfs_vdroop_override_setting;
+       bool                                  apply_avfs_cks_off_voltage;
+       uint32_t                              frame_time_x2;
+       uint16_t                              mem_latency_high;
+       uint16_t                              mem_latency_low;
+};
+
+/* To convert to Q8.8 format for firmware */
+#define SMU7_Q88_FORMAT_CONVERSION_UNIT             256
+
+enum SMU7_I2CLineID {
+       SMU7_I2CLineID_DDC1 = 0x90,
+       SMU7_I2CLineID_DDC2 = 0x91,
+       SMU7_I2CLineID_DDC3 = 0x92,
+       SMU7_I2CLineID_DDC4 = 0x93,
+       SMU7_I2CLineID_DDC5 = 0x94,
+       SMU7_I2CLineID_DDC6 = 0x95,
+       SMU7_I2CLineID_SCLSDA = 0x96,
+       SMU7_I2CLineID_DDCVGA = 0x97
+};
+
+#define SMU7_I2C_DDC1DATA          0
+#define SMU7_I2C_DDC1CLK           1
+#define SMU7_I2C_DDC2DATA          2
+#define SMU7_I2C_DDC2CLK           3
+#define SMU7_I2C_DDC3DATA          4
+#define SMU7_I2C_DDC3CLK           5
+#define SMU7_I2C_SDA               40
+#define SMU7_I2C_SCL               41
+#define SMU7_I2C_DDC4DATA          65
+#define SMU7_I2C_DDC4CLK           66
+#define SMU7_I2C_DDC5DATA          0x48
+#define SMU7_I2C_DDC5CLK           0x49
+#define SMU7_I2C_DDC6DATA          0x4a
+#define SMU7_I2C_DDC6CLK           0x4b
+#define SMU7_I2C_DDCVGADATA        0x4c
+#define SMU7_I2C_DDCVGACLK         0x4d
+
+#define SMU7_UNUSED_GPIO_PIN       0x7F
+uint32_t smu7_get_xclk(struct pp_hwmgr *hwmgr);
+uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
+               uint32_t clock_insr);
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c
new file mode 100644 (file)
index 0000000..41b634f
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ * Copyright 2015 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 "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 const struct gpu_pt_config_reg GCCACConfig_Polaris10[] = {
+/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ *      Offset                             Mask                                                Shift                                               Value       Type
+ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ */
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00060013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00860013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01060013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01860013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02060013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02860013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x03060013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x03860013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x04060013, GPU_CONFIGREG_GC_CAC_IND },
+
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x000E0013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x008E0013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x010E0013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x018E0013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x020E0013, GPU_CONFIGREG_GC_CAC_IND },
+
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00100013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00900013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01100013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01900013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02100013, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02900013, GPU_CONFIGREG_GC_CAC_IND },
+
+       {   0xFFFFFFFF  }
+};
+
+static const struct gpu_pt_config_reg GCCACConfig_Polaris11[] = {
+/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ *      Offset                             Mask                                                Shift                                               Value       Type
+ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ */
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00060011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00860011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01060011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01860011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02060011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02860011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x03060011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x03860011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x04060011, GPU_CONFIGREG_GC_CAC_IND },
+
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x000E0011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x008E0011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x010E0011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x018E0011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x020E0011, GPU_CONFIGREG_GC_CAC_IND },
+
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00100011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x00900011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01100011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x01900011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02100011, GPU_CONFIGREG_GC_CAC_IND },
+       {   ixGC_CAC_CNTL,                     0xFFFFFFFF,                                         0,                                                  0x02900011, GPU_CONFIGREG_GC_CAC_IND },
+
+       {   0xFFFFFFFF  }
+};
+
+static const struct gpu_pt_config_reg DIDTConfig_Polaris10[] = {
+/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ *      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_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__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__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 },
+
+       {   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__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__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 },
+       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__USE_REF_CLOCK_MASK,                  DIDT_SQ_CTRL0__USE_REF_CLOCK__SHIFT,                0x0000,     GPU_CONFIGREG_DIDT_IND },
+       {   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__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 },
+       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT1_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT1__SHIFT,                  0x0010,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT2_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT2__SHIFT,                  0x0017,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT3_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT3__SHIFT,                  0x002f,     GPU_CONFIGREG_DIDT_IND },
+
+       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT4_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT4__SHIFT,                  0x0046,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT5_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT5__SHIFT,                  0x005d,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT6_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT6__SHIFT,                  0x0000,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT7_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT7__SHIFT,                  0x0000,     GPU_CONFIGREG_DIDT_IND },
+
+       {   ixDIDT_TD_CTRL1,                   DIDT_TD_CTRL1__MIN_POWER_MASK,                      DIDT_TD_CTRL1__MIN_POWER__SHIFT,                    0x0000,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_CTRL1,                   DIDT_TD_CTRL1__MAX_POWER_MASK,                      DIDT_TD_CTRL1__MAX_POWER__SHIFT,                    0xffff,     GPU_CONFIGREG_DIDT_IND },
+
+       {   ixDIDT_TD_CTRL_OCP,                DIDT_TD_CTRL_OCP__UNUSED_0_MASK,                    DIDT_TD_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,   0x0009,     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,   0x0009,     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 const struct gpu_pt_config_reg DIDTConfig_Polaris11[] = {
+/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ *      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_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__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__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 },
+
+       {   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__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__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 },
+       {   ixDIDT_SQ_CTRL0,                   DIDT_SQ_CTRL0__USE_REF_CLOCK_MASK,                  DIDT_SQ_CTRL0__USE_REF_CLOCK__SHIFT,                0x0000,     GPU_CONFIGREG_DIDT_IND },
+       {   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__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 },
+       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT1_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT1__SHIFT,                  0x0010,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT2_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT2__SHIFT,                  0x0017,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT0_3,               DIDT_TD_WEIGHT0_3__WEIGHT3_MASK,                    DIDT_TD_WEIGHT0_3__WEIGHT3__SHIFT,                  0x002f,     GPU_CONFIGREG_DIDT_IND },
+
+       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT4_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT4__SHIFT,                  0x0046,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT5_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT5__SHIFT,                  0x005d,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT6_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT6__SHIFT,                  0x0000,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_WEIGHT4_7,               DIDT_TD_WEIGHT4_7__WEIGHT7_MASK,                    DIDT_TD_WEIGHT4_7__WEIGHT7__SHIFT,                  0x0000,     GPU_CONFIGREG_DIDT_IND },
+
+       {   ixDIDT_TD_CTRL1,                   DIDT_TD_CTRL1__MIN_POWER_MASK,                      DIDT_TD_CTRL1__MIN_POWER__SHIFT,                    0x0000,     GPU_CONFIGREG_DIDT_IND },
+       {   ixDIDT_TD_CTRL1,                   DIDT_TD_CTRL1__MAX_POWER_MASK,                      DIDT_TD_CTRL1__MAX_POWER__SHIFT,                    0xffff,     GPU_CONFIGREG_DIDT_IND },
+
+       {   ixDIDT_TD_CTRL_OCP,                DIDT_TD_CTRL_OCP__UNUSED_0_MASK,                    DIDT_TD_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;
+       int32_t result = 0;
+       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 (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;
+       }
+
+       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;
+       }
+
+       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);
+
+       return result;
+}
+
+static int smu7_program_pt_config_registers(struct pp_hwmgr *hwmgr,
+                               const struct gpu_pt_config_reg *cac_config_regs)
+{
+       const struct gpu_pt_config_reg *config_regs = cac_config_regs;
+       uint32_t cache = 0;
+       uint32_t data = 0;
+
+       PP_ASSERT_WITH_CODE((config_regs != NULL), "Invalid config register table.", return -EINVAL);
+
+       while (config_regs->offset != 0xFFFFFFFF) {
+               if (config_regs->type == GPU_CONFIGREG_CACHE)
+                       cache |= ((config_regs->value << config_regs->shift) & config_regs->mask);
+               else {
+                       switch (config_regs->type) {
+                       case GPU_CONFIGREG_SMC_IND:
+                               data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, config_regs->offset);
+                               break;
+
+                       case GPU_CONFIGREG_DIDT_IND:
+                               data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, config_regs->offset);
+                               break;
+
+                       case GPU_CONFIGREG_GC_CAC_IND:
+                               data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG_GC_CAC, config_regs->offset);
+                               break;
+
+                       default:
+                               data = cgs_read_register(hwmgr->device, config_regs->offset);
+                               break;
+                       }
+
+                       data &= ~config_regs->mask;
+                       data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
+                       data |= cache;
+
+                       switch (config_regs->type) {
+                       case GPU_CONFIGREG_SMC_IND:
+                               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, config_regs->offset, data);
+                               break;
+
+                       case GPU_CONFIGREG_DIDT_IND:
+                               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, config_regs->offset, data);
+                               break;
+
+                       case GPU_CONFIGREG_GC_CAC_IND:
+                               cgs_write_ind_register(hwmgr->device, CGS_IND_REG_GC_CAC, config_regs->offset, data);
+                               break;
+
+                       default:
+                               cgs_write_register(hwmgr->device, config_regs->offset, data);
+                               break;
+                       }
+                       cache = 0;
+               }
+
+               config_regs++;
+       }
+
+       return 0;
+}
+
+int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       uint32_t num_se = 0;
+       uint32_t count, value, value2;
+       struct cgs_system_info sys_info = {0};
+
+       sys_info.size = sizeof(struct cgs_system_info);
+       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;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping) ||
+               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 */
+               value = 0;
+               value2 = cgs_read_register(hwmgr->device, mmGRBM_GFX_INDEX);
+               for (count = 0; count < num_se; count++) {
+                       value = SYS_GRBM_GFX_INDEX_DATA__INSTANCE_BROADCAST_WRITES_MASK
+                               | SYS_GRBM_GFX_INDEX_DATA__SH_BROADCAST_WRITES_MASK
+                               | (count << SYS_GRBM_GFX_INDEX_DATA__SE_INDEX__SHIFT);
+                       cgs_write_register(hwmgr->device, mmGRBM_GFX_INDEX, value);
+
+                       if (hwmgr->chip_id == CHIP_POLARIS10) {
+                               result = smu7_program_pt_config_registers(hwmgr, GCCACConfig_Polaris10);
+                               PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
+                               result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris10);
+                               PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
+                       } else if (hwmgr->chip_id == CHIP_POLARIS11) {
+                               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_Polaris11);
+                               PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
+                       }
+               }
+               cgs_write_register(hwmgr->device, mmGRBM_GFX_INDEX, value2);
+
+               result = smu7_enable_didt(hwmgr, true);
+               PP_ASSERT_WITH_CODE((result == 0), "EnableDiDt failed.", return result);
+
+               /* TO DO Post DIDT enable clock gating */
+       }
+
+       return 0;
+}
+
+int smu7_disable_didt_config(struct pp_hwmgr *hwmgr)
+{
+       int result;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping) ||
+               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 */
+
+               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 */
+       }
+
+       return 0;
+}
+
+int smu7_enable_smc_cac(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       int result = 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_CAC)) {
+               int smc_result;
+               smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+                               (uint16_t)(PPSMC_MSG_EnableCac));
+               PP_ASSERT_WITH_CODE((0 == smc_result),
+                               "Failed to enable CAC in SMC.", result = -1);
+
+               data->cac_enabled = (0 == smc_result) ? true : false;
+       }
+       return result;
+}
+
+int smu7_disable_smc_cac(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       int result = 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_CAC) && data->cac_enabled) {
+               int smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+                               (uint16_t)(PPSMC_MSG_DisableCac));
+               PP_ASSERT_WITH_CODE((smc_result == 0),
+                               "Failed to disable CAC in SMC.", result = -1);
+
+               data->cac_enabled = false;
+       }
+       return result;
+}
+
+int smu7_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->power_containment_features &
+                       POWERCONTAINMENT_FEATURE_PkgPwrLimit)
+               return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_PkgPwrSetLimit, n);
+       return 0;
+}
+
+static int smu7_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
+{
+       return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
+                       PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
+}
+
+int smu7_enable_power_containment(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       int smc_result;
+       int result = 0;
+       struct phm_cac_tdp_table *cac_table;
+
+       data->power_containment_features = 0;
+       if (hwmgr->pp_table_version == PP_TABLE_V1)
+               cac_table = table_info->cac_dtp_table;
+       else
+               cac_table = hwmgr->dyn_state.cac_dtp_table;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PowerContainment)) {
+
+               if (data->enable_tdc_limit_feature) {
+                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+                                       (uint16_t)(PPSMC_MSG_TDCLimitEnable));
+                       PP_ASSERT_WITH_CODE((0 == smc_result),
+                                       "Failed to enable TDCLimit in SMC.", result = -1;);
+                       if (0 == smc_result)
+                               data->power_containment_features |=
+                                               POWERCONTAINMENT_FEATURE_TDCLimit;
+               }
+
+               if (data->enable_pkg_pwr_tracking_feature) {
+                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+                                       (uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
+                       PP_ASSERT_WITH_CODE((0 == smc_result),
+                                       "Failed to enable PkgPwrTracking in SMC.", result = -1;);
+                       if (0 == smc_result) {
+                               uint32_t default_limit =
+                                       (uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
+
+                               data->power_containment_features |=
+                                               POWERCONTAINMENT_FEATURE_PkgPwrLimit;
+
+                               if (smu7_set_power_limit(hwmgr, default_limit))
+                                       printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
+                       }
+               }
+       }
+       return result;
+}
+
+int smu7_disable_power_containment(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       int result = 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PowerContainment) &&
+                       data->power_containment_features) {
+               int smc_result;
+
+               if (data->power_containment_features &
+                               POWERCONTAINMENT_FEATURE_TDCLimit) {
+                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+                                       (uint16_t)(PPSMC_MSG_TDCLimitDisable));
+                       PP_ASSERT_WITH_CODE((smc_result == 0),
+                                       "Failed to disable TDCLimit in SMC.",
+                                       result = smc_result);
+               }
+
+               if (data->power_containment_features &
+                               POWERCONTAINMENT_FEATURE_DTE) {
+                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+                                       (uint16_t)(PPSMC_MSG_DisableDTE));
+                       PP_ASSERT_WITH_CODE((smc_result == 0),
+                                       "Failed to disable DTE in SMC.",
+                                       result = smc_result);
+               }
+
+               if (data->power_containment_features &
+                               POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
+                       smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+                                       (uint16_t)(PPSMC_MSG_PkgPwrLimitDisable));
+                       PP_ASSERT_WITH_CODE((smc_result == 0),
+                                       "Failed to disable PkgPwrTracking in SMC.",
+                                       result = smc_result);
+               }
+               data->power_containment_features = 0;
+       }
+
+       return result;
+}
+
+int smu7_power_control_set_level(struct pp_hwmgr *hwmgr)
+{
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_cac_tdp_table *cac_table;
+
+       int adjust_percent, target_tdp;
+       int result = 0;
+
+       if (hwmgr->pp_table_version == PP_TABLE_V1)
+               cac_table = table_info->cac_dtp_table;
+       else
+               cac_table = hwmgr->dyn_state.cac_dtp_table;
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PowerContainment)) {
+               /* adjustment percentage has already been validated */
+               adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
+                               hwmgr->platform_descriptor.TDPAdjustment :
+                               (-1 * hwmgr->platform_descriptor.TDPAdjustment);
+               /* SMC requested that target_tdp to be 7 bit fraction in DPM table
+                * but message to be 8 bit fraction for messages
+                */
+               target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
+               result = smu7_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
+       }
+
+       return result;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.h
new file mode 100644 (file)
index 0000000..22f86b6
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 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 _SMU7_POWERTUNE_H
+#define _SMU7_POWERTUNE_H
+
+#define DIDT_SQ_CTRL0__UNUSED_0_MASK    0xfffc0000
+#define DIDT_SQ_CTRL0__UNUSED_0__SHIFT  0x12
+#define DIDT_TD_CTRL0__UNUSED_0_MASK    0xfffc0000
+#define DIDT_TD_CTRL0__UNUSED_0__SHIFT  0x12
+#define DIDT_TCP_CTRL0__UNUSED_0_MASK   0xfffc0000
+#define DIDT_TCP_CTRL0__UNUSED_0__SHIFT 0x12
+#define DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK                 0xc0000000
+#define DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT               0x0000001e
+#define DIDT_TD_TUNING_CTRL__UNUSED_0_MASK                 0xc0000000
+#define DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT               0x0000001e
+#define DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK                0xc0000000
+#define DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT              0x0000001e
+
+/* PowerContainment Features */
+#define POWERCONTAINMENT_FEATURE_DTE             0x00000001
+#define POWERCONTAINMENT_FEATURE_TDCLimit        0x00000002
+#define POWERCONTAINMENT_FEATURE_PkgPwrLimit     0x00000004
+
+#define ixGC_CAC_CNTL 0x0000
+#define ixDIDT_SQ_STALL_CTRL 0x0004
+#define ixDIDT_SQ_TUNING_CTRL 0x0005
+#define ixDIDT_TD_STALL_CTRL 0x0044
+#define ixDIDT_TD_TUNING_CTRL 0x0045
+#define ixDIDT_TCP_STALL_CTRL 0x0064
+#define ixDIDT_TCP_TUNING_CTRL 0x0065
+
+
+int smu7_enable_smc_cac(struct pp_hwmgr *hwmgr);
+int smu7_disable_smc_cac(struct pp_hwmgr *hwmgr);
+int smu7_enable_power_containment(struct pp_hwmgr *hwmgr);
+int smu7_disable_power_containment(struct pp_hwmgr *hwmgr);
+int smu7_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
+int smu7_power_control_set_level(struct pp_hwmgr *hwmgr);
+int smu7_enable_didt_config(struct pp_hwmgr *hwmgr);
+int smu7_disable_didt_config(struct pp_hwmgr *hwmgr);
+#endif  /* DGPU_POWERTUNE_H */
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c
new file mode 100644 (file)
index 0000000..fb6c6f6
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+ * 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 <asm/div64.h>
+#include "smu7_thermal.h"
+#include "smu7_hwmgr.h"
+#include "smu7_common.h"
+
+int smu7_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
+               struct phm_fan_speed_info *fan_speed_info)
+{
+       if (hwmgr->thermal_controller.fanInfo.bNoFan)
+               return 0;
+
+       fan_speed_info->supports_percent_read = true;
+       fan_speed_info->supports_percent_write = true;
+       fan_speed_info->min_percent = 0;
+       fan_speed_info->max_percent = 100;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
+               hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
+               fan_speed_info->supports_rpm_read = true;
+               fan_speed_info->supports_rpm_write = true;
+               fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
+               fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
+       } else {
+               fan_speed_info->min_rpm = 0;
+               fan_speed_info->max_rpm = 0;
+       }
+
+       return 0;
+}
+
+int smu7_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
+               uint32_t *speed)
+{
+       uint32_t duty100;
+       uint32_t duty;
+       uint64_t tmp64;
+
+       if (hwmgr->thermal_controller.fanInfo.bNoFan)
+               return 0;
+
+       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_FDO_CTRL1, FMAX_DUTY100);
+       duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_THERMAL_STATUS, FDO_PWM_DUTY);
+
+       if (duty100 == 0)
+               return -EINVAL;
+
+
+       tmp64 = (uint64_t)duty * 100;
+       do_div(tmp64, duty100);
+       *speed = (uint32_t)tmp64;
+
+       if (*speed > 100)
+               *speed = 100;
+
+       return 0;
+}
+
+int smu7_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
+{
+       uint32_t tach_period;
+       uint32_t crystal_clock_freq;
+
+       if (hwmgr->thermal_controller.fanInfo.bNoFan ||
+                       (hwmgr->thermal_controller.fanInfo.
+                               ucTachometerPulsesPerRevolution == 0))
+               return 0;
+
+       tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_TACH_STATUS, TACH_PERIOD);
+
+       if (tach_period == 0)
+               return -EINVAL;
+
+       crystal_clock_freq = smu7_get_xclk(hwmgr);
+
+       *speed = 60 * crystal_clock_freq * 10000 / tach_period;
+
+       return 0;
+}
+
+/**
+* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
+* @param    hwmgr  the address of the powerplay hardware manager.
+*           mode    the fan control mode, 0 default, 1 by percent, 5, by RPM
+* @exception Should always succeed.
+*/
+int smu7_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+
+       if (hwmgr->fan_ctrl_is_in_default_mode) {
+               hwmgr->fan_ctrl_default_mode =
+                               PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,     CGS_IND_REG__SMC,
+                                               CG_FDO_CTRL2, FDO_PWM_MODE);
+               hwmgr->tmin =
+                               PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                                               CG_FDO_CTRL2, TMIN);
+               hwmgr->fan_ctrl_is_in_default_mode = false;
+       }
+
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_FDO_CTRL2, TMIN, 0);
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_FDO_CTRL2, FDO_PWM_MODE, mode);
+
+       return 0;
+}
+
+/**
+* Reset Fan Speed Control to default mode.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @exception Should always succeed.
+*/
+int smu7_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
+{
+       if (!hwmgr->fan_ctrl_is_in_default_mode) {
+               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                               CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
+               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                               CG_FDO_CTRL2, TMIN, hwmgr->tmin);
+               hwmgr->fan_ctrl_is_in_default_mode = true;
+       }
+
+       return 0;
+}
+
+static int smu7_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+       int result;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
+               cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
+               result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
+
+               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_FanSpeedInTableIsRPM))
+                       hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
+                                       hwmgr->thermal_controller.
+                                       advanceFanControlParameters.usMaxFanRPM);
+               else
+                       hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
+                                       hwmgr->thermal_controller.
+                                       advanceFanControlParameters.usMaxFanPWM);
+
+       } else {
+               cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
+               result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
+       }
+
+       if (!result && hwmgr->thermal_controller.
+                       advanceFanControlParameters.ucTargetTemperature)
+               result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_SetFanTemperatureTarget,
+                               hwmgr->thermal_controller.
+                               advanceFanControlParameters.ucTargetTemperature);
+
+       return result;
+}
+
+
+int smu7_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
+}
+
+/**
+* Set Fan Speed in percent.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    speed is the percentage value (0% - 100%) to be set.
+* @exception Fails is the 100% setting appears to be 0.
+*/
+int smu7_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
+               uint32_t speed)
+{
+       uint32_t duty100;
+       uint32_t duty;
+       uint64_t tmp64;
+
+       if (hwmgr->thermal_controller.fanInfo.bNoFan)
+               return 0;
+
+       if (speed > 100)
+               speed = 100;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_MicrocodeFanControl))
+               smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
+
+       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_FDO_CTRL1, FMAX_DUTY100);
+
+       if (duty100 == 0)
+               return -EINVAL;
+
+       tmp64 = (uint64_t)speed * duty100;
+       do_div(tmp64, 100);
+       duty = (uint32_t)tmp64;
+
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
+
+       return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+}
+
+/**
+* Reset Fan Speed to default.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @exception Always succeeds.
+*/
+int smu7_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
+{
+       int result;
+
+       if (hwmgr->thermal_controller.fanInfo.bNoFan)
+               return 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_MicrocodeFanControl)) {
+               result = smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+               if (!result)
+                       result = smu7_fan_ctrl_start_smc_fan_control(hwmgr);
+       } else
+               result = smu7_fan_ctrl_set_default_mode(hwmgr);
+
+       return result;
+}
+
+/**
+* Set Fan Speed in RPM.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    speed is the percentage value (min - max) to be set.
+* @exception Fails is the speed not lie between min and max.
+*/
+int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
+{
+       uint32_t tach_period;
+       uint32_t crystal_clock_freq;
+
+       if (hwmgr->thermal_controller.fanInfo.bNoFan ||
+                       (hwmgr->thermal_controller.fanInfo.
+                       ucTachometerPulsesPerRevolution == 0) ||
+                       (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
+                       (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
+               return 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_MicrocodeFanControl))
+               smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
+
+       crystal_clock_freq = smu7_get_xclk(hwmgr);
+
+       tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
+
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                               CG_TACH_STATUS, TACH_PERIOD, tach_period);
+
+       return smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+}
+
+/**
+* Reads the remote temperature from the SIslands thermal controller.
+*
+* @param    hwmgr The address of the hardware manager.
+*/
+int smu7_thermal_get_temperature(struct pp_hwmgr *hwmgr)
+{
+       int temp;
+
+       temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_MULT_THERMAL_STATUS, CTF_TEMP);
+
+       /* Bit 9 means the reading is lower than the lowest usable value. */
+       if (temp & 0x200)
+               temp = SMU7_THERMAL_MAXIMUM_TEMP_READING;
+       else
+               temp = temp & 0x1ff;
+
+       temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+       return temp;
+}
+
+/**
+* Set the requested temperature range for high and low alert signals
+*
+* @param    hwmgr The address of the hardware manager.
+* @param    range Temperature range to be programmed for high and low alert signals
+* @exception PP_Result_BadInput if the input data is not valid.
+*/
+static int smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
+               uint32_t low_temp, uint32_t high_temp)
+{
+       uint32_t low = SMU7_THERMAL_MINIMUM_ALERT_TEMP *
+                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       uint32_t high = SMU7_THERMAL_MAXIMUM_ALERT_TEMP *
+                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+       if (low < low_temp)
+               low = low_temp;
+       if (high > high_temp)
+               high = high_temp;
+
+       if (low > high)
+               return -EINVAL;
+
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_THERMAL_INT, DIG_THERM_INTH,
+                       (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_THERMAL_INT, DIG_THERM_INTL,
+                       (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_THERMAL_CTRL, DIG_THERM_DPM,
+                       (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+
+       return 0;
+}
+
+/**
+* Programs thermal controller one-time setting registers
+*
+* @param    hwmgr The address of the hardware manager.
+*/
+static int smu7_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+       if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
+               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                               CG_TACH_CTRL, EDGE_PER_REV,
+                               hwmgr->thermal_controller.fanInfo.
+                               ucTachometerPulsesPerRevolution - 1);
+
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
+
+       return 0;
+}
+
+/**
+* Enable thermal alerts on the RV770 thermal controller.
+*
+* @param    hwmgr The address of the hardware manager.
+*/
+int smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr)
+{
+       uint32_t alert;
+
+       alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_THERMAL_INT, THERM_INT_MASK);
+       alert &= ~(SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK);
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+       /* send message to SMU to enable internal thermal interrupts */
+       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable);
+}
+
+/**
+* Disable thermal alerts on the RV770 thermal controller.
+* @param    hwmgr The address of the hardware manager.
+*/
+int smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr)
+{
+       uint32_t alert;
+
+       alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_THERMAL_INT, THERM_INT_MASK);
+       alert |= (SMU7_THERMAL_HIGH_ALERT_MASK | SMU7_THERMAL_LOW_ALERT_MASK);
+       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+       /* send message to SMU to disable internal thermal interrupts */
+       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable);
+}
+
+/**
+* Uninitialize the thermal controller.
+* Currently just disables alerts.
+* @param    hwmgr The address of the hardware manager.
+*/
+int smu7_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+       int result = smu7_thermal_disable_alert(hwmgr);
+
+       if (!hwmgr->thermal_controller.fanInfo.bNoFan)
+               smu7_fan_ctrl_set_default_mode(hwmgr);
+
+       return result;
+}
+
+/**
+* Start the fan control on the SMC.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+static int tf_smu7_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
+               void *input, void *output, void *storage, int result)
+{
+/* If the fantable setup has failed we could have disabled
+ * PHM_PlatformCaps_MicrocodeFanControl even after
+ * this function was included in the table.
+ * Make sure that we still think controlling the fan is OK.
+*/
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_MicrocodeFanControl)) {
+               smu7_fan_ctrl_start_smc_fan_control(hwmgr);
+               smu7_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+       }
+
+       return 0;
+}
+
+/**
+* Set temperature range for high and low alerts
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+static int tf_smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
+               void *input, void *output, void *storage, int result)
+{
+       struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
+
+       if (range == NULL)
+               return -EINVAL;
+
+       return smu7_thermal_set_temperature_range(hwmgr, range->min, range->max);
+}
+
+/**
+* Programs one-time setting registers
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from initialize thermal controller routine
+*/
+static int tf_smu7_thermal_initialize(struct pp_hwmgr *hwmgr,
+               void *input, void *output, void *storage, int result)
+{
+       return smu7_thermal_initialize(hwmgr);
+}
+
+/**
+* Enable high and low alerts
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from enable alert routine
+*/
+static int tf_smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr,
+               void *input, void *output, void *storage, int result)
+{
+       return smu7_thermal_enable_alert(hwmgr);
+}
+
+/**
+* Disable high and low alerts
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from disable alert routine
+*/
+static int tf_smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr,
+               void *input, void *output, void *storage, int result)
+{
+       return smu7_thermal_disable_alert(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},
+/* 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}
+};
+
+static const struct phm_master_table_header
+phm_thermal_start_thermal_controller_master = {
+       0,
+       PHM_MasterTableFlag_None,
+       phm_thermal_start_thermal_controller_master_list
+};
+
+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}
+};
+
+static const struct phm_master_table_header
+phm_thermal_set_temperature_range_master = {
+       0,
+       PHM_MasterTableFlag_None,
+       phm_thermal_set_temperature_range_master_list
+};
+
+int smu7_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+       if (!hwmgr->thermal_controller.fanInfo.bNoFan)
+               smu7_fan_ctrl_set_default_mode(hwmgr);
+       return 0;
+}
+
+/**
+* Initializes the thermal controller related functions in the Hardware Manager structure.
+* @param    hwmgr The address of the hardware manager.
+* @exception Any error code from the low-level communication.
+*/
+int pp_smu7_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+       int result;
+
+       result = phm_construct_table(hwmgr,
+                       &phm_thermal_set_temperature_range_master,
+                       &(hwmgr->set_temperature_range));
+
+       if (!result) {
+               result = phm_construct_table(hwmgr,
+                               &phm_thermal_start_thermal_controller_master,
+                               &(hwmgr->start_thermal_controller));
+               if (result)
+                       phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
+       }
+
+       if (!result)
+               hwmgr->fan_ctrl_is_in_default_mode = true;
+       return result;
+}
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h
new file mode 100644 (file)
index 0000000..6face97
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _SMU7_THERMAL_H_
+#define _SMU7_THERMAL_H_
+
+#include "hwmgr.h"
+
+#define SMU7_THERMAL_HIGH_ALERT_MASK         0x1
+#define SMU7_THERMAL_LOW_ALERT_MASK          0x2
+
+#define SMU7_THERMAL_MINIMUM_TEMP_READING    -256
+#define SMU7_THERMAL_MAXIMUM_TEMP_READING    255
+
+#define SMU7_THERMAL_MINIMUM_ALERT_TEMP      0
+#define SMU7_THERMAL_MAXIMUM_ALERT_TEMP      255
+
+#define FDO_PWM_MODE_STATIC  1
+#define FDO_PWM_MODE_STATIC_RPM 5
+
+extern int smu7_thermal_get_temperature(struct pp_hwmgr *hwmgr);
+extern int smu7_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
+extern int smu7_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
+extern int smu7_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
+extern int smu7_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
+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 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);
+extern int smu7_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
+extern int smu7_thermal_enable_alert(struct pp_hwmgr *hwmgr);
+extern int smu7_thermal_disable_alert(struct pp_hwmgr *hwmgr);
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.c
deleted file mode 100644 (file)
index e58d038..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright 2015 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 "hwmgr.h"
-#include "tonga_clockpowergating.h"
-#include "tonga_ppsmc.h"
-#include "tonga_hwmgr.h"
-
-int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cf_want_uvd_power_gating(hwmgr))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                                                    PPSMC_MSG_UVDPowerOFF);
-       return 0;
-}
-
-int tonga_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cf_want_uvd_power_gating(hwmgr)) {
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                 PHM_PlatformCaps_UVDDynamicPowerGating)) {
-                       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                                               PPSMC_MSG_UVDPowerON, 1);
-               } else {
-                       return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                                               PPSMC_MSG_UVDPowerON, 0);
-               }
-       }
-
-       return 0;
-}
-
-int tonga_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cf_want_vce_power_gating(hwmgr))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                                                 PPSMC_MSG_VCEPowerOFF);
-       return 0;
-}
-
-int tonga_phm_powerup_vce(struct pp_hwmgr *hwmgr)
-{
-       if (phm_cf_want_vce_power_gating(hwmgr))
-               return smum_send_msg_to_smc(hwmgr->smumgr,
-                                                 PPSMC_MSG_VCEPowerON);
-       return 0;
-}
-
-int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating)
-{
-       int ret = 0;
-
-       switch (block) {
-       case PHM_AsicBlock_UVD_MVC:
-       case PHM_AsicBlock_UVD:
-       case PHM_AsicBlock_UVD_HD:
-       case PHM_AsicBlock_UVD_SD:
-               if (gating == PHM_ClockGateSetting_StaticOff)
-                       ret = tonga_phm_powerdown_uvd(hwmgr);
-               else
-                       ret = tonga_phm_powerup_uvd(hwmgr);
-               break;
-       case PHM_AsicBlock_GFX:
-       default:
-               break;
-       }
-
-       return ret;
-}
-
-int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       data->uvd_power_gated = false;
-       data->vce_power_gated = false;
-
-       tonga_phm_powerup_uvd(hwmgr);
-       tonga_phm_powerup_vce(hwmgr);
-
-       return 0;
-}
-
-int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       if (data->uvd_power_gated == bgate)
-               return 0;
-
-       data->uvd_power_gated = bgate;
-
-       if (bgate) {
-               cgs_set_clockgating_state(hwmgr->device,
-                                               AMD_IP_BLOCK_TYPE_UVD,
-                                               AMD_CG_STATE_UNGATE);
-               cgs_set_powergating_state(hwmgr->device,
-                                               AMD_IP_BLOCK_TYPE_UVD,
-                                               AMD_PG_STATE_GATE);
-               tonga_update_uvd_dpm(hwmgr, true);
-               tonga_phm_powerdown_uvd(hwmgr);
-       } else {
-               tonga_phm_powerup_uvd(hwmgr);
-               cgs_set_powergating_state(hwmgr->device,
-                                               AMD_IP_BLOCK_TYPE_UVD,
-                                               AMD_PG_STATE_UNGATE);
-               cgs_set_clockgating_state(hwmgr->device,
-                                               AMD_IP_BLOCK_TYPE_UVD,
-                                               AMD_PG_STATE_GATE);
-
-               tonga_update_uvd_dpm(hwmgr, false);
-       }
-
-       return 0;
-}
-
-int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct phm_set_power_state_input states;
-       const struct pp_power_state  *pcurrent;
-       struct pp_power_state  *requested;
-
-       pcurrent = hwmgr->current_ps;
-       requested = hwmgr->request_ps;
-
-       states.pcurrent_state = &(pcurrent->hardware);
-       states.pnew_state = &(requested->hardware);
-
-       if (phm_cf_want_vce_power_gating(hwmgr)) {
-               if (data->vce_power_gated != bgate) {
-                       if (bgate) {
-                               cgs_set_clockgating_state(
-                                                       hwmgr->device,
-                                                       AMD_IP_BLOCK_TYPE_VCE,
-                                                       AMD_CG_STATE_UNGATE);
-                               cgs_set_powergating_state(
-                                                       hwmgr->device,
-                                                       AMD_IP_BLOCK_TYPE_VCE,
-                                                       AMD_PG_STATE_GATE);
-                               tonga_enable_disable_vce_dpm(hwmgr, false);
-                               data->vce_power_gated = true;
-                       } else {
-                               tonga_phm_powerup_vce(hwmgr);
-                               data->vce_power_gated = false;
-                               cgs_set_powergating_state(
-                                                       hwmgr->device,
-                                                       AMD_IP_BLOCK_TYPE_VCE,
-                                                       AMD_PG_STATE_UNGATE);
-                               cgs_set_clockgating_state(
-                                                       hwmgr->device,
-                                                       AMD_IP_BLOCK_TYPE_VCE,
-                                                       AMD_PG_STATE_GATE);
-
-                               tonga_update_vce_dpm(hwmgr, &states);
-                               tonga_enable_disable_vce_dpm(hwmgr, true);
-                               return 0;
-                       }
-               }
-       } else {
-               tonga_update_vce_dpm(hwmgr, &states);
-               tonga_enable_disable_vce_dpm(hwmgr, true);
-               return 0;
-       }
-
-       if (!data->vce_power_gated)
-               tonga_update_vce_dpm(hwmgr, &states);
-
-       return 0;
-}
-
-int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
-                                       const uint32_t *msg_id)
-{
-       PPSMC_Msg msg;
-       uint32_t value;
-
-       switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
-       case PP_GROUP_GFX:
-               switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
-               case PP_BLOCK_GFX_CG:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
-                                 ? PPSMC_MSG_EnableClockGatingFeature
-                                 : PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_GFX_CGCG_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
-                                       ? PPSMC_MSG_EnableClockGatingFeature
-                                       : PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_GFX_CGLS_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_GFX_MG:
-                       /* For GFX MGCG, there are three different ones;
-                        * CPF, RLC, and all others.  CPF MGCG will not be used for Tonga.
-                        * For GFX MGLS, Tonga will not support it.
-                        * */
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
-                               ? PPSMC_MSG_EnableClockGatingFeature
-                               : PPSMC_MSG_DisableClockGatingFeature;
-                               value = (CG_RLC_MGCG_MASK | CG_GFX_OTHERS_MGCG_MASK);
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               default:
-                       return -1;
-               }
-               break;
-
-       case PP_GROUP_SYS:
-               switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
-               case PP_BLOCK_SYS_BIF:
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
-                               ? PPSMC_MSG_EnableClockGatingFeature
-                               : PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_BIF_MGLS_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_SYS_MC:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
-                               ? PPSMC_MSG_EnableClockGatingFeature
-                               : PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_MC_MGCG_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
-                               ? PPSMC_MSG_EnableClockGatingFeature
-                               : PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_MC_MGLS_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-
-                       }
-                       break;
-
-               case PP_BLOCK_SYS_HDP:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
-                                       ? PPSMC_MSG_EnableClockGatingFeature
-                                       : PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_HDP_MGCG_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
-                                       ? PPSMC_MSG_EnableClockGatingFeature
-                                       : PPSMC_MSG_DisableClockGatingFeature;
-
-                               value = CG_SYS_HDP_MGLS_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_SYS_SDMA:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
-                               ? PPSMC_MSG_EnableClockGatingFeature
-                               : PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_SDMA_MGCG_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-
-                       if (PP_STATE_SUPPORT_LS & *msg_id) {
-                               msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
-                               ? PPSMC_MSG_EnableClockGatingFeature
-                               : PPSMC_MSG_DisableClockGatingFeature;
-
-                               value = CG_SYS_SDMA_MGLS_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               case PP_BLOCK_SYS_ROM:
-                       if (PP_STATE_SUPPORT_CG & *msg_id) {
-                               msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
-                               ? PPSMC_MSG_EnableClockGatingFeature
-                               : PPSMC_MSG_DisableClockGatingFeature;
-                               value = CG_SYS_ROM_MASK;
-
-                               if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
-                                       return -1;
-                       }
-                       break;
-
-               default:
-                       return -1;
-
-               }
-               break;
-
-       default:
-               return -1;
-
-       }
-
-       return 0;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.h
deleted file mode 100644 (file)
index 8bc38cb..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2015 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 _TONGA_CLOCK_POWER_GATING_H_
-#define _TONGA_CLOCK_POWER_GATING_H_
-
-#include "tonga_hwmgr.h"
-#include "pp_asicblocks.h"
-
-extern int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
-extern int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
-extern int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
-extern int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
-extern int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
-extern int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id);
-#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_dyn_defaults.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_dyn_defaults.h
deleted file mode 100644 (file)
index 080d69d..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2015 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 TONGA_DYN_DEFAULTS_H
-#define TONGA_DYN_DEFAULTS_H
-
-
-/** \file
- * Volcanic Islands Dynamic default parameters.
- */
-
-enum TONGAdpm_TrendDetection {
-       TONGAdpm_TrendDetection_AUTO,
-       TONGAdpm_TrendDetection_UP,
-       TONGAdpm_TrendDetection_DOWN
-};
-typedef enum TONGAdpm_TrendDetection TONGAdpm_TrendDetection;
-
-/* Bit vector representing same fields as hardware register. */
-#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0              0x3FFFC102  /* CP_Gfx_busy */
-/* HDP_busy */
-/* IH_busy */
-/* DRM_busy */
-/* DRMDMA_busy */
-/* UVD_busy */
-/* VCE_busy */
-/* ACP_busy */
-/* SAMU_busy */
-/* AVP_busy  */
-/* SDMA enabled */
-#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1              0x000400  /* FE_Gfx_busy  - Intended for primary usage.   Rest are for flexibility. */
-/* SH_Gfx_busy */
-/* RB_Gfx_busy */
-/* VCE_busy */
-
-#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2              0xC00080  /* SH_Gfx_busy - Intended for primary usage.   Rest are for flexibility. */
-/* FE_Gfx_busy */
-/* RB_Gfx_busy */
-/* ACP_busy */
-
-#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3              0xC00200  /* RB_Gfx_busy - Intended for primary usage.   Rest are for flexibility. */
-/* FE_Gfx_busy */
-/* SH_Gfx_busy */
-/* UVD_busy */
-
-#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4              0xC01680  /* UVD_busy */
-/* VCE_busy */
-/* ACP_busy */
-/* SAMU_busy */
-
-#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5              0xC00033  /* GFX, HDP, DRMDMA */
-#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6              0xC00033  /* GFX, HDP, DRMDMA */
-#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7              0x3FFFC000  /* GFX, HDP, DRMDMA */
-
-
-/* thermal protection counter (units).*/
-#define PPTONGA_THERMALPROTECTCOUNTER_DFLT            0x200 /* ~19us */
-
-/* static screen threshold unit */
-#define PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT        0
-
-/* static screen threshold */
-#define PPTONGA_STATICSCREENTHRESHOLD_DFLT            0x00C8
-
-/* gfx idle clock stop threshold */
-#define PPTONGA_GFXIDLECLOCKSTOPTHRESHOLD_DFLT        0x200 /* ~19us with static screen threshold unit of 0 */
-
-/* Fixed reference divider to use when building baby stepping tables. */
-#define PPTONGA_REFERENCEDIVIDER_DFLT                  4
-
-/*
- * ULV voltage change delay time
- * Used to be delay_vreg in N.I. split for S.I.
- * Using N.I. delay_vreg value as default
- * ReferenceClock = 2700
- * VoltageResponseTime = 1000
- * VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
- */
-
-#define PPTONGA_ULVVOLTAGECHANGEDELAY_DFLT             1687
-
-#define PPTONGA_CGULVPARAMETER_DFLT                    0x00040035
-#define PPTONGA_CGULVCONTROL_DFLT                      0x00007450
-#define PPTONGA_TARGETACTIVITY_DFLT                     30  /*30%  */
-#define PPTONGA_MCLK_TARGETACTIVITY_DFLT                10  /*10%  */
-
-#endif
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c
deleted file mode 100644 (file)
index c7dc111..0000000
+++ /dev/null
@@ -1,6276 +0,0 @@
-/*
- * Copyright 2015 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/module.h>
-#include <linux/slab.h>
-#include <linux/fb.h>
-#include "linux/delay.h"
-#include "pp_acpi.h"
-#include "hwmgr.h"
-#include <atombios.h>
-#include "tonga_hwmgr.h"
-#include "pptable.h"
-#include "processpptables.h"
-#include "tonga_processpptables.h"
-#include "tonga_pptable.h"
-#include "pp_debug.h"
-#include "tonga_ppsmc.h"
-#include "cgs_common.h"
-#include "pppcielanes.h"
-#include "tonga_dyn_defaults.h"
-#include "smumgr.h"
-#include "tonga_smumgr.h"
-#include "tonga_clockpowergating.h"
-#include "tonga_thermal.h"
-
-#include "smu/smu_7_1_2_d.h"
-#include "smu/smu_7_1_2_sh_mask.h"
-
-#include "gmc/gmc_8_1_d.h"
-#include "gmc/gmc_8_1_sh_mask.h"
-
-#include "bif/bif_5_0_d.h"
-#include "bif/bif_5_0_sh_mask.h"
-
-#include "dce/dce_10_0_d.h"
-#include "dce/dce_10_0_sh_mask.h"
-
-#include "cgs_linux.h"
-#include "eventmgr.h"
-#include "amd_pcie_helpers.h"
-
-#define MC_CG_ARB_FREQ_F0           0x0a
-#define MC_CG_ARB_FREQ_F1           0x0b
-#define MC_CG_ARB_FREQ_F2           0x0c
-#define MC_CG_ARB_FREQ_F3           0x0d
-
-#define MC_CG_SEQ_DRAMCONF_S0       0x05
-#define MC_CG_SEQ_DRAMCONF_S1       0x06
-#define MC_CG_SEQ_YCLK_SUSPEND      0x04
-#define MC_CG_SEQ_YCLK_RESUME       0x0a
-
-#define PCIE_BUS_CLK                10000
-#define TCLK                        (PCIE_BUS_CLK / 10)
-
-#define SMC_RAM_END 0x40000
-#define SMC_CG_IND_START            0xc0030000
-#define SMC_CG_IND_END              0xc0040000  /* First byte after SMC_CG_IND*/
-
-#define VOLTAGE_SCALE               4
-#define VOLTAGE_VID_OFFSET_SCALE1   625
-#define VOLTAGE_VID_OFFSET_SCALE2   100
-
-#define VDDC_VDDCI_DELTA            200
-#define VDDC_VDDGFX_DELTA           300
-
-#define MC_SEQ_MISC0_GDDR5_SHIFT 28
-#define MC_SEQ_MISC0_GDDR5_MASK  0xf0000000
-#define MC_SEQ_MISC0_GDDR5_VALUE 5
-
-typedef uint32_t PECI_RegistryValue;
-
-/* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
-static const uint16_t PP_ClockStretcherLookupTable[2][4] = {
-       {600, 1050, 3, 0},
-       {600, 1050, 6, 1} };
-
-/* [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */
-static const uint32_t PP_ClockStretcherDDTTable[2][4][4] = {
-       { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
-       { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
-
-/* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */
-static const uint8_t PP_ClockStretchAmountConversion[2][6] = {
-       {0, 1, 3, 2, 4, 5},
-       {0, 2, 4, 5, 6, 5} };
-
-/* Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
-enum DPM_EVENT_SRC {
-       DPM_EVENT_SRC_ANALOG = 0,               /* Internal analog trip point */
-       DPM_EVENT_SRC_EXTERNAL = 1,             /* External (GPIO 17) signal */
-       DPM_EVENT_SRC_DIGITAL = 2,              /* Internal digital trip point (DIG_THERM_DPM) */
-       DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,   /* Internal analog or external */
-       DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4   /* Internal digital or external */
-};
-typedef enum DPM_EVENT_SRC DPM_EVENT_SRC;
-
-static const unsigned long PhwTonga_Magic = (unsigned long)(PHM_VIslands_Magic);
-
-struct tonga_power_state *cast_phw_tonga_power_state(
-                                 struct pp_hw_power_state *hw_ps)
-{
-       if (hw_ps == NULL)
-               return NULL;
-
-       PP_ASSERT_WITH_CODE((PhwTonga_Magic == hw_ps->magic),
-                               "Invalid Powerstate Type!",
-                                return NULL);
-
-       return (struct tonga_power_state *)hw_ps;
-}
-
-const struct tonga_power_state *cast_const_phw_tonga_power_state(
-                                const struct pp_hw_power_state *hw_ps)
-{
-       if (hw_ps == NULL)
-               return NULL;
-
-       PP_ASSERT_WITH_CODE((PhwTonga_Magic == hw_ps->magic),
-                               "Invalid Powerstate Type!",
-                                return NULL);
-
-       return (const struct tonga_power_state *)hw_ps;
-}
-
-int tonga_add_voltage(struct pp_hwmgr *hwmgr,
-       phm_ppt_v1_voltage_lookup_table *look_up_table,
-       phm_ppt_v1_voltage_lookup_record *record)
-{
-       uint32_t i;
-       PP_ASSERT_WITH_CODE((NULL != look_up_table),
-               "Lookup Table empty.", return -1;);
-       PP_ASSERT_WITH_CODE((0 != look_up_table->count),
-               "Lookup Table empty.", return -1;);
-       PP_ASSERT_WITH_CODE((SMU72_MAX_LEVELS_VDDGFX >= look_up_table->count),
-               "Lookup Table is full.", return -1;);
-
-       /* This is to avoid entering duplicate calculated records. */
-       for (i = 0; i < look_up_table->count; i++) {
-               if (look_up_table->entries[i].us_vdd == record->us_vdd) {
-                       if (look_up_table->entries[i].us_calculated == 1)
-                               return 0;
-                       else
-                               break;
-               }
-       }
-
-       look_up_table->entries[i].us_calculated = 1;
-       look_up_table->entries[i].us_vdd = record->us_vdd;
-       look_up_table->entries[i].us_cac_low = record->us_cac_low;
-       look_up_table->entries[i].us_cac_mid = record->us_cac_mid;
-       look_up_table->entries[i].us_cac_high = record->us_cac_high;
-       /* Only increment the count when we're appending, not replacing duplicate entry. */
-       if (i == look_up_table->count)
-               look_up_table->count++;
-
-       return 0;
-}
-
-int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display)
-{
-       PPSMC_Msg msg = has_display? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
-
-       return (smum_send_msg_to_smc(hwmgr->smumgr, msg) == 0) ?  0 : -1;
-}
-
-uint8_t tonga_get_voltage_id(pp_atomctrl_voltage_table *voltage_table,
-               uint32_t voltage)
-{
-       uint8_t count = (uint8_t) (voltage_table->count);
-       uint8_t i = 0;
-
-       PP_ASSERT_WITH_CODE((NULL != voltage_table),
-               "Voltage Table empty.", return 0;);
-       PP_ASSERT_WITH_CODE((0 != count),
-               "Voltage Table empty.", return 0;);
-
-       for (i = 0; i < count; i++) {
-               /* find first voltage bigger than requested */
-               if (voltage_table->entries[i].value >= voltage)
-                       return i;
-       }
-
-       /* voltage is bigger than max voltage in the table */
-       return i - 1;
-}
-
-/**
- * @brief PhwTonga_GetVoltageOrder
- *  Returns index of requested voltage record in lookup(table)
- * @param hwmgr - pointer to hardware manager
- * @param lookupTable - lookup list to search in
- * @param voltage - voltage to look for
- * @return 0 on success
- */
-uint8_t tonga_get_voltage_index(phm_ppt_v1_voltage_lookup_table *look_up_table,
-               uint16_t voltage)
-{
-       uint8_t count = (uint8_t) (look_up_table->count);
-       uint8_t i;
-
-       PP_ASSERT_WITH_CODE((NULL != look_up_table), "Lookup Table empty.", return 0;);
-       PP_ASSERT_WITH_CODE((0 != count), "Lookup Table empty.", return 0;);
-
-       for (i = 0; i < count; i++) {
-               /* find first voltage equal or bigger than requested */
-               if (look_up_table->entries[i].us_vdd >= voltage)
-                       return i;
-       }
-
-       /* voltage is bigger than max voltage in the table */
-       return i-1;
-}
-
-bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr)
-{
-       /*
-        * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
-        * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
-        * whereas voltage control is a fundemental change that will not be disabled
-        */
-
-       return (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                                       FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) ? 1 : 0);
-}
-
-/**
- * Re-generate the DPM level mask value
- * @param    hwmgr      the address of the hardware manager
- */
-static uint32_t tonga_get_dpm_level_enable_mask_value(
-                       struct tonga_single_dpm_table * dpm_table)
-{
-       uint32_t i;
-       uint32_t mask_value = 0;
-
-       for (i = dpm_table->count; i > 0; i--) {
-               mask_value = mask_value << 1;
-
-               if (dpm_table->dpm_levels[i-1].enabled)
-                       mask_value |= 0x1;
-               else
-                       mask_value &= 0xFFFFFFFE;
-       }
-       return mask_value;
-}
-
-/**
- * Retrieve DPM default values from registry (if available)
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- */
-void tonga_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       phw_tonga_ulv_parm *ulv = &(data->ulv);
-       uint32_t tmp;
-
-       ulv->ch_ulv_parameter = PPTONGA_CGULVPARAMETER_DFLT;
-       data->voting_rights_clients0 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0;
-       data->voting_rights_clients1 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1;
-       data->voting_rights_clients2 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2;
-       data->voting_rights_clients3 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3;
-       data->voting_rights_clients4 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4;
-       data->voting_rights_clients5 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5;
-       data->voting_rights_clients6 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6;
-       data->voting_rights_clients7 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7;
-
-       data->static_screen_threshold_unit = PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT;
-       data->static_screen_threshold = PPTONGA_STATICSCREENTHRESHOLD_DFLT;
-
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_ABM);
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_NonABMSupportInPPLib);
-
-       tmp = 0;
-       if (tmp == 0)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_DynamicACTiming);
-
-       tmp = 0;
-       if (0 != tmp)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_DisableMemoryTransition);
-
-       data->mclk_strobe_mode_threshold = 40000;
-       data->mclk_stutter_mode_threshold = 30000;
-       data->mclk_edc_enable_threshold = 40000;
-       data->mclk_edc_wr_enable_threshold = 40000;
-
-       tmp = 0;
-       if (tmp != 0)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_DisableMCLS);
-
-       data->pcie_gen_performance.max = PP_PCIEGen1;
-       data->pcie_gen_performance.min = PP_PCIEGen3;
-       data->pcie_gen_power_saving.max = PP_PCIEGen1;
-       data->pcie_gen_power_saving.min = PP_PCIEGen3;
-
-       data->pcie_lane_performance.max = 0;
-       data->pcie_lane_performance.min = 16;
-       data->pcie_lane_power_saving.max = 0;
-       data->pcie_lane_power_saving.min = 16;
-
-       tmp = 0;
-
-       if (tmp)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkThrottleLowNotification);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_DynamicUVDState);
-
-}
-
-int tonga_update_sclk_threshold(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       int result = 0;
-       uint32_t low_sclk_interrupt_threshold = 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkThrottleLowNotification)
-               && (hwmgr->gfx_arbiter.sclk_threshold != data->low_sclk_interrupt_threshold)) {
-               data->low_sclk_interrupt_threshold = hwmgr->gfx_arbiter.sclk_threshold;
-               low_sclk_interrupt_threshold = data->low_sclk_interrupt_threshold;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
-
-               result = tonga_copy_bytes_to_smc(
-                               hwmgr->smumgr,
-                               data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable,
-                               LowSclkInterruptThreshold),
-                               (uint8_t *)&low_sclk_interrupt_threshold,
-                               sizeof(uint32_t),
-                               data->sram_end
-                               );
-       }
-
-       return result;
-}
-
-/**
- * Find SCLK value that is associated with specified virtual_voltage_Id.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @param    virtual_voltage_Id  voltageId to look for.
- * @param    sclk output value .
- * @return   always 0 if success and 2 if association not found
- */
-static int tonga_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
-       phm_ppt_v1_voltage_lookup_table *lookup_table,
-       uint16_t virtual_voltage_id, uint32_t *sclk)
-{
-       uint8_t entryId;
-       uint8_t voltageId;
-       struct phm_ppt_v1_information *pptable_info =
-                                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -1);
-
-       /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
-       for (entryId = 0; entryId < pptable_info->vdd_dep_on_sclk->count; entryId++) {
-               voltageId = pptable_info->vdd_dep_on_sclk->entries[entryId].vddInd;
-               if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
-                       break;
-       }
-
-       PP_ASSERT_WITH_CODE(entryId < pptable_info->vdd_dep_on_sclk->count,
-                       "Can't find requested voltage id in vdd_dep_on_sclk table!",
-                       return -1;
-                       );
-
-       *sclk = pptable_info->vdd_dep_on_sclk->entries[entryId].clk;
-
-       return 0;
-}
-
-/**
- * Get Leakage VDDC based on leakage ID.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   2 if vddgfx returned is greater than 2V or if BIOS
- */
-int tonga_get_evv_voltage(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
-       uint16_t    virtual_voltage_id;
-       uint16_t    vddc = 0;
-       uint16_t    vddgfx = 0;
-       uint16_t    i, j;
-       uint32_t  sclk = 0;
-
-       /* retrieve voltage for leakage ID (0xff01 + i) */
-       for (i = 0; i < TONGA_MAX_LEAKAGE_COUNT; i++) {
-               virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
-
-               /* in split mode we should have only vddgfx EVV leakages */
-               if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
-                       if (0 == tonga_get_sclk_for_voltage_evv(hwmgr,
-                                               pptable_info->vddgfx_lookup_table, virtual_voltage_id, &sclk)) {
-                               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                                                       PHM_PlatformCaps_ClockStretcher)) {
-                                       for (j = 1; j < sclk_table->count; j++) {
-                                               if (sclk_table->entries[j].clk == sclk &&
-                                                               sclk_table->entries[j].cks_enable == 0) {
-                                                       sclk += 5000;
-                                                       break;
-                                               }
-                                       }
-                               }
-                               if (0 == atomctrl_get_voltage_evv_on_sclk
-                                   (hwmgr, VOLTAGE_TYPE_VDDGFX, sclk,
-                                    virtual_voltage_id, &vddgfx)) {
-                                       /* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
-                                       PP_ASSERT_WITH_CODE((vddgfx < 2000 && vddgfx != 0), "Invalid VDDGFX value!", return -1);
-
-                                       /* the voltage should not be zero nor equal to leakage ID */
-                                       if (vddgfx != 0 && vddgfx != virtual_voltage_id) {
-                                               data->vddcgfx_leakage.actual_voltage[data->vddcgfx_leakage.count] = vddgfx;
-                                               data->vddcgfx_leakage.leakage_id[data->vddcgfx_leakage.count] = virtual_voltage_id;
-                                               data->vddcgfx_leakage.count++;
-                                       }
-                               } else {
-                                       printk("Error retrieving EVV voltage value!\n");
-                               }
-                       }
-               } else {
-                       /*  in merged mode we have only vddc EVV leakages */
-                       if (0 == tonga_get_sclk_for_voltage_evv(hwmgr,
-                                               pptable_info->vddc_lookup_table,
-                                               virtual_voltage_id, &sclk)) {
-                               if (0 == atomctrl_get_voltage_evv_on_sclk
-                                   (hwmgr, VOLTAGE_TYPE_VDDC, sclk,
-                                    virtual_voltage_id, &vddc)) {
-                                       /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
-                                       PP_ASSERT_WITH_CODE(vddc < 2000, "Invalid VDDC value!", return -1);
-
-                                       /* the voltage should not be zero nor equal to leakage ID */
-                                       if (vddc != 0 && vddc != virtual_voltage_id) {
-                                               data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = vddc;
-                                               data->vddc_leakage.leakage_id[data->vddc_leakage.count] = virtual_voltage_id;
-                                               data->vddc_leakage.count++;
-                                       }
-                               } else {
-                                       printk("Error retrieving EVV voltage value!\n");
-                               }
-                       }
-               }
-       }
-
-       return 0;
-}
-
-int tonga_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       /* enable SCLK dpm */
-       if (0 == data->sclk_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                                  PPSMC_MSG_DPM_Enable)),
-                               "Failed to enable SCLK DPM during DPM Start Function!",
-                               return -1);
-       }
-
-       /* enable MCLK dpm */
-       if (0 == data->mclk_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                            PPSMC_MSG_MCLKDPM_Enable)),
-                               "Failed to enable MCLK DPM during DPM Start Function!",
-                               return -1);
-
-               PHM_WRITE_FIELD(hwmgr->device, MC_SEQ_CNTL_3, CAC_EN, 0x1);
-
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixLCAC_MC0_CNTL, 0x05);/* CH0,1 read */
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixLCAC_MC1_CNTL, 0x05);/* CH2,3 read */
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixLCAC_CPL_CNTL, 0x100005);/*Read */
-
-               udelay(10);
-
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixLCAC_MC0_CNTL, 0x400005);/* CH0,1 write */
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixLCAC_MC1_CNTL, 0x400005);/* CH2,3 write */
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixLCAC_CPL_CNTL, 0x500005);/* write */
-
-       }
-
-       return 0;
-}
-
-int tonga_start_dpm(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       /* enable general power management */
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, 1);
-       /* enable sclk deep sleep */
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, DYNAMIC_PM_EN, 1);
-
-       /* prepare for PCIE DPM */
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start +
-                       offsetof(SMU72_SoftRegisters, VoltageChangeTimeout), 0x1000);
-
-       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE, SWRST_COMMAND_1, RESETLC, 0x0);
-
-       PP_ASSERT_WITH_CODE(
-                       (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                       PPSMC_MSG_Voltage_Cntl_Enable)),
-                       "Failed to enable voltage DPM during DPM Start Function!",
-                       return -1);
-
-       if (0 != tonga_enable_sclk_mclk_dpm(hwmgr)) {
-               PP_ASSERT_WITH_CODE(0, "Failed to enable Sclk DPM and Mclk DPM!", return -1);
-       }
-
-       /* enable PCIE dpm */
-       if (0 == data->pcie_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_PCIeDPM_Enable)),
-                               "Failed to enable pcie DPM during DPM Start Function!",
-                               return -1
-                               );
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_Falcon_QuickTransition)) {
-                                  smum_send_msg_to_smc(hwmgr->smumgr,
-                                   PPSMC_MSG_EnableACDCGPIOInterrupt);
-       }
-
-       return 0;
-}
-
-int tonga_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       /* disable SCLK dpm */
-       if (0 == data->sclk_dpm_key_disabled) {
-               /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
-               PP_ASSERT_WITH_CODE(
-                               !tonga_is_dpm_running(hwmgr),
-                               "Trying to Disable SCLK DPM when DPM is disabled",
-                               return -1
-                               );
-
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                                 PPSMC_MSG_DPM_Disable)),
-                               "Failed to disable SCLK DPM during DPM stop Function!",
-                               return -1);
-       }
-
-       /* disable MCLK dpm */
-       if (0 == data->mclk_dpm_key_disabled) {
-               /* Checking if DPM is running.  If we discover hang because of this, we should skip this message. */
-               PP_ASSERT_WITH_CODE(
-                               !tonga_is_dpm_running(hwmgr),
-                               "Trying to Disable MCLK DPM when DPM is disabled",
-                               return -1
-                               );
-
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                           PPSMC_MSG_MCLKDPM_Disable)),
-                               "Failed to Disable MCLK DPM during DPM stop Function!",
-                               return -1);
-       }
-
-       return 0;
-}
-
-int tonga_stop_dpm(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, 0);
-       /* disable sclk deep sleep*/
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, DYNAMIC_PM_EN, 0);
-
-       /* disable PCIE dpm */
-       if (0 == data->pcie_dpm_key_disabled) {
-               /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
-               PP_ASSERT_WITH_CODE(
-                               !tonga_is_dpm_running(hwmgr),
-                               "Trying to Disable PCIE DPM when DPM is disabled",
-                               return -1
-                               );
-               PP_ASSERT_WITH_CODE(
-                               (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_PCIeDPM_Disable)),
-                               "Failed to disable pcie DPM during DPM stop Function!",
-                               return -1);
-       }
-
-       if (0 != tonga_disable_sclk_mclk_dpm(hwmgr))
-               PP_ASSERT_WITH_CODE(0, "Failed to disable Sclk DPM and Mclk DPM!", return -1);
-
-       /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
-       PP_ASSERT_WITH_CODE(
-                       !tonga_is_dpm_running(hwmgr),
-                       "Trying to Disable Voltage CNTL when DPM is disabled",
-                       return -1
-                       );
-
-       PP_ASSERT_WITH_CODE(
-                       (0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                       PPSMC_MSG_Voltage_Cntl_Disable)),
-                       "Failed to disable voltage DPM during DPM stop Function!",
-                       return -1);
-
-       return 0;
-}
-
-int tonga_enable_sclk_control(struct pp_hwmgr *hwmgr)
-{
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, 0);
-
-       return 0;
-}
-
-/**
- * Send a message to the SMC and return a parameter
- *
- * @param    hwmgr:  the address of the powerplay hardware manager.
- * @param    msg: the message to send.
- * @param    parameter: pointer to the received parameter
- * @return   The response that came from the SMC.
- */
-PPSMC_Result tonga_send_msg_to_smc_return_parameter(
-               struct pp_hwmgr *hwmgr,
-               PPSMC_Msg msg,
-               uint32_t *parameter)
-{
-       int result;
-
-       result = smum_send_msg_to_smc(hwmgr->smumgr, msg);
-
-       if ((0 == result) && parameter) {
-               *parameter = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-       }
-
-       return result;
-}
-
-/**
- * force DPM power State
- *
- * @param    hwmgr:  the address of the powerplay hardware manager.
- * @param    n     :  DPM level
- * @return   The response that came from the SMC.
- */
-int tonga_dpm_force_state(struct pp_hwmgr *hwmgr, uint32_t n)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       uint32_t level_mask = 1 << n;
-
-       /* Checking if DPM is running.  If we discover hang because of this, we should skip this message. */
-       PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr),
-                           "Trying to force SCLK when DPM is disabled",
-                           return -1;);
-       if (0 == data->sclk_dpm_key_disabled)
-               return (0 == smum_send_msg_to_smc_with_parameter(
-                                                            hwmgr->smumgr,
-                    (PPSMC_Msg)(PPSMC_MSG_SCLKDPM_SetEnabledMask),
-                                                   level_mask) ? 0 : 1);
-
-       return 0;
-}
-
-/**
- * force DPM power State
- *
- * @param    hwmgr:  the address of the powerplay hardware manager.
- * @param    n     :  DPM level
- * @return   The response that came from the SMC.
- */
-int tonga_dpm_force_state_mclk(struct pp_hwmgr *hwmgr, uint32_t n)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       uint32_t level_mask = 1 << n;
-
-       /* Checking if DPM is running.  If we discover hang because of this, we should skip this message. */
-       PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr),
-                           "Trying to Force MCLK when DPM is disabled",
-                           return -1;);
-       if (0 == data->mclk_dpm_key_disabled)
-               return (0 == smum_send_msg_to_smc_with_parameter(
-                                                               hwmgr->smumgr,
-                                                               (PPSMC_Msg)(PPSMC_MSG_MCLKDPM_SetEnabledMask),
-                                                               level_mask) ? 0 : 1);
-
-       return 0;
-}
-
-/**
- * force DPM power State
- *
- * @param    hwmgr:  the address of the powerplay hardware manager.
- * @param    n     :  DPM level
- * @return   The response that came from the SMC.
- */
-int tonga_dpm_force_state_pcie(struct pp_hwmgr *hwmgr, uint32_t n)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
-       PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr),
-                           "Trying to Force PCIE level when DPM is disabled",
-                           return -1;);
-       if (0 == data->pcie_dpm_key_disabled)
-               return (0 == smum_send_msg_to_smc_with_parameter(
-                                                            hwmgr->smumgr,
-                          (PPSMC_Msg)(PPSMC_MSG_PCIeDPM_ForceLevel),
-                                                               n) ? 0 : 1);
-
-       return 0;
-}
-
-/**
- * Set the initial state by calling SMC to switch to this state directly
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_set_boot_state(struct pp_hwmgr *hwmgr)
-{
-       /*
-       * SMC only stores one state that SW will ask to switch too,
-       * so we switch the the just uploaded one
-       */
-       return (0 == tonga_disable_sclk_mclk_dpm(hwmgr)) ? 0 : 1;
-}
-
-/**
- * Get the location of various tables inside the FW image.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_process_firmware_header(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_smumgr *tonga_smu = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
-
-       uint32_t tmp;
-       int result;
-       bool error = false;
-
-       result = tonga_read_smc_sram_dword(hwmgr->smumgr,
-                               SMU72_FIRMWARE_HEADER_LOCATION +
-                               offsetof(SMU72_Firmware_Header, DpmTable),
-                               &tmp, data->sram_end);
-
-       if (0 == result) {
-               data->dpm_table_start = tmp;
-       }
-
-       error |= (0 != result);
-
-       result = tonga_read_smc_sram_dword(hwmgr->smumgr,
-                               SMU72_FIRMWARE_HEADER_LOCATION +
-                               offsetof(SMU72_Firmware_Header, SoftRegisters),
-                               &tmp, data->sram_end);
-
-       if (0 == result) {
-               data->soft_regs_start = tmp;
-               tonga_smu->ulSoftRegsStart = tmp;
-       }
-
-       error |= (0 != result);
-
-
-       result = tonga_read_smc_sram_dword(hwmgr->smumgr,
-                               SMU72_FIRMWARE_HEADER_LOCATION +
-                               offsetof(SMU72_Firmware_Header, mcRegisterTable),
-                               &tmp, data->sram_end);
-
-       if (0 == result) {
-               data->mc_reg_table_start = tmp;
-       }
-
-       result = tonga_read_smc_sram_dword(hwmgr->smumgr,
-                               SMU72_FIRMWARE_HEADER_LOCATION +
-                               offsetof(SMU72_Firmware_Header, FanTable),
-                               &tmp, data->sram_end);
-
-       if (0 == result) {
-               data->fan_table_start = tmp;
-       }
-
-       error |= (0 != result);
-
-       result = tonga_read_smc_sram_dword(hwmgr->smumgr,
-                               SMU72_FIRMWARE_HEADER_LOCATION +
-                               offsetof(SMU72_Firmware_Header, mcArbDramTimingTable),
-                               &tmp, data->sram_end);
-
-       if (0 == result) {
-               data->arb_table_start = tmp;
-       }
-
-       error |= (0 != result);
-
-
-       result = tonga_read_smc_sram_dword(hwmgr->smumgr,
-                               SMU72_FIRMWARE_HEADER_LOCATION +
-                               offsetof(SMU72_Firmware_Header, Version),
-                               &tmp, data->sram_end);
-
-       if (0 == result) {
-               hwmgr->microcode_version_info.SMC = tmp;
-       }
-
-       error |= (0 != result);
-
-       return error ? 1 : 0;
-}
-
-/**
- * Read clock related registers.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_read_clock_registers(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       data->clock_registers.vCG_SPLL_FUNC_CNTL         =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL);
-       data->clock_registers.vCG_SPLL_FUNC_CNTL_2       =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_2);
-       data->clock_registers.vCG_SPLL_FUNC_CNTL_3       =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_3);
-       data->clock_registers.vCG_SPLL_FUNC_CNTL_4       =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_4);
-       data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM   =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM);
-       data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
-               cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM_2);
-       data->clock_registers.vDLL_CNTL                  =
-               cgs_read_register(hwmgr->device, mmDLL_CNTL);
-       data->clock_registers.vMCLK_PWRMGT_CNTL          =
-               cgs_read_register(hwmgr->device, mmMCLK_PWRMGT_CNTL);
-       data->clock_registers.vMPLL_AD_FUNC_CNTL         =
-               cgs_read_register(hwmgr->device, mmMPLL_AD_FUNC_CNTL);
-       data->clock_registers.vMPLL_DQ_FUNC_CNTL         =
-               cgs_read_register(hwmgr->device, mmMPLL_DQ_FUNC_CNTL);
-       data->clock_registers.vMPLL_FUNC_CNTL            =
-               cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL);
-       data->clock_registers.vMPLL_FUNC_CNTL_1          =
-               cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_1);
-       data->clock_registers.vMPLL_FUNC_CNTL_2          =
-               cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_2);
-       data->clock_registers.vMPLL_SS1                  =
-               cgs_read_register(hwmgr->device, mmMPLL_SS1);
-       data->clock_registers.vMPLL_SS2                  =
-               cgs_read_register(hwmgr->device, mmMPLL_SS2);
-
-       return 0;
-}
-
-/**
- * Find out if memory is GDDR5.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_get_memory_type(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       uint32_t temp;
-
-       temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
-
-       data->is_memory_GDDR5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
-                       ((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
-                        MC_SEQ_MISC0_GDDR5_SHIFT));
-
-       return 0;
-}
-
-/**
- * Enables Dynamic Power Management by SMC
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
-{
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, STATIC_PM_EN, 1);
-
-       return 0;
-}
-
-/**
- * Initialize PowerGating States for different engines
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_init_power_gate_state(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       data->uvd_power_gated = false;
-       data->vce_power_gated = false;
-       data->samu_power_gated = false;
-       data->acp_power_gated = false;
-       data->pg_acp_init = true;
-
-       return 0;
-}
-
-/**
- * Checks if DPM is enabled
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_check_for_dpm_running(struct pp_hwmgr *hwmgr)
-{
-       /*
-        * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
-        * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
-        * whereas voltage control is a fundemental change that will not be disabled
-        */
-       return (!tonga_is_dpm_running(hwmgr) ? 0 : 1);
-}
-
-/**
- * Checks if DPM is stopped
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_check_for_dpm_stopped(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       if (tonga_is_dpm_running(hwmgr)) {
-               /* If HW Virtualization is enabled, dpm_table_start will not have a valid value */
-               if (!data->dpm_table_start) {
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-/**
- * Remove repeated voltage values and create table with unique values.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @param    voltage_table  the pointer to changing voltage table
- * @return    1 in success
- */
-
-static int tonga_trim_voltage_table(struct pp_hwmgr *hwmgr,
-                       pp_atomctrl_voltage_table *voltage_table)
-{
-       uint32_t table_size, i, j;
-       uint16_t vvalue;
-       bool bVoltageFound = false;
-       pp_atomctrl_voltage_table *table;
-
-       PP_ASSERT_WITH_CODE((NULL != voltage_table), "Voltage Table empty.", return -1;);
-       table_size = sizeof(pp_atomctrl_voltage_table);
-       table = kzalloc(table_size, GFP_KERNEL);
-
-       if (NULL == table)
-               return -ENOMEM;
-
-       memset(table, 0x00, table_size);
-       table->mask_low = voltage_table->mask_low;
-       table->phase_delay = voltage_table->phase_delay;
-
-       for (i = 0; i < voltage_table->count; i++) {
-               vvalue = voltage_table->entries[i].value;
-               bVoltageFound = false;
-
-               for (j = 0; j < table->count; j++) {
-                       if (vvalue == table->entries[j].value) {
-                               bVoltageFound = true;
-                               break;
-                       }
-               }
-
-               if (!bVoltageFound) {
-                       table->entries[table->count].value = vvalue;
-                       table->entries[table->count].smio_low =
-                               voltage_table->entries[i].smio_low;
-                       table->count++;
-               }
-       }
-
-       memcpy(table, voltage_table, sizeof(pp_atomctrl_voltage_table));
-
-       kfree(table);
-
-       return 0;
-}
-
-static int tonga_get_svi2_vdd_ci_voltage_table(
-               struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_clock_voltage_dependency_table *voltage_dependency_table)
-{
-       uint32_t i;
-       int result;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       pp_atomctrl_voltage_table *vddci_voltage_table = &(data->vddci_voltage_table);
-
-       PP_ASSERT_WITH_CODE((0 != voltage_dependency_table->count),
-                       "Voltage Dependency Table empty.", return -1;);
-
-       vddci_voltage_table->mask_low = 0;
-       vddci_voltage_table->phase_delay = 0;
-       vddci_voltage_table->count = voltage_dependency_table->count;
-
-       for (i = 0; i < voltage_dependency_table->count; i++) {
-               vddci_voltage_table->entries[i].value =
-                       voltage_dependency_table->entries[i].vddci;
-               vddci_voltage_table->entries[i].smio_low = 0;
-       }
-
-       result = tonga_trim_voltage_table(hwmgr, vddci_voltage_table);
-       PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to trim VDDCI table.", return result;);
-
-       return 0;
-}
-
-
-
-static int tonga_get_svi2_vdd_voltage_table(
-               struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_voltage_lookup_table *look_up_table,
-               pp_atomctrl_voltage_table *voltage_table)
-{
-       uint8_t i = 0;
-
-       PP_ASSERT_WITH_CODE((0 != look_up_table->count),
-                       "Voltage Lookup Table empty.", return -1;);
-
-       voltage_table->mask_low = 0;
-       voltage_table->phase_delay = 0;
-
-       voltage_table->count = look_up_table->count;
-
-       for (i = 0; i < voltage_table->count; i++) {
-               voltage_table->entries[i].value = look_up_table->entries[i].us_vdd;
-               voltage_table->entries[i].smio_low = 0;
-       }
-
-       return 0;
-}
-
-/*
- * -------------------------------------------------------- Voltage Tables --------------------------------------------------------------------------
- * If the voltage table would be bigger than what will fit into the state table on the SMC keep only the higher entries.
- */
-
-static void tonga_trim_voltage_table_to_fit_state_table(
-               struct pp_hwmgr *hwmgr,
-               uint32_t max_voltage_steps,
-               pp_atomctrl_voltage_table *voltage_table)
-{
-       unsigned int i, diff;
-
-       if (voltage_table->count <= max_voltage_steps) {
-               return;
-       }
-
-       diff = voltage_table->count - max_voltage_steps;
-
-       for (i = 0; i < max_voltage_steps; i++) {
-               voltage_table->entries[i] = voltage_table->entries[i + diff];
-       }
-
-       voltage_table->count = max_voltage_steps;
-
-       return;
-}
-
-/**
- * Create Voltage Tables.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_construct_voltage_tables(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       int result;
-
-       /* MVDD has only GPIO voltage control */
-       if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
-               result = atomctrl_get_voltage_table_v3(hwmgr,
-                                       VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT, &(data->mvdd_voltage_table));
-               PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to retrieve MVDD table.", return result;);
-       }
-
-       if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
-               /* GPIO voltage */
-               result = atomctrl_get_voltage_table_v3(hwmgr,
-                                       VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT, &(data->vddci_voltage_table));
-               PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to retrieve VDDCI table.", return result;);
-       } else if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
-               /* SVI2 voltage */
-               result = tonga_get_svi2_vdd_ci_voltage_table(hwmgr,
-                                       pptable_info->vdd_dep_on_mclk);
-               PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to retrieve SVI2 VDDCI table from dependancy table.", return result;);
-       }
-
-       if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
-               /* VDDGFX has only SVI2 voltage control */
-               result = tonga_get_svi2_vdd_voltage_table(hwmgr,
-                                       pptable_info->vddgfx_lookup_table, &(data->vddgfx_voltage_table));
-               PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result;);
-       }
-
-       if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
-               /* VDDC has only SVI2 voltage control */
-               result = tonga_get_svi2_vdd_voltage_table(hwmgr,
-                                       pptable_info->vddc_lookup_table, &(data->vddc_voltage_table));
-               PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to retrieve SVI2 VDDC table from lookup table.", return result;);
-       }
-
-       PP_ASSERT_WITH_CODE(
-                       (data->vddc_voltage_table.count <= (SMU72_MAX_LEVELS_VDDC)),
-                       "Too many voltage values for VDDC. Trimming to fit state table.",
-                       tonga_trim_voltage_table_to_fit_state_table(hwmgr,
-                       SMU72_MAX_LEVELS_VDDC, &(data->vddc_voltage_table));
-                       );
-
-       PP_ASSERT_WITH_CODE(
-                       (data->vddgfx_voltage_table.count <= (SMU72_MAX_LEVELS_VDDGFX)),
-                       "Too many voltage values for VDDGFX. Trimming to fit state table.",
-                       tonga_trim_voltage_table_to_fit_state_table(hwmgr,
-                       SMU72_MAX_LEVELS_VDDGFX, &(data->vddgfx_voltage_table));
-                       );
-
-       PP_ASSERT_WITH_CODE(
-                       (data->vddci_voltage_table.count <= (SMU72_MAX_LEVELS_VDDCI)),
-                       "Too many voltage values for VDDCI. Trimming to fit state table.",
-                       tonga_trim_voltage_table_to_fit_state_table(hwmgr,
-                       SMU72_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table));
-                       );
-
-       PP_ASSERT_WITH_CODE(
-                       (data->mvdd_voltage_table.count <= (SMU72_MAX_LEVELS_MVDD)),
-                       "Too many voltage values for MVDD. Trimming to fit state table.",
-                       tonga_trim_voltage_table_to_fit_state_table(hwmgr,
-                       SMU72_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table));
-                       );
-
-       return 0;
-}
-
-/**
- * Vddc table preparation for SMC.
- *
- * @param    hwmgr      the address of the hardware manager
- * @param    table     the SMC DPM table structure to be populated
- * @return   always 0
- */
-static int tonga_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
-                       SMU72_Discrete_DpmTable *table)
-{
-       unsigned int count;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
-               table->VddcLevelCount = data->vddc_voltage_table.count;
-               for (count = 0; count < table->VddcLevelCount; count++) {
-                       table->VddcTable[count] =
-                               PP_HOST_TO_SMC_US(data->vddc_voltage_table.entries[count].value * VOLTAGE_SCALE);
-               }
-               CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
-       }
-       return 0;
-}
-
-/**
- * VddGfx table preparation for SMC.
- *
- * @param    hwmgr      the address of the hardware manager
- * @param    table     the SMC DPM table structure to be populated
- * @return   always 0
- */
-static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr *hwmgr,
-                       SMU72_Discrete_DpmTable *table)
-{
-       unsigned int count;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
-               table->VddGfxLevelCount = data->vddgfx_voltage_table.count;
-               for (count = 0; count < data->vddgfx_voltage_table.count; count++) {
-                       table->VddGfxTable[count] =
-                               PP_HOST_TO_SMC_US(data->vddgfx_voltage_table.entries[count].value * VOLTAGE_SCALE);
-               }
-               CONVERT_FROM_HOST_TO_SMC_UL(table->VddGfxLevelCount);
-       }
-       return 0;
-}
-
-/**
- * Vddci table preparation for SMC.
- *
- * @param    *hwmgr The address of the hardware manager.
- * @param    *table The SMC DPM table structure to be populated.
- * @return   0
- */
-static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
-                       SMU72_Discrete_DpmTable *table)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       uint32_t count;
-
-       table->VddciLevelCount = data->vddci_voltage_table.count;
-       for (count = 0; count < table->VddciLevelCount; count++) {
-               if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
-                       table->VddciTable[count] =
-                               PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
-               } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
-                       table->SmioTable1.Pattern[count].Voltage =
-                               PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
-                       /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
-                       table->SmioTable1.Pattern[count].Smio =
-                               (uint8_t) count;
-                       table->Smio[count] |=
-                               data->vddci_voltage_table.entries[count].smio_low;
-                       table->VddciTable[count] =
-                               PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
-               }
-       }
-
-       table->SmioMask1 = data->vddci_voltage_table.mask_low;
-       CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
-
-       return 0;
-}
-
-/**
- * Mvdd table preparation for SMC.
- *
- * @param    *hwmgr The address of the hardware manager.
- * @param    *table The SMC DPM table structure to be populated.
- * @return   0
- */
-static int tonga_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
-                       SMU72_Discrete_DpmTable *table)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       uint32_t count;
-
-       if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
-               table->MvddLevelCount = data->mvdd_voltage_table.count;
-               for (count = 0; count < table->MvddLevelCount; count++) {
-                       table->SmioTable2.Pattern[count].Voltage =
-                               PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE);
-                       /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
-                       table->SmioTable2.Pattern[count].Smio =
-                               (uint8_t) count;
-                       table->Smio[count] |=
-                               data->mvdd_voltage_table.entries[count].smio_low;
-               }
-               table->SmioMask2 = data->mvdd_voltage_table.mask_low;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
-       }
-
-       return 0;
-}
-
-/**
- * Convert a voltage value in mv unit to VID number required by SMU firmware
- */
-static uint8_t convert_to_vid(uint16_t vddc)
-{
-       return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
-}
-
-
-/**
- * Preparation of vddc and vddgfx CAC tables for SMC.
- *
- * @param    hwmgr      the address of the hardware manager
- * @param    table     the SMC DPM table structure to be populated
- * @return   always 0
- */
-static int tonga_populate_cac_tables(struct pp_hwmgr *hwmgr,
-                       SMU72_Discrete_DpmTable *table)
-{
-       uint32_t count;
-       uint8_t index;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table = pptable_info->vddgfx_lookup_table;
-       struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table = pptable_info->vddc_lookup_table;
-
-       /* pTables is already swapped, so in order to use the value from it, we need to swap it back. */
-       uint32_t vddcLevelCount = PP_SMC_TO_HOST_UL(table->VddcLevelCount);
-       uint32_t vddgfxLevelCount = PP_SMC_TO_HOST_UL(table->VddGfxLevelCount);
-
-       for (count = 0; count < vddcLevelCount; count++) {
-               /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
-               index = tonga_get_voltage_index(vddc_lookup_table,
-                       data->vddc_voltage_table.entries[count].value);
-               table->BapmVddcVidLoSidd[count] =
-                       convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
-               table->BapmVddcVidHiSidd[count] =
-                       convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
-               table->BapmVddcVidHiSidd2[count] =
-                       convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
-       }
-
-       if ((data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2)) {
-               /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
-               for (count = 0; count < vddgfxLevelCount; count++) {
-                       index = tonga_get_voltage_index(vddgfx_lookup_table,
-                               data->vddgfx_voltage_table.entries[count].value);
-                       table->BapmVddGfxVidLoSidd[count] =
-                               convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_low);
-                       table->BapmVddGfxVidHiSidd[count] =
-                               convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_mid);
-                       table->BapmVddGfxVidHiSidd2[count] =
-                               convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_high);
-               }
-       } else {
-               for (count = 0; count < vddcLevelCount; count++) {
-                       index = tonga_get_voltage_index(vddc_lookup_table,
-                               data->vddc_voltage_table.entries[count].value);
-                       table->BapmVddGfxVidLoSidd[count] =
-                               convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
-                       table->BapmVddGfxVidHiSidd[count] =
-                               convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
-                       table->BapmVddGfxVidHiSidd2[count] =
-                               convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
-               }
-       }
-
-       return 0;
-}
-
-
-/**
- * Preparation of voltage tables for SMC.
- *
- * @param    hwmgr      the address of the hardware manager
- * @param    table     the SMC DPM table structure to be populated
- * @return   always 0
- */
-
-int tonga_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
-       SMU72_Discrete_DpmTable *table)
-{
-       int result;
-
-       result = tonga_populate_smc_vddc_table(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "can not populate VDDC voltage table to SMC", return -1);
-
-       result = tonga_populate_smc_vdd_ci_table(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "can not populate VDDCI voltage table to SMC", return -1);
-
-       result = tonga_populate_smc_vdd_gfx_table(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "can not populate VDDGFX voltage table to SMC", return -1);
-
-       result = tonga_populate_smc_mvdd_table(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "can not populate MVDD voltage table to SMC", return -1);
-
-       result = tonga_populate_cac_tables(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-                       "can not populate CAC voltage tables to SMC", return -1);
-
-       return 0;
-}
-
-/**
- * Populates the SMC VRConfig field in DPM table.
- *
- * @param    hwmgr      the address of the hardware manager
- * @param    table     the SMC DPM table structure to be populated
- * @return   always 0
- */
-static int tonga_populate_vr_config(struct pp_hwmgr *hwmgr,
-                       SMU72_Discrete_DpmTable *table)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       uint16_t config;
-
-       if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
-               /*  Splitted mode */
-               config = VR_SVI2_PLANE_1;
-               table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
-
-               if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
-                       config = VR_SVI2_PLANE_2;
-                       table->VRConfig |= config;
-               } else {
-                       printk(KERN_ERR "[ powerplay ] VDDC and VDDGFX should be both on SVI2 control in splitted mode! \n");
-               }
-       } else {
-               /* Merged mode  */
-               config = VR_MERGED_WITH_VDDC;
-               table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
-
-               /* Set Vddc Voltage Controller  */
-               if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
-                       config = VR_SVI2_PLANE_1;
-                       table->VRConfig |= config;
-               } else {
-                       printk(KERN_ERR "[ powerplay ] VDDC should be on SVI2 control in merged mode! \n");
-               }
-       }
-
-       /* Set Vddci Voltage Controller  */
-       if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
-               config = VR_SVI2_PLANE_2;  /* only in merged mode */
-               table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
-       } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
-               config = VR_SMIO_PATTERN_1;
-               table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
-       }
-
-       /* Set Mvdd Voltage Controller */
-       if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
-               config = VR_SMIO_PATTERN_2;
-               table->VRConfig |= (config<<VRCONF_MVDD_SHIFT);
-       }
-
-       return 0;
-}
-
-static int tonga_get_dependecy_volt_by_clk(struct pp_hwmgr *hwmgr,
-       phm_ppt_v1_clock_voltage_dependency_table *allowed_clock_voltage_table,
-       uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
-{
-       uint32_t i = 0;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       /* clock - voltage dependency table is empty table */
-       if (allowed_clock_voltage_table->count == 0)
-               return -1;
-
-       for (i = 0; i < allowed_clock_voltage_table->count; i++) {
-               /* find first sclk bigger than request */
-               if (allowed_clock_voltage_table->entries[i].clk >= clock) {
-                       voltage->VddGfx = tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
-                                                               allowed_clock_voltage_table->entries[i].vddgfx);
-
-                       voltage->Vddc = tonga_get_voltage_index(pptable_info->vddc_lookup_table,
-                                                               allowed_clock_voltage_table->entries[i].vddc);
-
-                       if (allowed_clock_voltage_table->entries[i].vddci) {
-                               voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
-                                                                       allowed_clock_voltage_table->entries[i].vddci);
-                       } else {
-                               voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
-                                                                       allowed_clock_voltage_table->entries[i].vddc - data->vddc_vddci_delta);
-                       }
-
-                       if (allowed_clock_voltage_table->entries[i].mvdd) {
-                               *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i].mvdd;
-                       }
-
-                       voltage->Phases = 1;
-                       return 0;
-               }
-       }
-
-       /* sclk is bigger than max sclk in the dependence table */
-       voltage->VddGfx = tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
-               allowed_clock_voltage_table->entries[i-1].vddgfx);
-       voltage->Vddc = tonga_get_voltage_index(pptable_info->vddc_lookup_table,
-               allowed_clock_voltage_table->entries[i-1].vddc);
-
-       if (allowed_clock_voltage_table->entries[i-1].vddci) {
-               voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
-                       allowed_clock_voltage_table->entries[i-1].vddci);
-       }
-       if (allowed_clock_voltage_table->entries[i-1].mvdd) {
-               *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i-1].mvdd;
-       }
-
-       return 0;
-}
-
-/**
- * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_reset_to_default(struct pp_hwmgr *hwmgr)
-{
-       return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults) == 0) ? 0 : 1;
-}
-
-int tonga_populate_memory_timing_parameters(
-               struct pp_hwmgr *hwmgr,
-               uint32_t engine_clock,
-               uint32_t memory_clock,
-               struct SMU72_Discrete_MCArbDramTimingTableEntry *arb_regs
-               )
-{
-       uint32_t dramTiming;
-       uint32_t dramTiming2;
-       uint32_t burstTime;
-       int result;
-
-       result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
-                               engine_clock, memory_clock);
-
-       PP_ASSERT_WITH_CODE(result == 0,
-               "Error calling VBIOS to set DRAM_TIMING.", return result);
-
-       dramTiming  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
-       dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
-       burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
-
-       arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dramTiming);
-       arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
-       arb_regs->McArbBurstTime = (uint8_t)burstTime;
-
-       return 0;
-}
-
-/**
- * Setup parameters for the MC ARB.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- * This function is to be called from the SetPowerState table.
- */
-int tonga_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       int result = 0;
-       SMU72_Discrete_MCArbDramTimingTable  arb_regs;
-       uint32_t i, j;
-
-       memset(&arb_regs, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable));
-
-       for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
-               for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
-                       result = tonga_populate_memory_timing_parameters
-                               (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
-                                data->dpm_table.mclk_table.dpm_levels[j].value,
-                                &arb_regs.entries[i][j]);
-
-                       if (0 != result) {
-                               break;
-                       }
-               }
-       }
-
-       if (0 == result) {
-               result = tonga_copy_bytes_to_smc(
-                               hwmgr->smumgr,
-                               data->arb_table_start,
-                               (uint8_t *)&arb_regs,
-                               sizeof(SMU72_Discrete_MCArbDramTimingTable),
-                               data->sram_end
-                               );
-       }
-
-       return result;
-}
-
-static int tonga_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU72_Discrete_DpmTable *table)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_dpm_table *dpm_table = &data->dpm_table;
-       uint32_t i;
-
-       /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
-       for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
-               table->LinkLevel[i].PcieGenSpeed  =
-                       (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
-               table->LinkLevel[i].PcieLaneCount =
-                       (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
-               table->LinkLevel[i].EnabledForActivity =
-                       1;
-               table->LinkLevel[i].SPC =
-                       (uint8_t)(data->pcie_spc_cap & 0xff);
-               table->LinkLevel[i].DownThreshold =
-                       PP_HOST_TO_SMC_UL(5);
-               table->LinkLevel[i].UpThreshold =
-                       PP_HOST_TO_SMC_UL(30);
-       }
-
-       data->smc_state_table.LinkLevelCount =
-               (uint8_t)dpm_table->pcie_speed_table.count;
-       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
-               tonga_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
-
-       return 0;
-}
-
-static int tonga_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
-                                       SMU72_Discrete_DpmTable *table)
-{
-       int result = 0;
-
-       uint8_t count;
-       pp_atomctrl_clock_dividers_vi dividers;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
-
-       table->UvdLevelCount = (uint8_t) (mm_table->count);
-       table->UvdBootLevel = 0;
-
-       for (count = 0; count < table->UvdLevelCount; count++) {
-               table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
-               table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
-               table->UvdLevel[count].MinVoltage.Vddc =
-                       tonga_get_voltage_index(pptable_info->vddc_lookup_table,
-                                               mm_table->entries[count].vddc);
-               table->UvdLevel[count].MinVoltage.VddGfx =
-                       (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
-                       tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
-                                               mm_table->entries[count].vddgfx) : 0;
-               table->UvdLevel[count].MinVoltage.Vddci =
-                       tonga_get_voltage_id(&data->vddci_voltage_table,
-                                            mm_table->entries[count].vddc - data->vddc_vddci_delta);
-               table->UvdLevel[count].MinVoltage.Phases = 1;
-
-               /* retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                                                         table->UvdLevel[count].VclkFrequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                                   "can not find divide id for Vclk clock", return result);
-
-               table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
-
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                                                         table->UvdLevel[count].DclkFrequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                                   "can not find divide id for Dclk clock", return result);
-
-               table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
-               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
-               //CONVERT_FROM_HOST_TO_SMC_UL((uint32_t)table->UvdLevel[count].MinVoltage);
-       }
-
-       return result;
-
-}
-
-static int tonga_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
-               SMU72_Discrete_DpmTable *table)
-{
-       int result = 0;
-
-       uint8_t count;
-       pp_atomctrl_clock_dividers_vi dividers;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
-
-       table->VceLevelCount = (uint8_t) (mm_table->count);
-       table->VceBootLevel = 0;
-
-       for (count = 0; count < table->VceLevelCount; count++) {
-               table->VceLevel[count].Frequency =
-                       mm_table->entries[count].eclk;
-               table->VceLevel[count].MinVoltage.Vddc =
-                       tonga_get_voltage_index(pptable_info->vddc_lookup_table,
-                               mm_table->entries[count].vddc);
-               table->VceLevel[count].MinVoltage.VddGfx =
-                       (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
-                       tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
-                               mm_table->entries[count].vddgfx) : 0;
-               table->VceLevel[count].MinVoltage.Vddci =
-                       tonga_get_voltage_id(&data->vddci_voltage_table,
-                               mm_table->entries[count].vddc - data->vddc_vddci_delta);
-               table->VceLevel[count].MinVoltage.Phases = 1;
-
-               /* retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                                       table->VceLevel[count].Frequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "can not find divide id for VCE engine clock", return result);
-
-               table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
-       }
-
-       return result;
-}
-
-static int tonga_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
-               SMU72_Discrete_DpmTable *table)
-{
-       int result = 0;
-       uint8_t count;
-       pp_atomctrl_clock_dividers_vi dividers;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
-
-       table->AcpLevelCount = (uint8_t) (mm_table->count);
-       table->AcpBootLevel = 0;
-
-       for (count = 0; count < table->AcpLevelCount; count++) {
-               table->AcpLevel[count].Frequency =
-                       pptable_info->mm_dep_table->entries[count].aclk;
-               table->AcpLevel[count].MinVoltage.Vddc =
-                       tonga_get_voltage_index(pptable_info->vddc_lookup_table,
-                       mm_table->entries[count].vddc);
-               table->AcpLevel[count].MinVoltage.VddGfx =
-                       (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
-                       tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
-                               mm_table->entries[count].vddgfx) : 0;
-               table->AcpLevel[count].MinVoltage.Vddci =
-                       tonga_get_voltage_id(&data->vddci_voltage_table,
-                               mm_table->entries[count].vddc - data->vddc_vddci_delta);
-               table->AcpLevel[count].MinVoltage.Phases = 1;
-
-               /* retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                       table->AcpLevel[count].Frequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                       "can not find divide id for engine clock", return result);
-
-               table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
-       }
-
-       return result;
-}
-
-static int tonga_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
-       SMU72_Discrete_DpmTable *table)
-{
-       int result = 0;
-       uint8_t count;
-       pp_atomctrl_clock_dividers_vi dividers;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
-
-       table->SamuBootLevel = 0;
-       table->SamuLevelCount = (uint8_t) (mm_table->count);
-
-       for (count = 0; count < table->SamuLevelCount; count++) {
-               /* not sure whether we need evclk or not */
-               table->SamuLevel[count].Frequency =
-                       pptable_info->mm_dep_table->entries[count].samclock;
-               table->SamuLevel[count].MinVoltage.Vddc =
-                       tonga_get_voltage_index(pptable_info->vddc_lookup_table,
-                               mm_table->entries[count].vddc);
-               table->SamuLevel[count].MinVoltage.VddGfx =
-                       (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
-                       tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
-                               mm_table->entries[count].vddgfx) : 0;
-               table->SamuLevel[count].MinVoltage.Vddci =
-                       tonga_get_voltage_id(&data->vddci_voltage_table,
-                               mm_table->entries[count].vddc - data->vddc_vddci_delta);
-               table->SamuLevel[count].MinVoltage.Phases = 1;
-
-               /* retrieve divider value for VBIOS */
-               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
-                                       table->SamuLevel[count].Frequency, &dividers);
-               PP_ASSERT_WITH_CODE((0 == result),
-                       "can not find divide id for samu clock", return result);
-
-               table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
-
-               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
-       }
-
-       return result;
-}
-
-/**
- * Populates the SMC MCLK structure using the provided memory clock
- *
- * @param    hwmgr      the address of the hardware manager
- * @param    memory_clock the memory clock to use to populate the structure
- * @param    sclk        the SMC SCLK structure to be populated
- */
-static int tonga_calculate_mclk_params(
-               struct pp_hwmgr *hwmgr,
-               uint32_t memory_clock,
-               SMU72_Discrete_MemoryLevel *mclk,
-               bool strobe_mode,
-               bool dllStateOn
-               )
-{
-       const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       uint32_t  dll_cntl = data->clock_registers.vDLL_CNTL;
-       uint32_t  mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
-       uint32_t  mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
-       uint32_t  mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
-       uint32_t  mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
-       uint32_t  mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
-       uint32_t  mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
-       uint32_t  mpll_ss1 = data->clock_registers.vMPLL_SS1;
-       uint32_t  mpll_ss2 = data->clock_registers.vMPLL_SS2;
-
-       pp_atomctrl_memory_clock_param mpll_param;
-       int result;
-
-       result = atomctrl_get_memory_pll_dividers_si(hwmgr,
-                               memory_clock, &mpll_param, strobe_mode);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Error retrieving Memory Clock Parameters from VBIOS.", return result);
-
-       /* MPLL_FUNC_CNTL setup*/
-       mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL, mpll_param.bw_ctrl);
-
-       /* MPLL_FUNC_CNTL_1 setup*/
-       mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
-                                                       MPLL_FUNC_CNTL_1, CLKF, mpll_param.mpll_fb_divider.cl_kf);
-       mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
-                                                       MPLL_FUNC_CNTL_1, CLKFRAC, mpll_param.mpll_fb_divider.clk_frac);
-       mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
-                                                       MPLL_FUNC_CNTL_1, VCO_MODE, mpll_param.vco_mode);
-
-       /* MPLL_AD_FUNC_CNTL setup*/
-       mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
-                                                       MPLL_AD_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
-
-       if (data->is_memory_GDDR5) {
-               /* MPLL_DQ_FUNC_CNTL setup*/
-               mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
-                                                               MPLL_DQ_FUNC_CNTL, YCLK_SEL, mpll_param.yclk_sel);
-               mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
-                                                               MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
-               /*
-                ************************************
-                Fref = Reference Frequency
-                NF = Feedback divider ratio
-                NR = Reference divider ratio
-                Fnom = Nominal VCO output frequency = Fref * NF / NR
-                Fs = Spreading Rate
-                D = Percentage down-spread / 2
-                Fint = Reference input frequency to PFD = Fref / NR
-                NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
-                CLKS = NS - 1 = ISS_STEP_NUM[11:0]
-                NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
-                CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
-                *************************************
-                */
-               pp_atomctrl_internal_ss_info ss_info;
-               uint32_t freq_nom;
-               uint32_t tmp;
-               uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
-
-               /* for GDDR5 for all modes and DDR3 */
-               if (1 == mpll_param.qdr)
-                       freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
-               else
-                       freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
-
-               /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2  Note: S.I. reference_divider = 1*/
-               tmp = (freq_nom / reference_clock);
-               tmp = tmp * tmp;
-
-               if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
-                       /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
-                       /* ss.Info.speed_spectrum_rate -- in unit of khz */
-                       /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
-                       /*     = reference_clock * 5 / speed_spectrum_rate */
-                       uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
-
-                       /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
-                       /*     = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
-                       uint32_t clkv =
-                               (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
-                                                       ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
-
-                       mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
-                       mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
-               }
-       }
-
-       /* MCLK_PWRMGT_CNTL setup */
-       mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
-               MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
-       mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
-               MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
-       mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
-               MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
-
-
-       /* Save the result data to outpupt memory level structure */
-       mclk->MclkFrequency   = memory_clock;
-       mclk->MpllFuncCntl    = mpll_func_cntl;
-       mclk->MpllFuncCntl_1  = mpll_func_cntl_1;
-       mclk->MpllFuncCntl_2  = mpll_func_cntl_2;
-       mclk->MpllAdFuncCntl  = mpll_ad_func_cntl;
-       mclk->MpllDqFuncCntl  = mpll_dq_func_cntl;
-       mclk->MclkPwrmgtCntl  = mclk_pwrmgt_cntl;
-       mclk->DllCntl         = dll_cntl;
-       mclk->MpllSs1         = mpll_ss1;
-       mclk->MpllSs2         = mpll_ss2;
-
-       return 0;
-}
-
-static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock,
-               bool strobe_mode)
-{
-       uint8_t mc_para_index;
-
-       if (strobe_mode) {
-               if (memory_clock < 12500) {
-                       mc_para_index = 0x00;
-               } else if (memory_clock > 47500) {
-                       mc_para_index = 0x0f;
-               } else {
-                       mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
-               }
-       } else {
-               if (memory_clock < 65000) {
-                       mc_para_index = 0x00;
-               } else if (memory_clock > 135000) {
-                       mc_para_index = 0x0f;
-               } else {
-                       mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
-               }
-       }
-
-       return mc_para_index;
-}
-
-static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
-{
-       uint8_t mc_para_index;
-
-       if (memory_clock < 10000) {
-               mc_para_index = 0;
-       } else if (memory_clock >= 80000) {
-               mc_para_index = 0x0f;
-       } else {
-               mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
-       }
-
-       return mc_para_index;
-}
-
-static int tonga_populate_single_memory_level(
-               struct pp_hwmgr *hwmgr,
-               uint32_t memory_clock,
-               SMU72_Discrete_MemoryLevel *memory_level
-               )
-{
-       uint32_t minMvdd = 0;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       int result = 0;
-       bool dllStateOn;
-       struct cgs_display_info info = {0};
-
-
-       if (NULL != pptable_info->vdd_dep_on_mclk) {
-               result = tonga_get_dependecy_volt_by_clk(hwmgr,
-                       pptable_info->vdd_dep_on_mclk, memory_clock, &memory_level->MinVoltage, &minMvdd);
-               PP_ASSERT_WITH_CODE((0 == result),
-                       "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result);
-       }
-
-       if (data->mvdd_control == TONGA_VOLTAGE_CONTROL_NONE) {
-               memory_level->MinMvdd = data->vbios_boot_state.mvdd_bootup_value;
-       } else {
-               memory_level->MinMvdd = minMvdd;
-       }
-       memory_level->EnabledForThrottle = 1;
-       memory_level->EnabledForActivity = 0;
-       memory_level->UpHyst = 0;
-       memory_level->DownHyst = 100;
-       memory_level->VoltageDownHyst = 0;
-
-       /* Indicates maximum activity level for this performance level.*/
-       memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
-       memory_level->StutterEnable = 0;
-       memory_level->StrobeEnable = 0;
-       memory_level->EdcReadEnable = 0;
-       memory_level->EdcWriteEnable = 0;
-       memory_level->RttEnable = 0;
-
-       /* default set to low watermark. Highest level will be set to high later.*/
-       memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-       data->display_timing.num_existing_displays = info.display_count;
-
-       if ((data->mclk_stutter_mode_threshold != 0) &&
-           (memory_clock <= data->mclk_stutter_mode_threshold) &&
-           (!data->is_uvd_enabled)
-           && (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL, STUTTER_ENABLE) & 0x1)
-           && (data->display_timing.num_existing_displays <= 2)
-           && (data->display_timing.num_existing_displays != 0))
-               memory_level->StutterEnable = 1;
-
-       /* decide strobe mode*/
-       memory_level->StrobeEnable = (data->mclk_strobe_mode_threshold != 0) &&
-               (memory_clock <= data->mclk_strobe_mode_threshold);
-
-       /* decide EDC mode and memory clock ratio*/
-       if (data->is_memory_GDDR5) {
-               memory_level->StrobeRatio = tonga_get_mclk_frequency_ratio(memory_clock,
-                                       memory_level->StrobeEnable);
-
-               if ((data->mclk_edc_enable_threshold != 0) &&
-                               (memory_clock > data->mclk_edc_enable_threshold)) {
-                       memory_level->EdcReadEnable = 1;
-               }
-
-               if ((data->mclk_edc_wr_enable_threshold != 0) &&
-                               (memory_clock > data->mclk_edc_wr_enable_threshold)) {
-                       memory_level->EdcWriteEnable = 1;
-               }
-
-               if (memory_level->StrobeEnable) {
-                       if (tonga_get_mclk_frequency_ratio(memory_clock, 1) >=
-                                       ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf)) {
-                               dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
-                       } else {
-                               dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
-                       }
-
-               } else {
-                       dllStateOn = data->dll_defaule_on;
-               }
-       } else {
-               memory_level->StrobeRatio =
-                       tonga_get_ddr3_mclk_frequency_ratio(memory_clock);
-               dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
-       }
-
-       result = tonga_calculate_mclk_params(hwmgr,
-               memory_clock, memory_level, memory_level->StrobeEnable, dllStateOn);
-
-       if (0 == result) {
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinMvdd);
-               /* MCLK frequency in units of 10KHz*/
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
-               /* Indicates maximum activity level for this performance level.*/
-               CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
-               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
-       }
-
-       return result;
-}
-
-/**
- * Populates the SMC MVDD structure using the provided memory clock.
- *
- * @param    hwmgr      the address of the hardware manager
- * @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
- * @param    voltage     the SMC VOLTAGE structure to be populated
- */
-int tonga_populate_mvdd_value(struct pp_hwmgr *hwmgr, uint32_t mclk, SMIO_Pattern *smio_pattern)
-{
-       const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint32_t i = 0;
-
-       if (TONGA_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
-               /* find mvdd value which clock is more than request */
-               for (i = 0; i < pptable_info->vdd_dep_on_mclk->count; i++) {
-                       if (mclk <= pptable_info->vdd_dep_on_mclk->entries[i].clk) {
-                               /* Always round to higher voltage. */
-                               smio_pattern->Voltage = data->mvdd_voltage_table.entries[i].value;
-                               break;
-                       }
-               }
-
-               PP_ASSERT_WITH_CODE(i < pptable_info->vdd_dep_on_mclk->count,
-                       "MVDD Voltage is outside the supported range.", return -1);
-
-       } else {
-               return -1;
-       }
-
-       return 0;
-}
-
-
-static int tonga_populate_smv_acpi_level(struct pp_hwmgr *hwmgr,
-       SMU72_Discrete_DpmTable *table)
-{
-       int result = 0;
-       const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       pp_atomctrl_clock_dividers_vi dividers;
-       SMIO_Pattern voltage_level;
-       uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
-       uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
-       uint32_t dll_cntl          = data->clock_registers.vDLL_CNTL;
-       uint32_t mclk_pwrmgt_cntl  = data->clock_registers.vMCLK_PWRMGT_CNTL;
-
-       /* The ACPI state should not do DPM on DC (or ever).*/
-       table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
-
-       table->ACPILevel.MinVoltage = data->smc_state_table.GraphicsLevel[0].MinVoltage;
-
-       /* assign zero for now*/
-       table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
-
-       /* get the engine clock dividers for this clock value*/
-       result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
-               table->ACPILevel.SclkFrequency,  &dividers);
-
-       PP_ASSERT_WITH_CODE(result == 0,
-               "Error retrieving Engine Clock dividers from VBIOS.", return result);
-
-       /* divider ID for required SCLK*/
-       table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
-       table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
-       table->ACPILevel.DeepSleepDivId = 0;
-
-       spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
-                                                       CG_SPLL_FUNC_CNTL,   SPLL_PWRON,     0);
-       spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
-                                                       CG_SPLL_FUNC_CNTL,   SPLL_RESET,     1);
-       spll_func_cntl_2    = PHM_SET_FIELD(spll_func_cntl_2,
-                                                       CG_SPLL_FUNC_CNTL_2, SCLK_MUX_SEL,   4);
-
-       table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
-       table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
-       table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
-       table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
-       table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
-       table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
-       table->ACPILevel.CcPwrDynRm = 0;
-       table->ACPILevel.CcPwrDynRm1 = 0;
-
-
-       /* For various features to be enabled/disabled while this level is active.*/
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
-       /* SCLK frequency in units of 10KHz*/
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
-
-       /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
-       table->MemoryACPILevel.MinVoltage = data->smc_state_table.MemoryLevel[0].MinVoltage;
-
-       /*  CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
-
-       if (0 == tonga_populate_mvdd_value(hwmgr, 0, &voltage_level))
-               table->MemoryACPILevel.MinMvdd =
-                       PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
-       else
-               table->MemoryACPILevel.MinMvdd = 0;
-
-       /* Force reset on DLL*/
-       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
-               MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
-       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
-               MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
-
-       /* Disable DLL in ACPIState*/
-       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
-               MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
-       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
-               MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
-
-       /* Enable DLL bypass signal*/
-       dll_cntl            = PHM_SET_FIELD(dll_cntl,
-               DLL_CNTL, MRDCK0_BYPASS, 0);
-       dll_cntl            = PHM_SET_FIELD(dll_cntl,
-               DLL_CNTL, MRDCK1_BYPASS, 0);
-
-       table->MemoryACPILevel.DllCntl            =
-               PP_HOST_TO_SMC_UL(dll_cntl);
-       table->MemoryACPILevel.MclkPwrmgtCntl     =
-               PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
-       table->MemoryACPILevel.MpllAdFuncCntl     =
-               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
-       table->MemoryACPILevel.MpllDqFuncCntl     =
-               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
-       table->MemoryACPILevel.MpllFuncCntl       =
-               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
-       table->MemoryACPILevel.MpllFuncCntl_1     =
-               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
-       table->MemoryACPILevel.MpllFuncCntl_2     =
-               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
-       table->MemoryACPILevel.MpllSs1            =
-               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
-       table->MemoryACPILevel.MpllSs2            =
-               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
-
-       table->MemoryACPILevel.EnabledForThrottle = 0;
-       table->MemoryACPILevel.EnabledForActivity = 0;
-       table->MemoryACPILevel.UpHyst = 0;
-       table->MemoryACPILevel.DownHyst = 100;
-       table->MemoryACPILevel.VoltageDownHyst = 0;
-       /* Indicates maximum activity level for this performance level.*/
-       table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
-
-       table->MemoryACPILevel.StutterEnable = 0;
-       table->MemoryACPILevel.StrobeEnable = 0;
-       table->MemoryACPILevel.EdcReadEnable = 0;
-       table->MemoryACPILevel.EdcWriteEnable = 0;
-       table->MemoryACPILevel.RttEnable = 0;
-
-       return result;
-}
-
-static int tonga_find_boot_level(struct tonga_single_dpm_table *table, uint32_t value, uint32_t *boot_level)
-{
-       int result = 0;
-       uint32_t i;
-
-       for (i = 0; i < table->count; i++) {
-               if (value == table->dpm_levels[i].value) {
-                       *boot_level = i;
-                       result = 0;
-               }
-       }
-       return result;
-}
-
-static int tonga_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
-                       SMU72_Discrete_DpmTable *table)
-{
-       int result = 0;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       table->GraphicsBootLevel  = 0;        /* 0 == DPM[0] (low), etc. */
-       table->MemoryBootLevel    = 0;        /* 0 == DPM[0] (low), etc. */
-
-       /* find boot level from dpm table*/
-       result = tonga_find_boot_level(&(data->dpm_table.sclk_table),
-       data->vbios_boot_state.sclk_bootup_value,
-       (uint32_t *)&(data->smc_state_table.GraphicsBootLevel));
-
-       if (0 != result) {
-               data->smc_state_table.GraphicsBootLevel = 0;
-               printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
-                       in dependency table. Using Graphics DPM level 0!");
-               result = 0;
-       }
-
-       result = tonga_find_boot_level(&(data->dpm_table.mclk_table),
-               data->vbios_boot_state.mclk_bootup_value,
-               (uint32_t *)&(data->smc_state_table.MemoryBootLevel));
-
-       if (0 != result) {
-               data->smc_state_table.MemoryBootLevel = 0;
-               printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
-                       in dependency table. Using Memory DPM level 0!");
-               result = 0;
-       }
-
-       table->BootVoltage.Vddc =
-               tonga_get_voltage_id(&(data->vddc_voltage_table),
-                       data->vbios_boot_state.vddc_bootup_value);
-       table->BootVoltage.VddGfx =
-               tonga_get_voltage_id(&(data->vddgfx_voltage_table),
-                       data->vbios_boot_state.vddgfx_bootup_value);
-       table->BootVoltage.Vddci =
-               tonga_get_voltage_id(&(data->vddci_voltage_table),
-                       data->vbios_boot_state.vddci_bootup_value);
-       table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
-
-       CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
-
-       return result;
-}
-
-
-/**
- * Calculates the SCLK dividers using the provided engine clock
- *
- * @param    hwmgr      the address of the hardware manager
- * @param    engine_clock the engine clock to use to populate the structure
- * @param    sclk        the SMC SCLK structure to be populated
- */
-int tonga_calculate_sclk_params(struct pp_hwmgr *hwmgr,
-               uint32_t engine_clock, SMU72_Discrete_GraphicsLevel *sclk)
-{
-       const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       pp_atomctrl_clock_dividers_vi dividers;
-       uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
-       uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
-       uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
-       uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
-       uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
-       uint32_t    reference_clock;
-       uint32_t reference_divider;
-       uint32_t fbdiv;
-       int result;
-
-       /* get the engine clock dividers for this clock value*/
-       result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock,  &dividers);
-
-       PP_ASSERT_WITH_CODE(result == 0,
-               "Error retrieving Engine Clock dividers from VBIOS.", return result);
-
-       /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
-       reference_clock = atomctrl_get_reference_clock(hwmgr);
-
-       reference_divider = 1 + dividers.uc_pll_ref_div;
-
-       /* low 14 bits is fraction and high 12 bits is divider*/
-       fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
-
-       /* SPLL_FUNC_CNTL setup*/
-       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
-               CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div);
-       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
-               CG_SPLL_FUNC_CNTL, SPLL_PDIV_A,  dividers.uc_pll_post_div);
-
-       /* SPLL_FUNC_CNTL_3 setup*/
-       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
-               CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv);
-
-       /* set to use fractional accumulation*/
-       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
-               CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
-               pp_atomctrl_internal_ss_info ss_info;
-
-               uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div;
-               if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) {
-                       /*
-                       * ss_info.speed_spectrum_percentage -- in unit of 0.01%
-                       * ss_info.speed_spectrum_rate -- in unit of khz
-                       */
-                       /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
-                       uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate);
-
-                       /* clkv = 2 * D * fbdiv / NS */
-                       uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000);
-
-                       cg_spll_spread_spectrum =
-                               PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS);
-                       cg_spll_spread_spectrum =
-                               PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
-                       cg_spll_spread_spectrum_2 =
-                               PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV);
-               }
-       }
-
-       sclk->SclkFrequency        = engine_clock;
-       sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
-       sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
-       sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
-       sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
-       sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
-
-       return 0;
-}
-
-static uint8_t tonga_get_sleep_divider_id_from_clock(uint32_t engine_clock,
-               uint32_t min_engine_clock_in_sr)
-{
-       uint32_t i, temp;
-       uint32_t min = max(min_engine_clock_in_sr, (uint32_t)TONGA_MINIMUM_ENGINE_CLOCK);
-
-       PP_ASSERT_WITH_CODE((engine_clock >= min),
-                       "Engine clock can't satisfy stutter requirement!", return 0);
-
-       for (i = TONGA_MAX_DEEPSLEEP_DIVIDER_ID;; i--) {
-               temp = engine_clock >> i;
-
-               if(temp >= min || i == 0)
-                       break;
-       }
-       return (uint8_t)i;
-}
-
-/**
- * Populates single SMC SCLK structure using the provided engine clock
- *
- * @param    hwmgr      the address of the hardware manager
- * @param    engine_clock the engine clock to use to populate the structure
- * @param    sclk        the SMC SCLK structure to be populated
- */
-static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, uint32_t engine_clock, uint16_t sclk_activity_level_threshold, SMU72_Discrete_GraphicsLevel *graphic_level)
-{
-       int result;
-       uint32_t threshold;
-       uint32_t mvdd;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       result = tonga_calculate_sclk_params(hwmgr, engine_clock, graphic_level);
-
-
-       /* populate graphics levels*/
-       result = tonga_get_dependecy_volt_by_clk(hwmgr,
-               pptable_info->vdd_dep_on_sclk, engine_clock,
-               &graphic_level->MinVoltage, &mvdd);
-       PP_ASSERT_WITH_CODE((0 == result),
-               "can not find VDDC voltage value for VDDC       \
-               engine clock dependency table", return result);
-
-       /* SCLK frequency in units of 10KHz*/
-       graphic_level->SclkFrequency = engine_clock;
-
-       /* Indicates maximum activity level for this performance level. 50% for now*/
-       graphic_level->ActivityLevel = sclk_activity_level_threshold;
-
-       graphic_level->CcPwrDynRm = 0;
-       graphic_level->CcPwrDynRm1 = 0;
-       /* this level can be used if activity is high enough.*/
-       graphic_level->EnabledForActivity = 0;
-       /* this level can be used for throttling.*/
-       graphic_level->EnabledForThrottle = 1;
-       graphic_level->UpHyst = 0;
-       graphic_level->DownHyst = 0;
-       graphic_level->VoltageDownHyst = 0;
-       graphic_level->PowerThrottle = 0;
-
-       threshold = engine_clock * data->fast_watemark_threshold / 100;
-/*
-       *get the DAL clock. do it in funture.
-       PECI_GetMinClockSettings(hwmgr->peci, &minClocks);
-       data->display_timing.min_clock_insr = minClocks.engineClockInSR;
-*/
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_SclkDeepSleep))
-               graphic_level->DeepSleepDivId =
-                               tonga_get_sleep_divider_id_from_clock(engine_clock,
-                                               data->display_timing.min_clock_insr);
-
-       /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
-       graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
-
-       if (0 == result) {
-               /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
-               /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
-               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency);
-               CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel);
-               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3);
-               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4);
-               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum);
-               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2);
-               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm);
-               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1);
-       }
-
-       return result;
-}
-
-/**
- * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
- *
- * @param    hwmgr      the address of the hardware manager
- */
-static int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       struct tonga_dpm_table *dpm_table = &data->dpm_table;
-       phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
-       uint8_t pcie_entry_count = (uint8_t) data->dpm_table.pcie_speed_table.count;
-       int result = 0;
-       uint32_t level_array_adress = data->dpm_table_start +
-               offsetof(SMU72_Discrete_DpmTable, GraphicsLevel);
-       uint32_t level_array_size = sizeof(SMU72_Discrete_GraphicsLevel) *
-               SMU72_MAX_LEVELS_GRAPHICS;   /* 64 -> long; 32 -> int*/
-       SMU72_Discrete_GraphicsLevel *levels = data->smc_state_table.GraphicsLevel;
-       uint32_t i, maxEntry;
-       uint8_t highest_pcie_level_enabled = 0, lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0, count = 0;
-       PECI_RegistryValue reg_value;
-       memset(levels, 0x00, level_array_size);
-
-       for (i = 0; i < dpm_table->sclk_table.count; i++) {
-               result = tonga_populate_single_graphic_level(hwmgr,
-                                       dpm_table->sclk_table.dpm_levels[i].value,
-                                       (uint16_t)data->activity_target[i],
-                                       &(data->smc_state_table.GraphicsLevel[i]));
-
-               if (0 != result)
-                       return result;
-
-               /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
-               if (i > 1)
-                       data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
-
-               if (0 == i) {
-                       reg_value = 0;
-                       if (reg_value != 0)
-                               data->smc_state_table.GraphicsLevel[0].UpHyst = (uint8_t)reg_value;
-               }
-
-               if (1 == i) {
-                       reg_value = 0;
-                       if (reg_value != 0)
-                               data->smc_state_table.GraphicsLevel[1].UpHyst = (uint8_t)reg_value;
-               }
-       }
-
-       /* Only enable level 0 for now. */
-       data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
-
-       /* set highest level watermark to high */
-       if (dpm_table->sclk_table.count > 1)
-               data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark =
-                       PPSMC_DISPLAY_WATERMARK_HIGH;
-
-       data->smc_state_table.GraphicsDpmLevelCount =
-               (uint8_t)dpm_table->sclk_table.count;
-       data->dpm_level_enable_mask.sclk_dpm_enable_mask =
-               tonga_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
-
-       if (pcie_table != NULL) {
-               PP_ASSERT_WITH_CODE((pcie_entry_count >= 1),
-                       "There must be 1 or more PCIE levels defined in PPTable.", return -1);
-               maxEntry = pcie_entry_count - 1; /* for indexing, we need to decrement by 1.*/
-               for (i = 0; i < dpm_table->sclk_table.count; i++) {
-                       data->smc_state_table.GraphicsLevel[i].pcieDpmLevel =
-                               (uint8_t) ((i < maxEntry) ? i : maxEntry);
-               }
-       } else {
-               if (0 == data->dpm_level_enable_mask.pcie_dpm_enable_mask)
-                       printk(KERN_ERR "[ powerplay ] Pcie Dpm Enablemask is 0!");
-
-               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
-                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
-                                       (1<<(highest_pcie_level_enabled+1))) != 0)) {
-                       highest_pcie_level_enabled++;
-               }
-
-               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
-                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
-                                       (1<<lowest_pcie_level_enabled)) == 0)) {
-                       lowest_pcie_level_enabled++;
-               }
-
-               while ((count < highest_pcie_level_enabled) &&
-                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
-                                       (1<<(lowest_pcie_level_enabled+1+count))) == 0)) {
-                       count++;
-               }
-               mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ?
-                       (lowest_pcie_level_enabled+1+count) : highest_pcie_level_enabled;
-
-
-               /* set pcieDpmLevel to highest_pcie_level_enabled*/
-               for (i = 2; i < dpm_table->sclk_table.count; i++) {
-                       data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled;
-               }
-
-               /* set pcieDpmLevel to lowest_pcie_level_enabled*/
-               data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled;
-
-               /* set pcieDpmLevel to mid_pcie_level_enabled*/
-               data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled;
-       }
-       /* level count will send to smc once at init smc table and never change*/
-       result = tonga_copy_bytes_to_smc(hwmgr->smumgr, level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end);
-
-       if (0 != result)
-               return result;
-
-       return 0;
-}
-
-/**
- * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
- *
- * @param    hwmgr      the address of the hardware manager
- */
-
-static int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_dpm_table *dpm_table = &data->dpm_table;
-       int result;
-       /* populate MCLK dpm table to SMU7 */
-       uint32_t level_array_adress = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, MemoryLevel);
-       uint32_t level_array_size = sizeof(SMU72_Discrete_MemoryLevel) * SMU72_MAX_LEVELS_MEMORY;
-       SMU72_Discrete_MemoryLevel *levels = data->smc_state_table.MemoryLevel;
-       uint32_t i;
-
-       memset(levels, 0x00, level_array_size);
-
-       for (i = 0; i < dpm_table->mclk_table.count; i++) {
-               PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
-                       "can not populate memory level as memory clock is zero", return -1);
-               result = tonga_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value,
-                       &(data->smc_state_table.MemoryLevel[i]));
-               if (0 != result) {
-                       return result;
-               }
-       }
-
-       /* Only enable level 0 for now.*/
-       data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
-
-       /*
-       * in order to prevent MC activity from stutter mode to push DPM up.
-       * the UVD change complements this by putting the MCLK in a higher state
-       * by default such that we are not effected by up threshold or and MCLK DPM latency.
-       */
-       data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
-       CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.MemoryLevel[0].ActivityLevel);
-
-       data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
-       data->dpm_level_enable_mask.mclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
-       /* set highest level watermark to high*/
-       data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
-
-       /* level count will send to smc once at init smc table and never change*/
-       result = tonga_copy_bytes_to_smc(hwmgr->smumgr,
-               level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end);
-
-       if (0 != result) {
-               return result;
-       }
-
-       return 0;
-}
-
-struct TONGA_DLL_SPEED_SETTING {
-       uint16_t            Min;                          /* Minimum Data Rate*/
-       uint16_t            Max;                          /* Maximum Data Rate*/
-       uint32_t                        dll_speed;                     /* The desired DLL_SPEED setting*/
-};
-
-static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
-{
-       return 0;
-}
-
-/* ---------------------------------------- ULV related functions ----------------------------------------------------*/
-
-
-static int tonga_reset_single_dpm_table(
-       struct pp_hwmgr *hwmgr,
-       struct tonga_single_dpm_table *dpm_table,
-       uint32_t count)
-{
-       uint32_t i;
-       if (!(count <= MAX_REGULAR_DPM_NUMBER))
-               printk(KERN_ERR "[ powerplay ] Fatal error, can not set up single DPM \
-                       table entries to exceed max number! \n");
-
-       dpm_table->count = count;
-       for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++) {
-               dpm_table->dpm_levels[i].enabled = false;
-       }
-
-       return 0;
-}
-
-static void tonga_setup_pcie_table_entry(
-       struct tonga_single_dpm_table *dpm_table,
-       uint32_t index, uint32_t pcie_gen,
-       uint32_t pcie_lanes)
-{
-       dpm_table->dpm_levels[index].value = pcie_gen;
-       dpm_table->dpm_levels[index].param1 = pcie_lanes;
-       dpm_table->dpm_levels[index].enabled = true;
-}
-
-static int tonga_setup_default_pcie_tables(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
-       uint32_t i, maxEntry;
-
-       if (data->use_pcie_performance_levels && !data->use_pcie_power_saving_levels) {
-               data->pcie_gen_power_saving = data->pcie_gen_performance;
-               data->pcie_lane_power_saving = data->pcie_lane_performance;
-       } else if (!data->use_pcie_performance_levels && data->use_pcie_power_saving_levels) {
-               data->pcie_gen_performance = data->pcie_gen_power_saving;
-               data->pcie_lane_performance = data->pcie_lane_power_saving;
-       }
-
-       tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.pcie_speed_table, SMU72_MAX_LEVELS_LINK);
-
-       if (pcie_table != NULL) {
-               /*
-               * maxEntry is used to make sure we reserve one PCIE level for boot level (fix for A+A PSPP issue).
-               * If PCIE table from PPTable have ULV entry + 8 entries, then ignore the last entry.
-               */
-               maxEntry = (SMU72_MAX_LEVELS_LINK < pcie_table->count) ?
-                                               SMU72_MAX_LEVELS_LINK : pcie_table->count;
-               for (i = 1; i < maxEntry; i++) {
-                       tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i-1,
-                               get_pcie_gen_support(data->pcie_gen_cap, pcie_table->entries[i].gen_speed),
-                               get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
-               }
-               data->dpm_table.pcie_speed_table.count = maxEntry - 1;
-       } else {
-               /* Hardcode Pcie Table */
-               tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
-                       get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
-                       get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
-               tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
-                       get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
-                       get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
-               tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
-                       get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
-                       get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
-               tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
-                       get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
-                       get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
-               tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
-                       get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
-                       get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
-               tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
-                       get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
-                       get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
-               data->dpm_table.pcie_speed_table.count = 6;
-       }
-       /* Populate last level for boot PCIE level, but do not increment count. */
-       tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
-               data->dpm_table.pcie_speed_table.count,
-               get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
-               get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
-
-       return 0;
-
-}
-
-/*
- * This function is to initalize all DPM state tables for SMU7 based on the dependency table.
- * Dynamic state patching function will then trim these state tables to the allowed range based
- * on the power policy or external client requests, such as UVD request, etc.
- */
-static int tonga_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint32_t i;
-
-       phm_ppt_v1_clock_voltage_dependency_table *allowed_vdd_sclk_table =
-               pptable_info->vdd_dep_on_sclk;
-       phm_ppt_v1_clock_voltage_dependency_table *allowed_vdd_mclk_table =
-               pptable_info->vdd_dep_on_mclk;
-
-       PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
-               "SCLK dependency table is missing. This table is mandatory", return -1);
-       PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table->count >= 1,
-               "SCLK dependency table has to have is missing. This table is mandatory", return -1);
-
-       PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
-               "MCLK dependency table is missing. This table is mandatory", return -1);
-       PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table->count >= 1,
-               "VMCLK dependency table has to have is missing. This table is mandatory", return -1);
-
-       /* clear the state table to reset everything to default */
-       memset(&(data->dpm_table), 0x00, sizeof(data->dpm_table));
-       tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.sclk_table, SMU72_MAX_LEVELS_GRAPHICS);
-       tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.mclk_table, SMU72_MAX_LEVELS_MEMORY);
-       /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.VddcTable, SMU72_MAX_LEVELS_VDDC); */
-       /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_gfx_table, SMU72_MAX_LEVELS_VDDGFX);*/
-       /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_ci_table, SMU72_MAX_LEVELS_VDDCI);*/
-       /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.mvdd_table, SMU72_MAX_LEVELS_MVDD);*/
-
-       PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
-               "SCLK dependency table is missing. This table is mandatory", return -1);
-       /* Initialize Sclk DPM table based on allow Sclk values*/
-       data->dpm_table.sclk_table.count = 0;
-
-       for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
-               if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value !=
-                               allowed_vdd_sclk_table->entries[i].clk) {
-                       data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
-                               allowed_vdd_sclk_table->entries[i].clk;
-                       data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = true; /*(i==0) ? 1 : 0; to do */
-                       data->dpm_table.sclk_table.count++;
-               }
-       }
-
-       PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
-               "MCLK dependency table is missing. This table is mandatory", return -1);
-       /* Initialize Mclk DPM table based on allow Mclk values */
-       data->dpm_table.mclk_table.count = 0;
-       for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
-               if (i == 0 || data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count-1].value !=
-                       allowed_vdd_mclk_table->entries[i].clk) {
-                       data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
-                               allowed_vdd_mclk_table->entries[i].clk;
-                       data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = true; /*(i==0) ? 1 : 0; */
-                       data->dpm_table.mclk_table.count++;
-               }
-       }
-
-       /* setup PCIE gen speed levels*/
-       tonga_setup_default_pcie_tables(hwmgr);
-
-       /* save a copy of the default DPM table*/
-       memcpy(&(data->golden_dpm_table), &(data->dpm_table), sizeof(struct tonga_dpm_table));
-
-       return 0;
-}
-
-int tonga_populate_smc_initial_state(struct pp_hwmgr *hwmgr,
-               const struct tonga_power_state *bootState)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       uint8_t count, level;
-
-       count = (uint8_t) (pptable_info->vdd_dep_on_sclk->count);
-       for (level = 0; level < count; level++) {
-               if (pptable_info->vdd_dep_on_sclk->entries[level].clk >=
-                       bootState->performance_levels[0].engine_clock) {
-                       data->smc_state_table.GraphicsBootLevel = level;
-                       break;
-               }
-       }
-
-       count = (uint8_t) (pptable_info->vdd_dep_on_mclk->count);
-       for (level = 0; level < count; level++) {
-               if (pptable_info->vdd_dep_on_mclk->entries[level].clk >=
-                       bootState->performance_levels[0].memory_clock) {
-                       data->smc_state_table.MemoryBootLevel = level;
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-/**
- * Initializes the SMC table and uploads it
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @param    pInput  the pointer to input data (PowerState)
- * @return   always 0
- */
-int tonga_init_smc_table(struct pp_hwmgr *hwmgr)
-{
-       int result;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       SMU72_Discrete_DpmTable  *table = &(data->smc_state_table);
-       const phw_tonga_ulv_parm *ulv = &(data->ulv);
-       uint8_t i;
-       PECI_RegistryValue reg_value;
-       pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
-
-       result = tonga_setup_default_dpm_tables(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to setup default DPM tables!", return result;);
-       memset(&(data->smc_state_table), 0x00, sizeof(data->smc_state_table));
-       if (TONGA_VOLTAGE_CONTROL_NONE != data->voltage_control) {
-               tonga_populate_smc_voltage_tables(hwmgr, table);
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_AutomaticDCTransition)) {
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_StepVddc)) {
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
-       }
-
-       if (data->is_memory_GDDR5) {
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
-       }
-
-       i = PHM_READ_FIELD(hwmgr->device, CC_MC_MAX_CHANNEL, NOOFCHAN);
-
-       if (i == 1 || i == 0) {
-               table->SystemFlags |= PPSMC_SYSTEMFLAG_12CHANNEL;
-       }
-
-       if (ulv->ulv_supported && pptable_info->us_ulv_voltage_offset) {
-               PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to initialize ULV state!", return result;);
-
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCG_ULV_PARAMETER, ulv->ch_ulv_parameter);
-       }
-
-       result = tonga_populate_smc_link_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize Link Level!", return result;);
-
-       result = tonga_populate_all_graphic_levels(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize Graphics Level!", return result;);
-
-       result = tonga_populate_all_memory_levels(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize Memory Level!", return result;);
-
-       result = tonga_populate_smv_acpi_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize ACPI Level!", return result;);
-
-       result = tonga_populate_smc_vce_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize VCE Level!", return result;);
-
-       result = tonga_populate_smc_acp_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize ACP Level!", return result;);
-
-       result = tonga_populate_smc_samu_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize SAMU Level!", return result;);
-
-       /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
-       /* need to populate the  ARB settings for the initial state. */
-       result = tonga_program_memory_timing_parameters(hwmgr);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to Write ARB settings for the initial state.", return result;);
-
-       result = tonga_populate_smc_uvd_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize UVD Level!", return result;);
-
-       result = tonga_populate_smc_boot_level(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize Boot Level!", return result;);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ClockStretcher)) {
-               result = tonga_populate_clock_stretcher_data_table(hwmgr);
-               PP_ASSERT_WITH_CODE(0 == result,
-                       "Failed to populate Clock Stretcher Data Table!", return result;);
-       }
-       table->GraphicsVoltageChangeEnable  = 1;
-       table->GraphicsThermThrottleEnable  = 1;
-       table->GraphicsInterval = 1;
-       table->VoltageInterval  = 1;
-       table->ThermalInterval  = 1;
-       table->TemperatureLimitHigh =
-               pptable_info->cac_dtp_table->usTargetOperatingTemp *
-               TONGA_Q88_FORMAT_CONVERSION_UNIT;
-       table->TemperatureLimitLow =
-               (pptable_info->cac_dtp_table->usTargetOperatingTemp - 1) *
-               TONGA_Q88_FORMAT_CONVERSION_UNIT;
-       table->MemoryVoltageChangeEnable  = 1;
-       table->MemoryInterval  = 1;
-       table->VoltageResponseTime  = 0;
-       table->PhaseResponseTime  = 0;
-       table->MemoryThermThrottleEnable  = 1;
-
-       /*
-       * Cail reads current link status and reports it as cap (we cannot change this due to some previous issues we had)
-       * SMC drops the link status to lowest level after enabling DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
-       * but this time Cail reads current link status which was set to low by SMC and reports it as cap to powerplay
-       * To avoid it, we set PCIeBootLinkLevel to highest dpm level
-       */
-       PP_ASSERT_WITH_CODE((1 <= data->dpm_table.pcie_speed_table.count),
-                       "There must be 1 or more PCIE levels defined in PPTable.",
-                       return -1);
-
-       table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count);
-
-       table->PCIeGenInterval  = 1;
-
-       result = tonga_populate_vr_config(hwmgr, table);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to populate VRConfig setting!", return result);
-
-       table->ThermGpio  = 17;
-       table->SclkStepSize = 0x4000;
-
-       reg_value = 0;
-       if ((0 == reg_value) &&
-               (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID,
-                                               &gpio_pin_assignment))) {
-               table->VRHotGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_RegulatorHot);
-       } else {
-               table->VRHotGpio = TONGA_UNUSED_GPIO_PIN;
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_RegulatorHot);
-       }
-
-       /* ACDC Switch GPIO */
-       reg_value = 0;
-       if ((0 == reg_value) &&
-               (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
-                                               &gpio_pin_assignment))) {
-               table->AcDcGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_AutomaticDCTransition);
-       } else {
-               table->AcDcGpio = TONGA_UNUSED_GPIO_PIN;
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_AutomaticDCTransition);
-       }
-
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_Falcon_QuickTransition);
-
-       reg_value = 0;
-       if (1 == reg_value) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_AutomaticDCTransition);
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_Falcon_QuickTransition);
-       }
-
-       reg_value = 0;
-       if ((0 == reg_value) && (atomctrl_get_pp_assign_pin(hwmgr,
-                       THERMAL_INT_OUTPUT_GPIO_PINID, &gpio_pin_assignment))) {
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ThermalOutGPIO);
-
-               table->ThermOutGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
-
-               table->ThermOutPolarity =
-                       (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
-                       (1 << gpio_pin_assignment.uc_gpio_pin_bit_shift))) ? 1:0;
-
-               table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
-
-               /* if required, combine VRHot/PCC with thermal out GPIO*/
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_RegulatorHot) &&
-                       phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_CombinePCCWithThermalSignal)){
-                       table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
-               }
-       } else {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ThermalOutGPIO);
-
-               table->ThermOutGpio = 17;
-               table->ThermOutPolarity = 1;
-               table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
-       }
-
-       for (i = 0; i < SMU72_MAX_ENTRIES_SMIO; i++) {
-               table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
-       }
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
-       CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
-       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
-       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
-       CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
-       CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
-
-       /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
-       result = tonga_copy_bytes_to_smc(hwmgr->smumgr, data->dpm_table_start +
-                                                                               offsetof(SMU72_Discrete_DpmTable, SystemFlags),
-                                                                               (uint8_t *)&(table->SystemFlags),
-                                                                               sizeof(SMU72_Discrete_DpmTable)-3 * sizeof(SMU72_PIDController),
-                                                                               data->sram_end);
-
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to upload dpm data to SMC memory!", return result;);
-
-       return result;
-}
-
-/* Look up the voltaged based on DAL's requested level. and then send the requested VDDC voltage to SMC*/
-static void tonga_apply_dal_minimum_voltage_request(struct pp_hwmgr *hwmgr)
-{
-       return;
-}
-
-int tonga_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
-{
-       PPSMC_Result result;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       /* Apply minimum voltage based on DAL's request level */
-       tonga_apply_dal_minimum_voltage_request(hwmgr);
-
-       if (0 == data->sclk_dpm_key_disabled) {
-               /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
-               if (tonga_is_dpm_running(hwmgr))
-                       printk(KERN_ERR "[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
-
-               if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
-                       result = smum_send_msg_to_smc_with_parameter(
-                                                               hwmgr->smumgr,
-                               (PPSMC_Msg)PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                               data->dpm_level_enable_mask.sclk_dpm_enable_mask);
-                       PP_ASSERT_WITH_CODE((0 == result),
-                               "Set Sclk Dpm enable Mask failed", return -1);
-               }
-       }
-
-       if (0 == data->mclk_dpm_key_disabled) {
-               /* Checking if DPM is running.  If we discover hang because of this, we should skip this message.*/
-               if (tonga_is_dpm_running(hwmgr))
-                       printk(KERN_ERR "[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
-
-               if (0 != data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
-                       result = smum_send_msg_to_smc_with_parameter(
-                                                               hwmgr->smumgr,
-                               (PPSMC_Msg)PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                               data->dpm_level_enable_mask.mclk_dpm_enable_mask);
-                       PP_ASSERT_WITH_CODE((0 == result),
-                               "Set Mclk Dpm enable Mask failed", return -1);
-               }
-       }
-
-       return 0;
-}
-
-
-int tonga_force_dpm_highest(struct pp_hwmgr *hwmgr)
-{
-       uint32_t level, tmp;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       if (0 == data->pcie_dpm_key_disabled) {
-               /* PCIE */
-               if (data->dpm_level_enable_mask.pcie_dpm_enable_mask != 0) {
-                       level = 0;
-                       tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
-                       while (tmp >>= 1)
-                               level++ ;
-
-                       if (0 != level) {
-                               PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr, level)),
-                                       "force highest pcie dpm state failed!", return -1);
-                       }
-               }
-       }
-
-       if (0 == data->sclk_dpm_key_disabled) {
-               /* SCLK */
-               if (data->dpm_level_enable_mask.sclk_dpm_enable_mask != 0) {
-                       level = 0;
-                       tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
-                       while (tmp >>= 1)
-                               level++ ;
-
-                       if (0 != level) {
-                               PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr, level)),
-                                       "force highest sclk dpm state failed!", return -1);
-                               if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
-                                       CGS_IND_REG__SMC, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX) != level)
-                                       printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
-                                               Curr_Sclk_Index does not match the level \n");
-
-                       }
-               }
-       }
-
-       if (0 == data->mclk_dpm_key_disabled) {
-               /* MCLK */
-               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask != 0) {
-                       level = 0;
-                       tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
-                       while (tmp >>= 1)
-                               level++ ;
-
-                       if (0 != level) {
-                               PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr, level)),
-                                       "force highest mclk dpm state failed!", return -1);
-                               if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                                       TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX) != level)
-                                       printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
-                                               Curr_Mclk_Index does not match the level \n");
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/**
- * Find the MC microcode version and store it in the HwMgr struct
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr)
-{
-       cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX, 0x9F);
-
-       hwmgr->microcode_version_info.MC = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA);
-
-       return 0;
-}
-
-/**
- * Initialize Dynamic State Adjustment Rule Settings
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- */
-int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
-{
-       uint32_t table_size;
-       struct phm_clock_voltage_dependency_table *table_clk_vlt;
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       hwmgr->dyn_state.mclk_sclk_ratio = 4;
-       hwmgr->dyn_state.sclk_mclk_delta = 15000;      /* 150 MHz */
-       hwmgr->dyn_state.vddc_vddci_delta = 200;       /* 200mV */
-
-       /* initialize vddc_dep_on_dal_pwrl table */
-       table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record);
-       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");
-               return -ENOMEM;
-       } else {
-               table_clk_vlt->count = 4;
-               table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
-               table_clk_vlt->entries[0].v = 0;
-               table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
-               table_clk_vlt->entries[1].v = 720;
-               table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
-               table_clk_vlt->entries[2].v = 810;
-               table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
-               table_clk_vlt->entries[3].v = 900;
-               pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
-               hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
-       }
-
-       return 0;
-}
-
-static int tonga_set_private_var_based_on_pptale(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
-               pptable_info->vdd_dep_on_sclk;
-       phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
-               pptable_info->vdd_dep_on_mclk;
-
-       PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
-               "VDD dependency on SCLK table is missing.       \
-               This table is mandatory", return -1);
-       PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
-               "VDD dependency on SCLK table has to have is missing.   \
-               This table is mandatory", return -1);
-
-       PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
-               "VDD dependency on MCLK table is missing.       \
-               This table is mandatory", return -1);
-       PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
-               "VDD dependency on MCLK table has to have is missing.    \
-               This table is mandatory", return -1);
-
-       data->min_vddc_in_pp_table = (uint16_t)allowed_sclk_vdd_table->entries[0].vddc;
-       data->max_vddc_in_pp_table = (uint16_t)allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
-
-       pptable_info->max_clock_voltage_on_ac.sclk =
-               allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
-       pptable_info->max_clock_voltage_on_ac.mclk =
-               allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
-       pptable_info->max_clock_voltage_on_ac.vddc =
-               allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
-       pptable_info->max_clock_voltage_on_ac.vddci =
-               allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
-
-       hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
-               pptable_info->max_clock_voltage_on_ac.sclk;
-       hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
-               pptable_info->max_clock_voltage_on_ac.mclk;
-       hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
-               pptable_info->max_clock_voltage_on_ac.vddc;
-       hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
-               pptable_info->max_clock_voltage_on_ac.vddci;
-
-       return 0;
-}
-
-int tonga_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       int result = 1;
-
-       PP_ASSERT_WITH_CODE (!tonga_is_dpm_running(hwmgr),
-                            "Trying to Unforce DPM when DPM is disabled. Returning without sending SMC message.",
-                            return result);
-
-       if (0 == data->pcie_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(
-                                                            hwmgr->smumgr,
-                                       PPSMC_MSG_PCIeDPM_UnForceLevel)),
-                                          "unforce pcie level failed!",
-                                                               return -1);
-       }
-
-       result = tonga_upload_dpm_level_enable_mask(hwmgr);
-
-       return result;
-}
-
-static uint32_t tonga_get_lowest_enable_level(
-                               struct pp_hwmgr *hwmgr, uint32_t level_mask)
-{
-       uint32_t level = 0;
-
-       while (0 == (level_mask & (1 << level)))
-               level++;
-
-       return level;
-}
-
-static int tonga_force_dpm_lowest(struct pp_hwmgr *hwmgr)
-{
-       uint32_t level;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       if (0 == data->pcie_dpm_key_disabled) {
-               /* PCIE */
-               if (data->dpm_level_enable_mask.pcie_dpm_enable_mask != 0) {
-                       level = tonga_get_lowest_enable_level(hwmgr,
-                                                             data->dpm_level_enable_mask.pcie_dpm_enable_mask);
-                       PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr, level)),
-                                           "force lowest pcie dpm state failed!", return -1);
-               }
-       }
-
-       if (0 == data->sclk_dpm_key_disabled) {
-               /* SCLK */
-               if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
-                       level = tonga_get_lowest_enable_level(hwmgr,
-                                                             data->dpm_level_enable_mask.sclk_dpm_enable_mask);
-
-                       PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr, level)),
-                                           "force sclk dpm state failed!", return -1);
-
-                       if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
-                                                        CGS_IND_REG__SMC, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX) != level)
-                               printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index.        \
-                               Curr_Sclk_Index does not match the level \n");
-               }
-       }
-
-       if (0 == data->mclk_dpm_key_disabled) {
-               /* MCLK */
-               if (data->dpm_level_enable_mask.mclk_dpm_enable_mask != 0) {
-                       level = tonga_get_lowest_enable_level(hwmgr,
-                                                             data->dpm_level_enable_mask.mclk_dpm_enable_mask);
-                       PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr, level)),
-                                           "force lowest mclk dpm state failed!", return -1);
-                       if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                                                        TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX) != level)
-                               printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
-                                               Curr_Mclk_Index does not match the level \n");
-               }
-       }
-
-       return 0;
-}
-
-static int tonga_patch_voltage_dependency_tables_with_lookup_table(struct pp_hwmgr *hwmgr)
-{
-       uint8_t entryId;
-       uint8_t voltageId;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
-       phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
-       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
-
-       if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
-               for (entryId = 0; entryId < sclk_table->count; ++entryId) {
-                       voltageId = sclk_table->entries[entryId].vddInd;
-                       sclk_table->entries[entryId].vddgfx =
-                               pptable_info->vddgfx_lookup_table->entries[voltageId].us_vdd;
-               }
-       } else {
-               for (entryId = 0; entryId < sclk_table->count; ++entryId) {
-                       voltageId = sclk_table->entries[entryId].vddInd;
-                       sclk_table->entries[entryId].vddc =
-                               pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
-               }
-       }
-
-       for (entryId = 0; entryId < mclk_table->count; ++entryId) {
-               voltageId = mclk_table->entries[entryId].vddInd;
-               mclk_table->entries[entryId].vddc =
-                       pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
-       }
-
-       for (entryId = 0; entryId < mm_table->count; ++entryId) {
-               voltageId = mm_table->entries[entryId].vddcInd;
-               mm_table->entries[entryId].vddc =
-                       pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
-       }
-
-       return 0;
-
-}
-
-static int tonga_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
-{
-       uint8_t entryId;
-       phm_ppt_v1_voltage_lookup_record v_record;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
-       phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
-
-       if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
-               for (entryId = 0; entryId < sclk_table->count; ++entryId) {
-                       if (sclk_table->entries[entryId].vdd_offset & (1 << 15))
-                               v_record.us_vdd = sclk_table->entries[entryId].vddgfx +
-                                       sclk_table->entries[entryId].vdd_offset - 0xFFFF;
-                       else
-                               v_record.us_vdd = sclk_table->entries[entryId].vddgfx +
-                                       sclk_table->entries[entryId].vdd_offset;
-
-                       sclk_table->entries[entryId].vddc =
-                               v_record.us_cac_low = v_record.us_cac_mid =
-                               v_record.us_cac_high = v_record.us_vdd;
-
-                       tonga_add_voltage(hwmgr, pptable_info->vddc_lookup_table, &v_record);
-               }
-
-               for (entryId = 0; entryId < mclk_table->count; ++entryId) {
-                       if (mclk_table->entries[entryId].vdd_offset & (1 << 15))
-                               v_record.us_vdd = mclk_table->entries[entryId].vddc +
-                                       mclk_table->entries[entryId].vdd_offset - 0xFFFF;
-                       else
-                               v_record.us_vdd = mclk_table->entries[entryId].vddc +
-                                       mclk_table->entries[entryId].vdd_offset;
-
-                       mclk_table->entries[entryId].vddgfx = v_record.us_cac_low =
-                               v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
-                       tonga_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
-               }
-       }
-
-       return 0;
-
-}
-
-static int tonga_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
-{
-       uint32_t entryId;
-       phm_ppt_v1_voltage_lookup_record v_record;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
-
-       if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
-               for (entryId = 0; entryId < mm_table->count; entryId++) {
-                       if (mm_table->entries[entryId].vddgfx_offset & (1 << 15))
-                               v_record.us_vdd = mm_table->entries[entryId].vddc +
-                                       mm_table->entries[entryId].vddgfx_offset - 0xFFFF;
-                       else
-                               v_record.us_vdd = mm_table->entries[entryId].vddc +
-                                       mm_table->entries[entryId].vddgfx_offset;
-
-                       /* Add the calculated VDDGFX to the VDDGFX lookup table */
-                       mm_table->entries[entryId].vddgfx = v_record.us_cac_low =
-                               v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
-                       tonga_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
-               }
-       }
-       return 0;
-}
-
-
-/**
- * Change virtual leakage voltage to actual value.
- *
- * @param     hwmgr  the address of the powerplay hardware manager.
- * @param     pointer to changing voltage
- * @param     pointer to leakage table
- */
-static void tonga_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
-               uint16_t *voltage, phw_tonga_leakage_voltage *pLeakageTable)
-{
-       uint32_t leakage_index;
-
-       /* search for leakage voltage ID 0xff01 ~ 0xff08 */
-       for (leakage_index = 0; leakage_index < pLeakageTable->count; leakage_index++) {
-               /* if this voltage matches a leakage voltage ID */
-               /* patch with actual leakage voltage */
-               if (pLeakageTable->leakage_id[leakage_index] == *voltage) {
-                       *voltage = pLeakageTable->actual_voltage[leakage_index];
-                       break;
-               }
-       }
-
-       if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
-               printk(KERN_ERR "[ powerplay ] Voltage value looks like a Leakage ID but it's not patched \n");
-}
-
-/**
- * Patch voltage lookup table by EVV leakages.
- *
- * @param     hwmgr  the address of the powerplay hardware manager.
- * @param     pointer to voltage lookup table
- * @param     pointer to leakage table
- * @return     always 0
- */
-static int tonga_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_voltage_lookup_table *lookup_table,
-               phw_tonga_leakage_voltage *pLeakageTable)
-{
-       uint32_t i;
-
-       for (i = 0; i < lookup_table->count; i++) {
-               tonga_patch_with_vdd_leakage(hwmgr,
-                       &lookup_table->entries[i].us_vdd, pLeakageTable);
-       }
-
-       return 0;
-}
-
-static int tonga_patch_clock_voltage_lomits_with_vddc_leakage(struct pp_hwmgr *hwmgr,
-               phw_tonga_leakage_voltage *pLeakageTable, uint16_t *Vddc)
-{
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       tonga_patch_with_vdd_leakage(hwmgr, (uint16_t *)Vddc, pLeakageTable);
-       hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
-               pptable_info->max_clock_voltage_on_dc.vddc;
-
-       return 0;
-}
-
-static int tonga_patch_clock_voltage_limits_with_vddgfx_leakage(
-               struct pp_hwmgr *hwmgr, phw_tonga_leakage_voltage *pLeakageTable,
-               uint16_t *Vddgfx)
-{
-       tonga_patch_with_vdd_leakage(hwmgr, (uint16_t *)Vddgfx, pLeakageTable);
-       return 0;
-}
-
-int tonga_sort_lookup_table(struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_voltage_lookup_table *lookup_table)
-{
-       uint32_t table_size, i, j;
-       phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
-       table_size = lookup_table->count;
-
-       PP_ASSERT_WITH_CODE(0 != lookup_table->count,
-               "Lookup table is empty", return -1);
-
-       /* Sorting voltages */
-       for (i = 0; i < table_size - 1; i++) {
-               for (j = i + 1; j > 0; j--) {
-                       if (lookup_table->entries[j].us_vdd < lookup_table->entries[j-1].us_vdd) {
-                               tmp_voltage_lookup_record = lookup_table->entries[j-1];
-                               lookup_table->entries[j-1] = lookup_table->entries[j];
-                               lookup_table->entries[j] = tmp_voltage_lookup_record;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int tonga_complete_dependency_tables(struct pp_hwmgr *hwmgr)
-{
-       int result = 0;
-       int tmp_result;
-       tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
-               tmp_result = tonga_patch_lookup_table_with_leakage(hwmgr,
-                       pptable_info->vddgfx_lookup_table, &(data->vddcgfx_leakage));
-               if (tmp_result != 0)
-                       result = tmp_result;
-
-               tmp_result = tonga_patch_clock_voltage_limits_with_vddgfx_leakage(hwmgr,
-                       &(data->vddcgfx_leakage), &pptable_info->max_clock_voltage_on_dc.vddgfx);
-               if (tmp_result != 0)
-                       result = tmp_result;
-       } else {
-               tmp_result = tonga_patch_lookup_table_with_leakage(hwmgr,
-                       pptable_info->vddc_lookup_table, &(data->vddc_leakage));
-               if (tmp_result != 0)
-                       result = tmp_result;
-
-               tmp_result = tonga_patch_clock_voltage_lomits_with_vddc_leakage(hwmgr,
-                       &(data->vddc_leakage), &pptable_info->max_clock_voltage_on_dc.vddc);
-               if (tmp_result != 0)
-                       result = tmp_result;
-       }
-
-       tmp_result = tonga_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
-       if (tmp_result != 0)
-               result = tmp_result;
-
-       tmp_result = tonga_calc_voltage_dependency_tables(hwmgr);
-       if (tmp_result != 0)
-               result = tmp_result;
-
-       tmp_result = tonga_calc_mm_voltage_dependency_table(hwmgr);
-       if (tmp_result != 0)
-               result = tmp_result;
-
-       tmp_result = tonga_sort_lookup_table(hwmgr, pptable_info->vddgfx_lookup_table);
-       if (tmp_result != 0)
-               result = tmp_result;
-
-       tmp_result = tonga_sort_lookup_table(hwmgr, pptable_info->vddc_lookup_table);
-       if (tmp_result != 0)
-               result = tmp_result;
-
-       return result;
-}
-
-int tonga_init_sclk_threshold(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       data->low_sclk_interrupt_threshold = 0;
-
-       return 0;
-}
-
-int tonga_setup_asic_task(struct pp_hwmgr *hwmgr)
-{
-       int tmp_result, result = 0;
-
-       tmp_result = tonga_read_clock_registers(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to read clock registers!", result = tmp_result);
-
-       tmp_result = tonga_get_memory_type(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to get memory type!", result = tmp_result);
-
-       tmp_result = tonga_enable_acpi_power_management(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to enable ACPI power management!", result = tmp_result);
-
-       tmp_result = tonga_init_power_gate_state(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to init power gate state!", result = tmp_result);
-
-       tmp_result = tonga_get_mc_microcode_version(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to get MC microcode version!", result = tmp_result);
-
-       tmp_result = tonga_init_sclk_threshold(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to init sclk threshold!", result = tmp_result);
-
-       return result;
-}
-
-/**
- * Enable voltage control
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_enable_voltage_control(struct pp_hwmgr *hwmgr)
-{
-       /* enable voltage control */
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
-
-       return 0;
-}
-
-/**
- * Checks if we want to support voltage control
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- */
-bool cf_tonga_voltage_control(const struct pp_hwmgr *hwmgr)
-{
-       const struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       return(TONGA_VOLTAGE_CONTROL_NONE != data->voltage_control);
-}
-
-/*---------------------------MC----------------------------*/
-
-uint8_t tonga_get_memory_modile_index(struct pp_hwmgr *hwmgr)
-{
-       return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
-}
-
-bool tonga_check_s0_mc_reg_index(uint16_t inReg, uint16_t *outReg)
-{
-       bool result = true;
-
-       switch (inReg) {
-       case  mmMC_SEQ_RAS_TIMING:
-               *outReg = mmMC_SEQ_RAS_TIMING_LP;
-               break;
-
-       case  mmMC_SEQ_DLL_STBY:
-               *outReg = mmMC_SEQ_DLL_STBY_LP;
-               break;
-
-       case  mmMC_SEQ_G5PDX_CMD0:
-               *outReg = mmMC_SEQ_G5PDX_CMD0_LP;
-               break;
-
-       case  mmMC_SEQ_G5PDX_CMD1:
-               *outReg = mmMC_SEQ_G5PDX_CMD1_LP;
-               break;
-
-       case  mmMC_SEQ_G5PDX_CTRL:
-               *outReg = mmMC_SEQ_G5PDX_CTRL_LP;
-               break;
-
-       case mmMC_SEQ_CAS_TIMING:
-               *outReg = mmMC_SEQ_CAS_TIMING_LP;
-               break;
-
-       case mmMC_SEQ_MISC_TIMING:
-               *outReg = mmMC_SEQ_MISC_TIMING_LP;
-               break;
-
-       case mmMC_SEQ_MISC_TIMING2:
-               *outReg = mmMC_SEQ_MISC_TIMING2_LP;
-               break;
-
-       case mmMC_SEQ_PMG_DVS_CMD:
-               *outReg = mmMC_SEQ_PMG_DVS_CMD_LP;
-               break;
-
-       case mmMC_SEQ_PMG_DVS_CTL:
-               *outReg = mmMC_SEQ_PMG_DVS_CTL_LP;
-               break;
-
-       case mmMC_SEQ_RD_CTL_D0:
-               *outReg = mmMC_SEQ_RD_CTL_D0_LP;
-               break;
-
-       case mmMC_SEQ_RD_CTL_D1:
-               *outReg = mmMC_SEQ_RD_CTL_D1_LP;
-               break;
-
-       case mmMC_SEQ_WR_CTL_D0:
-               *outReg = mmMC_SEQ_WR_CTL_D0_LP;
-               break;
-
-       case mmMC_SEQ_WR_CTL_D1:
-               *outReg = mmMC_SEQ_WR_CTL_D1_LP;
-               break;
-
-       case mmMC_PMG_CMD_EMRS:
-               *outReg = mmMC_SEQ_PMG_CMD_EMRS_LP;
-               break;
-
-       case mmMC_PMG_CMD_MRS:
-               *outReg = mmMC_SEQ_PMG_CMD_MRS_LP;
-               break;
-
-       case mmMC_PMG_CMD_MRS1:
-               *outReg = mmMC_SEQ_PMG_CMD_MRS1_LP;
-               break;
-
-       case mmMC_SEQ_PMG_TIMING:
-               *outReg = mmMC_SEQ_PMG_TIMING_LP;
-               break;
-
-       case mmMC_PMG_CMD_MRS2:
-               *outReg = mmMC_SEQ_PMG_CMD_MRS2_LP;
-               break;
-
-       case mmMC_SEQ_WR_CTL_2:
-               *outReg = mmMC_SEQ_WR_CTL_2_LP;
-               break;
-
-       default:
-               result = false;
-               break;
-       }
-
-       return result;
-}
-
-int tonga_set_s0_mc_reg_index(phw_tonga_mc_reg_table *table)
-{
-       uint32_t i;
-       uint16_t address;
-
-       for (i = 0; i < table->last; i++) {
-               table->mc_reg_address[i].s0 =
-                       tonga_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address)
-                       ? address : table->mc_reg_address[i].s1;
-       }
-       return 0;
-}
-
-int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table, phw_tonga_mc_reg_table *ni_table)
-{
-       uint8_t i, j;
-
-       PP_ASSERT_WITH_CODE((table->last <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
-               "Invalid VramInfo table.", return -1);
-       PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
-               "Invalid VramInfo table.", return -1);
-
-       for (i = 0; i < table->last; i++) {
-               ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
-       }
-       ni_table->last = table->last;
-
-       for (i = 0; i < table->num_entries; i++) {
-               ni_table->mc_reg_table_entry[i].mclk_max =
-                       table->mc_reg_table_entry[i].mclk_max;
-               for (j = 0; j < table->last; j++) {
-                       ni_table->mc_reg_table_entry[i].mc_data[j] =
-                               table->mc_reg_table_entry[i].mc_data[j];
-               }
-       }
-
-       ni_table->num_entries = table->num_entries;
-
-       return 0;
-}
-
-/**
- * VBIOS omits some information to reduce size, we need to recover them here.
- * 1.   when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to  mmMC_PMG_CMD_EMRS /_LP[15:0].
- *      Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
- * 2.   when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
- * 3.   need to set these data for each clock range
- *
- * @param    hwmgr the address of the powerplay hardware manager.
- * @param    table the address of MCRegTable
- * @return   always 0
- */
-int tonga_set_mc_special_registers(struct pp_hwmgr *hwmgr, phw_tonga_mc_reg_table *table)
-{
-       uint8_t i, j, k;
-       uint32_t temp_reg;
-       const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       for (i = 0, j = table->last; i < table->last; i++) {
-               PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
-                       "Invalid VramInfo table.", return -1);
-               switch (table->mc_reg_address[i].s1) {
-               /*
-               * mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to  mmMC_PMG_CMD_EMRS /_LP[15:0].
-               * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
-               */
-               case mmMC_SEQ_MISC1:
-                       temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS);
-                       table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
-                       table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
-                       for (k = 0; k < table->num_entries; k++) {
-                               table->mc_reg_table_entry[k].mc_data[j] =
-                                       ((temp_reg & 0xffff0000)) |
-                                       ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
-                       }
-                       j++;
-                       PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
-                               "Invalid VramInfo table.", return -1);
-
-                       temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
-                       table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
-                       table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
-                       for (k = 0; k < table->num_entries; k++) {
-                               table->mc_reg_table_entry[k].mc_data[j] =
-                                       (temp_reg & 0xffff0000) |
-                                       (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
-
-                               if (!data->is_memory_GDDR5) {
-                                       table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
-                               }
-                       }
-                       j++;
-                       PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
-                               "Invalid VramInfo table.", return -1);
-
-                       if (!data->is_memory_GDDR5) {
-                               table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
-                               table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
-                               for (k = 0; k < table->num_entries; k++) {
-                                       table->mc_reg_table_entry[k].mc_data[j] =
-                                               (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
-                               }
-                               j++;
-                               PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
-                                       "Invalid VramInfo table.", return -1);
-                       }
-
-                       break;
-
-               case mmMC_SEQ_RESERVE_M:
-                       temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
-                       table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
-                       table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
-                       for (k = 0; k < table->num_entries; k++) {
-                               table->mc_reg_table_entry[k].mc_data[j] =
-                                       (temp_reg & 0xffff0000) |
-                                       (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
-                       }
-                       j++;
-                       PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
-                               "Invalid VramInfo table.", return -1);
-                       break;
-
-               default:
-                       break;
-               }
-
-       }
-
-       table->last = j;
-
-       return 0;
-}
-
-int tonga_set_valid_flag(phw_tonga_mc_reg_table *table)
-{
-       uint8_t i, j;
-       for (i = 0; i < table->last; i++) {
-               for (j = 1; j < table->num_entries; j++) {
-                       if (table->mc_reg_table_entry[j-1].mc_data[i] !=
-                               table->mc_reg_table_entry[j].mc_data[i]) {
-                               table->validflag |= (1<<i);
-                               break;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
-{
-       int result;
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-       pp_atomctrl_mc_reg_table *table;
-       phw_tonga_mc_reg_table *ni_table = &data->tonga_mc_reg_table;
-       uint8_t module_index = tonga_get_memory_modile_index(hwmgr);
-
-       table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
-
-       if (NULL == table)
-               return -ENOMEM;
-
-       /* Program additional LP registers that are no longer programmed by VBIOS */
-       cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
-       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
-
-       memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
-
-       result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
-
-       if (0 == result)
-               result = tonga_copy_vbios_smc_reg_table(table, ni_table);
-
-       if (0 == result) {
-               tonga_set_s0_mc_reg_index(ni_table);
-               result = tonga_set_mc_special_registers(hwmgr, ni_table);
-       }
-
-       if (0 == result)
-               tonga_set_valid_flag(ni_table);
-
-       kfree(table);
-       return result;
-}
-
-/*
-* Copy one arb setting to another and then switch the active set.
-* arbFreqSrc and arbFreqDest is one of the MC_CG_ARB_FREQ_Fx constants.
-*/
-int tonga_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
-               uint32_t arbFreqSrc, uint32_t arbFreqDest)
-{
-       uint32_t mc_arb_dram_timing;
-       uint32_t mc_arb_dram_timing2;
-       uint32_t burst_time;
-       uint32_t mc_cg_config;
-
-       switch (arbFreqSrc) {
-       case MC_CG_ARB_FREQ_F0:
-               mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
-               mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
-               burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
-               break;
-
-       case MC_CG_ARB_FREQ_F1:
-               mc_arb_dram_timing  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
-               mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
-               burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
-               break;
-
-       default:
-               return -1;
-       }
-
-       switch (arbFreqDest) {
-       case MC_CG_ARB_FREQ_F0:
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
-               PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
-               break;
-
-       case MC_CG_ARB_FREQ_F1:
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
-               cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
-               PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
-               break;
-
-       default:
-               return -1;
-       }
-
-       mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
-       mc_cg_config |= 0x0000000F;
-       cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
-       PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arbFreqDest);
-
-       return 0;
-}
-
-/**
- * Initial switch from ARB F0->F1
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- * This function is to be called from the SetPowerState table.
- */
-int tonga_initial_switch_from_arb_f0_to_f1(struct pp_hwmgr *hwmgr)
-{
-       return tonga_copy_and_switch_arb_sets(hwmgr, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
-}
-
-/**
- * Initialize the ARB DRAM timing table's index field.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_init_arb_table_index(struct pp_hwmgr *hwmgr)
-{
-       const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       uint32_t tmp;
-       int result;
-
-       /*
-       * This is a read-modify-write on the first byte of the ARB table.
-       * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure is the field 'current'.
-       * This solution is ugly, but we never write the whole table only individual fields in it.
-       * In reality this field should not be in that structure but in a soft register.
-       */
-       result = tonga_read_smc_sram_dword(hwmgr->smumgr,
-                               data->arb_table_start, &tmp, data->sram_end);
-
-       if (0 != result)
-               return result;
-
-       tmp &= 0x00FFFFFF;
-       tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
-
-       return tonga_write_smc_sram_dword(hwmgr->smumgr,
-                       data->arb_table_start,  tmp, data->sram_end);
-}
-
-int tonga_populate_mc_reg_address(struct pp_hwmgr *hwmgr, SMU72_Discrete_MCRegisters *mc_reg_table)
-{
-       const struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       uint32_t i, j;
-
-       for (i = 0, j = 0; j < data->tonga_mc_reg_table.last; j++) {
-               if (data->tonga_mc_reg_table.validflag & 1<<j) {
-                       PP_ASSERT_WITH_CODE(i < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE,
-                               "Index of mc_reg_table->address[] array out of boundary", return -1);
-                       mc_reg_table->address[i].s0 =
-                               PP_HOST_TO_SMC_US(data->tonga_mc_reg_table.mc_reg_address[j].s0);
-                       mc_reg_table->address[i].s1 =
-                               PP_HOST_TO_SMC_US(data->tonga_mc_reg_table.mc_reg_address[j].s1);
-                       i++;
-               }
-       }
-
-       mc_reg_table->last = (uint8_t)i;
-
-       return 0;
-}
-
-/*convert register values from driver to SMC format */
-void tonga_convert_mc_registers(
-       const phw_tonga_mc_reg_entry * pEntry,
-       SMU72_Discrete_MCRegisterSet *pData,
-       uint32_t numEntries, uint32_t validflag)
-{
-       uint32_t i, j;
-
-       for (i = 0, j = 0; j < numEntries; j++) {
-               if (validflag & 1<<j) {
-                       pData->value[i] = PP_HOST_TO_SMC_UL(pEntry->mc_data[j]);
-                       i++;
-               }
-       }
-}
-
-/* find the entry in the memory range table, then populate the value to SMC's tonga_mc_reg_table */
-int tonga_convert_mc_reg_table_entry_to_smc(
-               struct pp_hwmgr *hwmgr,
-               const uint32_t memory_clock,
-               SMU72_Discrete_MCRegisterSet *mc_reg_table_data
-               )
-{
-       const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       uint32_t i = 0;
-
-       for (i = 0; i < data->tonga_mc_reg_table.num_entries; i++) {
-               if (memory_clock <=
-                       data->tonga_mc_reg_table.mc_reg_table_entry[i].mclk_max) {
-                       break;
-               }
-       }
-
-       if ((i == data->tonga_mc_reg_table.num_entries) && (i > 0))
-               --i;
-
-       tonga_convert_mc_registers(&data->tonga_mc_reg_table.mc_reg_table_entry[i],
-               mc_reg_table_data, data->tonga_mc_reg_table.last, data->tonga_mc_reg_table.validflag);
-
-       return 0;
-}
-
-int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
-               SMU72_Discrete_MCRegisters *mc_reg_table)
-{
-       int result = 0;
-       tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       int res;
-       uint32_t i;
-
-       for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
-               res = tonga_convert_mc_reg_table_entry_to_smc(
-                               hwmgr,
-                               data->dpm_table.mclk_table.dpm_levels[i].value,
-                               &mc_reg_table->data[i]
-                               );
-
-               if (0 != res)
-                       result = res;
-       }
-
-       return result;
-}
-
-int tonga_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
-{
-       int result;
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       memset(&data->mc_reg_table, 0x00, sizeof(SMU72_Discrete_MCRegisters));
-       result = tonga_populate_mc_reg_address(hwmgr, &(data->mc_reg_table));
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize MCRegTable for the MC register addresses!", return result;);
-
-       result = tonga_convert_mc_reg_table_to_smc(hwmgr, &data->mc_reg_table);
-       PP_ASSERT_WITH_CODE(0 == result,
-               "Failed to initialize MCRegTable for driver state!", return result;);
-
-       return tonga_copy_bytes_to_smc(hwmgr->smumgr, data->mc_reg_table_start,
-                       (uint8_t *)&data->mc_reg_table, sizeof(SMU72_Discrete_MCRegisters), data->sram_end);
-}
-
-/**
- * Programs static screed detection parameters
- *
- * @param   hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_program_static_screen_threshold_parameters(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       /* Set static screen threshold unit*/
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
-               CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
-               data->static_screen_threshold_unit);
-       /* Set static screen threshold*/
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
-               CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
-               data->static_screen_threshold);
-
-       return 0;
-}
-
-/**
- * Setup display gap for glitch free memory clock switching.
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_enable_display_gap(struct pp_hwmgr *hwmgr)
-{
-       uint32_t display_gap = cgs_read_ind_register(hwmgr->device,
-                                                       CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
-
-       display_gap = PHM_SET_FIELD(display_gap,
-                                       CG_DISPLAY_GAP_CNTL, DISP_GAP, DISPLAY_GAP_IGNORE);
-
-       display_gap = PHM_SET_FIELD(display_gap,
-                                       CG_DISPLAY_GAP_CNTL, DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-               ixCG_DISPLAY_GAP_CNTL, display_gap);
-
-       return 0;
-}
-
-/**
- * Programs activity state transition voting clients
- *
- * @param    hwmgr  the address of the powerplay hardware manager.
- * @return   always 0
- */
-int tonga_program_voting_clients(struct pp_hwmgr *hwmgr)
-{
-       tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
-
-       /* Clear reset for voting clients before enabling DPM */
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-               SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-               SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-               ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-               ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-               ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-               ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-               ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-               ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-               ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-               ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
-
-       return 0;
-}
-
-
-int tonga_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
-{
-       int tmp_result, result = 0;
-
-       tmp_result = tonga_check_for_dpm_stopped(hwmgr);
-
-       if (cf_tonga_voltage_control(hwmgr)) {
-               tmp_result = tonga_enable_voltage_control(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to enable voltage control!", result = tmp_result);
-
-               tmp_result = tonga_construct_voltage_tables(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == tmp_result),
-                       "Failed to contruct voltage tables!", result = tmp_result);
-       }
-
-       tmp_result = tonga_initialize_mc_reg_table(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to initialize MC reg table!", result = tmp_result);
-
-       tmp_result = tonga_program_static_screen_threshold_parameters(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to program static screen threshold parameters!", result = tmp_result);
-
-       tmp_result = tonga_enable_display_gap(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to enable display gap!", result = tmp_result);
-
-       tmp_result = tonga_program_voting_clients(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to program voting clients!", result = tmp_result);
-
-       tmp_result = tonga_process_firmware_header(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to process firmware header!", result = tmp_result);
-
-       tmp_result = tonga_initial_switch_from_arb_f0_to_f1(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to initialize switch from ArbF0 to F1!", result = tmp_result);
-
-       tmp_result = tonga_init_smc_table(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to initialize SMC table!", result = tmp_result);
-
-       tmp_result = tonga_init_arb_table_index(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to initialize ARB table index!", result = tmp_result);
-
-       tmp_result = tonga_populate_initial_mc_reg_table(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to populate initialize MC Reg table!", result = tmp_result);
-
-       tmp_result = tonga_notify_smc_display_change(hwmgr, false);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to notify no display!", result = tmp_result);
-
-       /* enable SCLK control */
-       tmp_result = tonga_enable_sclk_control(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to enable SCLK control!", result = tmp_result);
-
-       /* enable DPM */
-       tmp_result = tonga_start_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to start DPM!", result = tmp_result);
-
-       return result;
-}
-
-int tonga_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
-{
-       int tmp_result, result = 0;
-
-       tmp_result = tonga_check_for_dpm_running(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "SMC is still running!", return 0);
-
-       tmp_result = tonga_stop_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to stop DPM!", result = tmp_result);
-
-       tmp_result = tonga_reset_to_default(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result),
-               "Failed to reset to default!", result = tmp_result);
-
-       return result;
-}
-
-int tonga_reset_asic_tasks(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       result = tonga_set_boot_state(hwmgr);
-       if (0 != result)
-               printk(KERN_ERR "[ powerplay ] Failed to reset asic via set boot state! \n");
-
-       return result;
-}
-
-int tonga_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
-{
-       return phm_hwmgr_backend_fini(hwmgr);
-}
-
-/**
- * Initializes the Volcanic Islands Hardware Manager
- *
- * @param   hwmgr the address of the powerplay hardware manager.
- * @return   1 if success; otherwise appropriate error code.
- */
-int tonga_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
-{
-       int result = 0;
-       SMU72_Discrete_DpmTable  *table = NULL;
-       tonga_hwmgr *data;
-       pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       phw_tonga_ulv_parm *ulv;
-       struct cgs_system_info sys_info = {0};
-
-       PP_ASSERT_WITH_CODE((NULL != hwmgr),
-               "Invalid Parameter!", return -1;);
-
-       data = kzalloc(sizeof(struct tonga_hwmgr), GFP_KERNEL);
-       if (data == NULL)
-               return -ENOMEM;
-
-       hwmgr->backend = data;
-
-       data->dll_defaule_on = false;
-       data->sram_end = SMC_RAM_END;
-
-       data->activity_target[0] = PPTONGA_TARGETACTIVITY_DFLT;
-       data->activity_target[1] = PPTONGA_TARGETACTIVITY_DFLT;
-       data->activity_target[2] = PPTONGA_TARGETACTIVITY_DFLT;
-       data->activity_target[3] = PPTONGA_TARGETACTIVITY_DFLT;
-       data->activity_target[4] = PPTONGA_TARGETACTIVITY_DFLT;
-       data->activity_target[5] = PPTONGA_TARGETACTIVITY_DFLT;
-       data->activity_target[6] = PPTONGA_TARGETACTIVITY_DFLT;
-       data->activity_target[7] = PPTONGA_TARGETACTIVITY_DFLT;
-
-       data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
-       data->vddc_vddgfx_delta = VDDC_VDDGFX_DELTA;
-       data->mclk_activity_target = PPTONGA_MCLK_TARGETACTIVITY_DFLT;
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_DisableVoltageIsland);
-
-       data->sclk_dpm_key_disabled = 0;
-       data->mclk_dpm_key_disabled = 0;
-       data->pcie_dpm_key_disabled = 0;
-       data->pcc_monitor_enabled = 0;
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_UnTabledHardwareInterface);
-
-       data->gpio_debug = 0;
-       data->engine_clock_data = 0;
-       data->memory_clock_data = 0;
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_DynamicPatchPowerState);
-
-       /* need to set voltage control types before EVV patching*/
-       data->voltage_control = TONGA_VOLTAGE_CONTROL_NONE;
-       data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_NONE;
-       data->vdd_gfx_control = TONGA_VOLTAGE_CONTROL_NONE;
-       data->mvdd_control = TONGA_VOLTAGE_CONTROL_NONE;
-       data->force_pcie_gen = PP_PCIEGenInvalid;
-
-       if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                               VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2)) {
-               data->voltage_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ControlVDDGFX)) {
-               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                       VOLTAGE_TYPE_VDDGFX, VOLTAGE_OBJ_SVID2)) {
-                       data->vdd_gfx_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
-               }
-       }
-
-       if (TONGA_VOLTAGE_CONTROL_NONE == data->vdd_gfx_control) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ControlVDDGFX);
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_EnableMVDDControl)) {
-               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                                       VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT)) {
-                       data->mvdd_control = TONGA_VOLTAGE_CONTROL_BY_GPIO;
-               }
-       }
-
-       if (TONGA_VOLTAGE_CONTROL_NONE == data->mvdd_control) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_EnableMVDDControl);
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ControlVDDCI)) {
-               if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                                       VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
-                       data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_BY_GPIO;
-               else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
-                                               VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
-                       data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
-       }
-
-       if (TONGA_VOLTAGE_CONTROL_NONE == data->vdd_ci_control)
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_ControlVDDCI);
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_TablelessHardwareInterface);
-
-       if (pptable_info->cac_dtp_table->usClockStretchAmount != 0)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ClockStretcher);
-
-       /* Initializes DPM default values*/
-       tonga_initialize_dpm_defaults(hwmgr);
-
-       /* Get leakage voltage based on leakage ID.*/
-       PP_ASSERT_WITH_CODE((0 == tonga_get_evv_voltage(hwmgr)),
-               "Get EVV Voltage Failed.  Abort Driver loading!", return -1);
-
-       tonga_complete_dependency_tables(hwmgr);
-
-       /* Parse pptable data read from VBIOS*/
-       tonga_set_private_var_based_on_pptale(hwmgr);
-
-       /* ULV Support*/
-       ulv = &(data->ulv);
-       ulv->ulv_supported = false;
-
-       /* Initalize Dynamic State Adjustment Rule Settings*/
-       result = tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
-       if (result)
-               printk(KERN_ERR "[ powerplay ] tonga_initializa_dynamic_state_adjustment_rule_settings failed!\n");
-       data->uvd_enabled = false;
-
-       table = &(data->smc_state_table);
-
-       /*
-       * if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable,
-       * Peak Current Control feature is enabled and we should program PCC HW register
-       */
-       if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_PCC_GPIO_PINID, &gpio_pin_assignment)) {
-               uint32_t temp_reg = cgs_read_ind_register(hwmgr->device,
-                                                                               CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL);
-
-               switch (gpio_pin_assignment.uc_gpio_pin_bit_shift) {
-               case 0:
-                       temp_reg = PHM_SET_FIELD(temp_reg,
-                               CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x1);
-                       break;
-               case 1:
-                       temp_reg = PHM_SET_FIELD(temp_reg,
-                               CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x2);
-                       break;
-               case 2:
-                       temp_reg = PHM_SET_FIELD(temp_reg,
-                               CNB_PWRMGT_CNTL, GNB_SLOW, 0x1);
-                       break;
-               case 3:
-                       temp_reg = PHM_SET_FIELD(temp_reg,
-                               CNB_PWRMGT_CNTL, FORCE_NB_PS1, 0x1);
-                       break;
-               case 4:
-                       temp_reg = PHM_SET_FIELD(temp_reg,
-                               CNB_PWRMGT_CNTL, DPM_ENABLED, 0x1);
-                       break;
-               default:
-                       printk(KERN_ERR "[ powerplay ] Failed to setup PCC HW register! \
-                               Wrong GPIO assigned for VDDC_PCC_GPIO_PINID! \n");
-                       break;
-               }
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
-                       ixCNB_PWRMGT_CNTL, temp_reg);
-       }
-
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_EnableSMU7ThermalManagement);
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_SMU7);
-
-       data->vddc_phase_shed_control = false;
-
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                     PHM_PlatformCaps_UVDPowerGating);
-       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
-                     PHM_PlatformCaps_VCEPowerGating);
-       sys_info.size = sizeof(struct cgs_system_info);
-       sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS;
-       result = cgs_query_system_info(hwmgr->device, &sys_info);
-       if (!result) {
-               if (sys_info.value & AMD_PG_SUPPORT_UVD)
-                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                     PHM_PlatformCaps_UVDPowerGating);
-               if (sys_info.value & AMD_PG_SUPPORT_VCE)
-                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                     PHM_PlatformCaps_VCEPowerGating);
-       }
-
-       if (0 == result) {
-               data->is_tlu_enabled = false;
-               hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
-                       TONGA_MAX_HARDWARE_POWERLEVELS;
-               hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
-               hwmgr->platform_descriptor.minimumClocksReductionPercentage  = 50;
-
-               sys_info.size = sizeof(struct cgs_system_info);
-               sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
-               result = cgs_query_system_info(hwmgr->device, &sys_info);
-               if (result)
-                       data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK;
-               else
-                       data->pcie_gen_cap = (uint32_t)sys_info.value;
-               if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
-                       data->pcie_spc_cap = 20;
-               sys_info.size = sizeof(struct cgs_system_info);
-               sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
-               result = cgs_query_system_info(hwmgr->device, &sys_info);
-               if (result)
-                       data->pcie_lane_cap = AMDGPU_DEFAULT_PCIE_MLW_MASK;
-               else
-                       data->pcie_lane_cap = (uint32_t)sys_info.value;
-       } else {
-               /* Ignore return value in here, we are cleaning up a mess. */
-               tonga_hwmgr_backend_fini(hwmgr);
-       }
-
-       return result;
-}
-
-static int tonga_force_dpm_level(struct pp_hwmgr *hwmgr,
-               enum amd_dpm_forced_level level)
-{
-       int ret = 0;
-
-       switch (level) {
-       case AMD_DPM_FORCED_LEVEL_HIGH:
-               ret = tonga_force_dpm_highest(hwmgr);
-               if (ret)
-                       return ret;
-               break;
-       case AMD_DPM_FORCED_LEVEL_LOW:
-               ret = tonga_force_dpm_lowest(hwmgr);
-               if (ret)
-                       return ret;
-               break;
-       case AMD_DPM_FORCED_LEVEL_AUTO:
-               ret = tonga_unforce_dpm_levels(hwmgr);
-               if (ret)
-                       return ret;
-               break;
-       default:
-               break;
-       }
-
-       hwmgr->dpm_level = level;
-       return ret;
-}
-
-static int tonga_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
-                               struct pp_power_state  *prequest_ps,
-                       const struct pp_power_state *pcurrent_ps)
-{
-       struct tonga_power_state *tonga_ps =
-                               cast_phw_tonga_power_state(&prequest_ps->hardware);
-
-       uint32_t sclk;
-       uint32_t mclk;
-       struct PP_Clocks minimum_clocks = {0};
-       bool disable_mclk_switching;
-       bool disable_mclk_switching_for_frame_lock;
-       struct cgs_display_info info = {0};
-       const struct phm_clock_and_voltage_limits *max_limits;
-       uint32_t i;
-       tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       int32_t count;
-       int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
-
-       data->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label);
-
-       PP_ASSERT_WITH_CODE(tonga_ps->performance_level_count == 2,
-                                "VI should always have 2 performance levels",
-                                );
-
-       max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
-                       &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
-                       &(hwmgr->dyn_state.max_clock_voltage_on_dc);
-
-       if (PP_PowerSource_DC == hwmgr->power_source) {
-               for (i = 0; i < tonga_ps->performance_level_count; i++) {
-                       if (tonga_ps->performance_levels[i].memory_clock > max_limits->mclk)
-                               tonga_ps->performance_levels[i].memory_clock = max_limits->mclk;
-                       if (tonga_ps->performance_levels[i].engine_clock > max_limits->sclk)
-                               tonga_ps->performance_levels[i].engine_clock = max_limits->sclk;
-               }
-       }
-
-       tonga_ps->vce_clocks.EVCLK = hwmgr->vce_arbiter.evclk;
-       tonga_ps->vce_clocks.ECCLK = hwmgr->vce_arbiter.ecclk;
-
-       tonga_ps->acp_clk = hwmgr->acp_arbiter.acpclk;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
-
-       /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) {
-
-               max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
-               stable_pstate_sclk = (max_limits->sclk * 75) / 100;
-
-               for (count = pptable_info->vdd_dep_on_sclk->count-1; count >= 0; count--) {
-                       if (stable_pstate_sclk >= pptable_info->vdd_dep_on_sclk->entries[count].clk) {
-                               stable_pstate_sclk = pptable_info->vdd_dep_on_sclk->entries[count].clk;
-                               break;
-                       }
-               }
-
-               if (count < 0)
-                       stable_pstate_sclk = pptable_info->vdd_dep_on_sclk->entries[0].clk;
-
-               stable_pstate_mclk = max_limits->mclk;
-
-               minimum_clocks.engineClock = stable_pstate_sclk;
-               minimum_clocks.memoryClock = stable_pstate_mclk;
-       }
-
-       if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
-               minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
-
-       if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
-               minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
-
-       tonga_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
-
-       if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
-               PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.engineClock),
-                                       "Overdrive sclk exceeds limit",
-                                       hwmgr->gfx_arbiter.sclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.engineClock);
-
-               if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
-                       tonga_ps->performance_levels[1].engine_clock = hwmgr->gfx_arbiter.sclk_over_drive;
-       }
-
-       if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
-               PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.memoryClock),
-                       "Overdrive mclk exceeds limit",
-                       hwmgr->gfx_arbiter.mclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.memoryClock);
-
-               if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
-                       tonga_ps->performance_levels[1].memory_clock = hwmgr->gfx_arbiter.mclk_over_drive;
-       }
-
-       disable_mclk_switching_for_frame_lock = phm_cap_enabled(
-                                   hwmgr->platform_descriptor.platformCaps,
-                                   PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
-
-       disable_mclk_switching = (1 < info.display_count) ||
-                                   disable_mclk_switching_for_frame_lock;
-
-       sclk  = tonga_ps->performance_levels[0].engine_clock;
-       mclk  = tonga_ps->performance_levels[0].memory_clock;
-
-       if (disable_mclk_switching)
-               mclk  = tonga_ps->performance_levels[tonga_ps->performance_level_count - 1].memory_clock;
-
-       if (sclk < minimum_clocks.engineClock)
-               sclk = (minimum_clocks.engineClock > max_limits->sclk) ? max_limits->sclk : minimum_clocks.engineClock;
-
-       if (mclk < minimum_clocks.memoryClock)
-               mclk = (minimum_clocks.memoryClock > max_limits->mclk) ? max_limits->mclk : minimum_clocks.memoryClock;
-
-       tonga_ps->performance_levels[0].engine_clock = sclk;
-       tonga_ps->performance_levels[0].memory_clock = mclk;
-
-       tonga_ps->performance_levels[1].engine_clock =
-               (tonga_ps->performance_levels[1].engine_clock >= tonga_ps->performance_levels[0].engine_clock) ?
-                             tonga_ps->performance_levels[1].engine_clock :
-                             tonga_ps->performance_levels[0].engine_clock;
-
-       if (disable_mclk_switching) {
-               if (mclk < tonga_ps->performance_levels[1].memory_clock)
-                       mclk = tonga_ps->performance_levels[1].memory_clock;
-
-               tonga_ps->performance_levels[0].memory_clock = mclk;
-               tonga_ps->performance_levels[1].memory_clock = mclk;
-       } else {
-               if (tonga_ps->performance_levels[1].memory_clock < tonga_ps->performance_levels[0].memory_clock)
-                       tonga_ps->performance_levels[1].memory_clock = tonga_ps->performance_levels[0].memory_clock;
-       }
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) {
-               for (i=0; i < tonga_ps->performance_level_count; i++) {
-                       tonga_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
-                       tonga_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
-                       tonga_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
-                       tonga_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
-               }
-       }
-
-       return 0;
-}
-
-int tonga_get_power_state_size(struct pp_hwmgr *hwmgr)
-{
-       return sizeof(struct tonga_power_state);
-}
-
-static int tonga_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
-{
-       struct pp_power_state  *ps;
-       struct tonga_power_state  *tonga_ps;
-
-       if (hwmgr == NULL)
-               return -EINVAL;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
-
-       if (low)
-               return tonga_ps->performance_levels[0].memory_clock;
-       else
-               return tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
-}
-
-static int tonga_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
-{
-       struct pp_power_state  *ps;
-       struct tonga_power_state  *tonga_ps;
-
-       if (hwmgr == NULL)
-               return -EINVAL;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
-
-       if (low)
-               return tonga_ps->performance_levels[0].engine_clock;
-       else
-               return tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
-}
-
-static uint16_t tonga_get_current_pcie_speed(
-                                                  struct pp_hwmgr *hwmgr)
-{
-       uint32_t speed_cntl = 0;
-
-       speed_cntl = cgs_read_ind_register(hwmgr->device,
-                                                  CGS_IND_REG__PCIE,
-                                                  ixPCIE_LC_SPEED_CNTL);
-       return((uint16_t)PHM_GET_FIELD(speed_cntl,
-                       PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
-}
-
-static int tonga_get_current_pcie_lane_number(
-                                                  struct pp_hwmgr *hwmgr)
-{
-       uint32_t link_width;
-
-       link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device,
-                                                       CGS_IND_REG__PCIE,
-                                                 PCIE_LC_LINK_WIDTH_CNTL,
-                                                       LC_LINK_WIDTH_RD);
-
-       PP_ASSERT_WITH_CODE((7 >= link_width),
-                       "Invalid PCIe lane width!", return 0);
-
-       return decode_pcie_lane_width(link_width);
-}
-
-static int tonga_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
-                                       struct pp_hw_power_state *hw_ps)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_power_state *ps = (struct tonga_power_state *)hw_ps;
-       ATOM_FIRMWARE_INFO_V2_2 *fw_info;
-       uint16_t size;
-       uint8_t frev, crev;
-       int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
-
-       /* First retrieve the Boot clocks and VDDC from the firmware info table.
-        * We assume here that fw_info is unchanged if this call fails.
-        */
-       fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
-                       hwmgr->device, index,
-                       &size, &frev, &crev);
-       if (!fw_info)
-               /* During a test, there is no firmware info table. */
-               return 0;
-
-       /* Patch the state. */
-       data->vbios_boot_state.sclk_bootup_value  = le32_to_cpu(fw_info->ulDefaultEngineClock);
-       data->vbios_boot_state.mclk_bootup_value  = le32_to_cpu(fw_info->ulDefaultMemoryClock);
-       data->vbios_boot_state.mvdd_bootup_value  = le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
-       data->vbios_boot_state.vddc_bootup_value  = le16_to_cpu(fw_info->usBootUpVDDCVoltage);
-       data->vbios_boot_state.vddci_bootup_value = le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
-       data->vbios_boot_state.pcie_gen_bootup_value = tonga_get_current_pcie_speed(hwmgr);
-       data->vbios_boot_state.pcie_lane_bootup_value =
-                       (uint16_t)tonga_get_current_pcie_lane_number(hwmgr);
-
-       /* set boot power state */
-       ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
-       ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
-       ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
-       ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
-
-       return 0;
-}
-
-static int tonga_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
-               void *state, struct pp_power_state *power_state,
-               void *pp_table, uint32_t classification_flag)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       struct tonga_power_state  *tonga_ps =
-                       (struct tonga_power_state *)(&(power_state->hardware));
-
-       struct tonga_performance_level *performance_level;
-
-       ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
-
-       ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
-                       (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
-
-       ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
-                       (ATOM_Tonga_SCLK_Dependency_Table *)
-                       (((unsigned long)powerplay_table) +
-                       le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
-
-       ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
-                       (ATOM_Tonga_MCLK_Dependency_Table *)
-                       (((unsigned long)powerplay_table) +
-                       le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
-
-       /* The following fields are not initialized here: id orderedList allStatesList */
-       power_state->classification.ui_label =
-                       (le16_to_cpu(state_entry->usClassification) &
-                       ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
-                       ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
-       power_state->classification.flags = classification_flag;
-       /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
-
-       power_state->classification.temporary_state = false;
-       power_state->classification.to_be_deleted = false;
-
-       power_state->validation.disallowOnDC =
-                       (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) & ATOM_Tonga_DISALLOW_ON_DC));
-
-       power_state->pcie.lanes = 0;
-
-       power_state->display.disableFrameModulation = false;
-       power_state->display.limitRefreshrate = false;
-       power_state->display.enableVariBright =
-                       (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) & ATOM_Tonga_ENABLE_VARIBRIGHT));
-
-       power_state->validation.supportedPowerLevels = 0;
-       power_state->uvd_clocks.VCLK = 0;
-       power_state->uvd_clocks.DCLK = 0;
-       power_state->temperatures.min = 0;
-       power_state->temperatures.max = 0;
-
-       performance_level = &(tonga_ps->performance_levels
-                       [tonga_ps->performance_level_count++]);
-
-       PP_ASSERT_WITH_CODE(
-                       (tonga_ps->performance_level_count < SMU72_MAX_LEVELS_GRAPHICS),
-                       "Performance levels exceeds SMC limit!",
-                       return -1);
-
-       PP_ASSERT_WITH_CODE(
-                       (tonga_ps->performance_level_count <=
-                                       hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
-                       "Performance levels exceeds Driver limit!",
-                       return -1);
-
-       /* Performance levels are arranged from low to high. */
-       performance_level->memory_clock =
-                               le32_to_cpu(mclk_dep_table->entries[state_entry->ucMemoryClockIndexLow].ulMclk);
-
-       performance_level->engine_clock =
-                               le32_to_cpu(sclk_dep_table->entries[state_entry->ucEngineClockIndexLow].ulSclk);
-
-       performance_level->pcie_gen = get_pcie_gen_support(
-                                                       data->pcie_gen_cap,
-                                            state_entry->ucPCIEGenLow);
-
-       performance_level->pcie_lane = get_pcie_lane_support(
-                                                   data->pcie_lane_cap,
-                                          state_entry->ucPCIELaneHigh);
-
-       performance_level =
-                       &(tonga_ps->performance_levels[tonga_ps->performance_level_count++]);
-
-       performance_level->memory_clock =
-                               le32_to_cpu(mclk_dep_table->entries[state_entry->ucMemoryClockIndexHigh].ulMclk);
-
-       performance_level->engine_clock =
-                               le32_to_cpu(sclk_dep_table->entries[state_entry->ucEngineClockIndexHigh].ulSclk);
-
-       performance_level->pcie_gen = get_pcie_gen_support(
-                                                       data->pcie_gen_cap,
-                                           state_entry->ucPCIEGenHigh);
-
-       performance_level->pcie_lane = get_pcie_lane_support(
-                                                   data->pcie_lane_cap,
-                                          state_entry->ucPCIELaneHigh);
-
-       return 0;
-}
-
-static int tonga_get_pp_table_entry(struct pp_hwmgr *hwmgr,
-                   unsigned long entry_index, struct pp_power_state *ps)
-{
-       int result;
-       struct tonga_power_state *tonga_ps;
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       struct phm_ppt_v1_information *table_info =
-                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
-                                          table_info->vdd_dep_on_mclk;
-
-       ps->hardware.magic = PhwTonga_Magic;
-
-       tonga_ps = cast_phw_tonga_power_state(&(ps->hardware));
-
-       result = tonga_get_powerplay_table_entry(hwmgr, entry_index, ps,
-                       tonga_get_pp_table_entry_callback_func);
-
-       /* This is the earliest time we have all the dependency table and the VBIOS boot state
-        * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
-        * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
-        */
-       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 "
-                                       "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 "
-                                       "does not match VBIOS boot VDDCI level");
-       }
-
-       /* set DC compatible flag if this state supports DC */
-       if (!ps->validation.disallowOnDC)
-               tonga_ps->dc_compatible = true;
-
-       if (ps->classification.flags & PP_StateClassificationFlag_ACPI)
-               data->acpi_pcie_gen = tonga_ps->performance_levels[0].pcie_gen;
-       else if (ps->classification.flags & PP_StateClassificationFlag_Boot) {
-               if (data->bacos.best_match == 0xffff) {
-                       /* For V.I. use boot state as base BACO state */
-                       data->bacos.best_match = PP_StateClassificationFlag_Boot;
-                       data->bacos.performance_level = tonga_ps->performance_levels[0];
-               }
-       }
-
-       tonga_ps->uvd_clocks.VCLK = ps->uvd_clocks.VCLK;
-       tonga_ps->uvd_clocks.DCLK = ps->uvd_clocks.DCLK;
-
-       if (!result) {
-               uint32_t i;
-
-               switch (ps->classification.ui_label) {
-               case PP_StateUILabel_Performance:
-                       data->use_pcie_performance_levels = true;
-
-                       for (i = 0; i < tonga_ps->performance_level_count; i++) {
-                               if (data->pcie_gen_performance.max <
-                                               tonga_ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_performance.max =
-                                                       tonga_ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_gen_performance.min >
-                                               tonga_ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_performance.min =
-                                                       tonga_ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_lane_performance.max <
-                                               tonga_ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_performance.max =
-                                                       tonga_ps->performance_levels[i].pcie_lane;
-
-                               if (data->pcie_lane_performance.min >
-                                               tonga_ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_performance.min =
-                                                       tonga_ps->performance_levels[i].pcie_lane;
-                       }
-                       break;
-               case PP_StateUILabel_Battery:
-                       data->use_pcie_power_saving_levels = true;
-
-                       for (i = 0; i < tonga_ps->performance_level_count; i++) {
-                               if (data->pcie_gen_power_saving.max <
-                                               tonga_ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_power_saving.max =
-                                                       tonga_ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_gen_power_saving.min >
-                                               tonga_ps->performance_levels[i].pcie_gen)
-                                       data->pcie_gen_power_saving.min =
-                                                       tonga_ps->performance_levels[i].pcie_gen;
-
-                               if (data->pcie_lane_power_saving.max <
-                                               tonga_ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_power_saving.max =
-                                                       tonga_ps->performance_levels[i].pcie_lane;
-
-                               if (data->pcie_lane_power_saving.min >
-                                               tonga_ps->performance_levels[i].pcie_lane)
-                                       data->pcie_lane_power_saving.min =
-                                                       tonga_ps->performance_levels[i].pcie_lane;
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-       return 0;
-}
-
-static void
-tonga_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
-{
-       uint32_t sclk, mclk, activity_percent;
-       uint32_t offset;
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetSclkFrequency));
-
-       sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-
-       smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetMclkFrequency));
-
-       mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-       seq_printf(m, "\n [  mclk  ]: %u MHz\n\n [  sclk  ]: %u MHz\n", mclk/100, sclk/100);
-
-       offset = data->soft_regs_start + offsetof(SMU72_SoftRegisters, AverageGraphicsActivity);
-       activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
-       activity_percent += 0x80;
-       activity_percent >>= 8;
-
-       seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent);
-
-       seq_printf(m, "uvd    %sabled\n", data->uvd_power_gated ? "dis" : "en");
-
-       seq_printf(m, "vce    %sabled\n", data->vce_power_gated ? "dis" : "en");
-}
-
-static int tonga_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
-       const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_single_dpm_table *psclk_table = &(data->dpm_table.sclk_table);
-       uint32_t sclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
-       struct tonga_single_dpm_table *pmclk_table = &(data->dpm_table.mclk_table);
-       uint32_t mclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
-       struct PP_Clocks min_clocks = {0};
-       uint32_t i;
-       struct cgs_display_info info = {0};
-
-       data->need_update_smu7_dpm_table = 0;
-
-       for (i = 0; i < psclk_table->count; i++) {
-               if (sclk == psclk_table->dpm_levels[i].value)
-                       break;
-       }
-
-       if (i >= psclk_table->count)
-               data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
-       else {
-       /* TODO: Check SCLK in DAL's minimum clocks in case DeepSleep divider update is required.*/
-               if(data->display_timing.min_clock_insr != min_clocks.engineClockInSR)
-                       data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
-       }
-
-       for (i=0; i < pmclk_table->count; i++) {
-               if (mclk == pmclk_table->dpm_levels[i].value)
-                       break;
-       }
-
-       if (i >= pmclk_table->count)
-               data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       if (data->display_timing.num_existing_displays != info.display_count)
-               data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
-
-       return 0;
-}
-
-static uint16_t tonga_get_maximum_link_speed(struct pp_hwmgr *hwmgr, const struct tonga_power_state *hw_ps)
-{
-       uint32_t i;
-       uint32_t sclk, max_sclk = 0;
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_dpm_table *pdpm_table = &data->dpm_table;
-
-       for (i = 0; i < hw_ps->performance_level_count; i++) {
-               sclk = hw_ps->performance_levels[i].engine_clock;
-               if (max_sclk < sclk)
-                       max_sclk = sclk;
-       }
-
-       for (i = 0; i < pdpm_table->sclk_table.count; i++) {
-               if (pdpm_table->sclk_table.dpm_levels[i].value == max_sclk)
-                       return (uint16_t) ((i >= pdpm_table->pcie_speed_table.count) ?
-                                       pdpm_table->pcie_speed_table.dpm_levels[pdpm_table->pcie_speed_table.count-1].value :
-                                       pdpm_table->pcie_speed_table.dpm_levels[i].value);
-       }
-
-       return 0;
-}
-
-static int tonga_request_link_speed_change_before_state_change(struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       const struct tonga_power_state *tonga_nps = cast_const_phw_tonga_power_state(states->pnew_state);
-       const struct tonga_power_state *tonga_cps = cast_const_phw_tonga_power_state(states->pcurrent_state);
-
-       uint16_t target_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_nps);
-       uint16_t current_link_speed;
-
-       if (data->force_pcie_gen == PP_PCIEGenInvalid)
-               current_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_cps);
-       else
-               current_link_speed = data->force_pcie_gen;
-
-       data->force_pcie_gen = PP_PCIEGenInvalid;
-       data->pspp_notify_required = false;
-       if (target_link_speed > current_link_speed) {
-               switch(target_link_speed) {
-               case PP_PCIEGen3:
-                       if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
-                               break;
-                       data->force_pcie_gen = PP_PCIEGen2;
-                       if (current_link_speed == PP_PCIEGen2)
-                               break;
-               case PP_PCIEGen2:
-                       if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
-                               break;
-               default:
-                       data->force_pcie_gen = tonga_get_current_pcie_speed(hwmgr);
-                       break;
-               }
-       } else {
-               if (target_link_speed < current_link_speed)
-                       data->pspp_notify_required = true;
-       }
-
-       return 0;
-}
-
-static int tonga_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       if (0 == data->need_update_smu7_dpm_table)
-               return 0;
-
-       if ((0 == data->sclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table &
-               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
-               PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr),
-                                   "Trying to freeze SCLK DPM when DPM is disabled",
-                       );
-               PP_ASSERT_WITH_CODE(
-                       0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                         PPSMC_MSG_SCLKDPM_FreezeLevel),
-                       "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
-                       return -1);
-       }
-
-       if ((0 == data->mclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table &
-                DPMTABLE_OD_UPDATE_MCLK)) {
-               PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr),
-                                   "Trying to freeze MCLK DPM when DPM is disabled",
-                       );
-               PP_ASSERT_WITH_CODE(
-                       0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                                       PPSMC_MSG_MCLKDPM_FreezeLevel),
-                       "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
-                       return -1);
-       }
-
-       return 0;
-}
-
-static int tonga_populate_and_upload_sclk_mclk_dpm_levels(struct pp_hwmgr *hwmgr, const void *input)
-{
-       int result = 0;
-
-       const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
-       const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       uint32_t sclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
-       uint32_t mclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
-       struct tonga_dpm_table *pdpm_table = &data->dpm_table;
-
-       struct tonga_dpm_table *pgolden_dpm_table = &data->golden_dpm_table;
-       uint32_t dpm_count, clock_percent;
-       uint32_t i;
-
-       if (0 == data->need_update_smu7_dpm_table)
-               return 0;
-
-       if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
-               pdpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value = sclk;
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
-                   phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
-               /* Need to do calculation based on the golden DPM table
-                * as the Heatmap GPU Clock axis is also based on the default values
-                */
-                       PP_ASSERT_WITH_CODE(
-                               (pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value != 0),
-                               "Divide by 0!",
-                               return -1);
-                       dpm_count = pdpm_table->sclk_table.count < 2 ? 0 : pdpm_table->sclk_table.count-2;
-                       for (i = dpm_count; i > 1; i--) {
-                               if (sclk > pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value) {
-                                       clock_percent = ((sclk - pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value)*100) /
-                                                       pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value;
-
-                                       pdpm_table->sclk_table.dpm_levels[i].value =
-                                                       pgolden_dpm_table->sclk_table.dpm_levels[i].value +
-                                                       (pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100;
-
-                               } else if (pgolden_dpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value > sclk) {
-                                       clock_percent = ((pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value - sclk)*100) /
-                                                               pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value;
-
-                                       pdpm_table->sclk_table.dpm_levels[i].value =
-                                                       pgolden_dpm_table->sclk_table.dpm_levels[i].value -
-                                                       (pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100;
-                               } else
-                                       pdpm_table->sclk_table.dpm_levels[i].value =
-                                                       pgolden_dpm_table->sclk_table.dpm_levels[i].value;
-                       }
-               }
-       }
-
-       if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
-               pdpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value = mclk;
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
-                       phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
-
-                       PP_ASSERT_WITH_CODE(
-                                       (pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value != 0),
-                                       "Divide by 0!",
-                                       return -1);
-                       dpm_count = pdpm_table->mclk_table.count < 2? 0 : pdpm_table->mclk_table.count-2;
-                       for (i = dpm_count; i > 1; i--) {
-                               if (mclk > pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value) {
-                                               clock_percent = ((mclk - pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value)*100) /
-                                                                   pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value;
-
-                                               pdpm_table->mclk_table.dpm_levels[i].value =
-                                                                               pgolden_dpm_table->mclk_table.dpm_levels[i].value +
-                                                                               (pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100;
-
-                               } else if (pgolden_dpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value > mclk) {
-                                               clock_percent = ((pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value - mclk)*100) /
-                                                                   pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value;
-
-                                               pdpm_table->mclk_table.dpm_levels[i].value =
-                                                                       pgolden_dpm_table->mclk_table.dpm_levels[i].value -
-                                                                       (pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100;
-                               } else
-                                       pdpm_table->mclk_table.dpm_levels[i].value = pgolden_dpm_table->mclk_table.dpm_levels[i].value;
-                       }
-               }
-       }
-
-       if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
-               result = tonga_populate_all_graphic_levels(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
-                       return result);
-       }
-
-       if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
-               /*populate MCLK dpm table to SMU7 */
-               result = tonga_populate_all_memory_levels(hwmgr);
-               PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
-                               return result);
-       }
-
-       return result;
-}
-
-static int tonga_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
-                         struct tonga_single_dpm_table * pdpm_table,
-                            uint32_t low_limit, uint32_t high_limit)
-{
-       uint32_t i;
-
-       for (i = 0; i < pdpm_table->count; i++) {
-               if ((pdpm_table->dpm_levels[i].value < low_limit) ||
-                   (pdpm_table->dpm_levels[i].value > high_limit))
-                       pdpm_table->dpm_levels[i].enabled = false;
-               else
-                       pdpm_table->dpm_levels[i].enabled = true;
-       }
-       return 0;
-}
-
-static int tonga_trim_dpm_states(struct pp_hwmgr *hwmgr, const struct tonga_power_state *hw_state)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       uint32_t high_limit_count;
-
-       PP_ASSERT_WITH_CODE((hw_state->performance_level_count >= 1),
-                               "power state did not have any performance level",
-                                return -1);
-
-       high_limit_count = (1 == hw_state->performance_level_count) ? 0: 1;
-
-       tonga_trim_single_dpm_states(hwmgr,
-                                       &(data->dpm_table.sclk_table),
-                                       hw_state->performance_levels[0].engine_clock,
-                                       hw_state->performance_levels[high_limit_count].engine_clock);
-
-       tonga_trim_single_dpm_states(hwmgr,
-                                               &(data->dpm_table.mclk_table),
-                                               hw_state->performance_levels[0].memory_clock,
-                                               hw_state->performance_levels[high_limit_count].memory_clock);
-
-       return 0;
-}
-
-static int tonga_generate_dpm_level_enable_mask(struct pp_hwmgr *hwmgr, const void *input)
-{
-       int result;
-       const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
-
-       result = tonga_trim_dpm_states(hwmgr, tonga_ps);
-       if (0 != result)
-               return result;
-
-       data->dpm_level_enable_mask.sclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
-       data->dpm_level_enable_mask.mclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
-       data->last_mclk_dpm_enable_mask = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
-       if (data->uvd_enabled)
-               data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
-
-       data->dpm_level_enable_mask.pcie_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
-
-       return 0;
-}
-
-int tonga_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
-                                 (PPSMC_Msg)PPSMC_MSG_VCEDPM_Enable :
-                                 (PPSMC_Msg)PPSMC_MSG_VCEDPM_Disable);
-}
-
-int tonga_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
-{
-       return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
-                                 (PPSMC_Msg)PPSMC_MSG_UVDDPM_Enable :
-                                 (PPSMC_Msg)PPSMC_MSG_UVDDPM_Disable);
-}
-
-int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       uint32_t mm_boot_level_offset, mm_boot_level_value;
-       struct phm_ppt_v1_information *ptable_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (!bgate) {
-               data->smc_state_table.UvdBootLevel = (uint8_t) (ptable_information->mm_dep_table->count - 1);
-               mm_boot_level_offset = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
-               mm_boot_level_offset /= 4;
-               mm_boot_level_offset *= 4;
-               mm_boot_level_value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset);
-               mm_boot_level_value &= 0x00FFFFFF;
-               mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
-
-               if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDDPM) ||
-                   phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                               PPSMC_MSG_UVDDPM_SetEnabledMask,
-                                               (uint32_t)(1 << data->smc_state_table.UvdBootLevel));
-       }
-
-       return tonga_enable_disable_uvd_dpm(hwmgr, !bgate);
-}
-
-int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       const struct tonga_power_state *tonga_nps = cast_const_phw_tonga_power_state(states->pnew_state);
-       const struct tonga_power_state *tonga_cps = cast_const_phw_tonga_power_state(states->pcurrent_state);
-
-       uint32_t mm_boot_level_offset, mm_boot_level_value;
-       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (tonga_nps->vce_clocks.EVCLK > 0 && (tonga_cps == NULL || tonga_cps->vce_clocks.EVCLK == 0)) {
-               data->smc_state_table.VceBootLevel = (uint8_t) (pptable_info->mm_dep_table->count - 1);
-
-               mm_boot_level_offset = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
-               mm_boot_level_offset /= 4;
-               mm_boot_level_offset *= 4;
-               mm_boot_level_value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset);
-               mm_boot_level_value &= 0xFF00FFFF;
-               mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
-               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
-
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_VCEDPM_SetEnabledMask,
-                               (uint32_t)(1 << data->smc_state_table.VceBootLevel));
-
-               tonga_enable_disable_vce_dpm(hwmgr, true);
-       } else if (tonga_nps->vce_clocks.EVCLK == 0 && tonga_cps != NULL && tonga_cps->vce_clocks.EVCLK > 0)
-               tonga_enable_disable_vce_dpm(hwmgr, false);
-
-       return 0;
-}
-
-static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       uint32_t address;
-       int32_t result;
-
-       if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
-               return 0;
-
-
-       memset(&data->mc_reg_table, 0, sizeof(SMU72_Discrete_MCRegisters));
-
-       result = tonga_convert_mc_reg_table_to_smc(hwmgr, &(data->mc_reg_table));
-
-       if(result != 0)
-               return result;
-
-
-       address = data->mc_reg_table_start + (uint32_t)offsetof(SMU72_Discrete_MCRegisters, data[0]);
-
-       return  tonga_copy_bytes_to_smc(hwmgr->smumgr, address,
-                                (uint8_t *)&data->mc_reg_table.data[0],
-                               sizeof(SMU72_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count,
-                               data->sram_end);
-}
-
-static int tonga_program_memory_timing_parameters_conditionally(struct pp_hwmgr *hwmgr)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       if (data->need_update_smu7_dpm_table &
-               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
-               return tonga_program_memory_timing_parameters(hwmgr);
-
-       return 0;
-}
-
-static int tonga_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       if (0 == data->need_update_smu7_dpm_table)
-               return 0;
-
-       if ((0 == data->sclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table &
-               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
-
-               PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr),
-                                   "Trying to Unfreeze SCLK DPM when DPM is disabled",
-                       );
-               PP_ASSERT_WITH_CODE(
-                        0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                        PPSMC_MSG_SCLKDPM_UnfreezeLevel),
-                       "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
-                       return -1);
-       }
-
-       if ((0 == data->mclk_dpm_key_disabled) &&
-               (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
-
-               PP_ASSERT_WITH_CODE(!tonga_is_dpm_running(hwmgr),
-                                   "Trying to Unfreeze MCLK DPM when DPM is disabled",
-                               );
-               PP_ASSERT_WITH_CODE(
-                        0 == smum_send_msg_to_smc(hwmgr->smumgr,
-                                        PPSMC_MSG_SCLKDPM_UnfreezeLevel),
-                   "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
-                   return -1);
-       }
-
-       data->need_update_smu7_dpm_table = 0;
-
-       return 0;
-}
-
-static int tonga_notify_link_speed_change_after_state_change(struct pp_hwmgr *hwmgr, const void *input)
-{
-       const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
-       uint16_t target_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_ps);
-       uint8_t  request;
-
-       if (data->pspp_notify_required  ||
-           data->pcie_performance_request) {
-               if (target_link_speed == PP_PCIEGen3)
-                       request = PCIE_PERF_REQ_GEN3;
-               else if (target_link_speed == PP_PCIEGen2)
-                       request = PCIE_PERF_REQ_GEN2;
-               else
-                       request = PCIE_PERF_REQ_GEN1;
-
-               if(request == PCIE_PERF_REQ_GEN1 && tonga_get_current_pcie_speed(hwmgr) > 0) {
-                       data->pcie_performance_request = false;
-                       return 0;
-               }
-
-               if (0 != acpi_pcie_perf_request(hwmgr->device, request, false)) {
-                       if (PP_PCIEGen2 == target_link_speed)
-                               printk("PSPP request to switch to Gen2 from Gen3 Failed!");
-                       else
-                               printk("PSPP request to switch to Gen1 from Gen2 Failed!");
-               }
-       }
-
-       data->pcie_performance_request = false;
-       return 0;
-}
-
-static int tonga_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
-{
-       int tmp_result, result = 0;
-
-       tmp_result = tonga_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to find DPM states clocks in DPM table!", result = tmp_result);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) {
-               tmp_result = tonga_request_link_speed_change_before_state_change(hwmgr, input);
-               PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to request link speed change before state change!", result = tmp_result);
-       }
-
-       tmp_result = tonga_freeze_sclk_mclk_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
-
-       tmp_result = tonga_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to populate and upload SCLK MCLK DPM levels!", result = tmp_result);
-
-       tmp_result = tonga_generate_dpm_level_enable_mask(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to generate DPM level enabled mask!", result = tmp_result);
-
-       tmp_result = tonga_update_vce_dpm(hwmgr, input);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update VCE DPM!", result = tmp_result);
-
-       tmp_result = tonga_update_sclk_threshold(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update SCLK threshold!", result = tmp_result);
-
-       tmp_result = tonga_update_and_upload_mc_reg_table(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload MC reg table!", result = tmp_result);
-
-       tmp_result = tonga_program_memory_timing_parameters_conditionally(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to program memory timing parameters!", result = tmp_result);
-
-       tmp_result = tonga_unfreeze_sclk_mclk_dpm(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to unfreeze SCLK MCLK DPM!", result = tmp_result);
-
-       tmp_result = tonga_upload_dpm_level_enable_mask(hwmgr);
-       PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload DPM level enabled mask!", result = tmp_result);
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) {
-               tmp_result = tonga_notify_link_speed_change_after_state_change(hwmgr, input);
-               PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to notify link speed change after state change!", result = tmp_result);
-       }
-
-       return result;
-}
-
-/**
-*  Set maximum target operating fan output PWM
-*
-* @param    pHwMgr:  the address of the powerplay hardware manager.
-* @param    usMaxFanPwm:  max operating fan PWM in percents
-* @return   The response that came from the SMC.
-*/
-static int tonga_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
-{
-       hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
-
-       if (phm_is_hw_access_blocked(hwmgr))
-               return 0;
-
-       return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm) ? 0 : -1);
-}
-
-int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
-{
-       uint32_t num_active_displays = 0;
-       struct cgs_display_info info = {0};
-       info.mode_info = NULL;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       num_active_displays = info.display_count;
-
-       if (num_active_displays > 1)  /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */
-               tonga_notify_smc_display_change(hwmgr, false);
-       else
-               tonga_notify_smc_display_change(hwmgr, true);
-
-       return 0;
-}
-
-/**
-* Programs the display gap
-*
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @return   always OK
-*/
-int tonga_program_display_gap(struct pp_hwmgr *hwmgr)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       uint32_t num_active_displays = 0;
-       uint32_t display_gap = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
-       uint32_t display_gap2;
-       uint32_t pre_vbi_time_in_us;
-       uint32_t frame_time_in_us;
-       uint32_t ref_clock;
-       uint32_t refresh_rate = 0;
-       struct cgs_display_info info = {0};
-       struct cgs_mode_info mode_info;
-
-       info.mode_info = &mode_info;
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-       num_active_displays = info.display_count;
-
-       display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL, DISP_GAP, (num_active_displays > 0)? DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL, display_gap);
-
-       ref_clock = mode_info.ref_clock;
-       refresh_rate = mode_info.refresh_rate;
-
-       if(0 == refresh_rate)
-               refresh_rate = 60;
-
-       frame_time_in_us = 1000000 / refresh_rate;
-
-       pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
-       display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU72_SoftRegisters, PreVBlankGap), 0x64);
-
-       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU72_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us));
-
-       if (num_active_displays == 1)
-               tonga_notify_smc_display_change(hwmgr, true);
-
-       return 0;
-}
-
-int tonga_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
-{
-
-       tonga_program_display_gap(hwmgr);
-
-       /* to do PhwTonga_CacUpdateDisplayConfiguration(pHwMgr); */
-       return 0;
-}
-
-/**
-*  Set maximum target operating fan output RPM
-*
-* @param    pHwMgr:  the address of the powerplay hardware manager.
-* @param    usMaxFanRpm:  max operating fan RPM value.
-* @return   The response that came from the SMC.
-*/
-static int tonga_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
-{
-       hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM = us_max_fan_pwm;
-
-       if (phm_is_hw_access_blocked(hwmgr))
-               return 0;
-
-       return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanRpmMax, us_max_fan_pwm) ? 0 : -1);
-}
-
-uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr)
-{
-       uint32_t reference_clock;
-       uint32_t tc;
-       uint32_t divide;
-
-       ATOM_FIRMWARE_INFO *fw_info;
-       uint16_t size;
-       uint8_t frev, crev;
-       int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
-
-       tc = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK);
-
-       if (tc)
-               return TCLK;
-
-       fw_info = (ATOM_FIRMWARE_INFO *)cgs_atom_get_data_table(hwmgr->device, index,
-                                                 &size, &frev, &crev);
-
-       if (!fw_info)
-               return 0;
-
-       reference_clock = le16_to_cpu(fw_info->usReferenceClock);
-
-       divide = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL, XTALIN_DIVIDE);
-
-       if (0 != divide)
-               return reference_clock / 4;
-
-       return reference_clock;
-}
-
-int tonga_dpm_set_interrupt_state(void *private_data,
-                                        unsigned src_id, unsigned type,
-                                        int enabled)
-{
-       uint32_t cg_thermal_int;
-       struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr;
-
-       if (hwmgr == NULL)
-               return -EINVAL;
-
-       switch (type) {
-       case AMD_THERMAL_IRQ_LOW_TO_HIGH:
-               if (enabled) {
-                       cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
-                       cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
-               } else {
-                       cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
-                       cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
-               }
-               break;
-
-       case AMD_THERMAL_IRQ_HIGH_TO_LOW:
-               if (enabled) {
-                       cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
-                       cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
-               } else {
-                       cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
-                       cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
-                       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
-               }
-               break;
-       default:
-               break;
-       }
-       return 0;
-}
-
-int tonga_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
-                                       const void *thermal_interrupt_info)
-{
-       int result;
-       const struct pp_interrupt_registration_info *info =
-                       (const struct pp_interrupt_registration_info *)thermal_interrupt_info;
-
-       if (info == NULL)
-               return -EINVAL;
-
-       result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST,
-                               tonga_dpm_set_interrupt_state,
-                               info->call_back, info->context);
-
-       if (result)
-               return -EINVAL;
-
-       result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST,
-                               tonga_dpm_set_interrupt_state,
-                               info->call_back, info->context);
-
-       if (result)
-               return -EINVAL;
-
-       return 0;
-}
-
-bool tonga_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       bool is_update_required = false;
-       struct cgs_display_info info = {0,0,NULL};
-
-       cgs_get_active_displays_info(hwmgr->device, &info);
-
-       if (data->display_timing.num_existing_displays != info.display_count)
-               is_update_required = true;
-/* TO DO NEED TO GET DEEP SLEEP CLOCK FROM DAL
-       if (phm_cap_enabled(hwmgr->hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
-               cgs_get_min_clock_settings(hwmgr->device, &min_clocks);
-               if(min_clocks.engineClockInSR != data->display_timing.minClockInSR)
-                       is_update_required = true;
-*/
-       return is_update_required;
-}
-
-static inline bool tonga_are_power_levels_equal(const struct tonga_performance_level *pl1,
-                                                          const struct tonga_performance_level *pl2)
-{
-       return ((pl1->memory_clock == pl2->memory_clock) &&
-                 (pl1->engine_clock == pl2->engine_clock) &&
-                 (pl1->pcie_gen == pl2->pcie_gen) &&
-                 (pl1->pcie_lane == pl2->pcie_lane));
-}
-
-int tonga_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal)
-{
-       const struct tonga_power_state *psa = cast_const_phw_tonga_power_state(pstate1);
-       const struct tonga_power_state *psb = cast_const_phw_tonga_power_state(pstate2);
-       int i;
-
-       if (equal == NULL || psa == NULL || psb == NULL)
-               return -EINVAL;
-
-       /* If the two states don't even have the same number of performance levels they cannot be the same state. */
-       if (psa->performance_level_count != psb->performance_level_count) {
-               *equal = false;
-               return 0;
-       }
-
-       for (i = 0; i < psa->performance_level_count; i++) {
-               if (!tonga_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
-                       /* If we have found even one performance level pair that is different the states are different. */
-                       *equal = false;
-                       return 0;
-               }
-       }
-
-       /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
-       *equal = ((psa->uvd_clocks.VCLK == psb->uvd_clocks.VCLK) && (psa->uvd_clocks.DCLK == psb->uvd_clocks.DCLK));
-       *equal &= ((psa->vce_clocks.EVCLK == psb->vce_clocks.EVCLK) && (psa->vce_clocks.ECCLK == psb->vce_clocks.ECCLK));
-       *equal &= (psa->sclk_threshold == psb->sclk_threshold);
-       *equal &= (psa->acp_clk == psb->acp_clk);
-
-       return 0;
-}
-
-static int tonga_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
-{
-       if (mode) {
-               /* stop auto-manage */
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
-                               PHM_PlatformCaps_MicrocodeFanControl))
-                       tonga_fan_ctrl_stop_smc_fan_control(hwmgr);
-               tonga_fan_ctrl_set_static_mode(hwmgr, mode);
-       } else
-               /* restart auto-manage */
-               tonga_fan_ctrl_reset_fan_speed_to_default(hwmgr);
-
-       return 0;
-}
-
-static int tonga_get_fan_control_mode(struct pp_hwmgr *hwmgr)
-{
-       if (hwmgr->fan_ctrl_is_in_default_mode)
-               return hwmgr->fan_ctrl_default_mode;
-       else
-               return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                               CG_FDO_CTRL2, FDO_PWM_MODE);
-}
-
-static int tonga_force_clock_level(struct pp_hwmgr *hwmgr,
-               enum pp_clock_type type, uint32_t mask)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-
-       if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
-               return -EINVAL;
-
-       switch (type) {
-       case PP_SCLK:
-               if (!data->sclk_dpm_key_disabled)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_SCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
-               break;
-       case PP_MCLK:
-               if (!data->mclk_dpm_key_disabled)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_MCLKDPM_SetEnabledMask,
-                                       data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
-               break;
-       case PP_PCIE:
-       {
-               uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
-               uint32_t level = 0;
-
-               while (tmp >>= 1)
-                       level++;
-
-               if (!data->pcie_dpm_key_disabled)
-                       smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
-                                       PPSMC_MSG_PCIeDPM_ForceLevel,
-                                       level);
-               break;
-       }
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int tonga_print_clock_levels(struct pp_hwmgr *hwmgr,
-               enum pp_clock_type type, char *buf)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
-       struct tonga_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
-       struct tonga_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table);
-       int i, now, size = 0;
-       uint32_t clock, pcie_speed;
-
-       switch (type) {
-       case PP_SCLK:
-               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
-               clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-
-               for (i = 0; i < sclk_table->count; i++) {
-                       if (clock > sclk_table->dpm_levels[i].value)
-                               continue;
-                       break;
-               }
-               now = i;
-
-               for (i = 0; i < sclk_table->count; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
-                                       i, sclk_table->dpm_levels[i].value / 100,
-                                       (i == now) ? "*" : "");
-               break;
-       case PP_MCLK:
-               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
-               clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
-
-               for (i = 0; i < mclk_table->count; i++) {
-                       if (clock > mclk_table->dpm_levels[i].value)
-                               continue;
-                       break;
-               }
-               now = i;
-
-               for (i = 0; i < mclk_table->count; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
-                                       i, mclk_table->dpm_levels[i].value / 100,
-                                       (i == now) ? "*" : "");
-               break;
-       case PP_PCIE:
-               pcie_speed = tonga_get_current_pcie_speed(hwmgr);
-               for (i = 0; i < pcie_table->count; i++) {
-                       if (pcie_speed != pcie_table->dpm_levels[i].value)
-                               continue;
-                       break;
-               }
-               now = i;
-
-               for (i = 0; i < pcie_table->count; i++)
-                       size += sprintf(buf + size, "%d: %s %s\n", i,
-                                       (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x8" :
-                                       (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" :
-                                       (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "",
-                                       (i == now) ? "*" : "");
-               break;
-       default:
-               break;
-       }
-       return size;
-}
-
-static int tonga_get_sclk_od(struct pp_hwmgr *hwmgr)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
-       struct tonga_single_dpm_table *golden_sclk_table =
-                       &(data->golden_dpm_table.sclk_table);
-       int value;
-
-       value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
-                       100 /
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
-
-       return value;
-}
-
-static int tonga_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_single_dpm_table *golden_sclk_table =
-                       &(data->golden_dpm_table.sclk_table);
-       struct pp_power_state  *ps;
-       struct tonga_power_state  *tonga_ps;
-
-       if (value > 20)
-               value = 20;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
-
-       tonga_ps->performance_levels[tonga_ps->performance_level_count - 1].engine_clock =
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
-                       value / 100 +
-                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
-
-       return 0;
-}
-
-static int tonga_get_mclk_od(struct pp_hwmgr *hwmgr)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
-       struct tonga_single_dpm_table *golden_mclk_table =
-                       &(data->golden_dpm_table.mclk_table);
-       int value;
-
-       value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
-                       100 /
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
-
-       return value;
-}
-
-static int tonga_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       struct tonga_single_dpm_table *golden_mclk_table =
-                       &(data->golden_dpm_table.mclk_table);
-       struct pp_power_state  *ps;
-       struct tonga_power_state  *tonga_ps;
-
-       if (value > 20)
-               value = 20;
-
-       ps = hwmgr->request_ps;
-
-       if (ps == NULL)
-               return -EINVAL;
-
-       tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
-
-       tonga_ps->performance_levels[tonga_ps->performance_level_count - 1].memory_clock =
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
-                       value / 100 +
-                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
-
-       return 0;
-}
-
-static const struct pp_hwmgr_func tonga_hwmgr_funcs = {
-       .backend_init = &tonga_hwmgr_backend_init,
-       .backend_fini = &tonga_hwmgr_backend_fini,
-       .asic_setup = &tonga_setup_asic_task,
-       .dynamic_state_management_enable = &tonga_enable_dpm_tasks,
-       .dynamic_state_management_disable = &tonga_disable_dpm_tasks,
-       .apply_state_adjust_rules = tonga_apply_state_adjust_rules,
-       .force_dpm_level = &tonga_force_dpm_level,
-       .power_state_set = tonga_set_power_state_tasks,
-       .get_power_state_size = tonga_get_power_state_size,
-       .get_mclk = tonga_dpm_get_mclk,
-       .get_sclk = tonga_dpm_get_sclk,
-       .patch_boot_state = tonga_dpm_patch_boot_state,
-       .get_pp_table_entry = tonga_get_pp_table_entry,
-       .get_num_of_pp_table_entries = tonga_get_number_of_powerplay_table_entries,
-       .print_current_perforce_level = tonga_print_current_perforce_level,
-       .powerdown_uvd = tonga_phm_powerdown_uvd,
-       .powergate_uvd = tonga_phm_powergate_uvd,
-       .powergate_vce = tonga_phm_powergate_vce,
-       .disable_clock_power_gating = tonga_phm_disable_clock_power_gating,
-       .update_clock_gatings = tonga_phm_update_clock_gatings,
-       .notify_smc_display_config_after_ps_adjustment = tonga_notify_smc_display_config_after_ps_adjustment,
-       .display_config_changed = tonga_display_configuration_changed_task,
-       .set_max_fan_pwm_output = tonga_set_max_fan_pwm_output,
-       .set_max_fan_rpm_output = tonga_set_max_fan_rpm_output,
-       .get_temperature = tonga_thermal_get_temperature,
-       .stop_thermal_controller = tonga_thermal_stop_thermal_controller,
-       .get_fan_speed_info = tonga_fan_ctrl_get_fan_speed_info,
-       .get_fan_speed_percent = tonga_fan_ctrl_get_fan_speed_percent,
-       .set_fan_speed_percent = tonga_fan_ctrl_set_fan_speed_percent,
-       .reset_fan_speed_to_default = tonga_fan_ctrl_reset_fan_speed_to_default,
-       .get_fan_speed_rpm = tonga_fan_ctrl_get_fan_speed_rpm,
-       .set_fan_speed_rpm = tonga_fan_ctrl_set_fan_speed_rpm,
-       .uninitialize_thermal_controller = tonga_thermal_ctrl_uninitialize_thermal_controller,
-       .register_internal_thermal_interrupt = tonga_register_internal_thermal_interrupt,
-       .check_smc_update_required_for_display_configuration = tonga_check_smc_update_required_for_display_configuration,
-       .check_states_equal = tonga_check_states_equal,
-       .set_fan_control_mode = tonga_set_fan_control_mode,
-       .get_fan_control_mode = tonga_get_fan_control_mode,
-       .force_clock_level = tonga_force_clock_level,
-       .print_clock_levels = tonga_print_clock_levels,
-       .get_sclk_od = tonga_get_sclk_od,
-       .set_sclk_od = tonga_set_sclk_od,
-       .get_mclk_od = tonga_get_mclk_od,
-       .set_mclk_od = tonga_set_mclk_od,
-};
-
-int tonga_hwmgr_init(struct pp_hwmgr *hwmgr)
-{
-       hwmgr->hwmgr_func = &tonga_hwmgr_funcs;
-       hwmgr->pptable_func = &tonga_pptable_funcs;
-       pp_tonga_thermal_initialize(hwmgr);
-       return 0;
-}
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h
deleted file mode 100644 (file)
index 3961884..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright 2015 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 TONGA_HWMGR_H
-#define TONGA_HWMGR_H
-
-#include "hwmgr.h"
-#include "smu72_discrete.h"
-#include "ppatomctrl.h"
-#include "ppinterrupt.h"
-#include "tonga_powertune.h"
-#include "pp_endian.h"
-
-#define TONGA_MAX_HARDWARE_POWERLEVELS 2
-#define TONGA_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15
-
-struct tonga_performance_level {
-       uint32_t        memory_clock;
-       uint32_t        engine_clock;
-       uint16_t    pcie_gen;
-       uint16_t    pcie_lane;
-};
-
-struct _phw_tonga_bacos {
-       uint32_t                          best_match;
-       uint32_t                          baco_flags;
-       struct tonga_performance_level            performance_level;
-};
-typedef struct _phw_tonga_bacos phw_tonga_bacos;
-
-struct _phw_tonga_uvd_clocks {
-       uint32_t   VCLK;
-       uint32_t   DCLK;
-};
-
-typedef struct _phw_tonga_uvd_clocks phw_tonga_uvd_clocks;
-
-struct _phw_tonga_vce_clocks {
-       uint32_t   EVCLK;
-       uint32_t   ECCLK;
-};
-
-typedef struct _phw_tonga_vce_clocks phw_tonga_vce_clocks;
-
-struct tonga_power_state {
-       uint32_t                    magic;
-       phw_tonga_uvd_clocks        uvd_clocks;
-       phw_tonga_vce_clocks        vce_clocks;
-       uint32_t                    sam_clk;
-       uint32_t                    acp_clk;
-       uint16_t                    performance_level_count;
-       bool                        dc_compatible;
-       uint32_t                    sclk_threshold;
-       struct tonga_performance_level performance_levels[TONGA_MAX_HARDWARE_POWERLEVELS];
-};
-
-struct _phw_tonga_dpm_level {
-       bool            enabled;
-       uint32_t    value;
-       uint32_t    param1;
-};
-typedef struct _phw_tonga_dpm_level phw_tonga_dpm_level;
-
-#define TONGA_MAX_DEEPSLEEP_DIVIDER_ID 5
-#define MAX_REGULAR_DPM_NUMBER 8
-#define TONGA_MINIMUM_ENGINE_CLOCK 2500
-
-struct tonga_single_dpm_table {
-       uint32_t count;
-       phw_tonga_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
-};
-
-struct tonga_dpm_table {
-       struct tonga_single_dpm_table  sclk_table;
-       struct tonga_single_dpm_table  mclk_table;
-       struct tonga_single_dpm_table  pcie_speed_table;
-       struct tonga_single_dpm_table  vddc_table;
-       struct tonga_single_dpm_table  vdd_gfx_table;
-       struct tonga_single_dpm_table  vdd_ci_table;
-       struct tonga_single_dpm_table  mvdd_table;
-};
-typedef struct _phw_tonga_dpm_table phw_tonga_dpm_table;
-
-
-struct _phw_tonga_clock_regisiters {
-       uint32_t  vCG_SPLL_FUNC_CNTL;
-       uint32_t  vCG_SPLL_FUNC_CNTL_2;
-       uint32_t  vCG_SPLL_FUNC_CNTL_3;
-       uint32_t  vCG_SPLL_FUNC_CNTL_4;
-       uint32_t  vCG_SPLL_SPREAD_SPECTRUM;
-       uint32_t  vCG_SPLL_SPREAD_SPECTRUM_2;
-       uint32_t  vDLL_CNTL;
-       uint32_t  vMCLK_PWRMGT_CNTL;
-       uint32_t  vMPLL_AD_FUNC_CNTL;
-       uint32_t  vMPLL_DQ_FUNC_CNTL;
-       uint32_t  vMPLL_FUNC_CNTL;
-       uint32_t  vMPLL_FUNC_CNTL_1;
-       uint32_t  vMPLL_FUNC_CNTL_2;
-       uint32_t  vMPLL_SS1;
-       uint32_t  vMPLL_SS2;
-};
-typedef struct _phw_tonga_clock_regisiters phw_tonga_clock_registers;
-
-struct _phw_tonga_voltage_smio_registers {
-       uint32_t vs0_vid_lower_smio_cntl;
-};
-typedef struct _phw_tonga_voltage_smio_registers phw_tonga_voltage_smio_registers;
-
-
-struct _phw_tonga_mc_reg_entry {
-       uint32_t mclk_max;
-       uint32_t mc_data[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
-};
-typedef struct _phw_tonga_mc_reg_entry phw_tonga_mc_reg_entry;
-
-struct _phw_tonga_mc_reg_table {
-       uint8_t   last;               /* number of registers*/
-       uint8_t   num_entries;        /* number of entries in mc_reg_table_entry used*/
-       uint16_t  validflag;          /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
-       phw_tonga_mc_reg_entry    mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
-       SMU72_Discrete_MCRegisterAddress mc_reg_address[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
-};
-typedef struct _phw_tonga_mc_reg_table phw_tonga_mc_reg_table;
-
-#define DISABLE_MC_LOADMICROCODE   1
-#define DISABLE_MC_CFGPROGRAMMING  2
-
-/*Ultra Low Voltage parameter structure */
-struct _phw_tonga_ulv_parm{
-       bool    ulv_supported;
-       uint32_t   ch_ulv_parameter;
-       uint32_t   ulv_volt_change_delay;
-       struct tonga_performance_level   ulv_power_level;
-};
-typedef struct _phw_tonga_ulv_parm phw_tonga_ulv_parm;
-
-#define TONGA_MAX_LEAKAGE_COUNT  8
-
-struct _phw_tonga_leakage_voltage {
-       uint16_t  count;
-       uint16_t  leakage_id[TONGA_MAX_LEAKAGE_COUNT];
-       uint16_t  actual_voltage[TONGA_MAX_LEAKAGE_COUNT];
-};
-typedef struct _phw_tonga_leakage_voltage phw_tonga_leakage_voltage;
-
-struct _phw_tonga_display_timing {
-       uint32_t min_clock_insr;
-       uint32_t num_existing_displays;
-};
-typedef struct _phw_tonga_display_timing phw_tonga_display_timing;
-
-struct _phw_tonga_dpmlevel_enable_mask {
-       uint32_t uvd_dpm_enable_mask;
-       uint32_t vce_dpm_enable_mask;
-       uint32_t acp_dpm_enable_mask;
-       uint32_t samu_dpm_enable_mask;
-       uint32_t sclk_dpm_enable_mask;
-       uint32_t mclk_dpm_enable_mask;
-       uint32_t pcie_dpm_enable_mask;
-};
-typedef struct _phw_tonga_dpmlevel_enable_mask phw_tonga_dpmlevel_enable_mask;
-
-struct _phw_tonga_pcie_perf_range {
-       uint16_t max;
-       uint16_t min;
-};
-typedef struct _phw_tonga_pcie_perf_range phw_tonga_pcie_perf_range;
-
-struct _phw_tonga_vbios_boot_state {
-       uint16_t                                        mvdd_bootup_value;
-       uint16_t                                        vddc_bootup_value;
-       uint16_t                                        vddci_bootup_value;
-       uint16_t                                        vddgfx_bootup_value;
-       uint32_t                                        sclk_bootup_value;
-       uint32_t                                        mclk_bootup_value;
-       uint16_t                                        pcie_gen_bootup_value;
-       uint16_t                                        pcie_lane_bootup_value;
-};
-typedef struct _phw_tonga_vbios_boot_state phw_tonga_vbios_boot_state;
-
-#define DPMTABLE_OD_UPDATE_SCLK     0x00000001
-#define DPMTABLE_OD_UPDATE_MCLK     0x00000002
-#define DPMTABLE_UPDATE_SCLK        0x00000004
-#define DPMTABLE_UPDATE_MCLK        0x00000008
-
-/* We need to review which fields are needed. */
-/* This is mostly a copy of the RV7xx/Evergreen structure which is close, but not identical to the N.Islands one. */
-struct tonga_hwmgr {
-       struct tonga_dpm_table               dpm_table;
-       struct tonga_dpm_table               golden_dpm_table;
-
-       uint32_t                           voting_rights_clients0;
-       uint32_t                           voting_rights_clients1;
-       uint32_t                           voting_rights_clients2;
-       uint32_t                           voting_rights_clients3;
-       uint32_t                           voting_rights_clients4;
-       uint32_t                           voting_rights_clients5;
-       uint32_t                           voting_rights_clients6;
-       uint32_t                           voting_rights_clients7;
-       uint32_t                           static_screen_threshold_unit;
-       uint32_t                           static_screen_threshold;
-       uint32_t                           voltage_control;
-       uint32_t                           vdd_gfx_control;
-
-       uint32_t                           vddc_vddci_delta;
-       uint32_t                           vddc_vddgfx_delta;
-
-       struct pp_interrupt_registration_info    internal_high_thermal_interrupt_info;
-       struct pp_interrupt_registration_info    internal_low_thermal_interrupt_info;
-       struct pp_interrupt_registration_info    smc_to_host_interrupt_info;
-       uint32_t                          active_auto_throttle_sources;
-
-       struct pp_interrupt_registration_info    external_throttle_interrupt;
-       irq_handler_func_t             external_throttle_callback;
-       void                             *external_throttle_context;
-
-       struct pp_interrupt_registration_info    ctf_interrupt_info;
-       irq_handler_func_t             ctf_callback;
-       void                             *ctf_context;
-
-       phw_tonga_clock_registers         clock_registers;
-       phw_tonga_voltage_smio_registers  voltage_smio_registers;
-
-       bool    is_memory_GDDR5;
-       uint16_t                          acpi_vddc;
-       bool    pspp_notify_required;        /* Flag to indicate if PSPP notification to SBIOS is required */
-       uint16_t                          force_pcie_gen;            /* The forced PCI-E speed if not 0xffff */
-       uint16_t                          acpi_pcie_gen;             /* The PCI-E speed at ACPI time */
-       uint32_t                           pcie_gen_cap;             /* The PCI-E speed capabilities bitmap from CAIL */
-       uint32_t                           pcie_lane_cap;            /* The PCI-E lane capabilities bitmap from CAIL */
-       uint32_t                           pcie_spc_cap;             /* Symbol Per Clock Capabilities from registry */
-       phw_tonga_leakage_voltage       vddc_leakage;            /* The Leakage VDDC supported (based on leakage ID).*/
-       phw_tonga_leakage_voltage       vddcgfx_leakage;         /* The Leakage VDDC supported (based on leakage ID). */
-       phw_tonga_leakage_voltage       vddci_leakage;           /* The Leakage VDDCI supported (based on leakage ID). */
-
-       uint32_t                           mvdd_control;
-       uint32_t                           vddc_mask_low;
-       uint32_t                           mvdd_mask_low;
-       uint16_t                          max_vddc_in_pp_table;        /* the maximum VDDC value in the powerplay table*/
-       uint16_t                          min_vddc_in_pp_table;
-       uint16_t                          max_vddci_in_pp_table;       /* the maximum VDDCI value in the powerplay table */
-       uint16_t                          min_vddci_in_pp_table;
-       uint32_t                           mclk_strobe_mode_threshold;
-       uint32_t                           mclk_stutter_mode_threshold;
-       uint32_t                           mclk_edc_enable_threshold;
-       uint32_t                           mclk_edc_wr_enable_threshold;
-       bool    is_uvd_enabled;
-       bool    is_xdma_enabled;
-       phw_tonga_vbios_boot_state      vbios_boot_state;
-
-       bool                         battery_state;
-       bool                         is_tlu_enabled;
-       bool                         pcie_performance_request;
-
-       /* -------------- SMC SRAM Address of firmware header tables ----------------*/
-       uint32_t                           sram_end;                 /* The first address after the SMC SRAM. */
-       uint32_t                           dpm_table_start;          /* The start of the dpm table in the SMC SRAM. */
-       uint32_t                           soft_regs_start;          /* The start of the soft registers in the SMC SRAM. */
-       uint32_t                           mc_reg_table_start;       /* The start of the mc register table in the SMC SRAM. */
-       uint32_t                           fan_table_start;          /* The start of the fan table in the SMC SRAM. */
-       uint32_t                           arb_table_start;          /* The start of the ARB setting table in the SMC SRAM. */
-       SMU72_Discrete_DpmTable         smc_state_table;             /* The carbon copy of the SMC state table. */
-       SMU72_Discrete_MCRegisters      mc_reg_table;
-       SMU72_Discrete_Ulv              ulv_setting;                 /* The carbon copy of ULV setting. */
-       /* -------------- Stuff originally coming from Evergreen --------------------*/
-       phw_tonga_mc_reg_table                  tonga_mc_reg_table;
-       uint32_t                         vdd_ci_control;
-       pp_atomctrl_voltage_table        vddc_voltage_table;
-       pp_atomctrl_voltage_table        vddci_voltage_table;
-       pp_atomctrl_voltage_table        vddgfx_voltage_table;
-       pp_atomctrl_voltage_table        mvdd_voltage_table;
-
-       uint32_t                           mgcg_cgtt_local2;
-       uint32_t                           mgcg_cgtt_local3;
-       uint32_t                           gpio_debug;
-       uint32_t                                                        mc_micro_code_feature;
-       uint32_t                                                        highest_mclk;
-       uint16_t                          acpi_vdd_ci;
-       uint8_t                           mvdd_high_index;
-       uint8_t                           mvdd_low_index;
-       bool                         dll_defaule_on;
-       bool                         performance_request_registered;
-
-       /* ----------------- Low Power Features ---------------------*/
-       phw_tonga_bacos                                 bacos;
-       phw_tonga_ulv_parm              ulv;
-       /* ----------------- CAC Stuff ---------------------*/
-       uint32_t                                        cac_table_start;
-       bool                         cac_configuration_required;    /* TRUE if PP_CACConfigurationRequired == 1 */
-       bool                         driver_calculate_cac_leakage;  /* TRUE if PP_DriverCalculateCACLeakage == 1 */
-       bool                         cac_enabled;
-       /* ----------------- DPM2 Parameters ---------------------*/
-       uint32_t                                        power_containment_features;
-       bool                         enable_bapm_feature;
-       bool                         enable_tdc_limit_feature;
-       bool                         enable_pkg_pwr_tracking_feature;
-       bool                         disable_uvd_power_tune_feature;
-       phw_tonga_pt_defaults           *power_tune_defaults;
-       SMU72_Discrete_PmFuses           power_tune_table;
-       uint32_t                           ul_dte_tj_offset;             /* Fudge factor in DPM table to correct HW DTE errors */
-       uint32_t                           fast_watemark_threshold;      /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */
-
-       /* ----------------- Phase Shedding ---------------------*/
-       bool                         vddc_phase_shed_control;
-       /* --------------------- DI/DT --------------------------*/
-       phw_tonga_display_timing       display_timing;
-       /* --------- ReadRegistry data for memory and engine clock margins ---- */
-       uint32_t                           engine_clock_data;
-       uint32_t                           memory_clock_data;
-       /* -------- Thermal Temperature Setting --------------*/
-       phw_tonga_dpmlevel_enable_mask     dpm_level_enable_mask;
-       uint32_t                           need_update_smu7_dpm_table;
-       uint32_t                           sclk_dpm_key_disabled;
-       uint32_t                           mclk_dpm_key_disabled;
-       uint32_t                           pcie_dpm_key_disabled;
-       uint32_t                           min_engine_clocks; /* used to store the previous dal min sclock */
-       phw_tonga_pcie_perf_range       pcie_gen_performance;
-       phw_tonga_pcie_perf_range       pcie_lane_performance;
-       phw_tonga_pcie_perf_range       pcie_gen_power_saving;
-       phw_tonga_pcie_perf_range       pcie_lane_power_saving;
-       bool                            use_pcie_performance_levels;
-       bool                            use_pcie_power_saving_levels;
-       uint32_t                           activity_target[SMU72_MAX_LEVELS_GRAPHICS]; /* percentage value from 0-100, default 50 */
-       uint32_t                           mclk_activity_target;
-       uint32_t                           low_sclk_interrupt_threshold;
-       uint32_t                           last_mclk_dpm_enable_mask;
-       bool                                                            uvd_enabled;
-       uint32_t                           pcc_monitor_enabled;
-
-       /* --------- Power Gating States ------------*/
-       bool                           uvd_power_gated;  /* 1: gated, 0:not gated */
-       bool                           vce_power_gated;  /* 1: gated, 0:not gated */
-       bool                           samu_power_gated; /* 1: gated, 0:not gated */
-       bool                           acp_power_gated;  /* 1: gated, 0:not gated */
-       bool                           pg_acp_init;
-};
-
-typedef struct tonga_hwmgr tonga_hwmgr;
-
-#define TONGA_DPM2_NEAR_TDP_DEC          10
-#define TONGA_DPM2_ABOVE_SAFE_INC        5
-#define TONGA_DPM2_BELOW_SAFE_INC        20
-
-#define TONGA_DPM2_LTA_WINDOW_SIZE       7  /* Log2 of the LTA window size (l2numWin_TDP). Eg. If LTA windows size is 128, then this value should be Log2(128) = 7. */
-
-#define TONGA_DPM2_LTS_TRUNCATE          0
-
-#define TONGA_DPM2_TDP_SAFE_LIMIT_PERCENT            80  /* Maximum 100 */
-
-#define TONGA_DPM2_MAXPS_PERCENT_H                   90  /* Maximum 0xFF */
-#define TONGA_DPM2_MAXPS_PERCENT_M                   90  /* Maximum 0xFF */
-
-#define TONGA_DPM2_PWREFFICIENCYRATIO_MARGIN         50
-
-#define TONGA_DPM2_SQ_RAMP_MAX_POWER                 0x3FFF
-#define TONGA_DPM2_SQ_RAMP_MIN_POWER                 0x12
-#define TONGA_DPM2_SQ_RAMP_MAX_POWER_DELTA           0x15
-#define TONGA_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE  0x1E
-#define TONGA_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO  0xF
-
-#define TONGA_VOLTAGE_CONTROL_NONE                   0x0
-#define TONGA_VOLTAGE_CONTROL_BY_GPIO                0x1
-#define TONGA_VOLTAGE_CONTROL_BY_SVID2               0x2
-#define TONGA_VOLTAGE_CONTROL_MERGED                 0x3
-
-#define TONGA_Q88_FORMAT_CONVERSION_UNIT             256 /*To convert to Q8.8 format for firmware */
-
-#define TONGA_UNUSED_GPIO_PIN                        0x7F
-
-int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
-int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
-int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
-int tonga_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable);
-int tonga_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
-uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
-
-#endif
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h
deleted file mode 100644 (file)
index 8e6670b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2015 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 TONGA_POWERTUNE_H
-#define TONGA_POWERTUNE_H
-
-enum _phw_tonga_ptc_config_reg_type {
-       TONGA_CONFIGREG_MMR = 0,
-       TONGA_CONFIGREG_SMC_IND,
-       TONGA_CONFIGREG_DIDT_IND,
-       TONGA_CONFIGREG_CACHE,
-
-       TONGA_CONFIGREG_MAX
-};
-typedef enum _phw_tonga_ptc_config_reg_type phw_tonga_ptc_config_reg_type;
-
-/* PowerContainment Features */
-#define POWERCONTAINMENT_FEATURE_BAPM            0x00000001
-#define POWERCONTAINMENT_FEATURE_TDCLimit        0x00000002
-#define POWERCONTAINMENT_FEATURE_PkgPwrLimit     0x00000004
-
-struct _phw_tonga_pt_config_reg {
-       uint32_t                           Offset;
-       uint32_t                           Mask;
-       uint32_t                           Shift;
-       uint32_t                           Value;
-       phw_tonga_ptc_config_reg_type     Type;
-};
-typedef struct _phw_tonga_pt_config_reg phw_tonga_pt_config_reg;
-
-struct _phw_tonga_pt_defaults {
-       uint8_t   svi_load_line_en;
-       uint8_t   svi_load_line_vddC;
-       uint8_t   tdc_vddc_throttle_release_limit_perc;
-       uint8_t   tdc_mawt;
-       uint8_t   tdc_waterfall_ctl;
-       uint8_t   dte_ambient_temp_base;
-       uint32_t  display_cac;
-       uint32_t  bamp_temp_gradient;
-       uint16_t  bapmti_r[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
-       uint16_t  bapmti_rc[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
-};
-typedef struct _phw_tonga_pt_defaults phw_tonga_pt_defaults;
-
-#endif
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_pptable.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_pptable.h
deleted file mode 100644 (file)
index f127198..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright 2015 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 TONGA_PPTABLE_H
-#define TONGA_PPTABLE_H
-
-/** \file
- * This is a PowerPlay table header file
- */
-#pragma pack(push, 1)
-
-#include "hwmgr.h"
-
-#define ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f
-#define ATOM_TONGA_PP_FANPARAMETERS_NOFAN                                 0x80    /* No fan is connected to this controller. */
-
-#define ATOM_TONGA_PP_THERMALCONTROLLER_NONE      0
-#define ATOM_TONGA_PP_THERMALCONTROLLER_LM96163   17
-#define ATOM_TONGA_PP_THERMALCONTROLLER_TONGA     21
-#define ATOM_TONGA_PP_THERMALCONTROLLER_FIJI      22
-
-/*
- * Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
- * We probably should reserve the bit 0x80 for this use.
- * To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here).
- * The driver can pick the correct internal controller based on the ASIC.
- */
-
-#define ATOM_TONGA_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL   0x89    /* ADT7473 Fan Control + Internal Thermal Controller */
-#define ATOM_TONGA_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL   0x8D    /* EMC2103 Fan Control + Internal Thermal Controller */
-
-/*/* ATOM_TONGA_POWERPLAYTABLE::ulPlatformCaps */
-#define ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL              0x1            /* This cap indicates whether vddgfx will be a separated power rail. */
-#define ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY                   0x2            /* This cap indicates whether this is a mobile part and CCC need to show Powerplay page. */
-#define ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE            0x4            /* This cap indicates whether power source notificaiton is done by SBIOS directly. */
-#define ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND      0x8            /* Enable the option to overwrite voltage island feature to be disabled, regardless of VddGfx power rail support. */
-#define ____RETIRE16____                                0x10
-#define ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC                 0x20            /* This cap indicates whether power source notificaiton is done by GPIO directly. */
-#define ____RETIRE64____                                0x40
-#define ____RETIRE128____                               0x80
-#define ____RETIRE256____                              0x100
-#define ____RETIRE512____                              0x200
-#define ____RETIRE1024____                             0x400
-#define ____RETIRE2048____                             0x800
-#define ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL             0x1000            /* This cap indicates dynamic MVDD is required. Uncheck to disable it. */
-#define ____RETIRE2000____                            0x2000
-#define ____RETIRE4000____                            0x4000
-#define ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL            0x8000            /* This cap indicates dynamic VDDCI is required. Uncheck to disable it. */
-#define ____RETIRE10000____                          0x10000
-#define ATOM_TONGA_PP_PLATFORM_CAP_BACO                    0x20000            /* Enable to indicate the driver supports BACO state. */
-
-#define ATOM_TONGA_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17         0x100000     /* Enable to indicate the driver supports thermal2GPIO17. */
-#define ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL  0x1000000     /* Enable to indicate if thermal and PCC are sharing the same GPIO */
-#define ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE       0x2000000
-
-/* ATOM_PPLIB_NONCLOCK_INFO::usClassification */
-#define ATOM_PPLIB_CLASSIFICATION_UI_MASK               0x0007
-#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT              0
-#define ATOM_PPLIB_CLASSIFICATION_UI_NONE               0
-#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY            1
-#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED           3
-#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE        5
-/* 2, 4, 6, 7 are reserved */
-
-#define ATOM_PPLIB_CLASSIFICATION_BOOT                  0x0008
-#define ATOM_PPLIB_CLASSIFICATION_THERMAL               0x0010
-#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE    0x0020
-#define ATOM_PPLIB_CLASSIFICATION_REST                  0x0040
-#define ATOM_PPLIB_CLASSIFICATION_FORCED                0x0080
-#define ATOM_PPLIB_CLASSIFICATION_ACPI                  0x1000
-
-/* ATOM_PPLIB_NONCLOCK_INFO::usClassification2 */
-#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001
-
-#define ATOM_Tonga_DISALLOW_ON_DC                       0x00004000
-#define ATOM_Tonga_ENABLE_VARIBRIGHT                    0x00008000
-
-#define ATOM_Tonga_TABLE_REVISION_TONGA                 7
-
-typedef struct _ATOM_Tonga_POWERPLAYTABLE {
-       ATOM_COMMON_TABLE_HEADER sHeader;
-
-       UCHAR  ucTableRevision;
-       USHORT usTableSize;                                             /*the size of header structure */
-
-       ULONG   ulGoldenPPID;
-       ULONG   ulGoldenRevision;
-       USHORT  usFormatID;
-
-       USHORT  usVoltageTime;                                   /*in microseconds */
-       ULONG   ulPlatformCaps;                                   /*See ATOM_Tonga_CAPS_* */
-
-       ULONG   ulMaxODEngineClock;                        /*For Overdrive.  */
-       ULONG   ulMaxODMemoryClock;                        /*For Overdrive. */
-
-       USHORT  usPowerControlLimit;
-       USHORT  usUlvVoltageOffset;                               /*in mv units */
-
-       USHORT  usStateArrayOffset;                               /*points to ATOM_Tonga_State_Array */
-       USHORT  usFanTableOffset;                                 /*points to ATOM_Tonga_Fan_Table */
-       USHORT  usThermalControllerOffset;                 /*points to ATOM_Tonga_Thermal_Controller */
-       USHORT  usReserv;                                                  /*CustomThermalPolicy removed for Tonga. Keep this filed as reserved. */
-
-       USHORT  usMclkDependencyTableOffset;       /*points to ATOM_Tonga_MCLK_Dependency_Table */
-       USHORT  usSclkDependencyTableOffset;       /*points to ATOM_Tonga_SCLK_Dependency_Table */
-       USHORT  usVddcLookupTableOffset;                   /*points to ATOM_Tonga_Voltage_Lookup_Table */
-       USHORT  usVddgfxLookupTableOffset;              /*points to ATOM_Tonga_Voltage_Lookup_Table */
-
-       USHORT  usMMDependencyTableOffset;                /*points to ATOM_Tonga_MM_Dependency_Table */
-
-       USHORT  usVCEStateTableOffset;                     /*points to ATOM_Tonga_VCE_State_Table; */
-
-       USHORT  usPPMTableOffset;                                 /*points to ATOM_Tonga_PPM_Table */
-       USHORT  usPowerTuneTableOffset;                   /*points to ATOM_PowerTune_Table */
-
-       USHORT  usHardLimitTableOffset;                    /*points to ATOM_Tonga_Hard_Limit_Table */
-
-       USHORT  usPCIETableOffset;                                /*points to ATOM_Tonga_PCIE_Table */
-
-       USHORT  usGPIOTableOffset;                                /*points to ATOM_Tonga_GPIO_Table */
-
-       USHORT  usReserved[6];                                     /*TODO: modify reserved size to fit structure aligning */
-} ATOM_Tonga_POWERPLAYTABLE;
-
-typedef struct _ATOM_Tonga_State {
-       UCHAR  ucEngineClockIndexHigh;
-       UCHAR  ucEngineClockIndexLow;
-
-       UCHAR  ucMemoryClockIndexHigh;
-       UCHAR  ucMemoryClockIndexLow;
-
-       UCHAR  ucPCIEGenLow;
-       UCHAR  ucPCIEGenHigh;
-
-       UCHAR  ucPCIELaneLow;
-       UCHAR  ucPCIELaneHigh;
-
-       USHORT usClassification;
-       ULONG ulCapsAndSettings;
-       USHORT usClassification2;
-       UCHAR  ucUnused[4];
-} ATOM_Tonga_State;
-
-typedef struct _ATOM_Tonga_State_Array {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;             /* Number of entries. */
-       ATOM_Tonga_State states[1];     /* Dynamically allocate entries. */
-} ATOM_Tonga_State_Array;
-
-typedef struct _ATOM_Tonga_MCLK_Dependency_Record {
-       UCHAR  ucVddcInd;       /* Vddc voltage */
-       USHORT usVddci;
-       USHORT usVddgfxOffset;  /* Offset relative to Vddc voltage */
-       USHORT usMvdd;
-       ULONG ulMclk;
-       USHORT usReserved;
-} ATOM_Tonga_MCLK_Dependency_Record;
-
-typedef struct _ATOM_Tonga_MCLK_Dependency_Table {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;                                                                             /* Number of entries. */
-       ATOM_Tonga_MCLK_Dependency_Record entries[1];                           /* Dynamically allocate entries. */
-} ATOM_Tonga_MCLK_Dependency_Table;
-
-typedef struct _ATOM_Tonga_SCLK_Dependency_Record {
-       UCHAR  ucVddInd;                                                                                        /* Base voltage */
-       USHORT usVddcOffset;                                                                            /* Offset relative to base voltage */
-       ULONG ulSclk;
-       USHORT usEdcCurrent;
-       UCHAR  ucReliabilityTemperature;
-       UCHAR  ucCKSVOffsetandDisable;                                                    /* Bits 0~6: Voltage offset for CKS, Bit 7: Disable/enable for the SCLK level. */
-} ATOM_Tonga_SCLK_Dependency_Record;
-
-typedef struct _ATOM_Tonga_SCLK_Dependency_Table {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;                                                                             /* Number of entries. */
-       ATOM_Tonga_SCLK_Dependency_Record entries[1];                            /* Dynamically allocate entries. */
-} ATOM_Tonga_SCLK_Dependency_Table;
-
-typedef struct _ATOM_Polaris_SCLK_Dependency_Record {
-       UCHAR  ucVddInd;                                                                                        /* Base voltage */
-       USHORT usVddcOffset;                                                                            /* Offset relative to base voltage */
-       ULONG ulSclk;
-       USHORT usEdcCurrent;
-       UCHAR  ucReliabilityTemperature;
-       UCHAR  ucCKSVOffsetandDisable;                  /* Bits 0~6: Voltage offset for CKS, Bit 7: Disable/enable for the SCLK level. */
-       ULONG  ulSclkOffset;
-} ATOM_Polaris_SCLK_Dependency_Record;
-
-typedef struct _ATOM_Polaris_SCLK_Dependency_Table {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;                                                     /* Number of entries. */
-       ATOM_Polaris_SCLK_Dependency_Record entries[1];                          /* Dynamically allocate entries. */
-} ATOM_Polaris_SCLK_Dependency_Table;
-
-typedef struct _ATOM_Tonga_PCIE_Record {
-       UCHAR ucPCIEGenSpeed;
-       UCHAR usPCIELaneWidth;
-       UCHAR ucReserved[2];
-} ATOM_Tonga_PCIE_Record;
-
-typedef struct _ATOM_Tonga_PCIE_Table {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;                                                                             /* Number of entries. */
-       ATOM_Tonga_PCIE_Record entries[1];                                                      /* Dynamically allocate entries. */
-} ATOM_Tonga_PCIE_Table;
-
-typedef struct _ATOM_Polaris10_PCIE_Record {
-       UCHAR ucPCIEGenSpeed;
-       UCHAR usPCIELaneWidth;
-       UCHAR ucReserved[2];
-       ULONG ulPCIE_Sclk;
-} ATOM_Polaris10_PCIE_Record;
-
-typedef struct _ATOM_Polaris10_PCIE_Table {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;                                         /* Number of entries. */
-       ATOM_Polaris10_PCIE_Record entries[1];                      /* Dynamically allocate entries. */
-} ATOM_Polaris10_PCIE_Table;
-
-
-typedef struct _ATOM_Tonga_MM_Dependency_Record {
-       UCHAR   ucVddcInd;                                                                                       /* VDDC voltage */
-       USHORT  usVddgfxOffset;                                                                   /* Offset relative to VDDC voltage */
-       ULONG  ulDClk;                                                                                          /* UVD D-clock */
-       ULONG  ulVClk;                                                                                          /* UVD V-clock */
-       ULONG  ulEClk;                                                                                          /* VCE clock */
-       ULONG  ulAClk;                                                                                          /* ACP clock */
-       ULONG  ulSAMUClk;                                                                                       /* SAMU clock */
-} ATOM_Tonga_MM_Dependency_Record;
-
-typedef struct _ATOM_Tonga_MM_Dependency_Table {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;                                                                             /* Number of entries. */
-       ATOM_Tonga_MM_Dependency_Record entries[1];                        /* Dynamically allocate entries. */
-} ATOM_Tonga_MM_Dependency_Table;
-
-typedef struct _ATOM_Tonga_Voltage_Lookup_Record {
-       USHORT usVdd;                                                                                      /* Base voltage */
-       USHORT usCACLow;
-       USHORT usCACMid;
-       USHORT usCACHigh;
-} ATOM_Tonga_Voltage_Lookup_Record;
-
-typedef struct _ATOM_Tonga_Voltage_Lookup_Table {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;                                                                             /* Number of entries. */
-       ATOM_Tonga_Voltage_Lookup_Record entries[1];                            /* Dynamically allocate entries. */
-} ATOM_Tonga_Voltage_Lookup_Table;
-
-typedef struct _ATOM_Tonga_Fan_Table {
-       UCHAR   ucRevId;                                                 /* Change this if the table format changes or version changes so that the other fields are not the same. */
-       UCHAR   ucTHyst;                                                 /* Temperature hysteresis. Integer. */
-       USHORT  usTMin;                                                  /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
-       USHORT  usTMed;                                                  /* The middle temperature where we change slopes. */
-       USHORT  usTHigh;                                                 /* The high point above TMed for adjusting the second slope. */
-       USHORT  usPWMMin;                                                /* The minimum PWM value in percent (0.01% increments). */
-       USHORT  usPWMMed;                                                /* The PWM value (in percent) at TMed. */
-       USHORT  usPWMHigh;                                               /* The PWM value at THigh. */
-       USHORT  usTMax;                                                  /* The max temperature */
-       UCHAR   ucFanControlMode;                                 /* Legacy or Fuzzy Fan mode */
-       USHORT  usFanPWMMax;                                      /* Maximum allowed fan power in percent */
-       USHORT  usFanOutputSensitivity;           /* Sensitivity of fan reaction to temepature changes */
-       USHORT  usFanRPMMax;                                      /* The default value in RPM */
-       ULONG  ulMinFanSCLKAcousticLimit;          /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
-       UCHAR   ucTargetTemperature;                     /* Advanced fan controller target temperature. */
-       UCHAR   ucMinimumPWMLimit;                        /* The minimum PWM that the advanced fan controller can set.  This should be set to the highest PWM that will run the fan at its lowest RPM. */
-       USHORT  usReserved;
-} ATOM_Tonga_Fan_Table;
-
-typedef struct _ATOM_Fiji_Fan_Table {
-       UCHAR   ucRevId;                                                 /* Change this if the table format changes or version changes so that the other fields are not the same. */
-       UCHAR   ucTHyst;                                                 /* Temperature hysteresis. Integer. */
-       USHORT  usTMin;                                                  /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
-       USHORT  usTMed;                                                  /* The middle temperature where we change slopes. */
-       USHORT  usTHigh;                                                 /* The high point above TMed for adjusting the second slope. */
-       USHORT  usPWMMin;                                                /* The minimum PWM value in percent (0.01% increments). */
-       USHORT  usPWMMed;                                                /* The PWM value (in percent) at TMed. */
-       USHORT  usPWMHigh;                                               /* The PWM value at THigh. */
-       USHORT  usTMax;                                                  /* The max temperature */
-       UCHAR   ucFanControlMode;                                 /* Legacy or Fuzzy Fan mode */
-       USHORT  usFanPWMMax;                                      /* Maximum allowed fan power in percent */
-       USHORT  usFanOutputSensitivity;           /* Sensitivity of fan reaction to temepature changes */
-       USHORT  usFanRPMMax;                                      /* The default value in RPM */
-       ULONG  ulMinFanSCLKAcousticLimit;               /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
-       UCHAR   ucTargetTemperature;                     /* Advanced fan controller target temperature. */
-       UCHAR   ucMinimumPWMLimit;                        /* The minimum PWM that the advanced fan controller can set.  This should be set to the highest PWM that will run the fan at its lowest RPM. */
-       USHORT  usFanGainEdge;
-       USHORT  usFanGainHotspot;
-       USHORT  usFanGainLiquid;
-       USHORT  usFanGainVrVddc;
-       USHORT  usFanGainVrMvdd;
-       USHORT  usFanGainPlx;
-       USHORT  usFanGainHbm;
-       USHORT  usReserved;
-} ATOM_Fiji_Fan_Table;
-
-typedef struct _ATOM_Tonga_Thermal_Controller {
-       UCHAR ucRevId;
-       UCHAR ucType;              /* one of ATOM_TONGA_PP_THERMALCONTROLLER_* */
-       UCHAR ucI2cLine;                /* as interpreted by DAL I2C */
-       UCHAR ucI2cAddress;
-       UCHAR ucFanParameters;  /* Fan Control Parameters. */
-       UCHAR ucFanMinRPM;       /* Fan Minimum RPM (hundreds) -- for display purposes only. */
-       UCHAR ucFanMaxRPM;       /* Fan Maximum RPM (hundreds) -- for display purposes only. */
-       UCHAR ucReserved;
-       UCHAR ucFlags;             /* to be defined */
-} ATOM_Tonga_Thermal_Controller;
-
-typedef struct _ATOM_Tonga_VCE_State_Record {
-       UCHAR  ucVCEClockIndex; /*index into usVCEDependencyTableOffset of 'ATOM_Tonga_MM_Dependency_Table' type */
-       UCHAR  ucFlag;          /* 2 bits indicates memory p-states */
-       UCHAR  ucSCLKIndex;             /*index into ATOM_Tonga_SCLK_Dependency_Table */
-       UCHAR  ucMCLKIndex;             /*index into ATOM_Tonga_MCLK_Dependency_Table */
-} ATOM_Tonga_VCE_State_Record;
-
-typedef struct _ATOM_Tonga_VCE_State_Table {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;
-       ATOM_Tonga_VCE_State_Record entries[1];
-} ATOM_Tonga_VCE_State_Table;
-
-typedef struct _ATOM_Tonga_PowerTune_Table {
-       UCHAR  ucRevId;
-       USHORT usTDP;
-       USHORT usConfigurableTDP;
-       USHORT usTDC;
-       USHORT usBatteryPowerLimit;
-       USHORT usSmallPowerLimit;
-       USHORT usLowCACLeakage;
-       USHORT usHighCACLeakage;
-       USHORT usMaximumPowerDeliveryLimit;
-       USHORT usTjMax;
-       USHORT usPowerTuneDataSetID;
-       USHORT usEDCLimit;
-       USHORT usSoftwareShutdownTemp;
-       USHORT usClockStretchAmount;
-       USHORT usReserve[2];
-} ATOM_Tonga_PowerTune_Table;
-
-typedef struct _ATOM_Fiji_PowerTune_Table {
-       UCHAR  ucRevId;
-       USHORT usTDP;
-       USHORT usConfigurableTDP;
-       USHORT usTDC;
-       USHORT usBatteryPowerLimit;
-       USHORT usSmallPowerLimit;
-       USHORT usLowCACLeakage;
-       USHORT usHighCACLeakage;
-       USHORT usMaximumPowerDeliveryLimit;
-       USHORT usTjMax;  /* For Fiji, this is also usTemperatureLimitEdge; */
-       USHORT usPowerTuneDataSetID;
-       USHORT usEDCLimit;
-       USHORT usSoftwareShutdownTemp;
-       USHORT usClockStretchAmount;
-       USHORT usTemperatureLimitHotspot;  /*The following are added for Fiji */
-       USHORT usTemperatureLimitLiquid1;
-       USHORT usTemperatureLimitLiquid2;
-       USHORT usTemperatureLimitVrVddc;
-       USHORT usTemperatureLimitVrMvdd;
-       USHORT usTemperatureLimitPlx;
-       UCHAR  ucLiquid1_I2C_address;  /*Liquid */
-       UCHAR  ucLiquid2_I2C_address;
-       UCHAR  ucLiquid_I2C_Line;
-       UCHAR  ucVr_I2C_address;        /*VR */
-       UCHAR  ucVr_I2C_Line;
-       UCHAR  ucPlx_I2C_address;  /*PLX */
-       UCHAR  ucPlx_I2C_Line;
-       USHORT usReserved;
-} ATOM_Fiji_PowerTune_Table;
-
-#define ATOM_PPM_A_A    1
-#define ATOM_PPM_A_I    2
-typedef struct _ATOM_Tonga_PPM_Table {
-       UCHAR   ucRevId;
-       UCHAR   ucPpmDesign;              /*A+I or A+A */
-       USHORT  usCpuCoreNumber;
-       ULONG  ulPlatformTDP;
-       ULONG  ulSmallACPlatformTDP;
-       ULONG  ulPlatformTDC;
-       ULONG  ulSmallACPlatformTDC;
-       ULONG  ulApuTDP;
-       ULONG  ulDGpuTDP;
-       ULONG  ulDGpuUlvPower;
-       ULONG  ulTjmax;
-} ATOM_Tonga_PPM_Table;
-
-typedef struct _ATOM_Tonga_Hard_Limit_Record {
-       ULONG  ulSCLKLimit;
-       ULONG  ulMCLKLimit;
-       USHORT  usVddcLimit;
-       USHORT  usVddciLimit;
-       USHORT  usVddgfxLimit;
-} ATOM_Tonga_Hard_Limit_Record;
-
-typedef struct _ATOM_Tonga_Hard_Limit_Table {
-       UCHAR ucRevId;
-       UCHAR ucNumEntries;
-       ATOM_Tonga_Hard_Limit_Record entries[1];
-} ATOM_Tonga_Hard_Limit_Table;
-
-typedef struct _ATOM_Tonga_GPIO_Table {
-       UCHAR  ucRevId;
-       UCHAR  ucVRHotTriggeredSclkDpmIndex;            /* If VRHot signal is triggered SCLK will be limited to this DPM level */
-       UCHAR  ucReserve[5];
-} ATOM_Tonga_GPIO_Table;
-
-typedef struct _PPTable_Generic_SubTable_Header {
-       UCHAR  ucRevId;
-} PPTable_Generic_SubTable_Header;
-
-
-#pragma pack(pop)
-
-
-#endif
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c
deleted file mode 100644 (file)
index cfb647f..0000000
+++ /dev/null
@@ -1,1214 +0,0 @@
-/*
- * Copyright 2015 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/module.h>
-#include <linux/slab.h>
-#include <linux/fb.h>
-
-#include "tonga_processpptables.h"
-#include "ppatomctrl.h"
-#include "atombios.h"
-#include "pp_debug.h"
-#include "hwmgr.h"
-#include "cgs_common.h"
-#include "tonga_pptable.h"
-
-/**
- * Private Function used during initialization.
- * @param hwmgr Pointer to the hardware manager.
- * @param setIt A flag indication if the capability should be set (TRUE) or reset (FALSE).
- * @param cap Which capability to set/reset.
- */
-static void set_hw_cap(struct pp_hwmgr *hwmgr, bool setIt, enum phm_platform_caps cap)
-{
-       if (setIt)
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
-       else
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
-}
-
-
-/**
- * Private Function used during initialization.
- * @param hwmgr Pointer to the hardware manager.
- * @param powerplay_caps the bit array (from BIOS) of capability bits.
- * @exception the current implementation always returns 1.
- */
-static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps)
-{
-       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE16____),
-               "ATOM_PP_PLATFORM_CAP_ASPM_L1 is not supported!", continue);
-       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE64____),
-               "ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY is not supported!", continue);
-       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE512____),
-               "ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL is not supported!", continue);
-       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE1024____),
-               "ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 is not supported!", continue);
-       PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE2048____),
-               "ATOM_PP_PLATFORM_CAP_HTLINKCONTROL is not supported!", continue);
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY),
-                       PHM_PlatformCaps_PowerPlaySupport
-                 );
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
-                       PHM_PlatformCaps_BiosPowerSourceControl
-                 );
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC),
-                       PHM_PlatformCaps_AutomaticDCTransition
-                 );
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL),
-                       PHM_PlatformCaps_EnableMVDDControl
-                 );
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL),
-                       PHM_PlatformCaps_ControlVDDCI
-                 );
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL),
-                       PHM_PlatformCaps_ControlVDDGFX
-                 );
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_BACO),
-                       PHM_PlatformCaps_BACO
-                 );
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND),
-                       PHM_PlatformCaps_DisableVoltageIsland
-                 );
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
-                       PHM_PlatformCaps_CombinePCCWithThermalSignal
-                 );
-
-       set_hw_cap(
-                       hwmgr,
-                       0 != (powerplay_caps & ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
-                       PHM_PlatformCaps_LoadPostProductionFirmware
-                 );
-
-       return 0;
-}
-
-/**
- * Private Function to get the PowerPlay Table Address.
- */
-const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
-{
-       int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
-
-       u16 size;
-       u8 frev, crev;
-       void *table_address = (void *)hwmgr->soft_pp_table;
-
-       if (!table_address) {
-               table_address = (ATOM_Tonga_POWERPLAYTABLE *)
-                               cgs_atom_get_data_table(hwmgr->device,
-                                               index, &size, &frev, &crev);
-               hwmgr->soft_pp_table = table_address;   /*Cache the result in RAM.*/
-               hwmgr->soft_pp_table_size = size;
-       }
-
-       return table_address;
-}
-
-static int get_vddc_lookup_table(
-               struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_voltage_lookup_table **lookup_table,
-               const ATOM_Tonga_Voltage_Lookup_Table   *vddc_lookup_pp_tables,
-               uint32_t        max_levels
-               )
-{
-       uint32_t table_size, i;
-       phm_ppt_v1_voltage_lookup_table *table;
-
-       PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries),
-               "Invalid CAC Leakage PowerPlay Table!", return 1);
-
-       table_size = sizeof(uint32_t) +
-               sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels;
-
-       table = kzalloc(table_size, GFP_KERNEL);
-
-       if (NULL == table)
-               return -ENOMEM;
-
-       memset(table, 0x00, table_size);
-
-       table->count = vddc_lookup_pp_tables->ucNumEntries;
-
-       for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) {
-               table->entries[i].us_calculated = 0;
-               table->entries[i].us_vdd =
-                       vddc_lookup_pp_tables->entries[i].usVdd;
-               table->entries[i].us_cac_low =
-                       vddc_lookup_pp_tables->entries[i].usCACLow;
-               table->entries[i].us_cac_mid =
-                       vddc_lookup_pp_tables->entries[i].usCACMid;
-               table->entries[i].us_cac_high =
-                       vddc_lookup_pp_tables->entries[i].usCACHigh;
-       }
-
-       *lookup_table = table;
-
-       return 0;
-}
-
-/**
- * Private Function used during initialization.
- * Initialize Platform Power Management Parameter table
- * @param hwmgr Pointer to the hardware manager.
- * @param atom_ppm_table Pointer to PPM table in VBIOS
- */
-static int get_platform_power_management_table(
-               struct pp_hwmgr *hwmgr,
-               ATOM_Tonga_PPM_Table *atom_ppm_table)
-{
-       struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL);
-       struct phm_ppt_v1_information *pp_table_information =
-               (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (NULL == ptr)
-               return -ENOMEM;
-
-       ptr->ppm_design
-               = atom_ppm_table->ucPpmDesign;
-       ptr->cpu_core_number
-               = atom_ppm_table->usCpuCoreNumber;
-       ptr->platform_tdp
-               = atom_ppm_table->ulPlatformTDP;
-       ptr->small_ac_platform_tdp
-               = atom_ppm_table->ulSmallACPlatformTDP;
-       ptr->platform_tdc
-               = atom_ppm_table->ulPlatformTDC;
-       ptr->small_ac_platform_tdc
-               = atom_ppm_table->ulSmallACPlatformTDC;
-       ptr->apu_tdp
-               = atom_ppm_table->ulApuTDP;
-       ptr->dgpu_tdp
-               = atom_ppm_table->ulDGpuTDP;
-       ptr->dgpu_ulv_power
-               = atom_ppm_table->ulDGpuUlvPower;
-       ptr->tj_max
-               = atom_ppm_table->ulTjmax;
-
-       pp_table_information->ppm_parameter_table = ptr;
-
-       return 0;
-}
-
-/**
- * Private Function used during initialization.
- * Initialize TDP limits for DPM2
- * @param hwmgr Pointer to the hardware manager.
- * @param powerplay_table Pointer to the PowerPlay Table.
- */
-static int init_dpm_2_parameters(
-               struct pp_hwmgr *hwmgr,
-               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
-               )
-{
-       int result = 0;
-       struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
-       ATOM_Tonga_PPM_Table *atom_ppm_table;
-       uint32_t disable_ppm = 0;
-       uint32_t disable_power_control = 0;
-
-       pp_table_information->us_ulv_voltage_offset =
-               le16_to_cpu(powerplay_table->usUlvVoltageOffset);
-
-       pp_table_information->ppm_parameter_table = NULL;
-       pp_table_information->vddc_lookup_table = NULL;
-       pp_table_information->vddgfx_lookup_table = NULL;
-       /* TDP limits */
-       hwmgr->platform_descriptor.TDPODLimit =
-               le16_to_cpu(powerplay_table->usPowerControlLimit);
-       hwmgr->platform_descriptor.TDPAdjustment = 0;
-       hwmgr->platform_descriptor.VidAdjustment = 0;
-       hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
-       hwmgr->platform_descriptor.VidMinLimit = 0;
-       hwmgr->platform_descriptor.VidMaxLimit = 1500000;
-       hwmgr->platform_descriptor.VidStep = 6250;
-
-       disable_power_control = 0;
-       if (0 == disable_power_control) {
-               /* enable TDP overdrive (PowerControl) feature as well if supported */
-               if (hwmgr->platform_descriptor.TDPODLimit != 0)
-                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_PowerControl);
-       }
-
-       if (0 != powerplay_table->usVddcLookupTableOffset) {
-               const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable =
-                       (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
-                       le16_to_cpu(powerplay_table->usVddcLookupTableOffset));
-
-               result = get_vddc_lookup_table(hwmgr,
-                       &pp_table_information->vddc_lookup_table, pVddcCACTable, 16);
-       }
-
-       if (0 != powerplay_table->usVddgfxLookupTableOffset) {
-               const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable =
-                       (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
-                       le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset));
-
-               result = get_vddc_lookup_table(hwmgr,
-                       &pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16);
-       }
-
-       disable_ppm = 0;
-       if (0 == disable_ppm) {
-               atom_ppm_table = (ATOM_Tonga_PPM_Table *)
-                       (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset));
-
-               if (0 != powerplay_table->usPPMTableOffset) {
-                       if (get_platform_power_management_table(hwmgr, atom_ppm_table) == 0) {
-                               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_EnablePlatformPowerManagement);
-                       }
-               }
-       }
-
-       return result;
-}
-
-static int get_valid_clk(
-               struct pp_hwmgr *hwmgr,
-               struct phm_clock_array **clk_table,
-               const phm_ppt_v1_clock_voltage_dependency_table  * clk_volt_pp_table
-               )
-{
-       uint32_t table_size, i;
-       struct phm_clock_array *table;
-
-       PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count),
-               "Invalid PowerPlay Table!", return -1);
-
-       table_size = sizeof(uint32_t) +
-               sizeof(uint32_t) * clk_volt_pp_table->count;
-
-       table = kzalloc(table_size, GFP_KERNEL);
-
-       if (NULL == table)
-               return -ENOMEM;
-
-       memset(table, 0x00, table_size);
-
-       table->count = (uint32_t)clk_volt_pp_table->count;
-
-       for (i = 0; i < table->count; i++)
-               table->values[i] = (uint32_t)clk_volt_pp_table->entries[i].clk;
-
-       *clk_table = table;
-
-       return 0;
-}
-
-static int get_hard_limits(
-               struct pp_hwmgr *hwmgr,
-               struct phm_clock_and_voltage_limits *limits,
-               const ATOM_Tonga_Hard_Limit_Table * limitable
-               )
-{
-       PP_ASSERT_WITH_CODE((0 != limitable->ucNumEntries), "Invalid PowerPlay Table!", return -1);
-
-       /* currently we always take entries[0] parameters */
-       limits->sclk = (uint32_t)limitable->entries[0].ulSCLKLimit;
-       limits->mclk = (uint32_t)limitable->entries[0].ulMCLKLimit;
-       limits->vddc = (uint16_t)limitable->entries[0].usVddcLimit;
-       limits->vddci = (uint16_t)limitable->entries[0].usVddciLimit;
-       limits->vddgfx = (uint16_t)limitable->entries[0].usVddgfxLimit;
-
-       return 0;
-}
-
-static int get_mclk_voltage_dependency_table(
-               struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_mclk_dep_table,
-               const ATOM_Tonga_MCLK_Dependency_Table * mclk_dep_table
-               )
-{
-       uint32_t table_size, i;
-       phm_ppt_v1_clock_voltage_dependency_table *mclk_table;
-
-       PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries),
-               "Invalid PowerPlay Table!", return -1);
-
-       table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
-               * mclk_dep_table->ucNumEntries;
-
-       mclk_table = kzalloc(table_size, GFP_KERNEL);
-
-       if (NULL == mclk_table)
-               return -ENOMEM;
-
-       memset(mclk_table, 0x00, table_size);
-
-       mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries;
-
-       for (i = 0; i < mclk_dep_table->ucNumEntries; i++) {
-               mclk_table->entries[i].vddInd =
-                       mclk_dep_table->entries[i].ucVddcInd;
-               mclk_table->entries[i].vdd_offset =
-                       mclk_dep_table->entries[i].usVddgfxOffset;
-               mclk_table->entries[i].vddci =
-                       mclk_dep_table->entries[i].usVddci;
-               mclk_table->entries[i].mvdd =
-                       mclk_dep_table->entries[i].usMvdd;
-               mclk_table->entries[i].clk =
-                       mclk_dep_table->entries[i].ulMclk;
-       }
-
-       *pp_tonga_mclk_dep_table = mclk_table;
-
-       return 0;
-}
-
-static int get_sclk_voltage_dependency_table(
-               struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_sclk_dep_table,
-               const PPTable_Generic_SubTable_Header *sclk_dep_table
-               )
-{
-       uint32_t table_size, i;
-       phm_ppt_v1_clock_voltage_dependency_table *sclk_table;
-
-       if (sclk_dep_table->ucRevId < 1) {
-               const ATOM_Tonga_SCLK_Dependency_Table *tonga_table =
-                           (ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table;
-
-               PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries),
-                       "Invalid PowerPlay Table!", return -1);
-
-               table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
-                       * tonga_table->ucNumEntries;
-
-               sclk_table = kzalloc(table_size, GFP_KERNEL);
-
-               if (NULL == sclk_table)
-                       return -ENOMEM;
-
-               memset(sclk_table, 0x00, table_size);
-
-               sclk_table->count = (uint32_t)tonga_table->ucNumEntries;
-
-               for (i = 0; i < tonga_table->ucNumEntries; i++) {
-                       sclk_table->entries[i].vddInd =
-                               tonga_table->entries[i].ucVddInd;
-                       sclk_table->entries[i].vdd_offset =
-                               tonga_table->entries[i].usVddcOffset;
-                       sclk_table->entries[i].clk =
-                               tonga_table->entries[i].ulSclk;
-                       sclk_table->entries[i].cks_enable =
-                               (((tonga_table->entries[i].ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0;
-                       sclk_table->entries[i].cks_voffset =
-                               (tonga_table->entries[i].ucCKSVOffsetandDisable & 0x7F);
-               }
-       } else {
-               const ATOM_Polaris_SCLK_Dependency_Table *polaris_table =
-                           (ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table;
-
-               PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries),
-                       "Invalid PowerPlay Table!", return -1);
-
-               table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
-                       * polaris_table->ucNumEntries;
-
-               sclk_table = kzalloc(table_size, GFP_KERNEL);
-
-               if (NULL == sclk_table)
-                       return -ENOMEM;
-
-               memset(sclk_table, 0x00, table_size);
-
-               sclk_table->count = (uint32_t)polaris_table->ucNumEntries;
-
-               for (i = 0; i < polaris_table->ucNumEntries; i++) {
-                       sclk_table->entries[i].vddInd =
-                               polaris_table->entries[i].ucVddInd;
-                       sclk_table->entries[i].vdd_offset =
-                               polaris_table->entries[i].usVddcOffset;
-                       sclk_table->entries[i].clk =
-                               polaris_table->entries[i].ulSclk;
-                       sclk_table->entries[i].cks_enable =
-                               (((polaris_table->entries[i].ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0;
-                       sclk_table->entries[i].cks_voffset =
-                               (polaris_table->entries[i].ucCKSVOffsetandDisable & 0x7F);
-                       sclk_table->entries[i].sclk_offset = polaris_table->entries[i].ulSclkOffset;
-               }
-       }
-       *pp_tonga_sclk_dep_table = sclk_table;
-
-       return 0;
-}
-
-static int get_pcie_table(
-               struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_pcie_table **pp_tonga_pcie_table,
-               const PPTable_Generic_SubTable_Header * pTable
-               )
-{
-       uint32_t table_size, i, pcie_count;
-       phm_ppt_v1_pcie_table *pcie_table;
-       struct phm_ppt_v1_information *pp_table_information =
-               (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       if (pTable->ucRevId < 1) {
-               const ATOM_Tonga_PCIE_Table *atom_pcie_table = (ATOM_Tonga_PCIE_Table *)pTable;
-               PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0),
-                       "Invalid PowerPlay Table!", return -1);
-
-               table_size = sizeof(uint32_t) +
-                       sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries;
-
-               pcie_table = kzalloc(table_size, GFP_KERNEL);
-
-               if (pcie_table == NULL)
-                       return -ENOMEM;
-
-               memset(pcie_table, 0x00, table_size);
-
-               /*
-               * Make sure the number of pcie entries are less than or equal to sclk dpm levels.
-               * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1.
-               */
-               pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1;
-               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! \
-                       Disregarding the excess entries... \n");
-
-               pcie_table->count = pcie_count;
-
-               for (i = 0; i < pcie_count; i++) {
-                       pcie_table->entries[i].gen_speed =
-                               atom_pcie_table->entries[i].ucPCIEGenSpeed;
-                       pcie_table->entries[i].lane_width =
-                               atom_pcie_table->entries[i].usPCIELaneWidth;
-               }
-
-               *pp_tonga_pcie_table = pcie_table;
-       } else {
-               /* Polaris10/Polaris11 and newer. */
-               const ATOM_Polaris10_PCIE_Table *atom_pcie_table = (ATOM_Polaris10_PCIE_Table *)pTable;
-               PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0),
-                       "Invalid PowerPlay Table!", return -1);
-
-               table_size = sizeof(uint32_t) +
-                       sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries;
-
-               pcie_table = kzalloc(table_size, GFP_KERNEL);
-
-               if (pcie_table == NULL)
-                       return -ENOMEM;
-
-               memset(pcie_table, 0x00, table_size);
-
-               /*
-               * Make sure the number of pcie entries are less than or equal to sclk dpm levels.
-               * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1.
-               */
-               pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1;
-               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! \
-                       Disregarding the excess entries... \n");
-
-               pcie_table->count = pcie_count;
-
-               for (i = 0; i < pcie_count; i++) {
-                       pcie_table->entries[i].gen_speed =
-                               atom_pcie_table->entries[i].ucPCIEGenSpeed;
-                       pcie_table->entries[i].lane_width =
-                               atom_pcie_table->entries[i].usPCIELaneWidth;
-                       pcie_table->entries[i].pcie_sclk =
-                               atom_pcie_table->entries[i].ulPCIE_Sclk;
-               }
-
-               *pp_tonga_pcie_table = pcie_table;
-       }
-
-       return 0;
-}
-
-static int get_cac_tdp_table(
-               struct pp_hwmgr *hwmgr,
-               struct phm_cac_tdp_table **cac_tdp_table,
-               const PPTable_Generic_SubTable_Header * table
-               )
-{
-       uint32_t table_size;
-       struct phm_cac_tdp_table *tdp_table;
-
-       table_size = sizeof(uint32_t) + sizeof(struct phm_cac_tdp_table);
-       tdp_table = kzalloc(table_size, GFP_KERNEL);
-
-       if (NULL == tdp_table)
-               return -ENOMEM;
-
-       memset(tdp_table, 0x00, table_size);
-
-       hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL);
-
-       if (NULL == hwmgr->dyn_state.cac_dtp_table) {
-               kfree(tdp_table);
-               return -ENOMEM;
-       }
-
-       memset(hwmgr->dyn_state.cac_dtp_table, 0x00, table_size);
-
-       if (table->ucRevId < 3) {
-               const ATOM_Tonga_PowerTune_Table *tonga_table =
-                       (ATOM_Tonga_PowerTune_Table *)table;
-               tdp_table->usTDP = tonga_table->usTDP;
-               tdp_table->usConfigurableTDP =
-                       tonga_table->usConfigurableTDP;
-               tdp_table->usTDC = tonga_table->usTDC;
-               tdp_table->usBatteryPowerLimit =
-                       tonga_table->usBatteryPowerLimit;
-               tdp_table->usSmallPowerLimit =
-                       tonga_table->usSmallPowerLimit;
-               tdp_table->usLowCACLeakage =
-                       tonga_table->usLowCACLeakage;
-               tdp_table->usHighCACLeakage =
-                       tonga_table->usHighCACLeakage;
-               tdp_table->usMaximumPowerDeliveryLimit =
-                       tonga_table->usMaximumPowerDeliveryLimit;
-               tdp_table->usDefaultTargetOperatingTemp =
-                       tonga_table->usTjMax;
-               tdp_table->usTargetOperatingTemp =
-                       tonga_table->usTjMax; /*Set the initial temp to the same as default */
-               tdp_table->usPowerTuneDataSetID =
-                       tonga_table->usPowerTuneDataSetID;
-               tdp_table->usSoftwareShutdownTemp =
-                       tonga_table->usSoftwareShutdownTemp;
-               tdp_table->usClockStretchAmount =
-                       tonga_table->usClockStretchAmount;
-       } else {   /* Fiji and newer */
-               const ATOM_Fiji_PowerTune_Table *fijitable =
-                       (ATOM_Fiji_PowerTune_Table *)table;
-               tdp_table->usTDP = fijitable->usTDP;
-               tdp_table->usConfigurableTDP = fijitable->usConfigurableTDP;
-               tdp_table->usTDC = fijitable->usTDC;
-               tdp_table->usBatteryPowerLimit = fijitable->usBatteryPowerLimit;
-               tdp_table->usSmallPowerLimit = fijitable->usSmallPowerLimit;
-               tdp_table->usLowCACLeakage = fijitable->usLowCACLeakage;
-               tdp_table->usHighCACLeakage = fijitable->usHighCACLeakage;
-               tdp_table->usMaximumPowerDeliveryLimit =
-                       fijitable->usMaximumPowerDeliveryLimit;
-               tdp_table->usDefaultTargetOperatingTemp =
-                       fijitable->usTjMax;
-               tdp_table->usTargetOperatingTemp =
-                       fijitable->usTjMax; /*Set the initial temp to the same as default */
-               tdp_table->usPowerTuneDataSetID =
-                       fijitable->usPowerTuneDataSetID;
-               tdp_table->usSoftwareShutdownTemp =
-                       fijitable->usSoftwareShutdownTemp;
-               tdp_table->usClockStretchAmount =
-                       fijitable->usClockStretchAmount;
-               tdp_table->usTemperatureLimitHotspot =
-                       fijitable->usTemperatureLimitHotspot;
-               tdp_table->usTemperatureLimitLiquid1 =
-                       fijitable->usTemperatureLimitLiquid1;
-               tdp_table->usTemperatureLimitLiquid2 =
-                       fijitable->usTemperatureLimitLiquid2;
-               tdp_table->usTemperatureLimitVrVddc =
-                       fijitable->usTemperatureLimitVrVddc;
-               tdp_table->usTemperatureLimitVrMvdd =
-                       fijitable->usTemperatureLimitVrMvdd;
-               tdp_table->usTemperatureLimitPlx =
-                       fijitable->usTemperatureLimitPlx;
-               tdp_table->ucLiquid1_I2C_address =
-                       fijitable->ucLiquid1_I2C_address;
-               tdp_table->ucLiquid2_I2C_address =
-                       fijitable->ucLiquid2_I2C_address;
-               tdp_table->ucLiquid_I2C_Line =
-                       fijitable->ucLiquid_I2C_Line;
-               tdp_table->ucVr_I2C_address = fijitable->ucVr_I2C_address;
-               tdp_table->ucVr_I2C_Line = fijitable->ucVr_I2C_Line;
-               tdp_table->ucPlx_I2C_address = fijitable->ucPlx_I2C_address;
-               tdp_table->ucPlx_I2C_Line = fijitable->ucPlx_I2C_Line;
-       }
-
-       *cac_tdp_table = tdp_table;
-
-       return 0;
-}
-
-static int get_mm_clock_voltage_table(
-               struct pp_hwmgr *hwmgr,
-               phm_ppt_v1_mm_clock_voltage_dependency_table **tonga_mm_table,
-               const ATOM_Tonga_MM_Dependency_Table * mm_dependency_table
-               )
-{
-       uint32_t table_size, i;
-       const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record;
-       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table;
-
-       PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries),
-               "Invalid PowerPlay Table!", return -1);
-       table_size = sizeof(uint32_t) +
-               sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record)
-               * mm_dependency_table->ucNumEntries;
-       mm_table = kzalloc(table_size, GFP_KERNEL);
-
-       if (NULL == mm_table)
-               return -ENOMEM;
-
-       memset(mm_table, 0x00, table_size);
-
-       mm_table->count = mm_dependency_table->ucNumEntries;
-
-       for (i = 0; i < mm_dependency_table->ucNumEntries; i++) {
-               mm_dependency_record = &mm_dependency_table->entries[i];
-               mm_table->entries[i].vddcInd = mm_dependency_record->ucVddcInd;
-               mm_table->entries[i].vddgfx_offset = mm_dependency_record->usVddgfxOffset;
-               mm_table->entries[i].aclk = mm_dependency_record->ulAClk;
-               mm_table->entries[i].samclock = mm_dependency_record->ulSAMUClk;
-               mm_table->entries[i].eclk = mm_dependency_record->ulEClk;
-               mm_table->entries[i].vclk = mm_dependency_record->ulVClk;
-               mm_table->entries[i].dclk = mm_dependency_record->ulDClk;
-       }
-
-       *tonga_mm_table = mm_table;
-
-       return 0;
-}
-
-/**
- * Private Function used during initialization.
- * Initialize clock voltage dependency
- * @param hwmgr Pointer to the hardware manager.
- * @param powerplay_table Pointer to the PowerPlay Table.
- */
-static int init_clock_voltage_dependency(
-               struct pp_hwmgr *hwmgr,
-               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
-               )
-{
-       int result = 0;
-       struct phm_ppt_v1_information *pp_table_information =
-               (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table =
-               (const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) +
-               le16_to_cpu(powerplay_table->usMMDependencyTableOffset));
-       const PPTable_Generic_SubTable_Header *pPowerTuneTable =
-               (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
-               le16_to_cpu(powerplay_table->usPowerTuneTableOffset));
-       const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
-               (const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
-               le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
-       const PPTable_Generic_SubTable_Header *sclk_dep_table =
-               (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
-               le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
-       const ATOM_Tonga_Hard_Limit_Table *pHardLimits =
-               (const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) +
-               le16_to_cpu(powerplay_table->usHardLimitTableOffset));
-       const PPTable_Generic_SubTable_Header *pcie_table =
-               (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
-               le16_to_cpu(powerplay_table->usPCIETableOffset));
-
-       pp_table_information->vdd_dep_on_sclk = NULL;
-       pp_table_information->vdd_dep_on_mclk = NULL;
-       pp_table_information->mm_dep_table = NULL;
-       pp_table_information->pcie_table = NULL;
-
-       if (powerplay_table->usMMDependencyTableOffset != 0)
-               result = get_mm_clock_voltage_table(hwmgr,
-               &pp_table_information->mm_dep_table, mm_dependency_table);
-
-       if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0)
-               result = get_cac_tdp_table(hwmgr,
-               &pp_table_information->cac_dtp_table, pPowerTuneTable);
-
-       if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0)
-               result = get_sclk_voltage_dependency_table(hwmgr,
-               &pp_table_information->vdd_dep_on_sclk, sclk_dep_table);
-
-       if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0)
-               result = get_mclk_voltage_dependency_table(hwmgr,
-               &pp_table_information->vdd_dep_on_mclk, mclk_dep_table);
-
-       if (result == 0 && powerplay_table->usPCIETableOffset != 0)
-               result = get_pcie_table(hwmgr,
-               &pp_table_information->pcie_table, pcie_table);
-
-       if (result == 0 && powerplay_table->usHardLimitTableOffset != 0)
-               result = get_hard_limits(hwmgr,
-               &pp_table_information->max_clock_voltage_on_dc, pHardLimits);
-
-       hwmgr->dyn_state.max_clock_voltage_on_dc.sclk =
-               pp_table_information->max_clock_voltage_on_dc.sclk;
-       hwmgr->dyn_state.max_clock_voltage_on_dc.mclk =
-               pp_table_information->max_clock_voltage_on_dc.mclk;
-       hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
-               pp_table_information->max_clock_voltage_on_dc.vddc;
-       hwmgr->dyn_state.max_clock_voltage_on_dc.vddci =
-               pp_table_information->max_clock_voltage_on_dc.vddci;
-
-       if (result == 0 && (NULL != pp_table_information->vdd_dep_on_mclk)
-               && (0 != pp_table_information->vdd_dep_on_mclk->count))
-               result = get_valid_clk(hwmgr, &pp_table_information->valid_mclk_values,
-               pp_table_information->vdd_dep_on_mclk);
-
-       if (result == 0 && (NULL != pp_table_information->vdd_dep_on_sclk)
-               && (0 != pp_table_information->vdd_dep_on_sclk->count))
-               result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values,
-               pp_table_information->vdd_dep_on_sclk);
-
-       return result;
-}
-
-/** Retrieves the (signed) Overdrive limits from VBIOS.
- * The max engine clock, memory clock and max temperature come from the firmware info table.
- *
- * The information is placed into the platform descriptor.
- *
- * @param hwmgr source of the VBIOS table and owner of the platform descriptor to be updated.
- * @param powerplay_table the address of the PowerPlay table.
- *
- * @return 1 as long as the firmware info table was present and of a supported version.
- */
-static int init_over_drive_limits(
-               struct pp_hwmgr *hwmgr,
-               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table)
-{
-       hwmgr->platform_descriptor.overdriveLimit.engineClock =
-               le16_to_cpu(powerplay_table->ulMaxODEngineClock);
-       hwmgr->platform_descriptor.overdriveLimit.memoryClock =
-               le16_to_cpu(powerplay_table->ulMaxODMemoryClock);
-
-       hwmgr->platform_descriptor.minOverdriveVDDC = 0;
-       hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
-       hwmgr->platform_descriptor.overdriveVDDCStep = 0;
-
-       if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 \
-               && hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) {
-               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                       PHM_PlatformCaps_ACOverdriveSupport);
-       }
-
-       return 0;
-}
-
-/**
- * Private Function used during initialization.
- * Inspect the PowerPlay table for obvious signs of corruption.
- * @param hwmgr Pointer to the hardware manager.
- * @param powerplay_table Pointer to the PowerPlay Table.
- * @exception This implementation always returns 1.
- */
-static int init_thermal_controller(
-               struct pp_hwmgr *hwmgr,
-               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
-               )
-{
-       const PPTable_Generic_SubTable_Header *fan_table;
-       ATOM_Tonga_Thermal_Controller *thermal_controller;
-
-       thermal_controller = (ATOM_Tonga_Thermal_Controller *)
-               (((unsigned long)powerplay_table) +
-               le16_to_cpu(powerplay_table->usThermalControllerOffset));
-       PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset),
-               "Thermal controller table not set!", return -1);
-
-       hwmgr->thermal_controller.ucType = thermal_controller->ucType;
-       hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine;
-       hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress;
-
-       hwmgr->thermal_controller.fanInfo.bNoFan =
-               (0 != (thermal_controller->ucFanParameters & ATOM_TONGA_PP_FANPARAMETERS_NOFAN));
-
-       hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
-               thermal_controller->ucFanParameters &
-               ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
-
-       hwmgr->thermal_controller.fanInfo.ulMinRPM
-               = thermal_controller->ucFanMinRPM * 100UL;
-       hwmgr->thermal_controller.fanInfo.ulMaxRPM
-               = thermal_controller->ucFanMaxRPM * 100UL;
-
-       set_hw_cap(
-                       hwmgr,
-                       ATOM_TONGA_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
-                       PHM_PlatformCaps_ThermalController
-                 );
-
-       if (0 == powerplay_table->usFanTableOffset)
-               return 0;
-
-       fan_table = (const PPTable_Generic_SubTable_Header *)
-               (((unsigned long)powerplay_table) +
-               le16_to_cpu(powerplay_table->usFanTableOffset));
-
-       PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset),
-               "Fan table not set!", return -1);
-       PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId),
-               "Unsupported fan table format!", return -1);
-
-       hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay
-               = 100000;
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-               PHM_PlatformCaps_MicrocodeFanControl);
-
-       if (fan_table->ucRevId < 8) {
-               const ATOM_Tonga_Fan_Table *tonga_fan_table =
-                       (ATOM_Tonga_Fan_Table *)fan_table;
-               hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
-                       = tonga_fan_table->ucTHyst;
-               hwmgr->thermal_controller.advanceFanControlParameters.usTMin
-                       = tonga_fan_table->usTMin;
-               hwmgr->thermal_controller.advanceFanControlParameters.usTMed
-                       = tonga_fan_table->usTMed;
-               hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
-                       = tonga_fan_table->usTHigh;
-               hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
-                       = tonga_fan_table->usPWMMin;
-               hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
-                       = tonga_fan_table->usPWMMed;
-               hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
-                       = tonga_fan_table->usPWMHigh;
-               hwmgr->thermal_controller.advanceFanControlParameters.usTMax
-                       = 10900;                  /* hard coded */
-               hwmgr->thermal_controller.advanceFanControlParameters.usTMax
-                       = tonga_fan_table->usTMax;
-               hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
-                       = tonga_fan_table->ucFanControlMode;
-               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
-                       = tonga_fan_table->usFanPWMMax;
-               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
-                       = 4836;
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
-                       = tonga_fan_table->usFanOutputSensitivity;
-               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
-                       = tonga_fan_table->usFanRPMMax;
-               hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
-                       = (tonga_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places.  SMC wants MHz. */
-               hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
-                       = tonga_fan_table->ucTargetTemperature;
-               hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
-                       = tonga_fan_table->ucMinimumPWMLimit;
-       } else {
-               const ATOM_Fiji_Fan_Table *fiji_fan_table =
-                       (ATOM_Fiji_Fan_Table *)fan_table;
-               hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
-                       = fiji_fan_table->ucTHyst;
-               hwmgr->thermal_controller.advanceFanControlParameters.usTMin
-                       = fiji_fan_table->usTMin;
-               hwmgr->thermal_controller.advanceFanControlParameters.usTMed
-                       = fiji_fan_table->usTMed;
-               hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
-                       = fiji_fan_table->usTHigh;
-               hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
-                       = fiji_fan_table->usPWMMin;
-               hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
-                       = fiji_fan_table->usPWMMed;
-               hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
-                       = fiji_fan_table->usPWMHigh;
-               hwmgr->thermal_controller.advanceFanControlParameters.usTMax
-                       = fiji_fan_table->usTMax;
-               hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
-                       = fiji_fan_table->ucFanControlMode;
-               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
-                       = fiji_fan_table->usFanPWMMax;
-               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
-                       = 4836;
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
-                       = fiji_fan_table->usFanOutputSensitivity;
-               hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
-                       = fiji_fan_table->usFanRPMMax;
-               hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
-                       = (fiji_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places.  SMC wants MHz. */
-               hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
-                       = fiji_fan_table->ucTargetTemperature;
-               hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
-                       = fiji_fan_table->ucMinimumPWMLimit;
-
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge
-                       = fiji_fan_table->usFanGainEdge;
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot
-                       = fiji_fan_table->usFanGainHotspot;
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid
-                       = fiji_fan_table->usFanGainLiquid;
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc
-                       = fiji_fan_table->usFanGainVrVddc;
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd
-                       = fiji_fan_table->usFanGainVrMvdd;
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx
-                       = fiji_fan_table->usFanGainPlx;
-               hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm
-                       = fiji_fan_table->usFanGainHbm;
-       }
-
-       return 0;
-}
-
-/**
- * Private Function used during initialization.
- * Inspect the PowerPlay table for obvious signs of corruption.
- * @param hwmgr Pointer to the hardware manager.
- * @param powerplay_table Pointer to the PowerPlay Table.
- * @exception 2 if the powerplay table is incorrect.
- */
-static int check_powerplay_tables(
-               struct pp_hwmgr *hwmgr,
-               const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
-               )
-{
-       const ATOM_Tonga_State_Array *state_arrays;
-
-       state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) +
-               le16_to_cpu(powerplay_table->usStateArrayOffset));
-
-       PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <=
-               powerplay_table->sHeader.ucTableFormatRevision),
-               "Unsupported PPTable format!", return -1);
-       PP_ASSERT_WITH_CODE((0 != powerplay_table->usStateArrayOffset),
-               "State table is not set!", return -1);
-       PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize),
-               "Invalid PowerPlay Table!", return -1);
-       PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
-               "Invalid PowerPlay Table!", return -1);
-
-       return 0;
-}
-
-int tonga_pp_tables_initialize(struct pp_hwmgr *hwmgr)
-{
-       int result = 0;
-       const ATOM_Tonga_POWERPLAYTABLE *powerplay_table;
-
-       hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL);
-
-       PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable),
-                           "Failed to allocate hwmgr->pptable!", return -ENOMEM);
-
-       memset(hwmgr->pptable, 0x00, sizeof(struct phm_ppt_v1_information));
-
-       powerplay_table = get_powerplay_table(hwmgr);
-
-       PP_ASSERT_WITH_CODE((NULL != powerplay_table),
-               "Missing PowerPlay Table!", return -1);
-
-       result = check_powerplay_tables(hwmgr, powerplay_table);
-
-       PP_ASSERT_WITH_CODE((result == 0),
-                           "check_powerplay_tables failed", return result);
-
-       result = set_platform_caps(hwmgr,
-                                  le32_to_cpu(powerplay_table->ulPlatformCaps));
-
-       PP_ASSERT_WITH_CODE((result == 0),
-                           "set_platform_caps failed", return result);
-
-       result = init_thermal_controller(hwmgr, powerplay_table);
-
-       PP_ASSERT_WITH_CODE((result == 0),
-                           "init_thermal_controller failed", return result);
-
-       result = init_over_drive_limits(hwmgr, powerplay_table);
-
-       PP_ASSERT_WITH_CODE((result == 0),
-                           "init_over_drive_limits failed", return result);
-
-       result = init_clock_voltage_dependency(hwmgr, powerplay_table);
-
-       PP_ASSERT_WITH_CODE((result == 0),
-                           "init_clock_voltage_dependency failed", return result);
-
-       result = init_dpm_2_parameters(hwmgr, powerplay_table);
-
-       PP_ASSERT_WITH_CODE((result == 0),
-                           "init_dpm_2_parameters failed", return result);
-
-       return result;
-}
-
-int tonga_pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
-{
-       struct phm_ppt_v1_information *pp_table_information =
-               (struct phm_ppt_v1_information *)(hwmgr->pptable);
-
-       kfree(pp_table_information->vdd_dep_on_sclk);
-       pp_table_information->vdd_dep_on_sclk = NULL;
-
-       kfree(pp_table_information->vdd_dep_on_mclk);
-       pp_table_information->vdd_dep_on_mclk = NULL;
-
-       kfree(pp_table_information->valid_mclk_values);
-       pp_table_information->valid_mclk_values = NULL;
-
-       kfree(pp_table_information->valid_sclk_values);
-       pp_table_information->valid_sclk_values = NULL;
-
-       kfree(pp_table_information->vddc_lookup_table);
-       pp_table_information->vddc_lookup_table = NULL;
-
-       kfree(pp_table_information->vddgfx_lookup_table);
-       pp_table_information->vddgfx_lookup_table = NULL;
-
-       kfree(pp_table_information->mm_dep_table);
-       pp_table_information->mm_dep_table = NULL;
-
-       kfree(pp_table_information->cac_dtp_table);
-       pp_table_information->cac_dtp_table = NULL;
-
-       kfree(hwmgr->dyn_state.cac_dtp_table);
-       hwmgr->dyn_state.cac_dtp_table = NULL;
-
-       kfree(pp_table_information->ppm_parameter_table);
-       pp_table_information->ppm_parameter_table = NULL;
-
-       kfree(pp_table_information->pcie_table);
-       pp_table_information->pcie_table = NULL;
-
-       kfree(hwmgr->pptable);
-       hwmgr->pptable = NULL;
-
-       return 0;
-}
-
-const struct pp_table_func tonga_pptable_funcs = {
-       .pptable_init = tonga_pp_tables_initialize,
-       .pptable_fini = tonga_pp_tables_uninitialize,
-};
-
-int tonga_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr)
-{
-       const ATOM_Tonga_State_Array * state_arrays;
-       const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
-
-       PP_ASSERT_WITH_CODE((NULL != pp_table),
-                       "Missing PowerPlay Table!", return -1);
-       PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >=
-                       ATOM_Tonga_TABLE_REVISION_TONGA),
-                       "Incorrect PowerPlay table revision!", return -1);
-
-       state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
-                       le16_to_cpu(pp_table->usStateArrayOffset));
-
-       return (uint32_t)(state_arrays->ucNumEntries);
-}
-
-/**
-* Private function to convert flags stored in the BIOS to software flags in PowerPlay.
-*/
-static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr,
-               uint16_t classification, uint16_t classification2)
-{
-       uint32_t result = 0;
-
-       if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
-               result |= PP_StateClassificationFlag_Boot;
-
-       if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
-               result |= PP_StateClassificationFlag_Thermal;
-
-       if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
-               result |= PP_StateClassificationFlag_LimitedPowerSource;
-
-       if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
-               result |= PP_StateClassificationFlag_Rest;
-
-       if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
-               result |= PP_StateClassificationFlag_Forced;
-
-       if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
-               result |= PP_StateClassificationFlag_ACPI;
-
-       if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
-               result |= PP_StateClassificationFlag_LimitedPowerSource_2;
-
-       return result;
-}
-
-/**
-* Create a Power State out of an entry in the PowerPlay table.
-* This function is called by the hardware back-end.
-* @param hwmgr Pointer to the hardware manager.
-* @param entry_index The index of the entry to be extracted from the table.
-* @param power_state The address of the PowerState instance being created.
-* @return -1 if the entry cannot be retrieved.
-*/
-int tonga_get_powerplay_table_entry(struct pp_hwmgr *hwmgr,
-               uint32_t entry_index, struct pp_power_state *power_state,
-               int (*call_back_func)(struct pp_hwmgr *, void *,
-                               struct pp_power_state *, void *, uint32_t))
-{
-       int result = 0;
-       const ATOM_Tonga_State_Array * state_arrays;
-       const ATOM_Tonga_State *state_entry;
-       const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
-
-       PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1;);
-       power_state->classification.bios_index = entry_index;
-
-       if (pp_table->sHeader.ucTableFormatRevision >=
-                       ATOM_Tonga_TABLE_REVISION_TONGA) {
-               state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
-                               le16_to_cpu(pp_table->usStateArrayOffset));
-
-               PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset),
-                               "Invalid PowerPlay Table State Array Offset.", return -1);
-               PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
-                               "Invalid PowerPlay Table State Array.", return -1);
-               PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
-                               "Invalid PowerPlay Table State Array Entry.", return -1);
-
-               state_entry = &(state_arrays->states[entry_index]);
-
-               result = call_back_func(hwmgr, (void *)state_entry, power_state,
-                               (void *)pp_table,
-                               make_classification_flags(hwmgr,
-                                       le16_to_cpu(state_entry->usClassification),
-                                       le16_to_cpu(state_entry->usClassification2)));
-       }
-
-       if (!result && (power_state->classification.flags &
-                       PP_StateClassificationFlag_Boot))
-               result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware));
-
-       return result;
-}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.h
deleted file mode 100644 (file)
index d24b888..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2015 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 TONGA_PROCESSPPTABLES_H
-#define TONGA_PROCESSPPTABLES_H
-
-#include "hwmgr.h"
-
-extern const struct pp_table_func tonga_pptable_funcs;
-extern int tonga_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr);
-extern int tonga_get_powerplay_table_entry(struct pp_hwmgr *hwmgr, uint32_t entry_index,
-               struct pp_power_state *power_state, int (*call_back_func)(struct pp_hwmgr *, void *,
-                               struct pp_power_state *, void *, uint32_t));
-
-#endif
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.c
deleted file mode 100644 (file)
index 47ef1ca..0000000
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright 2015 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 <asm/div64.h>
-#include "tonga_thermal.h"
-#include "tonga_hwmgr.h"
-#include "tonga_smumgr.h"
-#include "tonga_ppsmc.h"
-#include "smu/smu_7_1_2_d.h"
-#include "smu/smu_7_1_2_sh_mask.h"
-
-/**
-* Get Fan Speed Control Parameters.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pSpeed is the address of the structure where the result is to be placed.
-* @exception Always succeeds except if we cannot zero out the output structure.
-*/
-int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info)
-{
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       fan_speed_info->supports_percent_read = true;
-       fan_speed_info->supports_percent_write = true;
-       fan_speed_info->min_percent = 0;
-       fan_speed_info->max_percent = 100;
-
-       if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
-               fan_speed_info->supports_rpm_read = true;
-               fan_speed_info->supports_rpm_write = true;
-               fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
-               fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
-       } else {
-               fan_speed_info->min_rpm = 0;
-               fan_speed_info->max_rpm = 0;
-       }
-
-       return 0;
-}
-
-/**
-* Get Fan Speed in percent.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pSpeed is the address of the structure where the result is to be placed.
-* @exception Fails is the 100% setting appears to be 0.
-*/
-int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed)
-{
-       uint32_t duty100;
-       uint32_t duty;
-       uint64_t tmp64;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
-       duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY);
-
-       if (0 == duty100)
-               return -EINVAL;
-
-
-       tmp64 = (uint64_t)duty * 100;
-       do_div(tmp64, duty100);
-       *speed = (uint32_t)tmp64;
-
-       if (*speed > 100)
-               *speed = 100;
-
-       return 0;
-}
-
-/**
-* Get Fan Speed in RPM.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    speed is the address of the structure where the result is to be placed.
-* @exception Returns not supported if no fan is found or if pulses per revolution are not set
-*/
-int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
-{
-       return 0;
-}
-
-/**
-* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
-* @param    hwmgr  the address of the powerplay hardware manager.
-*           mode    the fan control mode, 0 default, 1 by percent, 5, by RPM
-* @exception Should always succeed.
-*/
-int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
-{
-
-       if (hwmgr->fan_ctrl_is_in_default_mode) {
-               hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE);
-               hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN);
-               hwmgr->fan_ctrl_is_in_default_mode = false;
-       }
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode);
-
-       return 0;
-}
-
-/**
-* Reset Fan Speed Control to default mode.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @exception Should always succeed.
-*/
-int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
-{
-       if (!hwmgr->fan_ctrl_is_in_default_mode) {
-               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
-               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin);
-               hwmgr->fan_ctrl_is_in_default_mode = true;
-       }
-
-       return 0;
-}
-
-int tonga_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
-               cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
-               result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ?  0 : -EINVAL;
-/*
-               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_FanSpeedInTableIsRPM))
-                       hwmgr->set_max_fan_rpm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM);
-               else
-                       hwmgr->set_max_fan_pwm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM);
-*/
-       } else {
-               cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
-               result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ?  0 : -EINVAL;
-       }
-/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
-       if (result == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature != 0)
-               result = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanTemperatureTarget, \
-                                                               hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature) ? 0 : -EINVAL);
-*/
-       return result;
-}
-
-
-int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
-{
-       return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ?  0 : -EINVAL;
-}
-
-/**
-* Set Fan Speed in percent.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    speed is the percentage value (0% - 100%) to be set.
-* @exception Fails is the 100% setting appears to be 0.
-*/
-int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed)
-{
-       uint32_t duty100;
-       uint32_t duty;
-       uint64_t tmp64;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return -EINVAL;
-
-       if (speed > 100)
-               speed = 100;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
-               tonga_fan_ctrl_stop_smc_fan_control(hwmgr);
-
-       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
-
-       if (0 == duty100)
-               return -EINVAL;
-
-       tmp64 = (uint64_t)speed * duty100;
-       do_div(tmp64, 100);
-       duty = (uint32_t)tmp64;
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
-
-       return tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-}
-
-/**
-* Reset Fan Speed to default.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @exception Always succeeds.
-*/
-int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
-
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
-               result = tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-               if (0 == result)
-                       result = tonga_fan_ctrl_start_smc_fan_control(hwmgr);
-       } else
-               result = tonga_fan_ctrl_set_default_mode(hwmgr);
-
-       return result;
-}
-
-/**
-* Set Fan Speed in RPM.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    speed is the percentage value (min - max) to be set.
-* @exception Fails is the speed not lie between min and max.
-*/
-int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
-{
-       return 0;
-}
-
-/**
-* Reads the remote temperature from the SIslands thermal controller.
-*
-* @param    hwmgr The address of the hardware manager.
-*/
-int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr)
-{
-       int temp;
-
-       temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP);
-
-/* Bit 9 means the reading is lower than the lowest usable value. */
-       if (0 != (0x200 & temp))
-               temp = TONGA_THERMAL_MAXIMUM_TEMP_READING;
-       else
-               temp = (temp & 0x1ff);
-
-       temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-
-       return temp;
-}
-
-/**
-* Set the requested temperature range for high and low alert signals
-*
-* @param    hwmgr The address of the hardware manager.
-* @param    range Temperature range to be programmed for high and low alert signals
-* @exception PP_Result_BadInput if the input data is not valid.
-*/
-static int tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp)
-{
-       uint32_t low = TONGA_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-       uint32_t high = TONGA_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-
-       if (low < low_temp)
-               low = low_temp;
-       if (high > high_temp)
-               high = high_temp;
-
-       if (low > high)
-               return -EINVAL;
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-
-       return 0;
-}
-
-/**
-* Programs thermal controller one-time setting registers
-*
-* @param    hwmgr The address of the hardware manager.
-*/
-static int tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
-{
-       if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
-               PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
-                                               CG_TACH_CTRL, EDGE_PER_REV,
-                                               hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1);
-
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
-
-       return 0;
-}
-
-/**
-* Enable thermal alerts on the RV770 thermal controller.
-*
-* @param    hwmgr The address of the hardware manager.
-*/
-static int tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr)
-{
-       uint32_t alert;
-
-       alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
-       alert &= ~(TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
-
-       /* send message to SMU to enable internal thermal interrupts */
-       return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1;
-}
-
-/**
-* Disable thermal alerts on the RV770 thermal controller.
-* @param    hwmgr The address of the hardware manager.
-*/
-static int tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr)
-{
-       uint32_t alert;
-
-       alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
-       alert |= (TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
-       PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
-
-       /* send message to SMU to disable internal thermal interrupts */
-       return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1;
-}
-
-/**
-* Uninitialize the thermal controller.
-* Currently just disables alerts.
-* @param    hwmgr The address of the hardware manager.
-*/
-int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
-{
-       int result = tonga_thermal_disable_alert(hwmgr);
-
-       if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               tonga_fan_ctrl_set_default_mode(hwmgr);
-
-       return result;
-}
-
-/**
-* Set up the fan table to control the fan using the SMC.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from set temperature range routine
-*/
-int tf_tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
-{
-       struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
-       SMU72_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
-       uint32_t duty100;
-       uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
-       uint16_t fdo_min, slope1, slope2;
-       uint32_t reference_clock;
-       int res;
-       uint64_t tmp64;
-
-       if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
-               return 0;
-
-       if (0 == data->fan_table_start) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
-               return 0;
-       }
-
-       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
-
-       if (0 == duty100) {
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
-               return 0;
-       }
-
-       tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
-       do_div(tmp64, 10000);
-       fdo_min = (uint16_t)tmp64;
-
-       t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
-       t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
-
-       pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
-       pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
-
-       slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
-       slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
-
-       fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
-       fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
-       fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
-
-       fan_table.Slope1 = cpu_to_be16(slope1);
-       fan_table.Slope2 = cpu_to_be16(slope2);
-
-       fan_table.FdoMin = cpu_to_be16(fdo_min);
-
-       fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
-
-       fan_table.HystUp = cpu_to_be16(1);
-
-       fan_table.HystSlope = cpu_to_be16(1);
-
-       fan_table.TempRespLim = cpu_to_be16(5);
-
-       reference_clock = tonga_get_xclk(hwmgr);
-
-       fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
-
-       fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
-
-       fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
-
-       fan_table.FanControl_GL_Flag = 1;
-
-       res = tonga_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), data->sram_end);
-/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
-       if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit != 0)
-               res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanMinPwm, \
-                                               hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit) ? 0 : -1);
-
-       if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit != 0)
-               res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanSclkTarget, \
-                                       hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit) ? 0 : -1);
-
-       if (0 != res)
-               phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
-*/
-       return 0;
-}
-
-/**
-* Start the fan control on the SMC.
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from set temperature range routine
-*/
-int tf_tonga_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
-{
-/* If the fantable setup has failed we could have disabled PHM_PlatformCaps_MicrocodeFanControl even after this function was included in the table.
- * Make sure that we still think controlling the fan is OK.
-*/
-       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
-               tonga_fan_ctrl_start_smc_fan_control(hwmgr);
-               tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
-       }
-
-       return 0;
-}
-
-/**
-* Set temperature range for high and low alerts
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from set temperature range routine
-*/
-int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
-{
-       struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
-
-       if (range == NULL)
-               return -EINVAL;
-
-       return tonga_thermal_set_temperature_range(hwmgr, range->min, range->max);
-}
-
-/**
-* Programs one-time setting registers
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from initialize thermal controller routine
-*/
-int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
-{
-    return tonga_thermal_initialize(hwmgr);
-}
-
-/**
-* Enable high and low alerts
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from enable alert routine
-*/
-int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
-{
-       return tonga_thermal_enable_alert(hwmgr);
-}
-
-/**
-* Disable high and low alerts
-* @param    hwmgr  the address of the powerplay hardware manager.
-* @param    pInput the pointer to input data
-* @param    pOutput the pointer to output data
-* @param    pStorage the pointer to temporary storage
-* @param    Result the last failure code
-* @return   result from disable alert routine
-*/
-static int tf_tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
-{
-       return tonga_thermal_disable_alert(hwmgr);
-}
-
-static const struct phm_master_table_item tonga_thermal_start_thermal_controller_master_list[] = {
-       { NULL, tf_tonga_thermal_initialize },
-       { NULL, tf_tonga_thermal_set_temperature_range },
-       { NULL, tf_tonga_thermal_enable_alert },
-/* 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, tf_tonga_thermal_setup_fan_table},
-       { NULL, tf_tonga_thermal_start_smc_fan_control},
-       { NULL, NULL }
-};
-
-static const struct phm_master_table_header tonga_thermal_start_thermal_controller_master = {
-       0,
-       PHM_MasterTableFlag_None,
-       tonga_thermal_start_thermal_controller_master_list
-};
-
-static const struct phm_master_table_item tonga_thermal_set_temperature_range_master_list[] = {
-       { NULL, tf_tonga_thermal_disable_alert},
-       { NULL, tf_tonga_thermal_set_temperature_range},
-       { NULL, tf_tonga_thermal_enable_alert},
-       { NULL, NULL }
-};
-
-static const struct phm_master_table_header tonga_thermal_set_temperature_range_master = {
-       0,
-       PHM_MasterTableFlag_None,
-       tonga_thermal_set_temperature_range_master_list
-};
-
-int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
-{
-       if (!hwmgr->thermal_controller.fanInfo.bNoFan)
-               tonga_fan_ctrl_set_default_mode(hwmgr);
-       return 0;
-}
-
-/**
-* Initializes the thermal controller related functions in the Hardware Manager structure.
-* @param    hwmgr The address of the hardware manager.
-* @exception Any error code from the low-level communication.
-*/
-int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
-{
-       int result;
-
-       result = phm_construct_table(hwmgr, &tonga_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range));
-
-       if (0 == result) {
-               result = phm_construct_table(hwmgr,
-                                               &tonga_thermal_start_thermal_controller_master,
-                                               &(hwmgr->start_thermal_controller));
-               if (0 != result)
-                       phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
-       }
-
-       if (0 == result)
-               hwmgr->fan_ctrl_is_in_default_mode = true;
-       return result;
-}
-
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.h
deleted file mode 100644 (file)
index aa335f2..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2015 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 TONGA_THERMAL_H
-#define TONGA_THERMAL_H
-
-#include "hwmgr.h"
-
-#define TONGA_THERMAL_HIGH_ALERT_MASK         0x1
-#define TONGA_THERMAL_LOW_ALERT_MASK          0x2
-
-#define TONGA_THERMAL_MINIMUM_TEMP_READING    -256
-#define TONGA_THERMAL_MAXIMUM_TEMP_READING    255
-
-#define TONGA_THERMAL_MINIMUM_ALERT_TEMP      0
-#define TONGA_THERMAL_MAXIMUM_ALERT_TEMP      255
-
-#define FDO_PWM_MODE_STATIC  1
-#define FDO_PWM_MODE_STATIC_RPM 5
-
-
-extern int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
-extern int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
-extern int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
-
-extern int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr);
-extern int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
-extern int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
-extern int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
-extern int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
-extern int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
-extern int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
-extern int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
-extern int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr);
-extern int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
-extern int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
-extern int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
-extern int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
-
-#endif
-
index b764c8c..3fb5e57 100644 (file)
 #include "amd_shared.h"
 #include "cgs_common.h"
 
+enum amd_pp_sensors {
+       AMDGPU_PP_SENSOR_GFX_SCLK = 0,
+       AMDGPU_PP_SENSOR_VDDNB,
+       AMDGPU_PP_SENSOR_VDDGFX,
+       AMDGPU_PP_SENSOR_UVD_VCLK,
+       AMDGPU_PP_SENSOR_UVD_DCLK,
+       AMDGPU_PP_SENSOR_VCE_ECCLK,
+       AMDGPU_PP_SENSOR_GPU_LOAD,
+       AMDGPU_PP_SENSOR_GFX_MCLK,
+       AMDGPU_PP_SENSOR_GPU_TEMP,
+       AMDGPU_PP_SENSOR_VCE_POWER,
+       AMDGPU_PP_SENSOR_UVD_POWER,
+};
 
 enum amd_pp_event {
        AMD_PP_EVENT_INITIALIZE = 0,
@@ -131,9 +144,8 @@ struct amd_pp_init {
        struct cgs_device *device;
        uint32_t chip_family;
        uint32_t chip_id;
-       uint32_t rev_id;
-       bool powercontainment_enabled;
 };
+
 enum amd_pp_display_config_type{
        AMD_PP_DisplayConfigType_None = 0,
        AMD_PP_DisplayConfigType_DP54 ,
@@ -261,6 +273,7 @@ enum amd_pp_clock_type {
 struct amd_pp_clocks {
        uint32_t count;
        uint32_t clock[MAX_NUM_CLOCKS];
+       uint32_t latency[MAX_NUM_CLOCKS];
 };
 
 
@@ -332,8 +345,6 @@ struct amd_powerplay_funcs {
        int (*powergate_uvd)(void *handle, bool gate);
        int (*dispatch_tasks)(void *handle, enum amd_pp_event event_id,
                                   void *input, void *output);
-       void (*print_current_performance_level)(void *handle,
-                                                     struct seq_file *m);
        int (*set_fan_control_mode)(void *handle, uint32_t mode);
        int (*get_fan_control_mode)(void *handle);
        int (*set_fan_speed_percent)(void *handle, uint32_t percent);
@@ -347,6 +358,7 @@ struct amd_powerplay_funcs {
        int (*set_sclk_od)(void *handle, uint32_t value);
        int (*get_mclk_od)(void *handle);
        int (*set_mclk_od)(void *handle, uint32_t value);
+       int (*read_sensor)(void *handle, int idx, int32_t *value);
 };
 
 struct amd_powerplay {
@@ -378,4 +390,6 @@ int amd_powerplay_get_clock_by_type(void *handle,
 int amd_powerplay_get_display_mode_validation_clocks(void *handle,
                struct amd_pp_simple_clock_info *output);
 
+int amd_set_clockgating_by_smu(void *handle, uint32_t msg_id);
+
 #endif /* _AMD_POWERPLAY_H_ */
index 962cb53..d449583 100644 (file)
@@ -341,7 +341,6 @@ extern int phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
 extern int phm_setup_asic(struct pp_hwmgr *hwmgr);
 extern int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr);
 extern int phm_disable_dynamic_state_management(struct pp_hwmgr *hwmgr);
-extern void phm_init_dynamic_caps(struct pp_hwmgr *hwmgr);
 extern bool phm_is_hw_access_blocked(struct pp_hwmgr *hwmgr);
 extern int phm_block_hw_access(struct pp_hwmgr *hwmgr, bool block);
 extern int phm_set_power_state(struct pp_hwmgr *hwmgr,
index bf0d2ac..4f0fedd 100644 (file)
 #include "hwmgr_ppt.h"
 #include "ppatomctrl.h"
 #include "hwmgr_ppt.h"
+#include "power_state.h"
 
 struct pp_instance;
 struct pp_hwmgr;
-struct pp_hw_power_state;
-struct pp_power_state;
-struct PP_VCEState;
 struct phm_fan_speed_info;
 struct pp_atomctrl_voltage_table;
 
+extern int amdgpu_powercontainment;
+extern int amdgpu_sclk_deep_sleep_en;
+extern unsigned amdgpu_pp_feature_mask;
+
+#define VOLTAGE_SCALE 4
+
+uint8_t convert_to_vid(uint16_t vddc);
 
 enum DISPLAY_GAP {
        DISPLAY_GAP_VBLANK_OR_WM = 0,   /* Wait for vblank or MCHG watermark. */
@@ -49,7 +54,6 @@ enum DISPLAY_GAP {
 };
 typedef enum DISPLAY_GAP DISPLAY_GAP;
 
-
 struct vi_dpm_level {
        bool enabled;
        uint32_t value;
@@ -71,6 +75,19 @@ enum PP_Result {
 #define PCIE_PERF_REQ_GEN2         3
 #define PCIE_PERF_REQ_GEN3         4
 
+enum PP_FEATURE_MASK {
+       PP_SCLK_DPM_MASK = 0x1,
+       PP_MCLK_DPM_MASK = 0x2,
+       PP_PCIE_DPM_MASK = 0x4,
+       PP_SCLK_DEEP_SLEEP_MASK = 0x8,
+       PP_POWER_CONTAINMENT_MASK = 0x10,
+       PP_UVD_HANDSHAKE_MASK = 0x20,
+       PP_SMC_VOLTAGE_CONTROL_MASK = 0x40,
+       PP_VBI_TIME_SUPPORT_MASK = 0x80,
+       PP_ULV_MASK = 0x100,
+       PP_ENABLE_GFX_CG_THRU_SMU = 0x200
+};
+
 enum PHM_BackEnd_Magic {
        PHM_Dummy_Magic       = 0xAA5555AA,
        PHM_RV770_Magic       = 0xDCBAABCD,
@@ -294,8 +311,6 @@ struct pp_hwmgr_func {
        int (*get_sclk)(struct pp_hwmgr *hwmgr, bool low);
        int (*power_state_set)(struct pp_hwmgr *hwmgr,
                                                const void *state);
-       void (*print_current_perforce_level)(struct pp_hwmgr *hwmgr,
-                                                       struct seq_file *m);
        int (*enable_clock_power_gating)(struct pp_hwmgr *hwmgr);
        int (*notify_smc_display_config_after_ps_adjustment)(struct pp_hwmgr *hwmgr);
        int (*display_config_changed)(struct pp_hwmgr *hwmgr);
@@ -342,6 +357,7 @@ struct pp_hwmgr_func {
        int (*set_sclk_od)(struct pp_hwmgr *hwmgr, uint32_t value);
        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);
 };
 
 struct pp_table_func {
@@ -351,7 +367,7 @@ struct pp_table_func {
        int (*pptable_get_vce_state_table_entry)(
                                                struct pp_hwmgr *hwmgr,
                                                unsigned long i,
-                                               struct PP_VCEState *vce_state,
+                                               struct pp_vce_state *vce_state,
                                                void **clock_info,
                                                unsigned long *flag);
 };
@@ -570,22 +586,43 @@ struct phm_microcode_version_info {
        uint32_t NB;
 };
 
+#define PP_MAX_VCE_LEVELS 6
+
+enum PP_VCE_LEVEL {
+       PP_VCE_LEVEL_AC_ALL = 0,     /* AC, All cases */
+       PP_VCE_LEVEL_DC_EE = 1,      /* DC, entropy encoding */
+       PP_VCE_LEVEL_DC_LL_LOW = 2,  /* DC, low latency queue, res <= 720 */
+       PP_VCE_LEVEL_DC_LL_HIGH = 3, /* DC, low latency queue, 1080 >= res > 720 */
+       PP_VCE_LEVEL_DC_GP_LOW = 4,  /* DC, general purpose queue, res <= 720 */
+       PP_VCE_LEVEL_DC_GP_HIGH = 5, /* DC, general purpose queue, 1080 >= res > 720 */
+};
+
+
+enum PP_TABLE_VERSION {
+       PP_TABLE_V0 = 0,
+       PP_TABLE_V1,
+       PP_TABLE_V2,
+       PP_TABLE_MAX
+};
+
 /**
  * The main hardware manager structure.
  */
 struct pp_hwmgr {
        uint32_t chip_family;
        uint32_t chip_id;
-       uint32_t hw_revision;
-       uint32_t sub_sys_id;
-       uint32_t sub_vendor_id;
 
+       uint32_t pp_table_version;
        void *device;
        struct pp_smumgr *smumgr;
        const void *soft_pp_table;
        uint32_t soft_pp_table_size;
        void *hardcode_pp_table;
        bool need_pp_table_upload;
+
+       struct pp_vce_state vce_states[PP_MAX_VCE_LEVELS];
+       uint32_t num_vce_state_tables;
+
        enum amd_dpm_forced_level dpm_level;
        bool block_hw_access;
        struct phm_gfx_arbiter gfx_arbiter;
@@ -614,7 +651,6 @@ struct pp_hwmgr {
        uint32_t num_ps;
        struct pp_thermal_controller_info thermal_controller;
        bool fan_ctrl_is_in_default_mode;
-       bool powercontainment_enabled;
        uint32_t fan_ctrl_default_mode;
        uint32_t tmin;
        struct phm_microcode_version_info microcode_version_info;
@@ -624,6 +660,7 @@ struct pp_hwmgr {
        struct pp_power_state    *boot_ps;
        struct pp_power_state    *uvd_ps;
        struct amd_pp_display_configuration display_config;
+       uint32_t feature_mask;
 };
 
 
@@ -637,16 +674,7 @@ extern int hw_init_power_state_table(struct pp_hwmgr *hwmgr);
 extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
                                uint32_t value, uint32_t mask);
 
-extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
-                               uint32_t index, uint32_t value, uint32_t mask);
 
-extern uint32_t phm_read_indirect_register(struct pp_hwmgr *hwmgr,
-               uint32_t indirect_port, uint32_t index);
-
-extern void phm_write_indirect_register(struct pp_hwmgr *hwmgr,
-               uint32_t indirect_port,
-               uint32_t index,
-               uint32_t value);
 
 extern void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
                                uint32_t indirect_port,
@@ -654,12 +682,7 @@ extern void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
                                uint32_t value,
                                uint32_t mask);
 
-extern void phm_wait_for_indirect_register_unequal(
-                               struct pp_hwmgr *hwmgr,
-                               uint32_t indirect_port,
-                               uint32_t index,
-                               uint32_t value,
-                               uint32_t mask);
+
 
 extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr);
 extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr);
@@ -673,6 +696,8 @@ extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, st
 extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max);
 extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes);
 extern int32_t phm_get_dpm_level_enable_mask_value(void *table);
+extern uint8_t phm_get_voltage_id(struct pp_atomctrl_voltage_table *voltage_table,
+               uint32_t voltage);
 extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage);
 extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci);
 extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level);
@@ -683,6 +708,10 @@ 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 phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
+                               uint32_t sclk, uint16_t id, uint16_t *voltage);
+
 #define PHM_ENTIRE_REGISTER_MASK 0xFFFFFFFFU
 
 #define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
@@ -697,44 +726,6 @@ extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr);
         PHM_FIELD_SHIFT(reg, field))
 
 
-#define PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, index, value, mask)       \
-       phm_wait_on_register(hwmgr, index, value, mask)
-
-#define PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, index, value, mask)       \
-       phm_wait_for_register_unequal(hwmgr, index, value, mask)
-
-#define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask)        \
-       phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask)
-
-#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask)        \
-       phm_wait_for_indirect_register_unequal(hwmgr, mm##port##_INDEX, index, value, mask)
-
-#define PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask)   \
-       phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX_0, index, value, mask)
-
-#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask)   \
-       phm_wait_for_indirect_register_unequal(hwmgr, mm##port##_INDEX_0, index, value, mask)
-
-/* Operations on named registers. */
-
-#define PHM_WAIT_REGISTER(hwmgr, reg, value, mask)     \
-       PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg, value, mask)
-
-#define PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, value, mask)     \
-       PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg, value, mask)
-
-#define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask)      \
-       PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
-
-#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask)      \
-       PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
-
-#define PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \
-       PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
-
-#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \
-       PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
-
 /* Operations on named fields. */
 
 #define PHM_READ_FIELD(device, reg, field)     \
@@ -762,60 +753,16 @@ extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr);
                        PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg),     \
                                reg, field, fieldval))
 
-#define PHM_WAIT_FIELD(hwmgr, reg, field, fieldval)    \
-       PHM_WAIT_REGISTER(hwmgr, reg, (fieldval)        \
-                       << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
-
-#define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval)     \
-       PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \
-                       << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
-
-#define PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval)        \
-       PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval)    \
-                       << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+#define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask)        \
+       phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask)
 
-#define PHM_WAIT_FIELD_UNEQUAL(hwmgr, reg, field, fieldval)    \
-       PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, (fieldval)        \
-                       << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
 
-#define PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval)     \
-       PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, (fieldval) \
-                       << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+#define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask)      \
+       PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
 
-#define PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval)        \
-       PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, (fieldval)    \
+#define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval)     \
+       PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \
                        << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
 
-/* Operations on arrays of registers & fields. */
-
-#define PHM_READ_ARRAY_REGISTER(device, reg, offset)   \
-       cgs_read_register(device, mm##reg + (offset))
-
-#define PHM_WRITE_ARRAY_REGISTER(device, reg, offset, value)   \
-       cgs_write_register(device, mm##reg + (offset), value)
-
-#define PHM_WAIT_ARRAY_REGISTER(hwmgr, reg, offset, value, mask)       \
-       PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg + (offset), value, mask)
-
-#define PHM_WAIT_ARRAY_REGISTER_UNEQUAL(hwmgr, reg, offset, value, mask)       \
-       PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg + (offset), value, mask)
-
-#define PHM_READ_ARRAY_FIELD(hwmgr, reg, offset, field) \
-       PHM_GET_FIELD(PHM_READ_ARRAY_REGISTER(hwmgr->device, reg, offset), reg, field)
-
-#define PHM_WRITE_ARRAY_FIELD(hwmgr, reg, offset, field, fieldvalue)   \
-       PHM_WRITE_ARRAY_REGISTER(hwmgr->device, reg, offset,    \
-                       PHM_SET_FIELD(PHM_READ_ARRAY_REGISTER(hwmgr->device, reg, offset),      \
-                               reg, field, fieldvalue))
-
-#define PHM_WAIT_ARRAY_FIELD(hwmgr, reg, offset, field, fieldvalue)    \
-       PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg + (offset),        \
-                       (fieldvalue) << PHM_FIELD_SHIFT(reg, field),    \
-                       PHM_FIELD_MASK(reg, field))
-
-#define PHM_WAIT_ARRAY_FIELD_UNEQUAL(hwmgr, reg, offset, field, fieldvalue)    \
-       PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg + (offset),        \
-                       (fieldvalue) << PHM_FIELD_SHIFT(reg, field),    \
-                       PHM_FIELD_MASK(reg, field))
 
 #endif /* _HWMGR_H_ */
index f497e7d..0de4436 100644 (file)
@@ -23,8 +23,7 @@
 #ifndef _POLARIS10_PWRVIRUS_H
 #define _POLARIS10_PWRVIRUS_H
 
-#define mmSMC_IND_INDEX_11                              0x01AC
-#define mmSMC_IND_DATA_11                               0x01AD
+
 #define mmCP_HYP_MEC1_UCODE_ADDR       0xf81a
 #define mmCP_HYP_MEC1_UCODE_DATA       0xf81b
 #define mmCP_HYP_MEC2_UCODE_ADDR       0xf81c
index a3f0ce4..9ceaed9 100644 (file)
@@ -158,7 +158,7 @@ struct pp_power_state {
 
 
 /*Structure to hold a VCE state entry*/
-struct PP_VCEState {
+struct pp_vce_state {
        uint32_t evclk;
        uint32_t ecclk;
        uint32_t sclk;
@@ -171,30 +171,28 @@ enum PP_MMProfilingState {
        PP_MMProfilingState_Stopped
 };
 
-struct PP_Clock_Engine_Request {
-       unsigned long clientType;
-       unsigned long ctxid;
+struct pp_clock_engine_request {
+       unsigned long client_type;
+       unsigned long ctx_id;
        uint64_t  context_handle;
        unsigned long sclk;
-       unsigned long sclkHardMin;
+       unsigned long sclk_hard_min;
        unsigned long mclk;
        unsigned long iclk;
        unsigned long evclk;
        unsigned long ecclk;
-       unsigned long ecclkHardMin;
+       unsigned long ecclk_hard_min;
        unsigned long vclk;
        unsigned long dclk;
-       unsigned long samclk;
-       unsigned long acpclk;
-       unsigned long sclkOverdrive;
-       unsigned long mclkOverdrive;
+       unsigned long sclk_over_drive;
+       unsigned long mclk_over_drive;
        unsigned long sclk_threshold;
        unsigned long flag;
        unsigned long vclk_ceiling;
        unsigned long dclk_ceiling;
        unsigned long num_cus;
-       unsigned long pmflag;
-       enum PP_MMProfilingState MMProfilingState;
+       unsigned long pm_flag;
+       enum PP_MMProfilingState mm_profiling_state;
 };
 
 #endif
index d7d83b7..bfdbec1 100644 (file)
@@ -43,5 +43,8 @@
        } while (0)
 
 
+#define GET_FLEXIBLE_ARRAY_MEMBER_ADDR(type, member, ptr, n)   \
+       (type *)((char *)&(ptr)->member + (sizeof(type) * (n)))
+
 #endif /* PP_DEBUG_H */
 
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu71.h b/drivers/gpu/drm/amd/powerplay/inc/smu71.h
new file mode 100644 (file)
index 0000000..71c9b2d
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * 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.
+ *
+ */
+#ifndef SMU71_H
+#define SMU71_H
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(push, 1)
+#endif
+
+#define SMU__NUM_PCIE_DPM_LEVELS 8
+#define SMU__NUM_SCLK_DPM_STATE 8
+#define SMU__NUM_MCLK_DPM_LEVELS 4
+#define SMU__VARIANT__ICELAND 1
+#define SMU__DGPU_ONLY 1
+#define SMU__DYNAMIC_MCARB_SETTINGS 1
+
+enum SID_OPTION {
+  SID_OPTION_HI,
+  SID_OPTION_LO,
+  SID_OPTION_COUNT
+};
+
+typedef struct {
+  uint32_t high;
+  uint32_t low;
+} data_64_t;
+
+typedef struct {
+  data_64_t high;
+  data_64_t low;
+} data_128_t;
+
+#define SMU7_CONTEXT_ID_SMC        1
+#define SMU7_CONTEXT_ID_VBIOS      2
+
+#define SMU71_MAX_LEVELS_VDDC            8
+#define SMU71_MAX_LEVELS_VDDCI           4
+#define SMU71_MAX_LEVELS_MVDD            4
+#define SMU71_MAX_LEVELS_VDDNB           8
+
+#define SMU71_MAX_LEVELS_GRAPHICS        SMU__NUM_SCLK_DPM_STATE
+#define SMU71_MAX_LEVELS_MEMORY          SMU__NUM_MCLK_DPM_LEVELS
+#define SMU71_MAX_LEVELS_GIO             SMU__NUM_LCLK_DPM_LEVELS
+#define SMU71_MAX_LEVELS_LINK            SMU__NUM_PCIE_DPM_LEVELS
+#define SMU71_MAX_ENTRIES_SMIO           32
+
+#define DPM_NO_LIMIT 0
+#define DPM_NO_UP 1
+#define DPM_GO_DOWN 2
+#define DPM_GO_UP 3
+
+#define SMU7_FIRST_DPM_GRAPHICS_LEVEL    0
+#define SMU7_FIRST_DPM_MEMORY_LEVEL      0
+
+#define GPIO_CLAMP_MODE_VRHOT      1
+#define GPIO_CLAMP_MODE_THERM      2
+#define GPIO_CLAMP_MODE_DC         4
+
+#define SCRATCH_B_TARG_PCIE_INDEX_SHIFT 0
+#define SCRATCH_B_TARG_PCIE_INDEX_MASK  (0x7<<SCRATCH_B_TARG_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_PCIE_INDEX_SHIFT 3
+#define SCRATCH_B_CURR_PCIE_INDEX_MASK  (0x7<<SCRATCH_B_CURR_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_UVD_INDEX_SHIFT  6
+#define SCRATCH_B_TARG_UVD_INDEX_MASK   (0x7<<SCRATCH_B_TARG_UVD_INDEX_SHIFT)
+#define SCRATCH_B_CURR_UVD_INDEX_SHIFT  9
+#define SCRATCH_B_CURR_UVD_INDEX_MASK   (0x7<<SCRATCH_B_CURR_UVD_INDEX_SHIFT)
+#define SCRATCH_B_TARG_VCE_INDEX_SHIFT  12
+#define SCRATCH_B_TARG_VCE_INDEX_MASK   (0x7<<SCRATCH_B_TARG_VCE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_VCE_INDEX_SHIFT  15
+#define SCRATCH_B_CURR_VCE_INDEX_MASK   (0x7<<SCRATCH_B_CURR_VCE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_ACP_INDEX_SHIFT  18
+#define SCRATCH_B_TARG_ACP_INDEX_MASK   (0x7<<SCRATCH_B_TARG_ACP_INDEX_SHIFT)
+#define SCRATCH_B_CURR_ACP_INDEX_SHIFT  21
+#define SCRATCH_B_CURR_ACP_INDEX_MASK   (0x7<<SCRATCH_B_CURR_ACP_INDEX_SHIFT)
+#define SCRATCH_B_TARG_SAMU_INDEX_SHIFT 24
+#define SCRATCH_B_TARG_SAMU_INDEX_MASK  (0x7<<SCRATCH_B_TARG_SAMU_INDEX_SHIFT)
+#define SCRATCH_B_CURR_SAMU_INDEX_SHIFT 27
+#define SCRATCH_B_CURR_SAMU_INDEX_MASK  (0x7<<SCRATCH_B_CURR_SAMU_INDEX_SHIFT)
+
+
+#if defined SMU__DGPU_ONLY
+#define SMU71_DTE_ITERATIONS 5
+#define SMU71_DTE_SOURCES 3
+#define SMU71_DTE_SINKS 1
+#define SMU71_NUM_CPU_TES 0
+#define SMU71_NUM_GPU_TES 1
+#define SMU71_NUM_NON_TES 2
+
+#endif
+
+#if defined SMU__FUSION_ONLY
+#define SMU7_DTE_ITERATIONS 5
+#define SMU7_DTE_SOURCES 5
+#define SMU7_DTE_SINKS 3
+#define SMU7_NUM_CPU_TES 2
+#define SMU7_NUM_GPU_TES 1
+#define SMU7_NUM_NON_TES 2
+
+#endif
+
+struct SMU71_PIDController
+{
+    uint32_t Ki;
+    int32_t LFWindupUpperLim;
+    int32_t LFWindupLowerLim;
+    uint32_t StatePrecision;
+    uint32_t LfPrecision;
+    uint32_t LfOffset;
+    uint32_t MaxState;
+    uint32_t MaxLfFraction;
+    uint32_t StateShift;
+};
+
+typedef struct SMU71_PIDController SMU71_PIDController;
+
+struct SMU7_LocalDpmScoreboard
+{
+    uint32_t PercentageBusy;
+
+    int32_t  PIDError;
+    int32_t  PIDIntegral;
+    int32_t  PIDOutput;
+
+    uint32_t SigmaDeltaAccum;
+    uint32_t SigmaDeltaOutput;
+    uint32_t SigmaDeltaLevel;
+
+    uint32_t UtilizationSetpoint;
+
+    uint8_t  TdpClampMode;
+    uint8_t  TdcClampMode;
+    uint8_t  ThermClampMode;
+    uint8_t  VoltageBusy;
+
+    int8_t   CurrLevel;
+    int8_t   TargLevel;
+    uint8_t  LevelChangeInProgress;
+    uint8_t  UpHyst;
+
+    uint8_t  DownHyst;
+    uint8_t  VoltageDownHyst;
+    uint8_t  DpmEnable;
+    uint8_t  DpmRunning;
+
+    uint8_t  DpmForce;
+    uint8_t  DpmForceLevel;
+    uint8_t  DisplayWatermark;
+    uint8_t  McArbIndex;
+
+    uint32_t MinimumPerfSclk;
+
+    uint8_t  AcpiReq;
+    uint8_t  AcpiAck;
+    uint8_t  GfxClkSlow;
+    uint8_t  GpioClampMode;
+
+    uint8_t  FpsFilterWeight;
+    uint8_t  EnabledLevelsChange;
+    uint8_t  DteClampMode;
+    uint8_t  FpsClampMode;
+
+    uint16_t LevelResidencyCounters [SMU71_MAX_LEVELS_GRAPHICS];
+    uint16_t LevelSwitchCounters [SMU71_MAX_LEVELS_GRAPHICS];
+
+    void     (*TargetStateCalculator)(uint8_t);
+    void     (*SavedTargetStateCalculator)(uint8_t);
+
+    uint16_t AutoDpmInterval;
+    uint16_t AutoDpmRange;
+
+    uint8_t  FpsEnabled;
+    uint8_t  MaxPerfLevel;
+    uint8_t  AllowLowClkInterruptToHost;
+    uint8_t  FpsRunning;
+
+    uint32_t MaxAllowedFrequency;
+};
+
+typedef struct SMU7_LocalDpmScoreboard SMU7_LocalDpmScoreboard;
+
+#define SMU7_MAX_VOLTAGE_CLIENTS 12
+
+struct SMU7_VoltageScoreboard
+{
+    uint16_t CurrentVoltage;
+    uint16_t HighestVoltage;
+    uint16_t MaxVid;
+    uint8_t  HighestVidOffset;
+    uint8_t  CurrentVidOffset;
+#if defined (SMU__DGPU_ONLY)
+    uint8_t  CurrentPhases;
+    uint8_t  HighestPhases;
+#else
+    uint8_t  AvsOffset;
+    uint8_t  AvsOffsetApplied;
+#endif
+    uint8_t  ControllerBusy;
+    uint8_t  CurrentVid;
+    uint16_t RequestedVoltage[SMU7_MAX_VOLTAGE_CLIENTS];
+#if defined (SMU__DGPU_ONLY)
+    uint8_t  RequestedPhases[SMU7_MAX_VOLTAGE_CLIENTS];
+#endif
+    uint8_t  EnabledRequest[SMU7_MAX_VOLTAGE_CLIENTS];
+    uint8_t  TargetIndex;
+    uint8_t  Delay;
+    uint8_t  ControllerEnable;
+    uint8_t  ControllerRunning;
+    uint16_t CurrentStdVoltageHiSidd;
+    uint16_t CurrentStdVoltageLoSidd;
+#if defined (SMU__DGPU_ONLY)
+    uint16_t RequestedVddci;
+    uint16_t CurrentVddci;
+    uint16_t HighestVddci;
+    uint8_t  CurrentVddciVid;
+    uint8_t  TargetVddciIndex;
+#endif
+};
+
+typedef struct SMU7_VoltageScoreboard SMU7_VoltageScoreboard;
+
+// -------------------------------------------------------------------------------------------------------------------------
+#define SMU7_MAX_PCIE_LINK_SPEEDS 3 /* 0:Gen1 1:Gen2 2:Gen3 */
+
+struct SMU7_PCIeLinkSpeedScoreboard
+{
+    uint8_t     DpmEnable;
+    uint8_t     DpmRunning;
+    uint8_t     DpmForce;
+    uint8_t     DpmForceLevel;
+
+    uint8_t     CurrentLinkSpeed;
+    uint8_t     EnabledLevelsChange;
+    uint16_t    AutoDpmInterval;
+
+    uint16_t    AutoDpmRange;
+    uint16_t    AutoDpmCount;
+
+    uint8_t     DpmMode;
+    uint8_t     AcpiReq;
+    uint8_t     AcpiAck;
+    uint8_t     CurrentLinkLevel;
+
+};
+
+typedef struct SMU7_PCIeLinkSpeedScoreboard SMU7_PCIeLinkSpeedScoreboard;
+
+// -------------------------------------------------------- CAC table ------------------------------------------------------
+#define SMU7_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
+#define SMU7_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16
+
+#define SMU7_SCALE_I  7
+#define SMU7_SCALE_R 12
+
+struct SMU7_PowerScoreboard
+{
+    uint16_t   MinVoltage;
+    uint16_t   MaxVoltage;
+
+    uint32_t   AvgGpuPower;
+
+    uint16_t   VddcLeakagePower[SID_OPTION_COUNT];
+    uint16_t   VddcSclkConstantPower[SID_OPTION_COUNT];
+    uint16_t   VddcSclkDynamicPower[SID_OPTION_COUNT];
+    uint16_t   VddcNonSclkDynamicPower[SID_OPTION_COUNT];
+    uint16_t   VddcTotalPower[SID_OPTION_COUNT];
+    uint16_t   VddcTotalCurrent[SID_OPTION_COUNT];
+    uint16_t   VddcLoadVoltage[SID_OPTION_COUNT];
+    uint16_t   VddcNoLoadVoltage[SID_OPTION_COUNT];
+
+    uint16_t   DisplayPhyPower;
+    uint16_t   PciePhyPower;
+
+    uint16_t   VddciTotalPower;
+    uint16_t   Vddr1TotalPower;
+
+    uint32_t   RocPower;
+
+    uint32_t   last_power;
+    uint32_t   enableWinAvg;
+
+    uint32_t   lkg_acc;
+    uint16_t   VoltLkgeScaler;
+    uint16_t   TempLkgeScaler;
+
+    uint32_t   uvd_cac_dclk;
+    uint32_t   uvd_cac_vclk;
+    uint32_t   vce_cac_eclk;
+    uint32_t   samu_cac_samclk;
+    uint32_t   display_cac_dispclk;
+    uint32_t   acp_cac_aclk;
+    uint32_t   unb_cac;
+
+    uint32_t   WinTime;
+
+    uint16_t  GpuPwr_MAWt;
+    uint16_t  FilteredVddcTotalPower;
+
+    uint8_t   CalculationRepeats;
+    uint8_t   WaterfallUp;
+    uint8_t   WaterfallDown;
+    uint8_t   WaterfallLimit;
+};
+
+typedef struct SMU7_PowerScoreboard SMU7_PowerScoreboard;
+
+// --------------------------------------------------------------------------------------------------
+
+struct SMU7_ThermalScoreboard
+{
+   int16_t  GpuLimit;
+   int16_t  GpuHyst;
+   uint16_t CurrGnbTemp;
+   uint16_t FilteredGnbTemp;
+   uint8_t  ControllerEnable;
+   uint8_t  ControllerRunning;
+   uint8_t  WaterfallUp;
+   uint8_t  WaterfallDown;
+   uint8_t  WaterfallLimit;
+   uint8_t  padding[3];
+};
+
+typedef struct SMU7_ThermalScoreboard SMU7_ThermalScoreboard;
+
+// For FeatureEnables:
+#define SMU7_SCLK_DPM_CONFIG_MASK                        0x01
+#define SMU7_VOLTAGE_CONTROLLER_CONFIG_MASK              0x02
+#define SMU7_THERMAL_CONTROLLER_CONFIG_MASK              0x04
+#define SMU7_MCLK_DPM_CONFIG_MASK                        0x08
+#define SMU7_UVD_DPM_CONFIG_MASK                         0x10
+#define SMU7_VCE_DPM_CONFIG_MASK                         0x20
+#define SMU7_ACP_DPM_CONFIG_MASK                         0x40
+#define SMU7_SAMU_DPM_CONFIG_MASK                        0x80
+#define SMU7_PCIEGEN_DPM_CONFIG_MASK                    0x100
+
+#define SMU7_ACP_MCLK_HANDSHAKE_DISABLE                  0x00000001
+#define SMU7_ACP_SCLK_HANDSHAKE_DISABLE                  0x00000002
+#define SMU7_UVD_MCLK_HANDSHAKE_DISABLE                  0x00000100
+#define SMU7_UVD_SCLK_HANDSHAKE_DISABLE                  0x00000200
+#define SMU7_VCE_MCLK_HANDSHAKE_DISABLE                  0x00010000
+#define SMU7_VCE_SCLK_HANDSHAKE_DISABLE                  0x00020000
+
+// All 'soft registers' should be uint32_t.
+struct SMU71_SoftRegisters
+{
+    uint32_t        RefClockFrequency;
+    uint32_t        PmTimerPeriod;
+    uint32_t        FeatureEnables;
+#if defined (SMU__DGPU_ONLY)
+    uint32_t        PreVBlankGap;
+    uint32_t        VBlankTimeout;
+    uint32_t        TrainTimeGap;
+    uint32_t        MvddSwitchTime;
+    uint32_t        LongestAcpiTrainTime;
+    uint32_t        AcpiDelay;
+    uint32_t        G5TrainTime;
+    uint32_t        DelayMpllPwron;
+    uint32_t        VoltageChangeTimeout;
+#endif
+    uint32_t        HandshakeDisables;
+
+    uint8_t         DisplayPhy1Config;
+    uint8_t         DisplayPhy2Config;
+    uint8_t         DisplayPhy3Config;
+    uint8_t         DisplayPhy4Config;
+
+    uint8_t         DisplayPhy5Config;
+    uint8_t         DisplayPhy6Config;
+    uint8_t         DisplayPhy7Config;
+    uint8_t         DisplayPhy8Config;
+
+    uint32_t        AverageGraphicsActivity;
+    uint32_t        AverageMemoryActivity;
+    uint32_t        AverageGioActivity;
+
+    uint8_t         SClkDpmEnabledLevels;
+    uint8_t         MClkDpmEnabledLevels;
+    uint8_t         LClkDpmEnabledLevels;
+    uint8_t         PCIeDpmEnabledLevels;
+
+    uint32_t        DRAM_LOG_ADDR_H;
+    uint32_t        DRAM_LOG_ADDR_L;
+    uint32_t        DRAM_LOG_PHY_ADDR_H;
+    uint32_t        DRAM_LOG_PHY_ADDR_L;
+    uint32_t        DRAM_LOG_BUFF_SIZE;
+    uint32_t        UlvEnterCount;
+    uint32_t        UlvTime;
+    uint32_t        UcodeLoadStatus;
+    uint8_t         DPMFreezeAndForced;
+    uint8_t         Activity_Weight;
+    uint8_t         Reserved8[2];
+    uint32_t        Reserved;
+};
+
+typedef struct SMU71_SoftRegisters SMU71_SoftRegisters;
+
+struct SMU71_Firmware_Header
+{
+    uint32_t Digest[5];
+    uint32_t Version;
+    uint32_t HeaderSize;
+    uint32_t Flags;
+    uint32_t EntryPoint;
+    uint32_t CodeSize;
+    uint32_t ImageSize;
+
+    uint32_t Rtos;
+    uint32_t SoftRegisters;
+    uint32_t DpmTable;
+    uint32_t FanTable;
+    uint32_t CacConfigTable;
+    uint32_t CacStatusTable;
+
+    uint32_t mcRegisterTable;
+
+    uint32_t mcArbDramTimingTable;
+
+    uint32_t PmFuseTable;
+    uint32_t Globals;
+    uint32_t UvdDpmTable;
+    uint32_t AcpDpmTable;
+    uint32_t VceDpmTable;
+    uint32_t SamuDpmTable;
+    uint32_t UlvSettings;
+    uint32_t Reserved[37];
+    uint32_t Signature;
+};
+
+typedef struct SMU71_Firmware_Header SMU71_Firmware_Header;
+
+struct SMU7_HystController_Data
+{
+    uint8_t waterfall_up;
+    uint8_t waterfall_down;
+    uint8_t pstate;
+    uint8_t clamp_mode;
+};
+
+typedef struct SMU7_HystController_Data SMU7_HystController_Data;
+
+#define SMU71_FIRMWARE_HEADER_LOCATION 0x20000
+
+enum  DisplayConfig {
+    PowerDown = 1,
+    DP54x4,
+    DP54x2,
+    DP54x1,
+    DP27x4,
+    DP27x2,
+    DP27x1,
+    HDMI297,
+    HDMI162,
+    LVDS,
+    DP324x4,
+    DP324x2,
+    DP324x1
+};
+
+//#define SX_BLOCK_COUNT 8
+//#define MC_BLOCK_COUNT 1
+//#define CPL_BLOCK_COUNT 27
+
+#if defined SMU__VARIANT__ICELAND
+  #define SX_BLOCK_COUNT 8
+  #define MC_BLOCK_COUNT 1
+  #define CPL_BLOCK_COUNT 29
+#endif
+
+struct SMU7_Local_Cac {
+  uint8_t BlockId;
+  uint8_t SignalId;
+  uint8_t Threshold;
+  uint8_t Padding;
+};
+
+typedef struct SMU7_Local_Cac SMU7_Local_Cac;
+
+struct SMU7_Local_Cac_Table {
+  SMU7_Local_Cac SxLocalCac[SX_BLOCK_COUNT];
+  SMU7_Local_Cac CplLocalCac[CPL_BLOCK_COUNT];
+  SMU7_Local_Cac McLocalCac[MC_BLOCK_COUNT];
+};
+
+typedef struct SMU7_Local_Cac_Table SMU7_Local_Cac_Table;
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+#endif
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu71_discrete.h b/drivers/gpu/drm/amd/powerplay/inc/smu71_discrete.h
new file mode 100644 (file)
index 0000000..c0e3936
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * 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.
+ *
+ */
+#ifndef SMU71_DISCRETE_H
+#define SMU71_DISCRETE_H
+
+#include "smu71.h"
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(push, 1)
+#endif
+
+#define VDDC_ON_SVI2  0x1
+#define VDDCI_ON_SVI2 0x2
+#define MVDD_ON_SVI2  0x4
+
+struct SMU71_Discrete_VoltageLevel
+{
+    uint16_t    Voltage;
+    uint16_t    StdVoltageHiSidd;
+    uint16_t    StdVoltageLoSidd;
+    uint8_t     Smio;
+    uint8_t     padding;
+};
+
+typedef struct SMU71_Discrete_VoltageLevel SMU71_Discrete_VoltageLevel;
+
+struct SMU71_Discrete_GraphicsLevel
+{
+    uint32_t    MinVddc;
+    uint32_t    MinVddcPhases;
+
+    uint32_t    SclkFrequency;
+
+    uint8_t     pcieDpmLevel;
+    uint8_t     DeepSleepDivId;
+    uint16_t    ActivityLevel;
+
+    uint32_t    CgSpllFuncCntl3;
+    uint32_t    CgSpllFuncCntl4;
+    uint32_t    SpllSpreadSpectrum;
+    uint32_t    SpllSpreadSpectrum2;
+    uint32_t    CcPwrDynRm;
+    uint32_t    CcPwrDynRm1;
+    uint8_t     SclkDid;
+    uint8_t     DisplayWatermark;
+    uint8_t     EnabledForActivity;
+    uint8_t     EnabledForThrottle;
+    uint8_t     UpHyst;
+    uint8_t     DownHyst;
+    uint8_t     VoltageDownHyst;
+    uint8_t     PowerThrottle;
+};
+
+typedef struct SMU71_Discrete_GraphicsLevel SMU71_Discrete_GraphicsLevel;
+
+struct SMU71_Discrete_ACPILevel
+{
+    uint32_t    Flags;
+    uint32_t    MinVddc;
+    uint32_t    MinVddcPhases;
+    uint32_t    SclkFrequency;
+    uint8_t     SclkDid;
+    uint8_t     DisplayWatermark;
+    uint8_t     DeepSleepDivId;
+    uint8_t     padding;
+    uint32_t    CgSpllFuncCntl;
+    uint32_t    CgSpllFuncCntl2;
+    uint32_t    CgSpllFuncCntl3;
+    uint32_t    CgSpllFuncCntl4;
+    uint32_t    SpllSpreadSpectrum;
+    uint32_t    SpllSpreadSpectrum2;
+    uint32_t    CcPwrDynRm;
+    uint32_t    CcPwrDynRm1;
+};
+
+typedef struct SMU71_Discrete_ACPILevel SMU71_Discrete_ACPILevel;
+
+struct SMU71_Discrete_Ulv
+{
+    uint32_t    CcPwrDynRm;
+    uint32_t    CcPwrDynRm1;
+    uint16_t    VddcOffset;
+    uint8_t     VddcOffsetVid;
+    uint8_t     VddcPhase;
+    uint32_t    Reserved;
+};
+
+typedef struct SMU71_Discrete_Ulv SMU71_Discrete_Ulv;
+
+struct SMU71_Discrete_MemoryLevel
+{
+    uint32_t    MinVddc;
+    uint32_t    MinVddcPhases;
+    uint32_t    MinVddci;
+    uint32_t    MinMvdd;
+
+    uint32_t    MclkFrequency;
+
+    uint8_t     EdcReadEnable;
+    uint8_t     EdcWriteEnable;
+    uint8_t     RttEnable;
+    uint8_t     StutterEnable;
+
+    uint8_t     StrobeEnable;
+    uint8_t     StrobeRatio;
+    uint8_t     EnabledForThrottle;
+    uint8_t     EnabledForActivity;
+
+    uint8_t     UpHyst;
+    uint8_t     DownHyst;
+    uint8_t     VoltageDownHyst;
+    uint8_t     padding;
+
+    uint16_t    ActivityLevel;
+    uint8_t     DisplayWatermark;
+    uint8_t     padding1;
+
+    uint32_t    MpllFuncCntl;
+    uint32_t    MpllFuncCntl_1;
+    uint32_t    MpllFuncCntl_2;
+    uint32_t    MpllAdFuncCntl;
+    uint32_t    MpllDqFuncCntl;
+    uint32_t    MclkPwrmgtCntl;
+    uint32_t    DllCntl;
+    uint32_t    MpllSs1;
+    uint32_t    MpllSs2;
+};
+
+typedef struct SMU71_Discrete_MemoryLevel SMU71_Discrete_MemoryLevel;
+
+struct SMU71_Discrete_LinkLevel
+{
+    uint8_t     PcieGenSpeed;           ///< 0:PciE-gen1 1:PciE-gen2 2:PciE-gen3
+    uint8_t     PcieLaneCount;          ///< 1=x1, 2=x2, 3=x4, 4=x8, 5=x12, 6=x16
+    uint8_t     EnabledForActivity;
+    uint8_t     SPC;
+    uint32_t    DownThreshold;
+    uint32_t    UpThreshold;
+    uint32_t    Reserved;
+};
+
+typedef struct SMU71_Discrete_LinkLevel SMU71_Discrete_LinkLevel;
+
+
+#ifdef SMU__DYNAMIC_MCARB_SETTINGS
+// MC ARB DRAM Timing registers.
+struct SMU71_Discrete_MCArbDramTimingTableEntry
+{
+    uint32_t McArbDramTiming;
+    uint32_t McArbDramTiming2;
+    uint8_t  McArbBurstTime;
+    uint8_t  padding[3];
+};
+
+typedef struct SMU71_Discrete_MCArbDramTimingTableEntry SMU71_Discrete_MCArbDramTimingTableEntry;
+
+struct SMU71_Discrete_MCArbDramTimingTable
+{
+    SMU71_Discrete_MCArbDramTimingTableEntry entries[SMU__NUM_SCLK_DPM_STATE][SMU__NUM_MCLK_DPM_LEVELS];
+};
+
+typedef struct SMU71_Discrete_MCArbDramTimingTable SMU71_Discrete_MCArbDramTimingTable;
+#endif
+
+// UVD VCLK/DCLK state (level) definition.
+struct SMU71_Discrete_UvdLevel
+{
+    uint32_t VclkFrequency;
+    uint32_t DclkFrequency;
+    uint16_t MinVddc;
+    uint8_t  MinVddcPhases;
+    uint8_t  VclkDivider;
+    uint8_t  DclkDivider;
+    uint8_t  padding[3];
+};
+
+typedef struct SMU71_Discrete_UvdLevel SMU71_Discrete_UvdLevel;
+
+// Clocks for other external blocks (VCE, ACP, SAMU).
+struct SMU71_Discrete_ExtClkLevel
+{
+    uint32_t Frequency;
+    uint16_t MinVoltage;
+    uint8_t  MinPhases;
+    uint8_t  Divider;
+};
+
+typedef struct SMU71_Discrete_ExtClkLevel SMU71_Discrete_ExtClkLevel;
+
+// Everything that we need to keep track of about the current state.
+// Use this instead of copies of the GraphicsLevel and MemoryLevel structures to keep track of state parameters
+// that need to be checked later.
+// We don't need to cache everything about a state, just a few parameters.
+struct SMU71_Discrete_StateInfo
+{
+    uint32_t SclkFrequency;
+    uint32_t MclkFrequency;
+    uint32_t VclkFrequency;
+    uint32_t DclkFrequency;
+    uint32_t SamclkFrequency;
+    uint32_t AclkFrequency;
+    uint32_t EclkFrequency;
+    uint16_t MvddVoltage;
+    uint16_t padding16;
+    uint8_t  DisplayWatermark;
+    uint8_t  McArbIndex;
+    uint8_t  McRegIndex;
+    uint8_t  SeqIndex;
+    uint8_t  SclkDid;
+    int8_t   SclkIndex;
+    int8_t   MclkIndex;
+    uint8_t  PCIeGen;
+
+};
+
+typedef struct SMU71_Discrete_StateInfo SMU71_Discrete_StateInfo;
+
+
+struct SMU71_Discrete_DpmTable
+{
+    // Multi-DPM controller settings
+    SMU71_PIDController                  GraphicsPIDController;
+    SMU71_PIDController                  MemoryPIDController;
+    SMU71_PIDController                  LinkPIDController;
+
+    uint32_t                            SystemFlags;
+
+    // SMIO masks for voltage and phase controls
+    uint32_t                            SmioMaskVddcVid;
+    uint32_t                            SmioMaskVddcPhase;
+    uint32_t                            SmioMaskVddciVid;
+    uint32_t                            SmioMaskMvddVid;
+
+    uint32_t                            VddcLevelCount;
+    uint32_t                            VddciLevelCount;
+    uint32_t                            MvddLevelCount;
+
+    SMU71_Discrete_VoltageLevel          VddcLevel               [SMU71_MAX_LEVELS_VDDC];
+    SMU71_Discrete_VoltageLevel          VddciLevel              [SMU71_MAX_LEVELS_VDDCI];
+    SMU71_Discrete_VoltageLevel          MvddLevel               [SMU71_MAX_LEVELS_MVDD];
+
+    uint8_t                             GraphicsDpmLevelCount;
+    uint8_t                             MemoryDpmLevelCount;
+    uint8_t                             LinkLevelCount;
+    uint8_t                             MasterDeepSleepControl;
+
+    uint32_t                            Reserved[5];
+
+    // State table entries for each DPM state
+    SMU71_Discrete_GraphicsLevel         GraphicsLevel           [SMU71_MAX_LEVELS_GRAPHICS];
+    SMU71_Discrete_MemoryLevel           MemoryACPILevel;
+    SMU71_Discrete_MemoryLevel           MemoryLevel             [SMU71_MAX_LEVELS_MEMORY];
+    SMU71_Discrete_LinkLevel             LinkLevel               [SMU71_MAX_LEVELS_LINK];
+    SMU71_Discrete_ACPILevel             ACPILevel;
+
+    uint32_t                            SclkStepSize;
+    uint32_t                            Smio                    [SMU71_MAX_ENTRIES_SMIO];
+
+    uint8_t                             GraphicsBootLevel;
+    uint8_t                             GraphicsVoltageChangeEnable;
+    uint8_t                             GraphicsThermThrottleEnable;
+    uint8_t                             GraphicsInterval;
+
+    uint8_t                             VoltageInterval;
+    uint8_t                             ThermalInterval;
+    uint16_t                            TemperatureLimitHigh;
+
+    uint16_t                            TemperatureLimitLow;
+    uint8_t                             MemoryBootLevel;
+    uint8_t                             MemoryVoltageChangeEnable;
+
+    uint8_t                             MemoryInterval;
+    uint8_t                             MemoryThermThrottleEnable;
+    uint8_t                             MergedVddci;
+    uint8_t                             padding2;
+
+    uint16_t                            VoltageResponseTime;
+    uint16_t                            PhaseResponseTime;
+
+    uint8_t                             PCIeBootLinkLevel;
+    uint8_t                             PCIeGenInterval;
+    uint8_t                             DTEInterval;
+    uint8_t                             DTEMode;
+
+    uint8_t                             SVI2Enable;
+    uint8_t                             VRHotGpio;
+    uint8_t                             AcDcGpio;
+    uint8_t                             ThermGpio;
+
+    uint32_t                            DisplayCac;
+
+    uint16_t                            MaxPwr;
+    uint16_t                            NomPwr;
+
+    uint16_t                            FpsHighThreshold;
+    uint16_t                            FpsLowThreshold;
+
+    uint16_t                            BAPMTI_R  [SMU71_DTE_ITERATIONS][SMU71_DTE_SOURCES][SMU71_DTE_SINKS];
+    uint16_t                            BAPMTI_RC [SMU71_DTE_ITERATIONS][SMU71_DTE_SOURCES][SMU71_DTE_SINKS];
+
+    uint8_t                             DTEAmbientTempBase;
+    uint8_t                             DTETjOffset;
+    uint8_t                             GpuTjMax;
+    uint8_t                             GpuTjHyst;
+
+    uint16_t                            BootVddc;
+    uint16_t                            BootVddci;
+
+    uint16_t                            BootMVdd;
+    uint16_t                            padding;
+
+    uint32_t                            BAPM_TEMP_GRADIENT;
+
+    uint32_t                            LowSclkInterruptThreshold;
+    uint32_t                            VddGfxReChkWait;
+
+    uint16_t                            PPM_PkgPwrLimit;
+    uint16_t                            PPM_TemperatureLimit;
+
+    uint16_t                            DefaultTdp;
+    uint16_t                            TargetTdp;
+};
+
+typedef struct SMU71_Discrete_DpmTable SMU71_Discrete_DpmTable;
+
+// --------------------------------------------------- AC Timing Parameters ------------------------------------------------
+#define SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE 16
+#define SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT SMU71_MAX_LEVELS_MEMORY
+
+struct SMU71_Discrete_MCRegisterAddress
+{
+    uint16_t s0;
+    uint16_t s1;
+};
+
+typedef struct SMU71_Discrete_MCRegisterAddress SMU71_Discrete_MCRegisterAddress;
+
+struct SMU71_Discrete_MCRegisterSet
+{
+    uint32_t value[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMU71_Discrete_MCRegisterSet SMU71_Discrete_MCRegisterSet;
+
+struct SMU71_Discrete_MCRegisters
+{
+    uint8_t                             last;
+    uint8_t                             reserved[3];
+    SMU71_Discrete_MCRegisterAddress     address[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+    SMU71_Discrete_MCRegisterSet         data[SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT];
+};
+
+typedef struct SMU71_Discrete_MCRegisters SMU71_Discrete_MCRegisters;
+
+
+// --------------------------------------------------- Fan Table -----------------------------------------------------------
+struct SMU71_Discrete_FanTable
+{
+    uint16_t FdoMode;
+    int16_t  TempMin;
+    int16_t  TempMed;
+    int16_t  TempMax;
+    int16_t  Slope1;
+    int16_t  Slope2;
+    int16_t  FdoMin;
+    int16_t  HystUp;
+    int16_t  HystDown;
+    int16_t  HystSlope;
+    int16_t  TempRespLim;
+    int16_t  TempCurr;
+    int16_t  SlopeCurr;
+    int16_t  PwmCurr;
+    uint32_t RefreshPeriod;
+    int16_t  FdoMax;
+    uint8_t  TempSrc;
+    int8_t   Padding;
+};
+
+typedef struct SMU71_Discrete_FanTable SMU71_Discrete_FanTable;
+
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG             4
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG_BIT         (0x1 << SMU7_DISCRETE_GPIO_SCLK_DEBUG)
+
+struct SMU71_MclkDpmScoreboard
+{
+
+    uint32_t PercentageBusy;
+
+    int32_t  PIDError;
+    int32_t  PIDIntegral;
+    int32_t  PIDOutput;
+
+    uint32_t SigmaDeltaAccum;
+    uint32_t SigmaDeltaOutput;
+    uint32_t SigmaDeltaLevel;
+
+    uint32_t UtilizationSetpoint;
+
+    uint8_t  TdpClampMode;
+    uint8_t  TdcClampMode;
+    uint8_t  ThermClampMode;
+    uint8_t  VoltageBusy;
+
+    int8_t   CurrLevel;
+    int8_t   TargLevel;
+    uint8_t  LevelChangeInProgress;
+    uint8_t  UpHyst;
+
+    uint8_t  DownHyst;
+    uint8_t  VoltageDownHyst;
+    uint8_t  DpmEnable;
+    uint8_t  DpmRunning;
+
+    uint8_t  DpmForce;
+    uint8_t  DpmForceLevel;
+    uint8_t  DisplayWatermark;
+    uint8_t  McArbIndex;
+
+    uint32_t MinimumPerfMclk;
+
+    uint8_t  AcpiReq;
+    uint8_t  AcpiAck;
+    uint8_t  MclkSwitchInProgress;
+    uint8_t  MclkSwitchCritical;
+
+    uint8_t  TargetMclkIndex;
+    uint8_t  TargetMvddIndex;
+    uint8_t  MclkSwitchResult;
+
+    uint8_t  EnabledLevelsChange;
+
+    uint16_t LevelResidencyCounters [SMU71_MAX_LEVELS_MEMORY];
+    uint16_t LevelSwitchCounters [SMU71_MAX_LEVELS_MEMORY];
+
+    void     (*TargetStateCalculator)(uint8_t);
+    void     (*SavedTargetStateCalculator)(uint8_t);
+
+    uint16_t AutoDpmInterval;
+    uint16_t AutoDpmRange;
+
+    uint16_t  MclkSwitchingTime;
+    uint8_t padding[2];
+};
+
+typedef struct SMU71_MclkDpmScoreboard SMU71_MclkDpmScoreboard;
+
+struct SMU71_UlvScoreboard
+{
+    uint8_t     EnterUlv;
+    uint8_t     ExitUlv;
+    uint8_t     UlvActive;
+    uint8_t     WaitingForUlv;
+    uint8_t     UlvEnable;
+    uint8_t     UlvRunning;
+    uint8_t     UlvMasterEnable;
+    uint8_t     padding;
+    uint32_t    UlvAbortedCount;
+    uint32_t    UlvTimeStamp;
+};
+
+typedef struct SMU71_UlvScoreboard SMU71_UlvScoreboard;
+
+struct SMU71_VddGfxScoreboard
+{
+    uint8_t     VddGfxEnable;
+    uint8_t     VddGfxActive;
+    uint8_t     padding[2];
+
+    uint32_t    VddGfxEnteredCount;
+    uint32_t    VddGfxAbortedCount;
+};
+
+typedef struct SMU71_VddGfxScoreboard SMU71_VddGfxScoreboard;
+
+struct SMU71_AcpiScoreboard {
+  uint32_t SavedInterruptMask[2];
+  uint8_t LastACPIRequest;
+  uint8_t CgBifResp;
+  uint8_t RequestType;
+  uint8_t Padding;
+  SMU71_Discrete_ACPILevel D0Level;
+};
+
+typedef struct SMU71_AcpiScoreboard SMU71_AcpiScoreboard;
+
+
+struct SMU71_Discrete_PmFuses {
+  // dw0-dw1
+  uint8_t BapmVddCVidHiSidd[8];
+
+  // dw2-dw3
+  uint8_t BapmVddCVidLoSidd[8];
+
+  // dw4-dw5
+  uint8_t VddCVid[8];
+
+  // dw6
+  uint8_t SviLoadLineEn;
+  uint8_t SviLoadLineVddC;
+  uint8_t SviLoadLineTrimVddC;
+  uint8_t SviLoadLineOffsetVddC;
+
+  // dw7
+  uint16_t TDC_VDDC_PkgLimit;
+  uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
+  uint8_t TDC_MAWt;
+
+  // dw8
+  uint8_t TdcWaterfallCtl;
+  uint8_t LPMLTemperatureMin;
+  uint8_t LPMLTemperatureMax;
+  uint8_t Reserved;
+
+  // dw9-dw12
+  uint8_t LPMLTemperatureScaler[16];
+
+  // dw13-dw14
+  int16_t FuzzyFan_ErrorSetDelta;
+  int16_t FuzzyFan_ErrorRateSetDelta;
+  int16_t FuzzyFan_PwmSetDelta;
+  uint16_t Reserved6;
+
+  // dw15
+  uint8_t GnbLPML[16];
+
+  // dw15
+  uint8_t GnbLPMLMaxVid;
+  uint8_t GnbLPMLMinVid;
+  uint8_t Reserved1[2];
+
+  // dw16
+  uint16_t BapmVddCBaseLeakageHiSidd;
+  uint16_t BapmVddCBaseLeakageLoSidd;
+};
+
+typedef struct SMU71_Discrete_PmFuses SMU71_Discrete_PmFuses;
+
+struct SMU71_Discrete_Log_Header_Table {
+  uint32_t    version;
+  uint32_t    asic_id;
+  uint16_t    flags;
+  uint16_t    entry_size;
+  uint32_t    total_size;
+  uint32_t    num_of_entries;
+  uint8_t     type;
+  uint8_t     mode;
+  uint8_t     filler_0[2];
+  uint32_t    filler_1[2];
+};
+
+typedef struct SMU71_Discrete_Log_Header_Table SMU71_Discrete_Log_Header_Table;
+
+struct SMU71_Discrete_Log_Cntl {
+    uint8_t             Enabled;
+    uint8_t             Type;
+    uint8_t             padding[2];
+    uint32_t            BufferSize;
+    uint32_t            SamplesLogged;
+    uint32_t            SampleSize;
+    uint32_t            AddrL;
+    uint32_t            AddrH;
+};
+
+typedef struct SMU71_Discrete_Log_Cntl SMU71_Discrete_Log_Cntl;
+
+#if defined SMU__DGPU_ONLY
+  #define CAC_ACC_NW_NUM_OF_SIGNALS 83
+#endif
+
+
+struct SMU71_Discrete_Cac_Collection_Table {
+  uint32_t temperature;
+  uint32_t cac_acc_nw[CAC_ACC_NW_NUM_OF_SIGNALS];
+  uint32_t filler[4];
+};
+
+typedef struct SMU71_Discrete_Cac_Collection_Table SMU71_Discrete_Cac_Collection_Table;
+
+struct SMU71_Discrete_Cac_Verification_Table {
+  uint32_t VddcTotalPower;
+  uint32_t VddcLeakagePower;
+  uint32_t VddcConstantPower;
+  uint32_t VddcGfxDynamicPower;
+  uint32_t VddcUvdDynamicPower;
+  uint32_t VddcVceDynamicPower;
+  uint32_t VddcAcpDynamicPower;
+  uint32_t VddcPcieDynamicPower;
+  uint32_t VddcDceDynamicPower;
+  uint32_t VddcCurrent;
+  uint32_t VddcVoltage;
+  uint32_t VddciTotalPower;
+  uint32_t VddciLeakagePower;
+  uint32_t VddciConstantPower;
+  uint32_t VddciDynamicPower;
+  uint32_t Vddr1TotalPower;
+  uint32_t Vddr1LeakagePower;
+  uint32_t Vddr1ConstantPower;
+  uint32_t Vddr1DynamicPower;
+  uint32_t spare[8];
+  uint32_t temperature;
+};
+
+typedef struct SMU71_Discrete_Cac_Verification_Table SMU71_Discrete_Cac_Verification_Table;
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+#endif
+
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7_common.h b/drivers/gpu/drm/amd/powerplay/inc/smu7_common.h
new file mode 100644 (file)
index 0000000..65eb630
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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 _PP_COMMON_H
+#define _PP_COMMON_H
+
+#include "smu7_ppsmc.h"
+#include "cgs_common.h"
+
+#include "smu/smu_7_1_3_d.h"
+#include "smu/smu_7_1_3_sh_mask.h"
+
+
+#include "smu74.h"
+#include "smu74_discrete.h"
+
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+
+
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+
+#include "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+
+#include "gca/gfx_8_0_d.h"
+#include "gca/gfx_8_0_sh_mask.h"
+
+#include "oss/oss_3_0_d.h"
+#include "oss/oss_3_0_sh_mask.h"
+
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h
new file mode 100644 (file)
index 0000000..bce0009
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2015 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 DGPU_VI_PP_SMC_H
+#define DGPU_VI_PP_SMC_H
+
+
+#pragma pack(push, 1)
+
+#define PPSMC_MSG_SetGBDroopSettings          ((uint16_t) 0x305)
+
+#define PPSMC_SWSTATE_FLAG_DC                           0x01
+#define PPSMC_SWSTATE_FLAG_UVD                          0x02
+#define PPSMC_SWSTATE_FLAG_VCE                          0x04
+
+#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL             0x00
+#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL             0x01
+#define PPSMC_THERMAL_PROTECT_TYPE_NONE                 0xff
+
+#define PPSMC_SYSTEMFLAG_GPIO_DC                        0x01
+#define PPSMC_SYSTEMFLAG_STEPVDDC                       0x02
+#define PPSMC_SYSTEMFLAG_GDDR5                          0x04
+
+#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP               0x08
+
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT                  0x10
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG           0x20
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK              0x07
+#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK     0x08
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE   0x00
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE  0x01
+
+
+#define PPSMC_DPM2FLAGS_TDPCLMP                         0x01
+#define PPSMC_DPM2FLAGS_PWRSHFT                         0x02
+#define PPSMC_DPM2FLAGS_OCP                             0x04
+
+
+#define PPSMC_DISPLAY_WATERMARK_LOW                     0
+#define PPSMC_DISPLAY_WATERMARK_HIGH                    1
+
+
+#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP    0x01
+#define PPSMC_STATEFLAG_POWERBOOST         0x02
+#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04
+#define PPSMC_STATEFLAG_POWERSHIFT         0x08
+#define PPSMC_STATEFLAG_SLOW_READ_MARGIN   0x10
+#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
+#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS   0x40
+
+
+#define FDO_MODE_HARDWARE 0
+#define FDO_MODE_PIECE_WISE_LINEAR 1
+
+enum FAN_CONTROL {
+       FAN_CONTROL_FUZZY,
+       FAN_CONTROL_TABLE
+};
+
+
+#define PPSMC_Result_OK             ((uint16_t)0x01)
+#define PPSMC_Result_NoMore         ((uint16_t)0x02)
+
+#define PPSMC_Result_NotNow         ((uint16_t)0x03)
+#define PPSMC_Result_Failed         ((uint16_t)0xFF)
+#define PPSMC_Result_UnknownCmd     ((uint16_t)0xFE)
+#define PPSMC_Result_UnknownVT      ((uint16_t)0xFD)
+
+typedef uint16_t PPSMC_Result;
+
+#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x))
+
+
+#define PPSMC_MSG_Halt                      ((uint16_t)0x10)
+#define PPSMC_MSG_Resume                    ((uint16_t)0x11)
+#define PPSMC_MSG_EnableDPMLevel            ((uint16_t)0x12)
+#define PPSMC_MSG_ZeroLevelsDisabled        ((uint16_t)0x13)
+#define PPSMC_MSG_OneLevelsDisabled         ((uint16_t)0x14)
+#define PPSMC_MSG_TwoLevelsDisabled         ((uint16_t)0x15)
+#define PPSMC_MSG_EnableThermalInterrupt    ((uint16_t)0x16)
+#define PPSMC_MSG_RunningOnAC               ((uint16_t)0x17)
+#define PPSMC_MSG_LevelUp                   ((uint16_t)0x18)
+#define PPSMC_MSG_LevelDown                 ((uint16_t)0x19)
+#define PPSMC_MSG_ResetDPMCounters          ((uint16_t)0x1a)
+#define PPSMC_MSG_SwitchToSwState           ((uint16_t)0x20)
+#define PPSMC_MSG_SwitchToSwStateLast       ((uint16_t)0x3f)
+#define PPSMC_MSG_SwitchToInitialState      ((uint16_t)0x40)
+#define PPSMC_MSG_NoForcedLevel             ((uint16_t)0x41)
+#define PPSMC_MSG_ForceHigh                 ((uint16_t)0x42)
+#define PPSMC_MSG_ForceMediumOrHigh         ((uint16_t)0x43)
+#define PPSMC_MSG_SwitchToMinimumPower      ((uint16_t)0x51)
+#define PPSMC_MSG_ResumeFromMinimumPower    ((uint16_t)0x52)
+#define PPSMC_MSG_EnableCac                 ((uint16_t)0x53)
+#define PPSMC_MSG_DisableCac                ((uint16_t)0x54)
+#define PPSMC_DPMStateHistoryStart          ((uint16_t)0x55)
+#define PPSMC_DPMStateHistoryStop           ((uint16_t)0x56)
+#define PPSMC_CACHistoryStart               ((uint16_t)0x57)
+#define PPSMC_CACHistoryStop                ((uint16_t)0x58)
+#define PPSMC_TDPClampingActive             ((uint16_t)0x59)
+#define PPSMC_TDPClampingInactive           ((uint16_t)0x5A)
+#define PPSMC_StartFanControl               ((uint16_t)0x5B)
+#define PPSMC_StopFanControl                ((uint16_t)0x5C)
+#define PPSMC_NoDisplay                     ((uint16_t)0x5D)
+#define PPSMC_HasDisplay                    ((uint16_t)0x5E)
+#define PPSMC_MSG_UVDPowerOFF               ((uint16_t)0x60)
+#define PPSMC_MSG_UVDPowerON                ((uint16_t)0x61)
+#define PPSMC_MSG_EnableULV                 ((uint16_t)0x62)
+#define PPSMC_MSG_DisableULV                ((uint16_t)0x63)
+#define PPSMC_MSG_EnterULV                  ((uint16_t)0x64)
+#define PPSMC_MSG_ExitULV                   ((uint16_t)0x65)
+#define PPSMC_PowerShiftActive              ((uint16_t)0x6A)
+#define PPSMC_PowerShiftInactive            ((uint16_t)0x6B)
+#define PPSMC_OCPActive                     ((uint16_t)0x6C)
+#define PPSMC_OCPInactive                   ((uint16_t)0x6D)
+#define PPSMC_CACLongTermAvgEnable          ((uint16_t)0x6E)
+#define PPSMC_CACLongTermAvgDisable         ((uint16_t)0x6F)
+#define PPSMC_MSG_InferredStateSweep_Start  ((uint16_t)0x70)
+#define PPSMC_MSG_InferredStateSweep_Stop   ((uint16_t)0x71)
+#define PPSMC_MSG_SwitchToLowestInfState    ((uint16_t)0x72)
+#define PPSMC_MSG_SwitchToNonInfState       ((uint16_t)0x73)
+#define PPSMC_MSG_AllStateSweep_Start       ((uint16_t)0x74)
+#define PPSMC_MSG_AllStateSweep_Stop        ((uint16_t)0x75)
+#define PPSMC_MSG_SwitchNextLowerInfState   ((uint16_t)0x76)
+#define PPSMC_MSG_SwitchNextHigherInfState  ((uint16_t)0x77)
+#define PPSMC_MSG_MclkRetrainingTest        ((uint16_t)0x78)
+#define PPSMC_MSG_ForceTDPClamping          ((uint16_t)0x79)
+#define PPSMC_MSG_CollectCAC_PowerCorreln   ((uint16_t)0x7A)
+#define PPSMC_MSG_CollectCAC_WeightCalib    ((uint16_t)0x7B)
+#define PPSMC_MSG_CollectCAC_SQonly         ((uint16_t)0x7C)
+#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D)
+
+#define PPSMC_MSG_ExtremitiesTest_Start     ((uint16_t)0x7E)
+#define PPSMC_MSG_ExtremitiesTest_Stop      ((uint16_t)0x7F)
+#define PPSMC_FlushDataCache                ((uint16_t)0x80)
+#define PPSMC_FlushInstrCache               ((uint16_t)0x81)
+
+#define PPSMC_MSG_SetEnabledLevels          ((uint16_t)0x82)
+#define PPSMC_MSG_SetForcedLevels           ((uint16_t)0x83)
+
+#define PPSMC_MSG_ResetToDefaults           ((uint16_t)0x84)
+
+#define PPSMC_MSG_SetForcedLevelsAndJump      ((uint16_t)0x85)
+#define PPSMC_MSG_SetCACHistoryMode           ((uint16_t)0x86)
+#define PPSMC_MSG_EnableDTE                   ((uint16_t)0x87)
+#define PPSMC_MSG_DisableDTE                  ((uint16_t)0x88)
+
+#define PPSMC_MSG_SmcSpaceSetAddress          ((uint16_t)0x89)
+#define PPSM_MSG_SmcSpaceWriteDWordInc        ((uint16_t)0x8A)
+#define PPSM_MSG_SmcSpaceWriteWordInc         ((uint16_t)0x8B)
+#define PPSM_MSG_SmcSpaceWriteByteInc         ((uint16_t)0x8C)
+
+#define PPSMC_MSG_BREAK                       ((uint16_t)0xF8)
+
+#define PPSMC_MSG_Test                        ((uint16_t) 0x100)
+#define PPSMC_MSG_DPM_Voltage_Pwrmgt          ((uint16_t) 0x101)
+#define PPSMC_MSG_DPM_Config                  ((uint16_t) 0x102)
+#define PPSMC_MSG_PM_Controller_Start         ((uint16_t) 0x103)
+#define PPSMC_MSG_DPM_ForceState              ((uint16_t) 0x104)
+#define PPSMC_MSG_PG_PowerDownSIMD            ((uint16_t) 0x105)
+#define PPSMC_MSG_PG_PowerUpSIMD              ((uint16_t) 0x106)
+#define PPSMC_MSG_PM_Controller_Stop          ((uint16_t) 0x107)
+#define PPSMC_MSG_PG_SIMD_Config              ((uint16_t) 0x108)
+#define PPSMC_MSG_Voltage_Cntl_Enable         ((uint16_t) 0x109)
+#define PPSMC_MSG_Thermal_Cntl_Enable         ((uint16_t) 0x10a)
+#define PPSMC_MSG_Reset_Service               ((uint16_t) 0x10b)
+#define PPSMC_MSG_VCEPowerOFF                 ((uint16_t) 0x10e)
+#define PPSMC_MSG_VCEPowerON                  ((uint16_t) 0x10f)
+#define PPSMC_MSG_DPM_Disable_VCE_HS          ((uint16_t) 0x110)
+#define PPSMC_MSG_DPM_Enable_VCE_HS           ((uint16_t) 0x111)
+#define PPSMC_MSG_DPM_N_LevelsDisabled        ((uint16_t) 0x112)
+#define PPSMC_MSG_DCEPowerOFF                 ((uint16_t) 0x113)
+#define PPSMC_MSG_DCEPowerON                  ((uint16_t) 0x114)
+#define PPSMC_MSG_PCIE_DDIPowerDown           ((uint16_t) 0x117)
+#define PPSMC_MSG_PCIE_DDIPowerUp             ((uint16_t) 0x118)
+#define PPSMC_MSG_PCIE_CascadePLLPowerDown    ((uint16_t) 0x119)
+#define PPSMC_MSG_PCIE_CascadePLLPowerUp      ((uint16_t) 0x11a)
+#define PPSMC_MSG_SYSPLLPowerOff              ((uint16_t) 0x11b)
+#define PPSMC_MSG_SYSPLLPowerOn               ((uint16_t) 0x11c)
+#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint16_t) 0x11d)
+#define PPSMC_MSG_DCE_AllowVoltageAdjustment  ((uint16_t) 0x11e)
+#define PPSMC_MSG_DISPLAYPHYStatusNotify      ((uint16_t) 0x11f)
+#define PPSMC_MSG_EnableBAPM                  ((uint16_t) 0x120)
+#define PPSMC_MSG_DisableBAPM                 ((uint16_t) 0x121)
+#define PPSMC_MSG_Spmi_Enable                 ((uint16_t) 0x122)
+#define PPSMC_MSG_Spmi_Timer                  ((uint16_t) 0x123)
+#define PPSMC_MSG_LCLK_DPM_Config             ((uint16_t) 0x124)
+#define PPSMC_MSG_VddNB_Request               ((uint16_t) 0x125)
+#define PPSMC_MSG_PCIE_DDIPhyPowerDown        ((uint32_t) 0x126)
+#define PPSMC_MSG_PCIE_DDIPhyPowerUp          ((uint32_t) 0x127)
+#define PPSMC_MSG_MCLKDPM_Config              ((uint16_t) 0x128)
+
+#define PPSMC_MSG_UVDDPM_Config               ((uint16_t) 0x129)
+#define PPSMC_MSG_VCEDPM_Config               ((uint16_t) 0x12A)
+#define PPSMC_MSG_ACPDPM_Config               ((uint16_t) 0x12B)
+#define PPSMC_MSG_SAMUDPM_Config              ((uint16_t) 0x12C)
+#define PPSMC_MSG_UVDDPM_SetEnabledMask       ((uint16_t) 0x12D)
+#define PPSMC_MSG_VCEDPM_SetEnabledMask       ((uint16_t) 0x12E)
+#define PPSMC_MSG_ACPDPM_SetEnabledMask       ((uint16_t) 0x12F)
+#define PPSMC_MSG_SAMUDPM_SetEnabledMask      ((uint16_t) 0x130)
+#define PPSMC_MSG_MCLKDPM_ForceState          ((uint16_t) 0x131)
+#define PPSMC_MSG_MCLKDPM_NoForcedLevel       ((uint16_t) 0x132)
+#define PPSMC_MSG_Thermal_Cntl_Disable        ((uint16_t) 0x133)
+#define PPSMC_MSG_SetTDPLimit                 ((uint16_t) 0x134)
+#define PPSMC_MSG_Voltage_Cntl_Disable        ((uint16_t) 0x135)
+#define PPSMC_MSG_PCIeDPM_Enable              ((uint16_t) 0x136)
+#define PPSMC_MSG_ACPPowerOFF                 ((uint16_t) 0x137)
+#define PPSMC_MSG_ACPPowerON                  ((uint16_t) 0x138)
+#define PPSMC_MSG_SAMPowerOFF                 ((uint16_t) 0x139)
+#define PPSMC_MSG_SAMPowerON                  ((uint16_t) 0x13a)
+#define PPSMC_MSG_SDMAPowerOFF                ((uint16_t) 0x13b)
+#define PPSMC_MSG_SDMAPowerON                 ((uint16_t) 0x13c)
+#define PPSMC_MSG_PCIeDPM_Disable             ((uint16_t) 0x13d)
+#define PPSMC_MSG_IOMMUPowerOFF               ((uint16_t) 0x13e)
+#define PPSMC_MSG_IOMMUPowerON                ((uint16_t) 0x13f)
+#define PPSMC_MSG_NBDPM_Enable                ((uint16_t) 0x140)
+#define PPSMC_MSG_NBDPM_Disable               ((uint16_t) 0x141)
+#define PPSMC_MSG_NBDPM_ForceNominal          ((uint16_t) 0x142)
+#define PPSMC_MSG_NBDPM_ForcePerformance      ((uint16_t) 0x143)
+#define PPSMC_MSG_NBDPM_UnForce               ((uint16_t) 0x144)
+#define PPSMC_MSG_SCLKDPM_SetEnabledMask      ((uint16_t) 0x145)
+#define PPSMC_MSG_MCLKDPM_SetEnabledMask      ((uint16_t) 0x146)
+#define PPSMC_MSG_PCIeDPM_ForceLevel          ((uint16_t) 0x147)
+#define PPSMC_MSG_PCIeDPM_UnForceLevel        ((uint16_t) 0x148)
+#define PPSMC_MSG_EnableACDCGPIOInterrupt     ((uint16_t) 0x149)
+#define PPSMC_MSG_EnableVRHotGPIOInterrupt    ((uint16_t) 0x14a)
+#define PPSMC_MSG_SwitchToAC                  ((uint16_t) 0x14b)
+#define PPSMC_MSG_XDMAPowerOFF                ((uint16_t) 0x14c)
+#define PPSMC_MSG_XDMAPowerON                 ((uint16_t) 0x14d)
+
+#define PPSMC_MSG_DPM_Enable                  ((uint16_t) 0x14e)
+#define PPSMC_MSG_DPM_Disable                 ((uint16_t) 0x14f)
+#define PPSMC_MSG_MCLKDPM_Enable              ((uint16_t) 0x150)
+#define PPSMC_MSG_MCLKDPM_Disable             ((uint16_t) 0x151)
+#define PPSMC_MSG_LCLKDPM_Enable              ((uint16_t) 0x152)
+#define PPSMC_MSG_LCLKDPM_Disable             ((uint16_t) 0x153)
+#define PPSMC_MSG_UVDDPM_Enable               ((uint16_t) 0x154)
+#define PPSMC_MSG_UVDDPM_Disable              ((uint16_t) 0x155)
+#define PPSMC_MSG_SAMUDPM_Enable              ((uint16_t) 0x156)
+#define PPSMC_MSG_SAMUDPM_Disable             ((uint16_t) 0x157)
+#define PPSMC_MSG_ACPDPM_Enable               ((uint16_t) 0x158)
+#define PPSMC_MSG_ACPDPM_Disable              ((uint16_t) 0x159)
+#define PPSMC_MSG_VCEDPM_Enable               ((uint16_t) 0x15a)
+#define PPSMC_MSG_VCEDPM_Disable              ((uint16_t) 0x15b)
+#define PPSMC_MSG_LCLKDPM_SetEnabledMask      ((uint16_t) 0x15c)
+#define PPSMC_MSG_DPM_FPS_Mode                ((uint16_t) 0x15d)
+#define PPSMC_MSG_DPM_Activity_Mode           ((uint16_t) 0x15e)
+#define PPSMC_MSG_VddC_Request                ((uint16_t) 0x15f)
+#define PPSMC_MSG_MCLKDPM_GetEnabledMask      ((uint16_t) 0x160)
+#define PPSMC_MSG_LCLKDPM_GetEnabledMask      ((uint16_t) 0x161)
+#define PPSMC_MSG_SCLKDPM_GetEnabledMask      ((uint16_t) 0x162)
+#define PPSMC_MSG_UVDDPM_GetEnabledMask       ((uint16_t) 0x163)
+#define PPSMC_MSG_SAMUDPM_GetEnabledMask      ((uint16_t) 0x164)
+#define PPSMC_MSG_ACPDPM_GetEnabledMask       ((uint16_t) 0x165)
+#define PPSMC_MSG_VCEDPM_GetEnabledMask       ((uint16_t) 0x166)
+#define PPSMC_MSG_PCIeDPM_SetEnabledMask      ((uint16_t) 0x167)
+#define PPSMC_MSG_PCIeDPM_GetEnabledMask      ((uint16_t) 0x168)
+#define PPSMC_MSG_TDCLimitEnable              ((uint16_t) 0x169)
+#define PPSMC_MSG_TDCLimitDisable             ((uint16_t) 0x16a)
+#define PPSMC_MSG_DPM_AutoRotate_Mode         ((uint16_t) 0x16b)
+#define PPSMC_MSG_DISPCLK_FROM_FCH            ((uint16_t) 0x16c)
+#define PPSMC_MSG_DISPCLK_FROM_DFS            ((uint16_t) 0x16d)
+#define PPSMC_MSG_DPREFCLK_FROM_FCH           ((uint16_t) 0x16e)
+#define PPSMC_MSG_DPREFCLK_FROM_DFS           ((uint16_t) 0x16f)
+#define PPSMC_MSG_PmStatusLogStart            ((uint16_t) 0x170)
+#define PPSMC_MSG_PmStatusLogSample           ((uint16_t) 0x171)
+#define PPSMC_MSG_SCLK_AutoDPM_ON             ((uint16_t) 0x172)
+#define PPSMC_MSG_MCLK_AutoDPM_ON             ((uint16_t) 0x173)
+#define PPSMC_MSG_LCLK_AutoDPM_ON             ((uint16_t) 0x174)
+#define PPSMC_MSG_UVD_AutoDPM_ON              ((uint16_t) 0x175)
+#define PPSMC_MSG_SAMU_AutoDPM_ON             ((uint16_t) 0x176)
+#define PPSMC_MSG_ACP_AutoDPM_ON              ((uint16_t) 0x177)
+#define PPSMC_MSG_VCE_AutoDPM_ON              ((uint16_t) 0x178)
+#define PPSMC_MSG_PCIe_AutoDPM_ON             ((uint16_t) 0x179)
+#define PPSMC_MSG_MASTER_AutoDPM_ON           ((uint16_t) 0x17a)
+#define PPSMC_MSG_MASTER_AutoDPM_OFF          ((uint16_t) 0x17b)
+#define PPSMC_MSG_DYNAMICDISPPHYPOWER         ((uint16_t) 0x17c)
+#define PPSMC_MSG_CAC_COLLECTION_ON           ((uint16_t) 0x17d)
+#define PPSMC_MSG_CAC_COLLECTION_OFF          ((uint16_t) 0x17e)
+#define PPSMC_MSG_CAC_CORRELATION_ON          ((uint16_t) 0x17f)
+#define PPSMC_MSG_CAC_CORRELATION_OFF         ((uint16_t) 0x180)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_ON        ((uint16_t) 0x181)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_OFF       ((uint16_t) 0x182)
+#define PPSMC_MSG_ALLOW_LOWSCLK_INTERRUPT     ((uint16_t) 0x184)
+#define PPSMC_MSG_PkgPwrLimitEnable           ((uint16_t) 0x185)
+#define PPSMC_MSG_PkgPwrLimitDisable          ((uint16_t) 0x186)
+#define PPSMC_MSG_PkgPwrSetLimit              ((uint16_t) 0x187)
+#define PPSMC_MSG_OverDriveSetTargetTdp       ((uint16_t) 0x188)
+#define PPSMC_MSG_SCLKDPM_FreezeLevel         ((uint16_t) 0x189)
+#define PPSMC_MSG_SCLKDPM_UnfreezeLevel       ((uint16_t) 0x18A)
+#define PPSMC_MSG_MCLKDPM_FreezeLevel         ((uint16_t) 0x18B)
+#define PPSMC_MSG_MCLKDPM_UnfreezeLevel       ((uint16_t) 0x18C)
+#define PPSMC_MSG_START_DRAM_LOGGING          ((uint16_t) 0x18D)
+#define PPSMC_MSG_STOP_DRAM_LOGGING           ((uint16_t) 0x18E)
+#define PPSMC_MSG_MASTER_DeepSleep_ON         ((uint16_t) 0x18F)
+#define PPSMC_MSG_MASTER_DeepSleep_OFF        ((uint16_t) 0x190)
+#define PPSMC_MSG_Remove_DC_Clamp             ((uint16_t) 0x191)
+#define PPSMC_MSG_DisableACDCGPIOInterrupt    ((uint16_t) 0x192)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddc       ((uint16_t) 0x193)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddci      ((uint16_t) 0x194)
+#define PPSMC_MSG_SetVidOffset_1              ((uint16_t) 0x195)
+#define PPSMC_MSG_SetVidOffset_2              ((uint16_t) 0x207)
+#define PPSMC_MSG_GetVidOffset_1              ((uint16_t) 0x196)
+#define PPSMC_MSG_GetVidOffset_2              ((uint16_t) 0x208)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Enable    ((uint16_t) 0x197)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Disable   ((uint16_t) 0x198)
+#define PPSMC_MSG_SetTjMax                    ((uint16_t) 0x199)
+#define PPSMC_MSG_SetFanPwmMax                ((uint16_t) 0x19A)
+#define PPSMC_MSG_WaitForMclkSwitchFinish     ((uint16_t) 0x19B)
+#define PPSMC_MSG_ENABLE_THERMAL_DPM          ((uint16_t) 0x19C)
+#define PPSMC_MSG_DISABLE_THERMAL_DPM         ((uint16_t) 0x19D)
+
+#define PPSMC_MSG_API_GetSclkFrequency        ((uint16_t) 0x200)
+#define PPSMC_MSG_API_GetMclkFrequency        ((uint16_t) 0x201)
+#define PPSMC_MSG_API_GetSclkBusy             ((uint16_t) 0x202)
+#define PPSMC_MSG_API_GetMclkBusy             ((uint16_t) 0x203)
+#define PPSMC_MSG_API_GetAsicPower            ((uint16_t) 0x204)
+#define PPSMC_MSG_SetFanRpmMax                ((uint16_t) 0x205)
+#define PPSMC_MSG_SetFanSclkTarget            ((uint16_t) 0x206)
+#define PPSMC_MSG_SetFanMinPwm                ((uint16_t) 0x209)
+#define PPSMC_MSG_SetFanTemperatureTarget     ((uint16_t) 0x20A)
+
+#define PPSMC_MSG_BACO_StartMonitor           ((uint16_t) 0x240)
+#define PPSMC_MSG_BACO_Cancel                 ((uint16_t) 0x241)
+#define PPSMC_MSG_EnableVddGfx                ((uint16_t) 0x242)
+#define PPSMC_MSG_DisableVddGfx               ((uint16_t) 0x243)
+#define PPSMC_MSG_UcodeAddressLow             ((uint16_t) 0x244)
+#define PPSMC_MSG_UcodeAddressHigh            ((uint16_t) 0x245)
+#define PPSMC_MSG_UcodeLoadStatus             ((uint16_t) 0x246)
+
+#define PPSMC_MSG_DRV_DRAM_ADDR_HI            ((uint16_t) 0x250)
+#define PPSMC_MSG_DRV_DRAM_ADDR_LO            ((uint16_t) 0x251)
+#define PPSMC_MSG_SMU_DRAM_ADDR_HI            ((uint16_t) 0x252)
+#define PPSMC_MSG_SMU_DRAM_ADDR_LO            ((uint16_t) 0x253)
+#define PPSMC_MSG_LoadUcodes                  ((uint16_t) 0x254)
+#define PPSMC_MSG_PowerStateNotify            ((uint16_t) 0x255)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_HI      ((uint16_t) 0x256)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_LO      ((uint16_t) 0x257)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_HI          ((uint16_t) 0x258)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_LO          ((uint16_t) 0x259)
+#define PPSMC_MSG_LoadVBios                   ((uint16_t) 0x25A)
+#define PPSMC_MSG_GetUcodeVersion             ((uint16_t) 0x25B)
+#define DMCUSMC_MSG_PSREntry                  ((uint16_t) 0x25C)
+#define DMCUSMC_MSG_PSRExit                   ((uint16_t) 0x25D)
+#define PPSMC_MSG_EnableClockGatingFeature    ((uint16_t) 0x260)
+#define PPSMC_MSG_DisableClockGatingFeature   ((uint16_t) 0x261)
+#define PPSMC_MSG_IsDeviceRunning             ((uint16_t) 0x262)
+#define PPSMC_MSG_LoadMetaData                ((uint16_t) 0x263)
+#define PPSMC_MSG_TMON_AutoCaliberate_Enable  ((uint16_t) 0x264)
+#define PPSMC_MSG_TMON_AutoCaliberate_Disable ((uint16_t) 0x265)
+#define PPSMC_MSG_GetTelemetry1Slope          ((uint16_t) 0x266)
+#define PPSMC_MSG_GetTelemetry1Offset         ((uint16_t) 0x267)
+#define PPSMC_MSG_GetTelemetry2Slope          ((uint16_t) 0x268)
+#define PPSMC_MSG_GetTelemetry2Offset         ((uint16_t) 0x269)
+#define PPSMC_MSG_EnableAvfs                  ((uint16_t) 0x26A)
+#define PPSMC_MSG_DisableAvfs                 ((uint16_t) 0x26B)
+
+#define PPSMC_MSG_PerformBtc                  ((uint16_t) 0x26C)
+#define PPSMC_MSG_VftTableIsValid             ((uint16_t) 0x275)
+#define PPSMC_MSG_UseNewGPIOScheme            ((uint16_t) 0x277)
+#define PPSMC_MSG_GetEnabledPsm               ((uint16_t) 0x400)
+#define PPSMC_MSG_AgmStartPsm                 ((uint16_t) 0x401)
+#define PPSMC_MSG_AgmReadPsm                  ((uint16_t) 0x402)
+#define PPSMC_MSG_AgmResetPsm                 ((uint16_t) 0x403)
+#define PPSMC_MSG_ReadVftCell                 ((uint16_t) 0x404)
+
+#define PPSMC_MSG_GFX_CU_PG_ENABLE            ((uint16_t) 0x280)
+#define PPSMC_MSG_GFX_CU_PG_DISABLE           ((uint16_t) 0x281)
+#define PPSMC_MSG_GetCurrPkgPwr               ((uint16_t) 0x282)
+
+#define PPSMC_MSG_SetGpuPllDfsForSclk         ((uint16_t) 0x300)
+#define PPSMC_MSG_Didt_Block_Function            ((uint16_t) 0x301)
+
+#define PPSMC_MSG_SetVBITimeout               ((uint16_t) 0x306)
+
+#define PPSMC_MSG_SecureSRBMWrite             ((uint16_t) 0x600)
+#define PPSMC_MSG_SecureSRBMRead              ((uint16_t) 0x601)
+#define PPSMC_MSG_SetAddress                  ((uint16_t) 0x800)
+#define PPSMC_MSG_GetData                     ((uint16_t) 0x801)
+#define PPSMC_MSG_SetData                     ((uint16_t) 0x802)
+
+typedef uint16_t PPSMC_Msg;
+
+#define PPSMC_EVENT_STATUS_THERMAL          0x00000001
+#define PPSMC_EVENT_STATUS_REGULATORHOT     0x00000002
+#define PPSMC_EVENT_STATUS_DC               0x00000004
+
+#pragma pack(pop)
+
+#endif
+
index 3c235f0..2139072 100644 (file)
@@ -28,6 +28,7 @@
 
 struct pp_smumgr;
 struct pp_instance;
+struct pp_hwmgr;
 
 #define smu_lower_32_bits(n) ((uint32_t)(n))
 #define smu_upper_32_bits(n) ((uint32_t)(((n)>>16)>>16))
@@ -53,6 +54,45 @@ enum AVFS_BTC_STATUS {
        AVFS_BTC_SMUMSG_ERROR
 };
 
+enum SMU_TABLE {
+       SMU_UVD_TABLE = 0,
+       SMU_VCE_TABLE,
+       SMU_SAMU_TABLE,
+       SMU_BIF_TABLE,
+};
+
+enum SMU_TYPE {
+       SMU_SoftRegisters = 0,
+       SMU_Discrete_DpmTable,
+};
+
+enum SMU_MEMBER {
+       HandshakeDisables = 0,
+       VoltageChangeTimeout,
+       AverageGraphicsActivity,
+       PreVBlankGap,
+       VBlankTimeout,
+       UcodeLoadStatus,
+       UvdBootLevel,
+       VceBootLevel,
+       SamuBootLevel,
+       LowSclkInterruptThreshold,
+};
+
+
+enum SMU_MAC_DEFINITION {
+       SMU_MAX_LEVELS_GRAPHICS = 0,
+       SMU_MAX_LEVELS_MEMORY,
+       SMU_MAX_LEVELS_LINK,
+       SMU_MAX_ENTRIES_SMIO,
+       SMU_MAX_LEVELS_VDDC,
+       SMU_MAX_LEVELS_VDDGFX,
+       SMU_MAX_LEVELS_VDDCI,
+       SMU_MAX_LEVELS_MVDD,
+       SMU_UVD_MCLK_HANDSHAKE_DISABLE,
+};
+
+
 struct pp_smumgr_func {
        int (*smu_init)(struct pp_smumgr *smumgr);
        int (*smu_fini)(struct pp_smumgr *smumgr);
@@ -69,12 +109,23 @@ struct pp_smumgr_func {
        int (*download_pptable_settings)(struct pp_smumgr *smumgr,
                                         void **table);
        int (*upload_pptable_settings)(struct pp_smumgr *smumgr);
+       int (*update_smc_table)(struct pp_hwmgr *hwmgr, uint32_t type);
+       int (*process_firmware_header)(struct pp_hwmgr *hwmgr);
+       int (*update_sclk_threshold)(struct pp_hwmgr *hwmgr);
+       int (*thermal_setup_fan_table)(struct pp_hwmgr *hwmgr);
+       int (*thermal_avfs_enable)(struct pp_hwmgr *hwmgr);
+       int (*init_smc_table)(struct pp_hwmgr *hwmgr);
+       int (*populate_all_graphic_levels)(struct pp_hwmgr *hwmgr);
+       int (*populate_all_memory_levels)(struct pp_hwmgr *hwmgr);
+       int (*initialize_mc_reg_table)(struct pp_hwmgr *hwmgr);
+       uint32_t (*get_offsetof)(uint32_t type, uint32_t member);
+       uint32_t (*get_mac_definition)(uint32_t value);
+       bool (*is_dpm_running)(struct pp_hwmgr *hwmgr);
 };
 
 struct pp_smumgr {
        uint32_t chip_family;
        uint32_t chip_id;
-       uint32_t hw_revision;
        void *device;
        void *backend;
        uint32_t usec_timeout;
@@ -122,6 +173,30 @@ extern int smu_allocate_memory(void *device, uint32_t size,
 
 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);
+extern int smum_process_firmware_header(struct pp_hwmgr *hwmgr);
+extern int smum_thermal_avfs_enable(struct pp_hwmgr *hwmgr,
+               void *input, void *output, void *storage, int result);
+extern int smum_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
+               void *input, void *output, void *storage, int result);
+extern int smum_init_smc_table(struct pp_hwmgr *hwmgr);
+extern int smum_populate_all_graphic_levels(struct pp_hwmgr *hwmgr);
+extern int smum_populate_all_memory_levels(struct pp_hwmgr *hwmgr);
+extern int smum_initialize_mc_reg_table(struct pp_hwmgr *hwmgr);
+extern uint32_t smum_get_offsetof(struct pp_smumgr *smumgr,
+                               uint32_t type, uint32_t member);
+extern uint32_t smum_get_mac_definition(struct pp_smumgr *smumgr, uint32_t value);
+
+extern bool smum_is_dpm_running(struct pp_hwmgr *hwmgr);
+
 #define SMUM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
 
 #define SMUM_FIELD_MASK(reg, field) reg##__##field##_MASK
index f10fb64..51ff083 100644 (file)
@@ -2,7 +2,9 @@
 # Makefile for the 'smu manager' sub-component of powerplay.
 # It provides the smu management services for the driver.
 
-SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o polaris10_smumgr.o
+SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o fiji_smc.o \
+         polaris10_smumgr.o iceland_smumgr.o polaris10_smc.o tonga_smc.o \
+         smu7_smumgr.o iceland_smc.o
 
 AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR))
 
index 87c023e..5a44485 100644 (file)
@@ -89,13 +89,8 @@ static int cz_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
        if (result != 0)
                return result;
 
-       result = SMUM_WAIT_FIELD_UNEQUAL(smumgr,
+       return SMUM_WAIT_FIELD_UNEQUAL(smumgr,
                                        SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
-
-       if (result != 0)
-               return result;
-
-       return 0;
 }
 
 static int cz_set_smc_sram_address(struct pp_smumgr *smumgr,
@@ -106,12 +101,12 @@ static int cz_set_smc_sram_address(struct pp_smumgr *smumgr,
 
        if (0 != (3 & smc_address)) {
                printk(KERN_ERR "[ powerplay ] SMC address must be 4 byte aligned\n");
-               return -1;
+               return -EINVAL;
        }
 
        if (limit <= (smc_address + 3)) {
                printk(KERN_ERR "[ powerplay ] SMC address beyond the SMC RAM area\n");
-               return -1;
+               return -EINVAL;
        }
 
        cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX_0,
@@ -129,9 +124,10 @@ static int cz_write_smc_sram_dword(struct pp_smumgr *smumgr,
                return -EINVAL;
 
        result = cz_set_smc_sram_address(smumgr, smc_address, limit);
-       cgs_write_register(smumgr->device, mmMP0PUB_IND_DATA_0, value);
+       if (!result)
+               cgs_write_register(smumgr->device, mmMP0PUB_IND_DATA_0, value);
 
-       return 0;
+       return result;
 }
 
 static int cz_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
@@ -148,7 +144,6 @@ static int cz_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
 static int cz_request_smu_load_fw(struct pp_smumgr *smumgr)
 {
        struct cz_smumgr *cz_smu = (struct cz_smumgr *)(smumgr->backend);
-       int result = 0;
        uint32_t smc_address;
 
        if (!smumgr->reload_fw) {
@@ -177,11 +172,9 @@ static int cz_request_smu_load_fw(struct pp_smumgr *smumgr)
        cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
                                cz_smu->toc_entry_power_profiling_index);
 
-       result = cz_send_msg_to_smc_with_parameter(smumgr,
+       return cz_send_msg_to_smc_with_parameter(smumgr,
                                        PPSMC_MSG_ExecuteJob,
                                        cz_smu->toc_entry_initialize_index);
-
-       return result;
 }
 
 static int cz_check_fw_load_finish(struct pp_smumgr *smumgr,
@@ -195,9 +188,6 @@ static int cz_check_fw_load_finish(struct pp_smumgr *smumgr,
        if (smumgr == NULL || smumgr->device == NULL)
                return -EINVAL;
 
-       return cgs_read_register(smumgr->device,
-                                       mmSMU_MP1_SRBM2P_ARG_0);
-
        cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX, index);
 
        for (i = 0; i < smumgr->usec_timeout; i++) {
@@ -275,7 +265,10 @@ static int cz_start_smu(struct pp_smumgr *smumgr)
        if (smumgr->chip_id == CHIP_STONEY)
                fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK);
 
-       cz_request_smu_load_fw(smumgr);
+       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);
@@ -566,10 +559,7 @@ static int cz_smu_construct_toc_for_bootup(struct pp_smumgr *smumgr)
 
        cz_smu_populate_single_ucode_load_task(smumgr,
                                CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
-       if (smumgr->chip_id == CHIP_STONEY)
-               cz_smu_populate_single_ucode_load_task(smumgr,
-                               CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
-       else
+       if (smumgr->chip_id != CHIP_STONEY)
                cz_smu_populate_single_ucode_load_task(smumgr,
                                CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, false);
        cz_smu_populate_single_ucode_load_task(smumgr,
@@ -580,10 +570,7 @@ static int cz_smu_construct_toc_for_bootup(struct pp_smumgr *smumgr)
                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
        cz_smu_populate_single_ucode_load_task(smumgr,
                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
-       if (smumgr->chip_id == CHIP_STONEY)
-               cz_smu_populate_single_ucode_load_task(smumgr,
-                               CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
-       else
+       if (smumgr->chip_id != CHIP_STONEY)
                cz_smu_populate_single_ucode_load_task(smumgr,
                                CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
        cz_smu_populate_single_ucode_load_task(smumgr,
@@ -610,19 +597,12 @@ static int cz_smu_construct_toc(struct pp_smumgr *smumgr)
        struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
 
        cz_smu->toc_entry_used_count = 0;
-
        cz_smu_initialize_toc_empty_job_list(smumgr);
-
        cz_smu_construct_toc_for_rlc_aram_save(smumgr);
-
        cz_smu_construct_toc_for_vddgfx_enter(smumgr);
-
        cz_smu_construct_toc_for_vddgfx_exit(smumgr);
-
        cz_smu_construct_toc_for_power_profiling(smumgr);
-
        cz_smu_construct_toc_for_bootup(smumgr);
-
        cz_smu_construct_toc_for_clock_table(smumgr);
 
        return 0;
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c
new file mode 100644 (file)
index 0000000..76310ac
--- /dev/null
@@ -0,0 +1,2374 @@
+/*
+ * Copyright 2015 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 "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"
+#include "pppcielanes.h"
+#include "smu7_ppsmc.h"
+#include "smu73.h"
+#include "smu/smu_7_1_3_d.h"
+#include "smu/smu_7_1_3_sh_mask.h"
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+#include "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+#include "smu7_smumgr.h"
+
+#define VOLTAGE_SCALE 4
+#define POWERTUNE_DEFAULT_SET_MAX    1
+#define VOLTAGE_VID_OFFSET_SCALE1   625
+#define VOLTAGE_VID_OFFSET_SCALE2   100
+#define VDDC_VDDCI_DELTA            300
+#define MC_CG_ARB_FREQ_F1           0x0b
+
+/* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
+ * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
+ */
+static const uint16_t fiji_clock_stretcher_lookup_table[2][4] = {
+                               {600, 1050, 3, 0}, {600, 1050, 6, 1} };
+
+/* [FF, SS] type, [] 4 voltage ranges, and
+ * [Floor Freq, Boundary Freq, VID min , VID max]
+ */
+static const uint32_t fiji_clock_stretcher_ddt_table[2][4][4] = {
+       { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
+       { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
+
+/* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
+ * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
+ */
+static const uint8_t fiji_clock_stretch_amount_conversion[2][6] = {
+                               {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
+
+static const struct fiji_pt_defaults fiji_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
+               /*sviLoadLIneEn,  SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */
+               {1,               0xF,             0xFD,
+               /* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */
+               0x19,        5,               45}
+};
+
+/* PPGen has the gain setting generated in x * 100 unit
+ * This function is to convert the unit to x * 4096(0x1000) unit.
+ *  This is the unit expected by SMC firmware
+ */
+static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
+               struct phm_ppt_v1_clock_voltage_dependency_table *dep_table,
+               uint32_t clock, uint32_t *voltage, uint32_t *mvdd)
+{
+       uint32_t i;
+       uint16_t vddci;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       *voltage = *mvdd = 0;
+
+
+       /* clock - voltage dependency table is empty table */
+       if (dep_table->count == 0)
+               return -EINVAL;
+
+       for (i = 0; i < dep_table->count; i++) {
+               /* find first sclk bigger than request */
+               if (dep_table->entries[i].clk >= clock) {
+                       *voltage |= (dep_table->entries[i].vddc *
+                                       VOLTAGE_SCALE) << VDDC_SHIFT;
+                       if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
+                               *voltage |= (data->vbios_boot_state.vddci_bootup_value *
+                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
+                       else if (dep_table->entries[i].vddci)
+                               *voltage |= (dep_table->entries[i].vddci *
+                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
+                       else {
+                               vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
+                                               (dep_table->entries[i].vddc -
+                                                               VDDC_VDDCI_DELTA));
+                               *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+                       }
+
+                       if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control)
+                               *mvdd = data->vbios_boot_state.mvdd_bootup_value *
+                                       VOLTAGE_SCALE;
+                       else if (dep_table->entries[i].mvdd)
+                               *mvdd = (uint32_t) dep_table->entries[i].mvdd *
+                                       VOLTAGE_SCALE;
+
+                       *voltage |= 1 << PHASES_SHIFT;
+                       return 0;
+               }
+       }
+
+       /* sclk is bigger than max sclk in the dependence table */
+       *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
+
+       if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
+               *voltage |= (data->vbios_boot_state.vddci_bootup_value *
+                               VOLTAGE_SCALE) << VDDCI_SHIFT;
+       else if (dep_table->entries[i-1].vddci) {
+               vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
+                               (dep_table->entries[i].vddc -
+                                               VDDC_VDDCI_DELTA));
+               *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+       }
+
+       if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control)
+               *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
+       else if (dep_table->entries[i].mvdd)
+               *mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE;
+
+       return 0;
+}
+
+
+static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
+{
+       uint32_t tmp;
+       tmp = raw_setting * 4096 / 100;
+       return (uint16_t)tmp;
+}
+
+static void get_scl_sda_value(uint8_t line, uint8_t *scl, uint8_t *sda)
+{
+       switch (line) {
+       case SMU7_I2CLineID_DDC1:
+               *scl = SMU7_I2C_DDC1CLK;
+               *sda = SMU7_I2C_DDC1DATA;
+               break;
+       case SMU7_I2CLineID_DDC2:
+               *scl = SMU7_I2C_DDC2CLK;
+               *sda = SMU7_I2C_DDC2DATA;
+               break;
+       case SMU7_I2CLineID_DDC3:
+               *scl = SMU7_I2C_DDC3CLK;
+               *sda = SMU7_I2C_DDC3DATA;
+               break;
+       case SMU7_I2CLineID_DDC4:
+               *scl = SMU7_I2C_DDC4CLK;
+               *sda = SMU7_I2C_DDC4DATA;
+               break;
+       case SMU7_I2CLineID_DDC5:
+               *scl = SMU7_I2C_DDC5CLK;
+               *sda = SMU7_I2C_DDC5DATA;
+               break;
+       case SMU7_I2CLineID_DDC6:
+               *scl = SMU7_I2C_DDC6CLK;
+               *sda = SMU7_I2C_DDC6DATA;
+               break;
+       case SMU7_I2CLineID_SCLSDA:
+               *scl = SMU7_I2C_SCL;
+               *sda = SMU7_I2C_SDA;
+               break;
+       case SMU7_I2CLineID_DDCVGA:
+               *scl = SMU7_I2C_DDCVGACLK;
+               *sda = SMU7_I2C_DDCVGADATA;
+               break;
+       default:
+               *scl = 0;
+               *sda = 0;
+               break;
+       }
+}
+
+static void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct  phm_ppt_v1_information *)(hwmgr->pptable);
+
+       if (table_info &&
+                       table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
+                       table_info->cac_dtp_table->usPowerTuneDataSetID)
+               smu_data->power_tune_defaults =
+                               &fiji_power_tune_data_set_array
+                               [table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
+       else
+               smu_data->power_tune_defaults = &fiji_power_tune_data_set_array[0];
+
+}
+
+static int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
+{
+
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults;
+
+       SMU73_Discrete_DpmTable  *dpm_table = &(smu_data->smc_state_table);
+
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
+       struct pp_advance_fan_control_parameters *fan_table =
+                       &hwmgr->thermal_controller.advanceFanControlParameters;
+       uint8_t uc_scl, uc_sda;
+
+       /* TDP number of fraction bits are changed from 8 to 7 for Fiji
+        * as requested by SMC team
+        */
+       dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
+                       (uint16_t)(cac_dtp_table->usTDP * 128));
+       dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
+                       (uint16_t)(cac_dtp_table->usTDP * 128));
+
+       PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
+                       "Target Operating Temp is out of Range!",
+                       );
+
+       dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
+       dpm_table->GpuTjHyst = 8;
+
+       dpm_table->DTEAmbientTempBase = defaults->DTEAmbientTempBase;
+
+       /* The following are for new Fiji Multi-input fan/thermal control */
+       dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
+                       cac_dtp_table->usTargetOperatingTemp * 256);
+       dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
+                       cac_dtp_table->usTemperatureLimitHotspot * 256);
+       dpm_table->TemperatureLimitLiquid1 = PP_HOST_TO_SMC_US(
+                       cac_dtp_table->usTemperatureLimitLiquid1 * 256);
+       dpm_table->TemperatureLimitLiquid2 = PP_HOST_TO_SMC_US(
+                       cac_dtp_table->usTemperatureLimitLiquid2 * 256);
+       dpm_table->TemperatureLimitVrVddc = PP_HOST_TO_SMC_US(
+                       cac_dtp_table->usTemperatureLimitVrVddc * 256);
+       dpm_table->TemperatureLimitVrMvdd = PP_HOST_TO_SMC_US(
+                       cac_dtp_table->usTemperatureLimitVrMvdd * 256);
+       dpm_table->TemperatureLimitPlx = PP_HOST_TO_SMC_US(
+                       cac_dtp_table->usTemperatureLimitPlx * 256);
+
+       dpm_table->FanGainEdge = PP_HOST_TO_SMC_US(
+                       scale_fan_gain_settings(fan_table->usFanGainEdge));
+       dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US(
+                       scale_fan_gain_settings(fan_table->usFanGainHotspot));
+       dpm_table->FanGainLiquid = PP_HOST_TO_SMC_US(
+                       scale_fan_gain_settings(fan_table->usFanGainLiquid));
+       dpm_table->FanGainVrVddc = PP_HOST_TO_SMC_US(
+                       scale_fan_gain_settings(fan_table->usFanGainVrVddc));
+       dpm_table->FanGainVrMvdd = PP_HOST_TO_SMC_US(
+                       scale_fan_gain_settings(fan_table->usFanGainVrMvdd));
+       dpm_table->FanGainPlx = PP_HOST_TO_SMC_US(
+                       scale_fan_gain_settings(fan_table->usFanGainPlx));
+       dpm_table->FanGainHbm = PP_HOST_TO_SMC_US(
+                       scale_fan_gain_settings(fan_table->usFanGainHbm));
+
+       dpm_table->Liquid1_I2C_address = cac_dtp_table->ucLiquid1_I2C_address;
+       dpm_table->Liquid2_I2C_address = cac_dtp_table->ucLiquid2_I2C_address;
+       dpm_table->Vr_I2C_address = cac_dtp_table->ucVr_I2C_address;
+       dpm_table->Plx_I2C_address = cac_dtp_table->ucPlx_I2C_address;
+
+       get_scl_sda_value(cac_dtp_table->ucLiquid_I2C_Line, &uc_scl, &uc_sda);
+       dpm_table->Liquid_I2C_LineSCL = uc_scl;
+       dpm_table->Liquid_I2C_LineSDA = uc_sda;
+
+       get_scl_sda_value(cac_dtp_table->ucVr_I2C_Line, &uc_scl, &uc_sda);
+       dpm_table->Vr_I2C_LineSCL = uc_scl;
+       dpm_table->Vr_I2C_LineSDA = uc_sda;
+
+       get_scl_sda_value(cac_dtp_table->ucPlx_I2C_Line, &uc_scl, &uc_sda);
+       dpm_table->Plx_I2C_LineSCL = uc_scl;
+       dpm_table->Plx_I2C_LineSDA = uc_sda;
+
+       return 0;
+}
+
+
+static int fiji_populate_svi_load_line(struct pp_hwmgr *hwmgr)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults;
+
+       smu_data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
+       smu_data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
+       smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
+       smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
+
+       return 0;
+}
+
+
+static int fiji_populate_tdc_limit(struct pp_hwmgr *hwmgr)
+{
+       uint16_t tdc_limit;
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults;
+
+       /* TDC number of fraction bits are changed from 8 to 7
+        * for Fiji as requested by SMC team
+        */
+       tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
+       smu_data->power_tune_table.TDC_VDDC_PkgLimit =
+                       CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
+       smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
+                       defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
+       smu_data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
+
+       return 0;
+}
+
+static int fiji_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       const struct fiji_pt_defaults *defaults = smu_data->power_tune_defaults;
+       uint32_t temp;
+
+       if (smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       fuse_table_offset +
+                       offsetof(SMU73_Discrete_PmFuses, TdcWaterfallCtl),
+                       (uint32_t *)&temp, SMC_RAM_END))
+               PP_ASSERT_WITH_CODE(false,
+                               "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
+                               return -EINVAL);
+       else {
+               smu_data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
+               smu_data->power_tune_table.LPMLTemperatureMin =
+                               (uint8_t)((temp >> 16) & 0xff);
+               smu_data->power_tune_table.LPMLTemperatureMax =
+                               (uint8_t)((temp >> 8) & 0xff);
+               smu_data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
+       }
+       return 0;
+}
+
+static int fiji_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
+{
+       int i;
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+
+       /* Currently not used. Set all to zero. */
+       for (i = 0; i < 16; i++)
+               smu_data->power_tune_table.LPMLTemperatureScaler[i] = 0;
+
+       return 0;
+}
+
+static int fiji_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+
+       if ((hwmgr->thermal_controller.advanceFanControlParameters.
+                       usFanOutputSensitivity & (1 << 15)) ||
+                       0 == hwmgr->thermal_controller.advanceFanControlParameters.
+                       usFanOutputSensitivity)
+               hwmgr->thermal_controller.advanceFanControlParameters.
+               usFanOutputSensitivity = hwmgr->thermal_controller.
+                       advanceFanControlParameters.usDefaultFanOutputSensitivity;
+
+       smu_data->power_tune_table.FuzzyFan_PwmSetDelta =
+                       PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
+                                       advanceFanControlParameters.usFanOutputSensitivity);
+       return 0;
+}
+
+static int fiji_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
+{
+       int i;
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+
+       /* Currently not used. Set all to zero. */
+       for (i = 0; i < 16; i++)
+               smu_data->power_tune_table.GnbLPML[i] = 0;
+
+       return 0;
+}
+
+static int fiji_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
+{
+       return 0;
+}
+
+static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       uint16_t HiSidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd;
+       uint16_t LoSidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd;
+       struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
+
+       HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
+       LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
+
+       smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
+                       CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
+       smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
+                       CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
+
+       return 0;
+}
+
+static int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr)
+{
+       uint32_t pm_fuse_table_offset;
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PowerContainment)) {
+               if (smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU7_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU73_Firmware_Header, PmFuseTable),
+                               &pm_fuse_table_offset, SMC_RAM_END))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to get pm_fuse_table_offset Failed!",
+                                       return -EINVAL);
+
+               /* DW6 */
+               if (fiji_populate_svi_load_line(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate SviLoadLine Failed!",
+                                       return -EINVAL);
+               /* DW7 */
+               if (fiji_populate_tdc_limit(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate TDCLimit Failed!", return -EINVAL);
+               /* DW8 */
+               if (fiji_populate_dw8(hwmgr, pm_fuse_table_offset))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate TdcWaterfallCtl, "
+                                       "LPMLTemperature Min and Max Failed!",
+                                       return -EINVAL);
+
+               /* DW9-DW12 */
+               if (0 != fiji_populate_temperature_scaler(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate LPMLTemperatureScaler Failed!",
+                                       return -EINVAL);
+
+               /* DW13-DW14 */
+               if (fiji_populate_fuzzy_fan(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate Fuzzy Fan Control parameters Failed!",
+                                       return -EINVAL);
+
+               /* DW15-DW18 */
+               if (fiji_populate_gnb_lpml(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate GnbLPML Failed!",
+                                       return -EINVAL);
+
+               /* DW19 */
+               if (fiji_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate GnbLPML Min and Max Vid Failed!",
+                                       return -EINVAL);
+
+               /* DW20 */
+               if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate BapmVddCBaseLeakage Hi and Lo "
+                                       "Sidd Failed!", return -EINVAL);
+
+               if (smu7_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
+                               (uint8_t *)&smu_data->power_tune_table,
+                               sizeof(struct SMU73_Discrete_PmFuses), SMC_RAM_END))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to download PmFuseTable Failed!",
+                                       return -EINVAL);
+       }
+       return 0;
+}
+
+/**
+* Preparation of vddc and vddgfx CAC tables for SMC.
+*
+* @param    hwmgr  the address of the hardware manager
+* @param    table  the SMC DPM table structure to be populated
+* @return   always 0
+*/
+static int fiji_populate_cac_table(struct pp_hwmgr *hwmgr,
+               struct SMU73_Discrete_DpmTable *table)
+{
+       uint32_t count;
+       uint8_t index;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_voltage_lookup_table *lookup_table =
+                       table_info->vddc_lookup_table;
+       /* tables is already swapped, so in order to use the value from it,
+        * we need to swap it back.
+        * We are populating vddc CAC data to BapmVddc table
+        * in split and merged mode
+        */
+
+       for (count = 0; count < lookup_table->count; count++) {
+               index = phm_get_voltage_index(lookup_table,
+                               data->vddc_voltage_table.entries[count].value);
+               table->BapmVddcVidLoSidd[count] =
+                       convert_to_vid(lookup_table->entries[index].us_cac_low);
+               table->BapmVddcVidHiSidd[count] =
+                       convert_to_vid(lookup_table->entries[index].us_cac_high);
+       }
+
+       return 0;
+}
+
+/**
+* Preparation of voltage tables for SMC.
+*
+* @param    hwmgr   the address of the hardware manager
+* @param    table   the SMC DPM table structure to be populated
+* @return   always  0
+*/
+
+static int fiji_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
+               struct SMU73_Discrete_DpmTable *table)
+{
+       int result;
+
+       result = fiji_populate_cac_table(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "can not populate CAC voltage tables to SMC",
+                       return -EINVAL);
+
+       return 0;
+}
+
+static int fiji_populate_ulv_level(struct pp_hwmgr *hwmgr,
+               struct SMU73_Discrete_Ulv *state)
+{
+       int result = 0;
+
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       state->CcPwrDynRm = 0;
+       state->CcPwrDynRm1 = 0;
+
+       state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
+       state->VddcOffsetVid = (uint8_t)(table_info->us_ulv_voltage_offset *
+                       VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
+
+       state->VddcPhase = 1;
+
+       if (!result) {
+               CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
+               CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
+               CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
+       }
+       return result;
+}
+
+static int fiji_populate_ulv_state(struct pp_hwmgr *hwmgr,
+               struct SMU73_Discrete_DpmTable *table)
+{
+       return fiji_populate_ulv_level(hwmgr, &table->Ulv);
+}
+
+static int fiji_populate_smc_link_level(struct pp_hwmgr *hwmgr,
+               struct SMU73_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       int i;
+
+       /* Index (dpm_table->pcie_speed_table.count)
+        * is reserved for PCIE boot level. */
+       for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
+               table->LinkLevel[i].PcieGenSpeed  =
+                               (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
+               table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width(
+                               dpm_table->pcie_speed_table.dpm_levels[i].param1);
+               table->LinkLevel[i].EnabledForActivity = 1;
+               table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff);
+               table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5);
+               table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30);
+       }
+
+       smu_data->smc_state_table.LinkLevelCount =
+                       (uint8_t)dpm_table->pcie_speed_table.count;
+       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+                       phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
+
+       return 0;
+}
+
+
+/**
+* Calculates the SCLK dividers using the provided engine clock
+*
+* @param    hwmgr  the address of the hardware manager
+* @param    clock  the engine clock to use to populate the structure
+* @param    sclk   the SMC SCLK structure to be populated
+*/
+static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr,
+               uint32_t clock, struct SMU73_Discrete_GraphicsLevel *sclk)
+{
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+       uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+       uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+       uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+       uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+       uint32_t ref_clock;
+       uint32_t ref_divider;
+       uint32_t fbdiv;
+       int result;
+
+       /* get the engine clock dividers for this clock value */
+       result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock,  &dividers);
+
+       PP_ASSERT_WITH_CODE(result == 0,
+                       "Error retrieving Engine Clock dividers from VBIOS.",
+                       return result);
+
+       /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
+       ref_clock = atomctrl_get_reference_clock(hwmgr);
+       ref_divider = 1 + dividers.uc_pll_ref_div;
+
+       /* low 14 bits is fraction and high 12 bits is divider */
+       fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
+
+       /* SPLL_FUNC_CNTL setup */
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+                       SPLL_REF_DIV, dividers.uc_pll_ref_div);
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+                       SPLL_PDIV_A,  dividers.uc_pll_post_div);
+
+       /* SPLL_FUNC_CNTL_3 setup*/
+       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
+                       SPLL_FB_DIV, fbdiv);
+
+       /* set to use fractional accumulation*/
+       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
+                       SPLL_DITHEN, 1);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
+               struct pp_atomctrl_internal_ss_info ssInfo;
+
+               uint32_t vco_freq = clock * dividers.uc_pll_post_div;
+               if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr,
+                               vco_freq, &ssInfo)) {
+                       /*
+                        * ss_info.speed_spectrum_percentage -- in unit of 0.01%
+                        * ss_info.speed_spectrum_rate -- in unit of khz
+                        *
+                        * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
+                        */
+                       uint32_t clk_s = ref_clock * 5 /
+                                       (ref_divider * ssInfo.speed_spectrum_rate);
+                       /* clkv = 2 * D * fbdiv / NS */
+                       uint32_t clk_v = 4 * ssInfo.speed_spectrum_percentage *
+                                       fbdiv / (clk_s * 10000);
+
+                       cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
+                                       CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s);
+                       cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
+                                       CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
+                       cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2,
+                                       CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v);
+               }
+       }
+
+       sclk->SclkFrequency        = clock;
+       sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
+       sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
+       sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
+       sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
+       sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
+
+       return 0;
+}
+
+/**
+* Populates single SMC SCLK structure using the provided engine clock
+*
+* @param    hwmgr      the address of the hardware manager
+* @param    clock the engine clock to use to populate the structure
+* @param    sclk        the SMC SCLK structure to be populated
+*/
+
+static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
+               uint32_t clock, uint16_t sclk_al_threshold,
+               struct SMU73_Discrete_GraphicsLevel *level)
+{
+       int result;
+       /* PP_Clocks minClocks; */
+       uint32_t threshold, mvdd;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       result = fiji_calculate_sclk_params(hwmgr, clock, level);
+
+       /* populate graphics levels */
+       result = fiji_get_dependency_volt_by_clk(hwmgr,
+                       table_info->vdd_dep_on_sclk, clock,
+                       (uint32_t *)(&level->MinVoltage), &mvdd);
+       PP_ASSERT_WITH_CODE((0 == result),
+                       "can not find VDDC voltage value for "
+                       "VDDC engine clock dependency table",
+                       return result);
+
+       level->SclkFrequency = clock;
+       level->ActivityLevel = sclk_al_threshold;
+       level->CcPwrDynRm = 0;
+       level->CcPwrDynRm1 = 0;
+       level->EnabledForActivity = 0;
+       level->EnabledForThrottle = 1;
+       level->UpHyst = 10;
+       level->DownHyst = 0;
+       level->VoltageDownHyst = 0;
+       level->PowerThrottle = 0;
+
+       threshold = clock * data->fast_watermark_threshold / 100;
+
+       data->display_timing.min_clock_in_sr = hwmgr->display_config.min_core_set_clock_in_sr;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
+               level->DeepSleepDivId = smu7_get_sleep_divider_id_from_clock(clock,
+                                                               hwmgr->display_config.min_core_set_clock_in_sr);
+
+
+       /* Default to slow, highest DPM level will be
+        * set to PPSMC_DISPLAY_WATERMARK_LOW later.
+        */
+       level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+       CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency);
+       CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
+
+       return 0;
+}
+/**
+* Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
+*
+* @param    hwmgr      the address of the hardware manager
+*/
+int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
+       uint8_t pcie_entry_cnt = (uint8_t) data->dpm_table.pcie_speed_table.count;
+       int result = 0;
+       uint32_t array = smu_data->smu7_data.dpm_table_start +
+                       offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
+       uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) *
+                       SMU73_MAX_LEVELS_GRAPHICS;
+       struct SMU73_Discrete_GraphicsLevel *levels =
+                       smu_data->smc_state_table.GraphicsLevel;
+       uint32_t i, max_entry;
+       uint8_t hightest_pcie_level_enabled = 0,
+                       lowest_pcie_level_enabled = 0,
+                       mid_pcie_level_enabled = 0,
+                       count = 0;
+
+       for (i = 0; i < dpm_table->sclk_table.count; i++) {
+               result = fiji_populate_single_graphic_level(hwmgr,
+                               dpm_table->sclk_table.dpm_levels[i].value,
+                               (uint16_t)smu_data->activity_target[i],
+                               &levels[i]);
+               if (result)
+                       return result;
+
+               /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
+               if (i > 1)
+                       levels[i].DeepSleepDivId = 0;
+       }
+
+       /* Only enable level 0 for now.*/
+       levels[0].EnabledForActivity = 1;
+
+       /* set highest level watermark to high */
+       levels[dpm_table->sclk_table.count - 1].DisplayWatermark =
+                       PPSMC_DISPLAY_WATERMARK_HIGH;
+
+       smu_data->smc_state_table.GraphicsDpmLevelCount =
+                       (uint8_t)dpm_table->sclk_table.count;
+       data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+                       phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
+
+       if (pcie_table != NULL) {
+               PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt),
+                               "There must be 1 or more PCIE levels defined in PPTable.",
+                               return -EINVAL);
+               max_entry = pcie_entry_cnt - 1;
+               for (i = 0; i < dpm_table->sclk_table.count; i++)
+                       levels[i].pcieDpmLevel =
+                                       (uint8_t) ((i < max_entry) ? i : max_entry);
+       } else {
+               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                                               (1 << (hightest_pcie_level_enabled + 1))) != 0))
+                       hightest_pcie_level_enabled++;
+
+               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                                               (1 << lowest_pcie_level_enabled)) == 0))
+                       lowest_pcie_level_enabled++;
+
+               while ((count < hightest_pcie_level_enabled) &&
+                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                                               (1 << (lowest_pcie_level_enabled + 1 + count))) == 0))
+                       count++;
+
+               mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1 + count) <
+                               hightest_pcie_level_enabled ?
+                                               (lowest_pcie_level_enabled + 1 + count) :
+                                               hightest_pcie_level_enabled;
+
+               /* set pcieDpmLevel to hightest_pcie_level_enabled */
+               for (i = 2; i < dpm_table->sclk_table.count; i++)
+                       levels[i].pcieDpmLevel = hightest_pcie_level_enabled;
+
+               /* set pcieDpmLevel to lowest_pcie_level_enabled */
+               levels[0].pcieDpmLevel = lowest_pcie_level_enabled;
+
+               /* set pcieDpmLevel to mid_pcie_level_enabled */
+               levels[1].pcieDpmLevel = mid_pcie_level_enabled;
+       }
+       /* level count will send to smc once at init smc table and never change */
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
+                       (uint32_t)array_size, SMC_RAM_END);
+
+       return result;
+}
+
+
+/**
+ * MCLK Frequency Ratio
+ * SEQ_CG_RESP  Bit[31:24] - 0x0
+ * Bit[27:24] \96 DDR3 Frequency ratio
+ * 0x0 <= 100MHz,       450 < 0x8 <= 500MHz
+ * 100 < 0x1 <= 150MHz,       500 < 0x9 <= 550MHz
+ * 150 < 0x2 <= 200MHz,       550 < 0xA <= 600MHz
+ * 200 < 0x3 <= 250MHz,       600 < 0xB <= 650MHz
+ * 250 < 0x4 <= 300MHz,       650 < 0xC <= 700MHz
+ * 300 < 0x5 <= 350MHz,       700 < 0xD <= 750MHz
+ * 350 < 0x6 <= 400MHz,       750 < 0xE <= 800MHz
+ * 400 < 0x7 <= 450MHz,       800 < 0xF
+ */
+static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock)
+{
+       if (mem_clock <= 10000)
+               return 0x0;
+       if (mem_clock <= 15000)
+               return 0x1;
+       if (mem_clock <= 20000)
+               return 0x2;
+       if (mem_clock <= 25000)
+               return 0x3;
+       if (mem_clock <= 30000)
+               return 0x4;
+       if (mem_clock <= 35000)
+               return 0x5;
+       if (mem_clock <= 40000)
+               return 0x6;
+       if (mem_clock <= 45000)
+               return 0x7;
+       if (mem_clock <= 50000)
+               return 0x8;
+       if (mem_clock <= 55000)
+               return 0x9;
+       if (mem_clock <= 60000)
+               return 0xa;
+       if (mem_clock <= 65000)
+               return 0xb;
+       if (mem_clock <= 70000)
+               return 0xc;
+       if (mem_clock <= 75000)
+               return 0xd;
+       if (mem_clock <= 80000)
+               return 0xe;
+       /* mem_clock > 800MHz */
+       return 0xf;
+}
+
+/**
+* Populates the SMC MCLK structure using the provided memory clock
+*
+* @param    hwmgr   the address of the hardware manager
+* @param    clock   the memory clock to use to populate the structure
+* @param    sclk    the SMC SCLK structure to be populated
+*/
+static int fiji_calculate_mclk_params(struct pp_hwmgr *hwmgr,
+    uint32_t clock, struct SMU73_Discrete_MemoryLevel *mclk)
+{
+       struct pp_atomctrl_memory_clock_param mem_param;
+       int result;
+
+       result = atomctrl_get_memory_pll_dividers_vi(hwmgr, clock, &mem_param);
+       PP_ASSERT_WITH_CODE((0 == result),
+                       "Failed to get Memory PLL Dividers.",
+                       );
+
+       /* Save the result data to outpupt memory level structure */
+       mclk->MclkFrequency   = clock;
+       mclk->MclkDivider     = (uint8_t)mem_param.mpll_post_divider;
+       mclk->FreqRange       = fiji_get_mclk_frequency_ratio(clock);
+
+       return result;
+}
+
+static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr,
+               uint32_t clock, struct SMU73_Discrete_MemoryLevel *mem_level)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       int result = 0;
+       uint32_t mclk_stutter_mode_threshold = 60000;
+
+       if (table_info->vdd_dep_on_mclk) {
+               result = fiji_get_dependency_volt_by_clk(hwmgr,
+                               table_info->vdd_dep_on_mclk, clock,
+                               (uint32_t *)(&mem_level->MinVoltage), &mem_level->MinMvdd);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find MinVddc voltage value from memory "
+                               "VDDC voltage dependency table", return result);
+       }
+
+       mem_level->EnabledForThrottle = 1;
+       mem_level->EnabledForActivity = 0;
+       mem_level->UpHyst = 0;
+       mem_level->DownHyst = 100;
+       mem_level->VoltageDownHyst = 0;
+       mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
+       mem_level->StutterEnable = false;
+
+       mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+       /* enable stutter mode if all the follow condition applied
+        * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
+        * &(data->DisplayTiming.numExistingDisplays));
+        */
+       data->display_timing.num_existing_displays = 1;
+
+       if (mclk_stutter_mode_threshold &&
+               (clock <= mclk_stutter_mode_threshold) &&
+               (!data->is_uvd_enabled) &&
+               (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL,
+                               STUTTER_ENABLE) & 0x1))
+               mem_level->StutterEnable = true;
+
+       result = fiji_calculate_mclk_params(hwmgr, clock, mem_level);
+       if (!result) {
+               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd);
+               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency);
+               CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel);
+               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage);
+       }
+       return result;
+}
+
+/**
+* Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
+*
+* @param    hwmgr      the address of the hardware manager
+*/
+int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       int result;
+       /* populate MCLK dpm table to SMU7 */
+       uint32_t array = smu_data->smu7_data.dpm_table_start +
+                       offsetof(SMU73_Discrete_DpmTable, MemoryLevel);
+       uint32_t array_size = sizeof(SMU73_Discrete_MemoryLevel) *
+                       SMU73_MAX_LEVELS_MEMORY;
+       struct SMU73_Discrete_MemoryLevel *levels =
+                       smu_data->smc_state_table.MemoryLevel;
+       uint32_t i;
+
+       for (i = 0; i < dpm_table->mclk_table.count; i++) {
+               PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
+                               "can not populate memory level as memory clock is zero",
+                               return -EINVAL);
+               result = fiji_populate_single_memory_level(hwmgr,
+                               dpm_table->mclk_table.dpm_levels[i].value,
+                               &levels[i]);
+               if (result)
+                       return result;
+       }
+
+       /* Only enable level 0 for now. */
+       levels[0].EnabledForActivity = 1;
+
+       /* in order to prevent MC activity from stutter mode to push DPM up.
+        * the UVD change complements this by putting the MCLK in
+        * a higher state by default such that we are not effected by
+        * up threshold or and MCLK DPM latency.
+        */
+       levels[0].ActivityLevel = (uint16_t)data->mclk_dpm0_activity_target;
+       CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel);
+
+       smu_data->smc_state_table.MemoryDpmLevelCount =
+                       (uint8_t)dpm_table->mclk_table.count;
+       data->dpm_level_enable_mask.mclk_dpm_enable_mask =
+                       phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
+       /* set highest level watermark to high */
+       levels[dpm_table->mclk_table.count - 1].DisplayWatermark =
+                       PPSMC_DISPLAY_WATERMARK_HIGH;
+
+       /* level count will send to smc once at init smc table and never change */
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
+                       (uint32_t)array_size, SMC_RAM_END);
+
+       return result;
+}
+
+
+/**
+* Populates the SMC MVDD structure using the provided memory clock.
+*
+* @param    hwmgr      the address of the hardware manager
+* @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
+* @param    voltage     the SMC VOLTAGE structure to be populated
+*/
+static int fiji_populate_mvdd_value(struct pp_hwmgr *hwmgr,
+               uint32_t mclk, SMIO_Pattern *smio_pat)
+{
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       uint32_t i = 0;
+
+       if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
+               /* find mvdd value which clock is more than request */
+               for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
+                       if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
+                               smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value;
+                               break;
+                       }
+               }
+               PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
+                               "MVDD Voltage is outside the supported range.",
+                               return -EINVAL);
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
+               SMU73_Discrete_DpmTable *table)
+{
+       int result = 0;
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       SMIO_Pattern vol_level;
+       uint32_t mvdd;
+       uint16_t us_mvdd;
+       uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+       uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
+
+       table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+       if (!data->sclk_dpm_key_disabled) {
+               /* Get MinVoltage and Frequency from DPM0,
+                * already converted to SMC_UL */
+               table->ACPILevel.SclkFrequency =
+                               data->dpm_table.sclk_table.dpm_levels[0].value;
+               result = fiji_get_dependency_volt_by_clk(hwmgr,
+                               table_info->vdd_dep_on_sclk,
+                               table->ACPILevel.SclkFrequency,
+                               (uint32_t *)(&table->ACPILevel.MinVoltage), &mvdd);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "Cannot find ACPI VDDC voltage value " \
+                               "in Clock Dependency Table",
+                               );
+       } else {
+               table->ACPILevel.SclkFrequency =
+                               data->vbios_boot_state.sclk_bootup_value;
+               table->ACPILevel.MinVoltage =
+                               data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE;
+       }
+
+       /* get the engine clock dividers for this clock value */
+       result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
+                       table->ACPILevel.SclkFrequency,  &dividers);
+       PP_ASSERT_WITH_CODE(result == 0,
+                       "Error retrieving Engine Clock dividers from VBIOS.",
+                       return result);
+
+       table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
+       table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+       table->ACPILevel.DeepSleepDivId = 0;
+
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+                       SPLL_PWRON, 0);
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+                       SPLL_RESET, 1);
+       spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
+                       SCLK_MUX_SEL, 4);
+
+       table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
+       table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
+       table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+       table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+       table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+       table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+       table->ACPILevel.CcPwrDynRm = 0;
+       table->ACPILevel.CcPwrDynRm1 = 0;
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
+
+       if (!data->mclk_dpm_key_disabled) {
+               /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
+               table->MemoryACPILevel.MclkFrequency =
+                               data->dpm_table.mclk_table.dpm_levels[0].value;
+               result = fiji_get_dependency_volt_by_clk(hwmgr,
+                               table_info->vdd_dep_on_mclk,
+                               table->MemoryACPILevel.MclkFrequency,
+                       (uint32_t *)(&table->MemoryACPILevel.MinVoltage), &mvdd);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "Cannot find ACPI VDDCI voltage value in Clock Dependency Table",
+                               );
+       } else {
+               table->MemoryACPILevel.MclkFrequency =
+                               data->vbios_boot_state.mclk_bootup_value;
+               table->MemoryACPILevel.MinVoltage =
+                               data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE;
+       }
+
+       us_mvdd = 0;
+       if ((SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) ||
+                       (data->mclk_dpm_key_disabled))
+               us_mvdd = data->vbios_boot_state.mvdd_bootup_value;
+       else {
+               if (!fiji_populate_mvdd_value(hwmgr,
+                               data->dpm_table.mclk_table.dpm_levels[0].value,
+                               &vol_level))
+                       us_mvdd = vol_level.Voltage;
+       }
+
+       table->MemoryACPILevel.MinMvdd =
+                       PP_HOST_TO_SMC_UL(us_mvdd * VOLTAGE_SCALE);
+
+       table->MemoryACPILevel.EnabledForThrottle = 0;
+       table->MemoryACPILevel.EnabledForActivity = 0;
+       table->MemoryACPILevel.UpHyst = 0;
+       table->MemoryACPILevel.DownHyst = 100;
+       table->MemoryACPILevel.VoltageDownHyst = 0;
+       table->MemoryACPILevel.ActivityLevel =
+                       PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
+
+       table->MemoryACPILevel.StutterEnable = false;
+       CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);
+
+       return result;
+}
+
+static int fiji_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
+               SMU73_Discrete_DpmTable *table)
+{
+       int result = -EINVAL;
+       uint8_t count;
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                       table_info->mm_dep_table;
+
+       table->VceLevelCount = (uint8_t)(mm_table->count);
+       table->VceBootLevel = 0;
+
+       for (count = 0; count < table->VceLevelCount; count++) {
+               table->VceLevel[count].Frequency = mm_table->entries[count].eclk;
+               table->VceLevel[count].MinVoltage = 0;
+               table->VceLevel[count].MinVoltage |=
+                               (mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
+               table->VceLevel[count].MinVoltage |=
+                               ((mm_table->entries[count].vddc - VDDC_VDDCI_DELTA) *
+                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
+               table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+               /*retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                               table->VceLevel[count].Frequency, &dividers);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find divide id for VCE engine clock",
+                               return result);
+
+               table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage);
+       }
+       return result;
+}
+
+static int fiji_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
+               SMU73_Discrete_DpmTable *table)
+{
+       int result = -EINVAL;
+       uint8_t count;
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                       table_info->mm_dep_table;
+
+       table->AcpLevelCount = (uint8_t)(mm_table->count);
+       table->AcpBootLevel = 0;
+
+       for (count = 0; count < table->AcpLevelCount; count++) {
+               table->AcpLevel[count].Frequency = mm_table->entries[count].aclk;
+               table->AcpLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+                               VOLTAGE_SCALE) << VDDC_SHIFT;
+               table->AcpLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
+                               VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT;
+               table->AcpLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+               /* retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                               table->AcpLevel[count].Frequency, &dividers);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find divide id for engine clock", return result);
+
+               table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].MinVoltage);
+       }
+       return result;
+}
+
+static int fiji_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
+               SMU73_Discrete_DpmTable *table)
+{
+       int result = -EINVAL;
+       uint8_t count;
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                       table_info->mm_dep_table;
+
+       table->SamuBootLevel = 0;
+       table->SamuLevelCount = (uint8_t)(mm_table->count);
+
+       for (count = 0; count < table->SamuLevelCount; count++) {
+               /* not sure whether we need evclk or not */
+               table->SamuLevel[count].MinVoltage = 0;
+               table->SamuLevel[count].Frequency = mm_table->entries[count].samclock;
+               table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+                               VOLTAGE_SCALE) << VDDC_SHIFT;
+               table->SamuLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
+                               VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT;
+               table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+               /* retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                               table->SamuLevel[count].Frequency, &dividers);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find divide id for samu clock", return result);
+
+               table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage);
+       }
+       return result;
+}
+
+static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr,
+               int32_t eng_clock, int32_t mem_clock,
+               struct SMU73_Discrete_MCArbDramTimingTableEntry *arb_regs)
+{
+       uint32_t dram_timing;
+       uint32_t dram_timing2;
+       uint32_t burstTime;
+       ULONG state, trrds, trrdl;
+       int result;
+
+       result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
+                       eng_clock, mem_clock);
+       PP_ASSERT_WITH_CODE(result == 0,
+                       "Error calling VBIOS to set DRAM_TIMING.", return result);
+
+       dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+       dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+       burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME);
+
+       state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0);
+       trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0);
+       trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0);
+
+       arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dram_timing);
+       arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2);
+       arb_regs->McArbBurstTime   = (uint8_t)burstTime;
+       arb_regs->TRRDS            = (uint8_t)trrds;
+       arb_regs->TRRDL            = (uint8_t)trrdl;
+
+       return 0;
+}
+
+static int fiji_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       struct SMU73_Discrete_MCArbDramTimingTable arb_regs;
+       uint32_t i, j;
+       int result = 0;
+
+       for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
+               for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
+                       result = fiji_populate_memory_timing_parameters(hwmgr,
+                                       data->dpm_table.sclk_table.dpm_levels[i].value,
+                                       data->dpm_table.mclk_table.dpm_levels[j].value,
+                                       &arb_regs.entries[i][j]);
+                       if (result)
+                               break;
+               }
+       }
+
+       if (!result)
+               result = smu7_copy_bytes_to_smc(
+                               hwmgr->smumgr,
+                               smu_data->smu7_data.arb_table_start,
+                               (uint8_t *)&arb_regs,
+                               sizeof(SMU73_Discrete_MCArbDramTimingTable),
+                               SMC_RAM_END);
+       return result;
+}
+
+static int fiji_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
+               struct SMU73_Discrete_DpmTable *table)
+{
+       int result = -EINVAL;
+       uint8_t count;
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                       table_info->mm_dep_table;
+
+       table->UvdLevelCount = (uint8_t)(mm_table->count);
+       table->UvdBootLevel = 0;
+
+       for (count = 0; count < table->UvdLevelCount; count++) {
+               table->UvdLevel[count].MinVoltage = 0;
+               table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
+               table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
+               table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+                               VOLTAGE_SCALE) << VDDC_SHIFT;
+               table->UvdLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
+                               VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT;
+               table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+               /* retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                               table->UvdLevel[count].VclkFrequency, &dividers);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find divide id for Vclk clock", return result);
+
+               table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
+
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                               table->UvdLevel[count].DclkFrequency, &dividers);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find divide id for Dclk clock", return result);
+
+               table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage);
+
+       }
+       return result;
+}
+
+static int fiji_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
+               struct SMU73_Discrete_DpmTable *table)
+{
+       int result = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       table->GraphicsBootLevel = 0;
+       table->MemoryBootLevel = 0;
+
+       /* find boot level from dpm table */
+       result = phm_find_boot_level(&(data->dpm_table.sclk_table),
+                       data->vbios_boot_state.sclk_bootup_value,
+                       (uint32_t *)&(table->GraphicsBootLevel));
+
+       result = phm_find_boot_level(&(data->dpm_table.mclk_table),
+                       data->vbios_boot_state.mclk_bootup_value,
+                       (uint32_t *)&(table->MemoryBootLevel));
+
+       table->BootVddc  = data->vbios_boot_state.vddc_bootup_value *
+                       VOLTAGE_SCALE;
+       table->BootVddci = data->vbios_boot_state.vddci_bootup_value *
+                       VOLTAGE_SCALE;
+       table->BootMVdd  = data->vbios_boot_state.mvdd_bootup_value *
+                       VOLTAGE_SCALE;
+
+       CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc);
+       CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci);
+       CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
+
+       return 0;
+}
+
+static int fiji_populate_smc_initailial_state(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       uint8_t count, level;
+
+       count = (uint8_t)(table_info->vdd_dep_on_sclk->count);
+       for (level = 0; level < count; level++) {
+               if (table_info->vdd_dep_on_sclk->entries[level].clk >=
+                               data->vbios_boot_state.sclk_bootup_value) {
+                       smu_data->smc_state_table.GraphicsBootLevel = level;
+                       break;
+               }
+       }
+
+       count = (uint8_t)(table_info->vdd_dep_on_mclk->count);
+       for (level = 0; level < count; level++) {
+               if (table_info->vdd_dep_on_mclk->entries[level].clk >=
+                               data->vbios_boot_state.mclk_bootup_value) {
+                       smu_data->smc_state_table.MemoryBootLevel = level;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
+{
+       uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
+                       volt_with_cks, value;
+       uint16_t clock_freq_u16;
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
+                       volt_offset = 0;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+                       table_info->vdd_dep_on_sclk;
+
+       stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
+
+       /* Read SMU_Eefuse to read and calculate RO and determine
+        * if the part is SS or FF. if RO >= 1660MHz, part is FF.
+        */
+       efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixSMU_EFUSE_0 + (146 * 4));
+       efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixSMU_EFUSE_0 + (148 * 4));
+       efuse &= 0xFF000000;
+       efuse = efuse >> 24;
+       efuse2 &= 0xF;
+
+       if (efuse2 == 1)
+               ro = (2300 - 1350) * efuse / 255 + 1350;
+       else
+               ro = (2500 - 1000) * efuse / 255 + 1000;
+
+       if (ro >= 1660)
+               type = 0;
+       else
+               type = 1;
+
+       /* Populate Stretch amount */
+       smu_data->smc_state_table.ClockStretcherAmount = stretch_amount;
+
+       /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
+       for (i = 0; i < sclk_table->count; i++) {
+               smu_data->smc_state_table.Sclk_CKS_masterEn0_7 |=
+                               sclk_table->entries[i].cks_enable << i;
+               volt_without_cks = (uint32_t)((14041 *
+                       (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
+                       (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
+               volt_with_cks = (uint32_t)((13946 *
+                       (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
+                       (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
+               if (volt_without_cks >= volt_with_cks)
+                       volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
+                                       sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
+               smu_data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
+       }
+
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+                       STRETCH_ENABLE, 0x0);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+                       masterReset, 0x1);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+                       staticEnable, 0x1);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+                       masterReset, 0x0);
+
+       /* Populate CKS Lookup Table */
+       if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
+               stretch_amount2 = 0;
+       else if (stretch_amount == 3 || stretch_amount == 4)
+               stretch_amount2 = 1;
+       else {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_ClockStretcher);
+               PP_ASSERT_WITH_CODE(false,
+                               "Stretch Amount in PPTable not supported\n",
+                               return -EINVAL);
+       }
+
+       value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixPWR_CKS_CNTL);
+       value &= 0xFFC2FF87;
+       smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
+                       fiji_clock_stretcher_lookup_table[stretch_amount2][0];
+       smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
+                       fiji_clock_stretcher_lookup_table[stretch_amount2][1];
+       clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(smu_data->smc_state_table.
+                       GraphicsLevel[smu_data->smc_state_table.GraphicsDpmLevelCount - 1].
+                       SclkFrequency) / 100);
+       if (fiji_clock_stretcher_lookup_table[stretch_amount2][0] <
+                       clock_freq_u16 &&
+           fiji_clock_stretcher_lookup_table[stretch_amount2][1] >
+                       clock_freq_u16) {
+               /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
+               value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
+               /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
+               value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
+               /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
+               value |= (fiji_clock_stretch_amount_conversion
+                               [fiji_clock_stretcher_lookup_table[stretch_amount2][3]]
+                                [stretch_amount]) << 3;
+       }
+       CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
+                       CKS_LOOKUPTableEntry[0].minFreq);
+       CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
+                       CKS_LOOKUPTableEntry[0].maxFreq);
+       smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
+                       fiji_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
+       smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
+                       (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixPWR_CKS_CNTL, value);
+
+       /* Populate DDT Lookup Table */
+       for (i = 0; i < 4; i++) {
+               /* Assign the minimum and maximum VID stored
+                * in the last row of Clock Stretcher Voltage Table.
+                */
+               smu_data->smc_state_table.ClockStretcherDataTable.
+               ClockStretcherDataTableEntry[i].minVID =
+                               (uint8_t) fiji_clock_stretcher_ddt_table[type][i][2];
+               smu_data->smc_state_table.ClockStretcherDataTable.
+               ClockStretcherDataTableEntry[i].maxVID =
+                               (uint8_t) fiji_clock_stretcher_ddt_table[type][i][3];
+               /* Loop through each SCLK and check the frequency
+                * to see if it lies within the frequency for clock stretcher.
+                */
+               for (j = 0; j < smu_data->smc_state_table.GraphicsDpmLevelCount; j++) {
+                       cks_setting = 0;
+                       clock_freq = PP_SMC_TO_HOST_UL(
+                                       smu_data->smc_state_table.GraphicsLevel[j].SclkFrequency);
+                       /* Check the allowed frequency against the sclk level[j].
+                        *  Sclk's endianness has already been converted,
+                        *  and it's in 10Khz unit,
+                        *  as opposed to Data table, which is in Mhz unit.
+                        */
+                       if (clock_freq >=
+                                       (fiji_clock_stretcher_ddt_table[type][i][0]) * 100) {
+                               cks_setting |= 0x2;
+                               if (clock_freq <
+                                               (fiji_clock_stretcher_ddt_table[type][i][1]) * 100)
+                                       cks_setting |= 0x1;
+                       }
+                       smu_data->smc_state_table.ClockStretcherDataTable.
+                       ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
+               }
+               CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.
+                               ClockStretcherDataTable.
+                               ClockStretcherDataTableEntry[i].setting);
+       }
+
+       value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL);
+       value &= 0xFFFFFFFE;
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value);
+
+       return 0;
+}
+
+/**
+* Populates the SMC VRConfig field in DPM table.
+*
+* @param    hwmgr   the address of the hardware manager
+* @param    table   the SMC DPM table structure to be populated
+* @return   always 0
+*/
+static int fiji_populate_vr_config(struct pp_hwmgr *hwmgr,
+               struct SMU73_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint16_t config;
+
+       config = VR_MERGED_WITH_VDDC;
+       table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT);
+
+       /* Set Vddc Voltage Controller */
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+               config = VR_SVI2_PLANE_1;
+               table->VRConfig |= config;
+       } else {
+               PP_ASSERT_WITH_CODE(false,
+                               "VDDC should be on SVI2 control in merged mode!",
+                               );
+       }
+       /* Set Vddci Voltage Controller */
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
+               config = VR_SVI2_PLANE_2;  /* only in merged mode */
+               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+       } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+               config = VR_SMIO_PATTERN_1;
+               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+       } else {
+               config = VR_STATIC_VOLTAGE;
+               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+       }
+       /* Set Mvdd Voltage Controller */
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
+               config = VR_SVI2_PLANE_2;
+               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+       } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+               config = VR_SMIO_PATTERN_2;
+               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+       } else {
+               config = VR_STATIC_VOLTAGE;
+               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+       }
+
+       return 0;
+}
+
+static int fiji_init_arb_table_index(struct pp_smumgr *smumgr)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(smumgr->backend);
+       uint32_t tmp;
+       int result;
+
+       /* This is a read-modify-write on the first byte of the ARB table.
+        * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
+        * is the field 'current'.
+        * This solution is ugly, but we never write the whole table only
+        * individual fields in it.
+        * In reality this field should not be in that structure
+        * but in a soft register.
+        */
+       result = smu7_read_smc_sram_dword(smumgr,
+                       smu_data->smu7_data.arb_table_start, &tmp, SMC_RAM_END);
+
+       if (result)
+               return result;
+
+       tmp &= 0x00FFFFFF;
+       tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
+
+       return smu7_write_smc_sram_dword(smumgr,
+                       smu_data->smu7_data.arb_table_start,  tmp, SMC_RAM_END);
+}
+
+/**
+* Initializes the SMC table and uploads it
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput  the pointer to input data (PowerState)
+* @return   always 0
+*/
+int fiji_init_smc_table(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct SMU73_Discrete_DpmTable *table = &(smu_data->smc_state_table);
+       uint8_t i;
+       struct pp_atomctrl_gpio_pin_assignment gpio_pin;
+
+       fiji_initialize_power_tune_defaults(hwmgr);
+
+       if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control)
+               fiji_populate_smc_voltage_tables(hwmgr, table);
+
+       table->SystemFlags = 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_AutomaticDCTransition))
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StepVddc))
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+       if (data->is_memory_gddr5)
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+       if (data->ulv_supported && table_info->us_ulv_voltage_offset) {
+               result = fiji_populate_ulv_state(hwmgr, table);
+               PP_ASSERT_WITH_CODE(0 == result,
+                               "Failed to initialize ULV state!", return result);
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                               ixCG_ULV_PARAMETER, 0x40035);
+       }
+
+       result = fiji_populate_smc_link_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Link Level!", return result);
+
+       result = fiji_populate_all_graphic_levels(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Graphics Level!", return result);
+
+       result = fiji_populate_all_memory_levels(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Memory Level!", return result);
+
+       result = fiji_populate_smc_acpi_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize ACPI Level!", return result);
+
+       result = fiji_populate_smc_vce_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize VCE Level!", return result);
+
+       result = fiji_populate_smc_acp_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize ACP Level!", return result);
+
+       result = fiji_populate_smc_samu_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize SAMU Level!", return result);
+
+       /* Since only the initial state is completely set up at this point
+        * (the other states are just copies of the boot state) we only
+        * need to populate the  ARB settings for the initial state.
+        */
+       result = fiji_program_memory_timing_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to Write ARB settings for the initial state.", return result);
+
+       result = fiji_populate_smc_uvd_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize UVD Level!", return result);
+
+       result = fiji_populate_smc_boot_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Boot Level!", return result);
+
+       result = fiji_populate_smc_initailial_state(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Boot State!", return result);
+
+       result = fiji_populate_bapm_parameters_in_dpm_table(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to populate BAPM Parameters!", return result);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ClockStretcher)) {
+               result = fiji_populate_clock_stretcher_data_table(hwmgr);
+               PP_ASSERT_WITH_CODE(0 == result,
+                               "Failed to populate Clock Stretcher Data Table!",
+                               return result);
+       }
+
+       table->GraphicsVoltageChangeEnable  = 1;
+       table->GraphicsThermThrottleEnable  = 1;
+       table->GraphicsInterval = 1;
+       table->VoltageInterval  = 1;
+       table->ThermalInterval  = 1;
+       table->TemperatureLimitHigh =
+                       table_info->cac_dtp_table->usTargetOperatingTemp *
+                       SMU7_Q88_FORMAT_CONVERSION_UNIT;
+       table->TemperatureLimitLow  =
+                       (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
+                       SMU7_Q88_FORMAT_CONVERSION_UNIT;
+       table->MemoryVoltageChangeEnable = 1;
+       table->MemoryInterval = 1;
+       table->VoltageResponseTime = 0;
+       table->PhaseResponseTime = 0;
+       table->MemoryThermThrottleEnable = 1;
+       table->PCIeBootLinkLevel = 0;      /* 0:Gen1 1:Gen2 2:Gen3*/
+       table->PCIeGenInterval = 1;
+       table->VRConfig = 0;
+
+       result = fiji_populate_vr_config(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to populate VRConfig setting!", return result);
+
+       table->ThermGpio = 17;
+       table->SclkStepSize = 0x4000;
+
+       if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
+               table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_RegulatorHot);
+       } else {
+               table->VRHotGpio = SMU7_UNUSED_GPIO_PIN;
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_RegulatorHot);
+       }
+
+       if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
+                       &gpio_pin)) {
+               table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift;
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_AutomaticDCTransition);
+       } else {
+               table->AcDcGpio = SMU7_UNUSED_GPIO_PIN;
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_AutomaticDCTransition);
+       }
+
+       /* Thermal Output GPIO */
+       if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID,
+                       &gpio_pin)) {
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_ThermalOutGPIO);
+
+               table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift;
+
+               /* For porlarity read GPIOPAD_A with assigned Gpio pin
+                * since VBIOS will program this register to set 'inactive state',
+                * driver can then determine 'active state' from this and
+                * program SMU with correct polarity
+                */
+               table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
+                               (1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0;
+               table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
+
+               /* if required, combine VRHot/PCC with thermal out GPIO */
+               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_RegulatorHot) &&
+                       phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_CombinePCCWithThermalSignal))
+                       table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
+       } else {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_ThermalOutGPIO);
+               table->ThermOutGpio = 17;
+               table->ThermOutPolarity = 1;
+               table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
+       }
+
+       for (i = 0; i < SMU73_MAX_ENTRIES_SMIO; i++)
+               table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
+       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
+       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
+       CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
+       CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
+
+       /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr,
+                       smu_data->smu7_data.dpm_table_start +
+                       offsetof(SMU73_Discrete_DpmTable, SystemFlags),
+                       (uint8_t *)&(table->SystemFlags),
+                       sizeof(SMU73_Discrete_DpmTable) - 3 * sizeof(SMU73_PIDController),
+                       SMC_RAM_END);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to upload dpm data to SMC memory!", return result);
+
+       result = fiji_init_arb_table_index(hwmgr->smumgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to upload arb data to SMC memory!", return result);
+
+       result = fiji_populate_pm_fuses(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to  populate PM fuses to SMC memory!", return result);
+       return 0;
+}
+
+/**
+* Set up the fan table to control the fan using the SMC.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+
+       SMU73_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+       uint32_t duty100;
+       uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+       uint16_t fdo_min, slope1, slope2;
+       uint32_t reference_clock;
+       int res;
+       uint64_t tmp64;
+
+       if (smu_data->smu7_data.fan_table_start == 0) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_MicrocodeFanControl);
+               return 0;
+       }
+
+       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_FDO_CTRL1, FMAX_DUTY100);
+
+       if (duty100 == 0) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_MicrocodeFanControl);
+               return 0;
+       }
+
+       tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
+                       usPWMMin * duty100;
+       do_div(tmp64, 10000);
+       fdo_min = (uint16_t)tmp64;
+
+       t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
+                       hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
+       t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
+                       hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
+
+       pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
+                       hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
+       pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
+                       hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
+
+       slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+       slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+       fan_table.TempMin = cpu_to_be16((50 + hwmgr->
+                       thermal_controller.advanceFanControlParameters.usTMin) / 100);
+       fan_table.TempMed = cpu_to_be16((50 + hwmgr->
+                       thermal_controller.advanceFanControlParameters.usTMed) / 100);
+       fan_table.TempMax = cpu_to_be16((50 + hwmgr->
+                       thermal_controller.advanceFanControlParameters.usTMax) / 100);
+
+       fan_table.Slope1 = cpu_to_be16(slope1);
+       fan_table.Slope2 = cpu_to_be16(slope2);
+
+       fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+       fan_table.HystDown = cpu_to_be16(hwmgr->
+                       thermal_controller.advanceFanControlParameters.ucTHyst);
+
+       fan_table.HystUp = cpu_to_be16(1);
+
+       fan_table.HystSlope = cpu_to_be16(1);
+
+       fan_table.TempRespLim = cpu_to_be16(5);
+
+       reference_clock = smu7_get_xclk(hwmgr);
+
+       fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
+                       thermal_controller.advanceFanControlParameters.ulCycleDelay *
+                       reference_clock) / 1600);
+
+       fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
+
+       fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
+                       hwmgr->device, CGS_IND_REG__SMC,
+                       CG_MULT_THERMAL_CTRL, TEMP_SEL);
+
+       res = smu7_copy_bytes_to_smc(hwmgr->smumgr, smu_data->smu7_data.fan_table_start,
+                       (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
+                       SMC_RAM_END);
+
+       if (!res && hwmgr->thermal_controller.
+                       advanceFanControlParameters.ucMinimumPWMLimit)
+               res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_SetFanMinPwm,
+                               hwmgr->thermal_controller.
+                               advanceFanControlParameters.ucMinimumPWMLimit);
+
+       if (!res && hwmgr->thermal_controller.
+                       advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
+               res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_SetFanSclkTarget,
+                               hwmgr->thermal_controller.
+                               advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
+
+       if (res)
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_MicrocodeFanControl);
+
+       return 0;
+}
+
+int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->need_update_smu7_dpm_table &
+               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+               return fiji_program_memory_timing_parameters(hwmgr);
+
+       return 0;
+}
+
+int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+
+       int result = 0;
+       uint32_t low_sclk_interrupt_threshold = 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkThrottleLowNotification)
+               && (hwmgr->gfx_arbiter.sclk_threshold !=
+                               data->low_sclk_interrupt_threshold)) {
+               data->low_sclk_interrupt_threshold =
+                               hwmgr->gfx_arbiter.sclk_threshold;
+               low_sclk_interrupt_threshold =
+                               data->low_sclk_interrupt_threshold;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
+
+               result = smu7_copy_bytes_to_smc(
+                               hwmgr->smumgr,
+                               smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU73_Discrete_DpmTable,
+                                       LowSclkInterruptThreshold),
+                               (uint8_t *)&low_sclk_interrupt_threshold,
+                               sizeof(uint32_t),
+                               SMC_RAM_END);
+       }
+       result = fiji_program_mem_timing_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE((result == 0),
+                       "Failed to program memory timing parameters!",
+                       );
+       return result;
+}
+
+uint32_t fiji_get_offsetof(uint32_t type, uint32_t member)
+{
+       switch (type) {
+       case SMU_SoftRegisters:
+               switch (member) {
+               case HandshakeDisables:
+                       return offsetof(SMU73_SoftRegisters, HandshakeDisables);
+               case VoltageChangeTimeout:
+                       return offsetof(SMU73_SoftRegisters, VoltageChangeTimeout);
+               case AverageGraphicsActivity:
+                       return offsetof(SMU73_SoftRegisters, AverageGraphicsActivity);
+               case PreVBlankGap:
+                       return offsetof(SMU73_SoftRegisters, PreVBlankGap);
+               case VBlankTimeout:
+                       return offsetof(SMU73_SoftRegisters, VBlankTimeout);
+               case UcodeLoadStatus:
+                       return offsetof(SMU73_SoftRegisters, UcodeLoadStatus);
+               }
+       case SMU_Discrete_DpmTable:
+               switch (member) {
+               case UvdBootLevel:
+                       return offsetof(SMU73_Discrete_DpmTable, UvdBootLevel);
+               case VceBootLevel:
+                       return offsetof(SMU73_Discrete_DpmTable, VceBootLevel);
+               case SamuBootLevel:
+                       return offsetof(SMU73_Discrete_DpmTable, SamuBootLevel);
+               case LowSclkInterruptThreshold:
+                       return offsetof(SMU73_Discrete_DpmTable, LowSclkInterruptThreshold);
+               }
+       }
+       printk("cant't get the offset of type %x member %x \n", type, member);
+       return 0;
+}
+
+uint32_t fiji_get_mac_definition(uint32_t value)
+{
+       switch (value) {
+       case SMU_MAX_LEVELS_GRAPHICS:
+               return SMU73_MAX_LEVELS_GRAPHICS;
+       case SMU_MAX_LEVELS_MEMORY:
+               return SMU73_MAX_LEVELS_MEMORY;
+       case SMU_MAX_LEVELS_LINK:
+               return SMU73_MAX_LEVELS_LINK;
+       case SMU_MAX_ENTRIES_SMIO:
+               return SMU73_MAX_ENTRIES_SMIO;
+       case SMU_MAX_LEVELS_VDDC:
+               return SMU73_MAX_LEVELS_VDDC;
+       case SMU_MAX_LEVELS_VDDGFX:
+               return SMU73_MAX_LEVELS_VDDGFX;
+       case SMU_MAX_LEVELS_VDDCI:
+               return SMU73_MAX_LEVELS_VDDCI;
+       case SMU_MAX_LEVELS_MVDD:
+               return SMU73_MAX_LEVELS_MVDD;
+       }
+
+       printk("cant't get the mac of %x \n", value);
+       return 0;
+}
+
+
+static int fiji_update_uvd_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t mm_boot_level_offset, mm_boot_level_value;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       smu_data->smc_state_table.UvdBootLevel = 0;
+       if (table_info->mm_dep_table->count > 0)
+               smu_data->smc_state_table.UvdBootLevel =
+                               (uint8_t) (table_info->mm_dep_table->count - 1);
+       mm_boot_level_offset = smu_data->smu7_data.dpm_table_start + offsetof(SMU73_Discrete_DpmTable,
+                                               UvdBootLevel);
+       mm_boot_level_offset /= 4;
+       mm_boot_level_offset *= 4;
+       mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset);
+       mm_boot_level_value &= 0x00FFFFFF;
+       mm_boot_level_value |= smu_data->smc_state_table.UvdBootLevel << 24;
+       cgs_write_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+       if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_UVDDPM) ||
+               phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StablePState))
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_UVDDPM_SetEnabledMask,
+                               (uint32_t)(1 << smu_data->smc_state_table.UvdBootLevel));
+       return 0;
+}
+
+static int fiji_update_vce_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t mm_boot_level_offset, mm_boot_level_value;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_StablePState))
+               smu_data->smc_state_table.VceBootLevel =
+                       (uint8_t) (table_info->mm_dep_table->count - 1);
+       else
+               smu_data->smc_state_table.VceBootLevel = 0;
+
+       mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
+                                       offsetof(SMU73_Discrete_DpmTable, VceBootLevel);
+       mm_boot_level_offset /= 4;
+       mm_boot_level_offset *= 4;
+       mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset);
+       mm_boot_level_value &= 0xFF00FFFF;
+       mm_boot_level_value |= smu_data->smc_state_table.VceBootLevel << 16;
+       cgs_write_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_VCEDPM_SetEnabledMask,
+                               (uint32_t)1 << smu_data->smc_state_table.VceBootLevel);
+       return 0;
+}
+
+static int fiji_update_samu_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t mm_boot_level_offset, mm_boot_level_value;
+
+
+       smu_data->smc_state_table.SamuBootLevel = 0;
+       mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU73_Discrete_DpmTable, SamuBootLevel);
+
+       mm_boot_level_offset /= 4;
+       mm_boot_level_offset *= 4;
+       mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset);
+       mm_boot_level_value &= 0xFFFFFF00;
+       mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0;
+       cgs_write_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StablePState))
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_SAMUDPM_SetEnabledMask,
+                               (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel));
+       return 0;
+}
+
+int fiji_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
+{
+       switch (type) {
+       case SMU_UVD_TABLE:
+               fiji_update_uvd_smc_table(hwmgr);
+               break;
+       case SMU_VCE_TABLE:
+               fiji_update_vce_smc_table(hwmgr);
+               break;
+       case SMU_SAMU_TABLE:
+               fiji_update_samu_smc_table(hwmgr);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+
+/**
+* Get the location of various tables inside the FW image.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always  0
+*/
+int fiji_process_firmware_header(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t tmp;
+       int result;
+       bool error = false;
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU73_Firmware_Header, DpmTable),
+                       &tmp, SMC_RAM_END);
+
+       if (0 == result)
+               smu_data->smu7_data.dpm_table_start = tmp;
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU73_Firmware_Header, SoftRegisters),
+                       &tmp, SMC_RAM_END);
+
+       if (!result) {
+               data->soft_regs_start = tmp;
+               smu_data->smu7_data.soft_regs_start = tmp;
+       }
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU73_Firmware_Header, mcRegisterTable),
+                       &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.mc_reg_table_start = tmp;
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU73_Firmware_Header, FanTable),
+                       &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.fan_table_start = tmp;
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU73_Firmware_Header, mcArbDramTimingTable),
+                       &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.arb_table_start = tmp;
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU73_Firmware_Header, Version),
+                       &tmp, SMC_RAM_END);
+
+       if (!result)
+               hwmgr->microcode_version_info.SMC = tmp;
+
+       error |= (0 != result);
+
+       return error ? -1 : 0;
+}
+
+int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+
+       /* Program additional LP registers
+        * that are no longer programmed by VBIOS
+        */
+       cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
+
+       return 0;
+}
+
+bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr)
+{
+       return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
+                       CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
+                       ? true : false;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.h b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.h
new file mode 100644 (file)
index 0000000..d30d150
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015 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 FIJI_SMC_H
+#define FIJI_SMC_H
+
+#include "smumgr.h"
+#include "smu73.h"
+
+struct fiji_pt_defaults {
+       uint8_t   SviLoadLineEn;
+       uint8_t   SviLoadLineVddC;
+       uint8_t   TDC_VDDC_ThrottleReleaseLimitPerc;
+       uint8_t   TDC_MAWt;
+       uint8_t   TdcWaterfallCtl;
+       uint8_t   DTEAmbientTempBase;
+};
+
+int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr);
+int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr);
+int fiji_init_smc_table(struct pp_hwmgr *hwmgr);
+int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr);
+int fiji_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type);
+int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr);
+uint32_t fiji_get_offsetof(uint32_t type, uint32_t member);
+uint32_t fiji_get_mac_definition(uint32_t value);
+int fiji_process_firmware_header(struct pp_hwmgr *hwmgr);
+int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr);
+bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr);
+
+#endif
+
old mode 100644 (file)
new mode 100755 (executable)
index 8e52a2e..02fe1df
@@ -38,6 +38,7 @@
 #include "bif/bif_5_0_sh_mask.h"
 #include "pp_debug.h"
 #include "fiji_pwrvirus.h"
+#include "fiji_smc.h"
 
 #define AVFS_EN_MSB                                        1568
 #define AVFS_EN_LSB                                        1568
@@ -57,509 +58,6 @@ static const struct SMU73_Discrete_GraphicsLevel avfs_graphics_level[8] = {
                { 0xf811d047, 0x80380100,   0x01,     0x00,   0x1e00, 0x00000610, 0x87020000, 0x21680000, 0x12000000,   0,      0,   0x0c,   0x01,       0x01,        0x01,      0x00,   0x00,      0x00,     0x00 }
 };
 
-static enum cgs_ucode_id fiji_convert_fw_type_to_cgs(uint32_t fw_type)
-{
-       enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
-
-       switch (fw_type) {
-       case UCODE_ID_SMU:
-               result = CGS_UCODE_ID_SMU;
-               break;
-       case UCODE_ID_SDMA0:
-               result = CGS_UCODE_ID_SDMA0;
-               break;
-       case UCODE_ID_SDMA1:
-               result = CGS_UCODE_ID_SDMA1;
-               break;
-       case UCODE_ID_CP_CE:
-               result = CGS_UCODE_ID_CP_CE;
-               break;
-       case UCODE_ID_CP_PFP:
-               result = CGS_UCODE_ID_CP_PFP;
-               break;
-       case UCODE_ID_CP_ME:
-               result = CGS_UCODE_ID_CP_ME;
-               break;
-       case UCODE_ID_CP_MEC:
-               result = CGS_UCODE_ID_CP_MEC;
-               break;
-       case UCODE_ID_CP_MEC_JT1:
-               result = CGS_UCODE_ID_CP_MEC_JT1;
-               break;
-       case UCODE_ID_CP_MEC_JT2:
-               result = CGS_UCODE_ID_CP_MEC_JT2;
-               break;
-       case UCODE_ID_RLC_G:
-               result = CGS_UCODE_ID_RLC_G;
-               break;
-       default:
-               break;
-       }
-
-       return result;
-}
-/**
-* Set the address for reading/writing the SMC SRAM space.
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    smc_addr the address in the SMC RAM to access.
-*/
-static int fiji_set_smc_sram_address(struct pp_smumgr *smumgr,
-               uint32_t smc_addr, uint32_t limit)
-{
-       PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)),
-                       "SMC address must be 4 byte aligned.", return -EINVAL;);
-       PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)),
-                       "SMC address is beyond the SMC RAM area.", return -EINVAL;);
-
-       cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smc_addr);
-       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
-
-       return 0;
-}
-
-/**
-* Copy bytes from an array into the SMC RAM space.
-*
-* @param    smumgr  the address of the powerplay SMU manager.
-* @param    smcStartAddress the start address in the SMC RAM to copy bytes to.
-* @param    src the byte array to copy the bytes from.
-* @param    byteCount the number of bytes to copy.
-*/
-int fiji_copy_bytes_to_smc(struct pp_smumgr *smumgr,
-               uint32_t smcStartAddress, const uint8_t *src,
-               uint32_t byteCount, uint32_t limit)
-{
-       int result;
-       uint32_t data, originalData;
-       uint32_t addr, extraShift;
-
-       PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)),
-                       "SMC address must be 4 byte aligned.", return -EINVAL;);
-       PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)),
-                       "SMC address is beyond the SMC RAM area.", return -EINVAL;);
-
-       addr = smcStartAddress;
-
-       while (byteCount >= 4) {
-               /* Bytes are written into the SMC addres space with the MSB first. */
-               data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
-
-               result = fiji_set_smc_sram_address(smumgr, addr, limit);
-               if (result)
-                       return result;
-
-               cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
-
-               src += 4;
-               byteCount -= 4;
-               addr += 4;
-       }
-
-       if (byteCount) {
-               /* Now write the odd bytes left.
-                * Do a read modify write cycle.
-                */
-               data = 0;
-
-               result = fiji_set_smc_sram_address(smumgr, addr, limit);
-               if (result)
-                       return result;
-
-               originalData = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
-               extraShift = 8 * (4 - byteCount);
-
-               while (byteCount > 0) {
-                       /* Bytes are written into the SMC addres
-                        * space with the MSB first.
-                        */
-                       data = (0x100 * data) + *src++;
-                       byteCount--;
-               }
-               data <<= extraShift;
-               data |= (originalData & ~((~0UL) << extraShift));
-
-               result = fiji_set_smc_sram_address(smumgr, addr, limit);
-               if (!result)
-                       return result;
-
-               cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
-       }
-       return 0;
-}
-
-int fiji_program_jump_on_start(struct pp_smumgr *smumgr)
-{
-       static const unsigned char data[] = { 0xE0, 0x00, 0x80, 0x40 };
-
-       fiji_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data) + 1);
-
-       return 0;
-}
-
-/**
-* Return if the SMC is currently running.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-*/
-bool fiji_is_smc_ram_running(struct pp_smumgr *smumgr)
-{
-       return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device,
-                       CGS_IND_REG__SMC,
-                       SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
-                       && (0x20100 <= cgs_read_ind_register(smumgr->device,
-                                       CGS_IND_REG__SMC, ixSMC_PC_C)));
-}
-
-/**
-* Send a message to the SMC, and wait for its response.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    msg the message to send.
-* @return   The response that came from the SMC.
-*/
-int fiji_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
-{
-       if (!fiji_is_smc_ram_running(smumgr))
-               return -1;
-
-       if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
-               printk(KERN_ERR "Failed to send Previous Message.");
-               SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-       }
-
-       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-
-       return 0;
-}
-
-/**
- * Send a message to the SMC with parameter
- * @param    smumgr:  the address of the powerplay hardware manager.
- * @param    msg: the message to send.
- * @param    parameter: the parameter to send
- * @return   The response that came from the SMC.
- */
-int fiji_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
-               uint16_t msg, uint32_t parameter)
-{
-       if (!fiji_is_smc_ram_running(smumgr))
-               return -1;
-
-       if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
-               printk(KERN_ERR "Failed to send Previous Message.");
-               SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-       }
-
-       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
-       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-
-       return 0;
-}
-
-
-/**
-* Send a message to the SMC with parameter, do not wait for response
-*
-* @param    smumgr:  the address of the powerplay hardware manager.
-* @param    msg: the message to send.
-* @param    parameter: the parameter to send
-* @return   The response that came from the SMC.
-*/
-int fiji_send_msg_to_smc_with_parameter_without_waiting(
-               struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
-{
-       if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
-               printk(KERN_ERR "Failed to send Previous Message.");
-               SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-       }
-       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
-       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
-
-       return 0;
-}
-
-/**
-* Uploads the SMU firmware from .hex file
-*
-* @param    smumgr  the address of the powerplay SMU manager.
-* @return   0 or -1.
-*/
-
-static int fiji_upload_smu_firmware_image(struct pp_smumgr *smumgr)
-{
-       const uint8_t *src;
-       uint32_t byte_count;
-       uint32_t *data;
-       struct cgs_firmware_info info = {0};
-
-       cgs_get_firmware_info(smumgr->device,
-                       fiji_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
-
-       if (info.image_size & 3) {
-               printk(KERN_ERR "SMC ucode is not 4 bytes aligned\n");
-               return -EINVAL;
-       }
-
-       if (info.image_size > FIJI_SMC_SIZE) {
-               printk(KERN_ERR "SMC address is beyond the SMC RAM area\n");
-               return -EINVAL;
-       }
-
-       cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, 0x20000);
-       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
-
-       byte_count = info.image_size;
-       src = (const uint8_t *)info.kptr;
-
-       data = (uint32_t *)src;
-       for (; byte_count >= 4; data++, byte_count -= 4)
-               cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data[0]);
-
-       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
-       return 0;
-}
-
-/**
-* Read a 32bit value from the SMC SRAM space.
-* ALL PARAMETERS ARE IN HOST BYTE ORDER.
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    smc_addr the address in the SMC RAM to access.
-* @param    value and output parameter for the data read from the SMC SRAM.
-*/
-int fiji_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
-               uint32_t *value, uint32_t limit)
-{
-       int     result = fiji_set_smc_sram_address(smumgr, smc_addr, limit);
-
-       if (result)
-               return result;
-
-       *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
-       return 0;
-}
-
-/**
-* Write a 32bit value to the SMC SRAM space.
-* ALL PARAMETERS ARE IN HOST BYTE ORDER.
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    smc_addr the address in the SMC RAM to access.
-* @param    value to write to the SMC SRAM.
-*/
-int fiji_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
-               uint32_t value, uint32_t limit)
-{
-       int result;
-
-       result = fiji_set_smc_sram_address(smumgr, smc_addr, limit);
-
-       if (result)
-               return result;
-
-       cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value);
-       return 0;
-}
-
-static uint32_t fiji_get_mask_for_firmware_type(uint32_t fw_type)
-{
-       uint32_t result = 0;
-
-       switch (fw_type) {
-       case UCODE_ID_SDMA0:
-               result = UCODE_ID_SDMA0_MASK;
-               break;
-       case UCODE_ID_SDMA1:
-               result = UCODE_ID_SDMA1_MASK;
-               break;
-       case UCODE_ID_CP_CE:
-               result = UCODE_ID_CP_CE_MASK;
-               break;
-       case UCODE_ID_CP_PFP:
-               result = UCODE_ID_CP_PFP_MASK;
-               break;
-       case UCODE_ID_CP_ME:
-               result = UCODE_ID_CP_ME_MASK;
-               break;
-       case UCODE_ID_CP_MEC_JT1:
-               result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK;
-               break;
-       case UCODE_ID_CP_MEC_JT2:
-               result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT2_MASK;
-               break;
-       case UCODE_ID_RLC_G:
-               result = UCODE_ID_RLC_G_MASK;
-               break;
-       default:
-               printk(KERN_ERR "UCode type is out of range!");
-               result = 0;
-       }
-
-       return result;
-}
-
-/* Populate one firmware image to the data structure */
-static int fiji_populate_single_firmware_entry(struct pp_smumgr *smumgr,
-               uint32_t fw_type, struct SMU_Entry *entry)
-{
-       int result;
-       struct cgs_firmware_info info = {0};
-
-       result = cgs_get_firmware_info(
-                       smumgr->device,
-                       fiji_convert_fw_type_to_cgs(fw_type),
-                       &info);
-
-       if (!result) {
-               entry->version = 0;
-               entry->id = (uint16_t)fw_type;
-               entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
-               entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
-               entry->meta_data_addr_high = 0;
-               entry->meta_data_addr_low = 0;
-               entry->data_size_byte = info.image_size;
-               entry->num_register_entries = 0;
-
-               if (fw_type == UCODE_ID_RLC_G)
-                       entry->flags = 1;
-               else
-                       entry->flags = 0;
-       }
-
-       return result;
-}
-
-static int fiji_request_smu_load_fw(struct pp_smumgr *smumgr)
-{
-       struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
-       uint32_t fw_to_load;
-       struct SMU_DRAMData_TOC *toc;
-
-       if (priv->soft_regs_start)
-               cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
-                               priv->soft_regs_start +
-                               offsetof(SMU73_SoftRegisters, UcodeLoadStatus),
-                               0x0);
-
-       toc = (struct SMU_DRAMData_TOC *)priv->header;
-       toc->num_entries = 0;
-       toc->structure_version = 1;
-
-       PP_ASSERT_WITH_CODE(
-                       0 == fiji_populate_single_firmware_entry(smumgr,
-                                       UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]),
-                       "Failed to Get Firmware Entry.\n" , return -1 );
-       PP_ASSERT_WITH_CODE(
-                       0 == fiji_populate_single_firmware_entry(smumgr,
-                                       UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]),
-                       "Failed to Get Firmware Entry.\n" , return -1 );
-       PP_ASSERT_WITH_CODE(
-                       0 == fiji_populate_single_firmware_entry(smumgr,
-                                       UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
-                       "Failed to Get Firmware Entry.\n" , return -1 );
-       PP_ASSERT_WITH_CODE(
-                       0 == fiji_populate_single_firmware_entry(smumgr,
-                                       UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
-                       "Failed to Get Firmware Entry.\n" , return -1 );
-       PP_ASSERT_WITH_CODE(
-                       0 == fiji_populate_single_firmware_entry(smumgr,
-                                       UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
-                       "Failed to Get Firmware Entry.\n" , return -1 );
-       PP_ASSERT_WITH_CODE(
-                       0 == fiji_populate_single_firmware_entry(smumgr,
-                                       UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
-                                       "Failed to Get Firmware Entry.\n" , return -1 );
-       PP_ASSERT_WITH_CODE(
-                       0 == fiji_populate_single_firmware_entry(smumgr,
-                                       UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
-                                       "Failed to Get Firmware Entry.\n" , return -1 );
-       PP_ASSERT_WITH_CODE(
-                       0 == fiji_populate_single_firmware_entry(smumgr,
-                                       UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
-                                       "Failed to Get Firmware Entry.\n" , return -1 );
-       PP_ASSERT_WITH_CODE(
-                       0 == fiji_populate_single_firmware_entry(smumgr,
-                                       UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
-                                       "Failed to Get Firmware Entry.\n" , return -1 );
-
-       fiji_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI,
-                       priv->header_buffer.mc_addr_high);
-       fiji_send_msg_to_smc_with_parameter(smumgr,PPSMC_MSG_DRV_DRAM_ADDR_LO,
-                       priv->header_buffer.mc_addr_low);
-
-       fw_to_load = 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_MASK
-                       + UCODE_ID_CP_MEC_JT1_MASK
-                       + UCODE_ID_CP_MEC_JT2_MASK;
-
-       if (fiji_send_msg_to_smc_with_parameter(smumgr,
-                       PPSMC_MSG_LoadUcodes, fw_to_load))
-               printk(KERN_ERR "Fail to Request SMU Load uCode");
-
-       return 0;
-}
-
-
-/* Check if the FW has been loaded, SMU will not return
- * if loading has not finished.
- */
-static int fiji_check_fw_load_finish(struct pp_smumgr *smumgr,
-               uint32_t fw_type)
-{
-       struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
-       uint32_t mask = fiji_get_mask_for_firmware_type(fw_type);
-
-       /* Check SOFT_REGISTERS_TABLE_28.UcodeLoadStatus */
-       if (smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX,
-                       priv->soft_regs_start +
-                       offsetof(SMU73_SoftRegisters, UcodeLoadStatus),
-                       mask, mask)) {
-               printk(KERN_ERR "check firmware loading failed\n");
-               return -EINVAL;
-       }
-       return 0;
-}
-
-
-static int fiji_reload_firmware(struct pp_smumgr *smumgr)
-{
-       return smumgr->smumgr_funcs->start_smu(smumgr);
-}
-
-static bool fiji_is_hw_virtualization_enabled(struct pp_smumgr *smumgr)
-{
-       uint32_t value;
-
-       value = cgs_read_register(smumgr->device, mmBIF_IOV_FUNC_IDENTIFIER);
-       if (value & BIF_IOV_FUNC_IDENTIFIER__IOV_ENABLE_MASK) {
-               /* driver reads on SR-IOV enabled PF: 0x80000000
-                * driver reads on SR-IOV enabled VF: 0x80000001
-                * driver reads on SR-IOV disabled:   0x00000000
-                */
-               return true;
-       }
-       return false;
-}
-
-static int fiji_request_smu_specific_fw_load(struct pp_smumgr *smumgr, uint32_t fw_type)
-{
-       if (fiji_is_hw_virtualization_enabled(smumgr)) {
-               uint32_t masks = fiji_get_mask_for_firmware_type(fw_type);
-               if (fiji_send_msg_to_smc_with_parameter_without_waiting(smumgr,
-                               PPSMC_MSG_LoadUcodes, masks))
-                       printk(KERN_ERR "Fail to Request SMU Load uCode");
-       }
-       /* For non-virtualization cases,
-        * SMU loads all FWs at once in fiji_request_smu_load_fw.
-        */
-       return 0;
-}
-
 static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
 {
        int result = 0;
@@ -571,7 +69,7 @@ static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
        SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
                        SMC_SYSCON_RESET_CNTL, rst_reg, 1);
 
-       result = fiji_upload_smu_firmware_image(smumgr);
+       result = smu7_upload_smu_firmware_image(smumgr);
        if (result)
                return result;
 
@@ -610,8 +108,8 @@ static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
                        SMU_STATUS, SMU_DONE, 0);
 
        /* Check pass/failed indicator */
-       if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
-                       SMU_STATUS, SMU_PASS)) {
+       if (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+                       SMU_STATUS, SMU_PASS) != 1) {
                PP_ASSERT_WITH_CODE(false,
                                "SMU Firmware start failed!", return -1);
        }
@@ -639,12 +137,12 @@ static int fiji_start_smu_in_non_protection_mode(struct pp_smumgr *smumgr)
        SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
                        SMC_SYSCON_RESET_CNTL, rst_reg, 1);
 
-       result = fiji_upload_smu_firmware_image(smumgr);
+       result = smu7_upload_smu_firmware_image(smumgr);
        if (result)
                return result;
 
        /* Set smc instruct start point at 0x0 */
-       fiji_program_jump_on_start(smumgr);
+       smu7_program_jump_on_start(smumgr);
 
        /* Enable clock */
        SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
@@ -698,15 +196,15 @@ static int fiji_start_avfs_btc(struct pp_smumgr *smumgr)
 
        priv->avfs.AvfsBtcStatus = AVFS_BTC_STARTED;
        if (priv->avfs.AvfsBtcParam) {
-               if (!fiji_send_msg_to_smc_with_parameter(smumgr,
+               if (!smum_send_msg_to_smc_with_parameter(smumgr,
                                PPSMC_MSG_PerformBtc, priv->avfs.AvfsBtcParam)) {
-                       if (!fiji_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs)) {
+                       if (!smum_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs)) {
                                priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_UNSAVED;
                                result = 0;
                        } else {
                                printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] Attempt"
                                                " to Enable AVFS Failed!");
-                               fiji_send_msg_to_smc(smumgr, PPSMC_MSG_DisableAvfs);
+                               smum_send_msg_to_smc(smumgr, PPSMC_MSG_DisableAvfs);
                                result = -1;
                        }
                } else {
@@ -736,7 +234,7 @@ int fiji_setup_pm_fuse_for_avfs(struct pp_smumgr *smumgr)
        charz_freq = 0x30750000; /* In 10KHz units 0x00007530 Actual value */
        inversion_voltage = 0x1A04; /* mV Q14.2 0x41A Actual value */
 
-       PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr,
+       PP_ASSERT_WITH_CODE(0 == smu7_read_smc_sram_dword(smumgr,
                        SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU73_Firmware_Header,
                                        PmFuseTable), &table_start, 0x40000),
                        "[AVFS][Fiji_SetupGfxLvlStruct] SMU could not communicate "
@@ -748,13 +246,13 @@ int fiji_setup_pm_fuse_for_avfs(struct pp_smumgr *smumgr)
        inversion_voltage_addr = table_start +
                        offsetof(struct SMU73_Discrete_PmFuses, InversionVoltage);
 
-       result = fiji_copy_bytes_to_smc(smumgr, charz_freq_addr,
+       result = smu7_copy_bytes_to_smc(smumgr, charz_freq_addr,
                        (uint8_t *)(&charz_freq), sizeof(charz_freq), 0x40000);
        PP_ASSERT_WITH_CODE(0 == result,
                        "[AVFS][fiji_setup_pm_fuse_for_avfs] charz_freq could not "
                        "be populated.", return -1;);
 
-       result = fiji_copy_bytes_to_smc(smumgr, inversion_voltage_addr,
+       result = smu7_copy_bytes_to_smc(smumgr, inversion_voltage_addr,
                        (uint8_t *)(&inversion_voltage), sizeof(inversion_voltage), 0x40000);
        PP_ASSERT_WITH_CODE(0 == result, "[AVFS][fiji_setup_pm_fuse_for_avfs] "
                        "charz_freq could not be populated.", return -1;);
@@ -769,7 +267,7 @@ int fiji_setup_graphics_level_structure(struct pp_smumgr *smumgr)
        uint32_t level_addr, vr_config_addr;
        uint32_t level_size = sizeof(avfs_graphics_level);
 
-       PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr,
+       PP_ASSERT_WITH_CODE(0 == smu7_read_smc_sram_dword(smumgr,
                        SMU7_FIRMWARE_HEADER_LOCATION +
                        offsetof(SMU73_Firmware_Header, DpmTable),
                        &table_start, 0x40000),
@@ -784,7 +282,7 @@ int fiji_setup_graphics_level_structure(struct pp_smumgr *smumgr)
        vr_config_addr = table_start +
                        offsetof(SMU73_Discrete_DpmTable, VRConfig);
 
-       PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, vr_config_addr,
+       PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, vr_config_addr,
                        (uint8_t *)&vr_config, sizeof(int32_t), 0x40000),
                        "[AVFS][Fiji_SetupGfxLvlStruct] Problems copying "
                        "vr_config value over to SMC",
@@ -792,7 +290,7 @@ int fiji_setup_graphics_level_structure(struct pp_smumgr *smumgr)
 
        level_addr = table_start + offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
 
-       PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, level_addr,
+       PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, level_addr,
                        (uint8_t *)(&avfs_graphics_level), level_size, 0x40000),
                        "[AVFS][Fiji_SetupGfxLvlStruct] Copying of DPM table failed!",
                        return -1;);
@@ -839,13 +337,13 @@ int fiji_avfs_event_mgr(struct pp_smumgr *smumgr, bool smu_started)
                break;
        case AVFS_BTC_COMPLETED_RESTORED: /*S3 State - Post SMU Start*/
                priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR;
-               PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr,
-                               PPSMC_MSG_VftTableIsValid),
+               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(smumgr,
+                               0x666),
                                "[AVFS][fiji_avfs_event_mgr] SMU did not respond "
                                "correctly to VftTableIsValid Msg",
                                return -1;);
                priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR;
-               PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr,
+               PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(smumgr,
                                PPSMC_MSG_EnableAvfs),
                                "[AVFS][fiji_avfs_event_mgr] SMU did not respond "
                                "correctly to EnableAvfs Message Msg",
@@ -898,7 +396,7 @@ static int fiji_start_smu(struct pp_smumgr *smumgr)
        struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
 
        /* Only start SMC if SMC RAM is not running */
-       if (!fiji_is_smc_ram_running(smumgr)) {
+       if (!smu7_is_smc_ram_running(smumgr)) {
                fiji_avfs_event_mgr(smumgr, false);
 
                /* Check if SMU is running in protected mode */
@@ -929,12 +427,12 @@ static int fiji_start_smu(struct pp_smumgr *smumgr)
        /* Setup SoftRegsStart here for register lookup in case
         * DummyBackEnd is used and ProcessFirmwareHeader is not executed
         */
-       fiji_read_smc_sram_dword(smumgr,
+       smu7_read_smc_sram_dword(smumgr,
                        SMU7_FIRMWARE_HEADER_LOCATION +
                        offsetof(SMU73_Firmware_Header, SoftRegisters),
-                       &(priv->soft_regs_start), 0x40000);
+                       &(priv->smu7_data.soft_regs_start), 0x40000);
 
-       result = fiji_request_smu_load_fw(smumgr);
+       result = smu7_request_smu_load_fw(smumgr);
 
        return result;
 }
@@ -963,28 +461,10 @@ 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);
-       uint64_t mc_addr;
-
-       priv->header_buffer.data_size =
-                       ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
-       smu_allocate_memory(smumgr->device,
-                       priv->header_buffer.data_size,
-                       CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
-                       PAGE_SIZE,
-                       &mc_addr,
-                       &priv->header_buffer.kaddr,
-                       &priv->header_buffer.handle);
-
-       priv->header = priv->header_buffer.kaddr;
-       priv->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
-       priv->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
-
-       PP_ASSERT_WITH_CODE((NULL != priv->header),
-                       "Out of memory.",
-                       kfree(smumgr->backend);
-                       cgs_free_gpu_mem(smumgr->device,
-                       (cgs_handle_t)priv->header_buffer.handle);
-                       return -1);
+       int i;
+
+       if (smu7_init(smumgr))
+               return -EINVAL;
 
        priv->avfs.AvfsBtcStatus = AVFS_BTC_BOOT;
        if (fiji_is_hw_avfs_present(smumgr))
@@ -999,37 +479,35 @@ static int fiji_smu_init(struct pp_smumgr *smumgr)
        else
                priv->avfs.AvfsBtcStatus = AVFS_BTC_NOTSUPPORTED;
 
-       priv->acpi_optimization = 1;
+       for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++)
+               priv->activity_target[i] = 30;
 
        return 0;
 }
 
-static int fiji_smu_fini(struct pp_smumgr *smumgr)
-{
-       struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
-
-       smu_free_memory(smumgr->device, (void *)priv->header_buffer.handle);
-
-       if (smumgr->backend) {
-               kfree(smumgr->backend);
-               smumgr->backend = NULL;
-       }
-
-       cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU);
-       return 0;
-}
 
 static const struct pp_smumgr_func fiji_smu_funcs = {
        .smu_init = &fiji_smu_init,
-       .smu_fini = &fiji_smu_fini,
+       .smu_fini = &smu7_smu_fini,
        .start_smu = &fiji_start_smu,
-       .check_fw_load_finish = &fiji_check_fw_load_finish,
-       .request_smu_load_fw = &fiji_reload_firmware,
-       .request_smu_load_specific_fw = &fiji_request_smu_specific_fw_load,
-       .send_msg_to_smc = &fiji_send_msg_to_smc,
-       .send_msg_to_smc_with_parameter = &fiji_send_msg_to_smc_with_parameter,
+       .check_fw_load_finish = &smu7_check_fw_load_finish,
+       .request_smu_load_fw = &smu7_reload_firmware,
+       .request_smu_load_specific_fw = NULL,
+       .send_msg_to_smc = &smu7_send_msg_to_smc,
+       .send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
        .download_pptable_settings = NULL,
        .upload_pptable_settings = NULL,
+       .update_smc_table = fiji_update_smc_table,
+       .get_offsetof = fiji_get_offsetof,
+       .process_firmware_header = fiji_process_firmware_header,
+       .init_smc_table = fiji_init_smc_table,
+       .update_sclk_threshold = fiji_update_sclk_threshold,
+       .thermal_setup_fan_table = fiji_thermal_setup_fan_table,
+       .populate_all_graphic_levels = fiji_populate_all_graphic_levels,
+       .populate_all_memory_levels = fiji_populate_all_memory_levels,
+       .get_mac_definition = fiji_get_mac_definition,
+       .initialize_mc_reg_table = fiji_initialize_mc_reg_table,
+       .is_dpm_running = fiji_is_dpm_running,
 };
 
 int fiji_smum_init(struct pp_smumgr *smumgr)
index b4eb483..adcbdfb 100644 (file)
 #ifndef _FIJI_SMUMANAGER_H_
 #define _FIJI_SMUMANAGER_H_
 
+#include "smu73_discrete.h"
+#include <pp_endian.h>
+#include "smu7_smumgr.h"
+
+
 
 struct fiji_smu_avfs {
        enum AVFS_BTC_STATUS AvfsBtcStatus;
        uint32_t           AvfsBtcParam;
 };
 
-struct fiji_buffer_entry {
-       uint32_t data_size;
-       uint32_t mc_addr_low;
-       uint32_t mc_addr_high;
-       void *kaddr;
-       unsigned long  handle;
-};
 
 struct fiji_smumgr {
-       uint8_t        *header;
-       uint8_t        *mec_image;
-       uint32_t        soft_regs_start;
+       struct smu7_smumgr                   smu7_data;
+
        struct fiji_smu_avfs avfs;
-       uint32_t        acpi_optimization;
+       struct SMU73_Discrete_DpmTable       smc_state_table;
+       struct SMU73_Discrete_Ulv            ulv_setting;
+       struct SMU73_Discrete_PmFuses  power_tune_table;
+       const struct fiji_pt_defaults  *power_tune_defaults;
+       uint32_t        activity_target[SMU73_MAX_LEVELS_GRAPHICS];
 
-       struct fiji_buffer_entry header_buffer;
 };
 
-int fiji_smum_init(struct pp_smumgr *smumgr);
-int fiji_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
-               uint32_t *value, uint32_t limit);
-int fiji_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
-               uint32_t value, uint32_t limit);
-int fiji_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smcStartAddress,
-               const uint8_t *src,     uint32_t byteCount, uint32_t limit);
+
 
 #endif
 
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c
new file mode 100644 (file)
index 0000000..eda802b
--- /dev/null
@@ -0,0 +1,2576 @@
+/*
+ * Copyright 2015 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 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.
+ * 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.
+ *
+ *
+ */
+
+#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"
+#include "pp_endian.h"
+#include "smu7_ppsmc.h"
+
+#include "smu71_discrete.h"
+
+#include "smu/smu_7_1_1_d.h"
+#include "smu/smu_7_1_1_sh_mask.h"
+
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+
+#include "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+#include "processpptables.h"
+
+#include "iceland_smumgr.h"
+
+#define VOLTAGE_SCALE 4
+#define POWERTUNE_DEFAULT_SET_MAX    1
+#define VOLTAGE_VID_OFFSET_SCALE1   625
+#define VOLTAGE_VID_OFFSET_SCALE2   100
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define VDDC_VDDCI_DELTA            200
+
+#define DEVICE_ID_VI_ICELAND_M_6900    0x6900
+#define DEVICE_ID_VI_ICELAND_M_6901    0x6901
+#define DEVICE_ID_VI_ICELAND_M_6902    0x6902
+#define DEVICE_ID_VI_ICELAND_M_6903    0x6903
+
+static const struct iceland_pt_defaults defaults_iceland = {
+       /*
+        * sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc,
+        * TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT
+        */
+       1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
+       { 0x79,  0x253, 0x25D, 0xAE,  0x72,  0x80,  0x83,  0x86,  0x6F,  0xC8,  0xC9,  0xC9,  0x2F,  0x4D,  0x61  },
+       { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
+};
+
+/* 35W - XT, XTL */
+static const struct iceland_pt_defaults defaults_icelandxt = {
+       /*
+        * sviLoadLIneEn, SviLoadLineVddC,
+        * TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
+        * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,
+        * BAPM_TEMP_GRADIENT
+        */
+       1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0,
+       { 0xA7,  0x0, 0x0, 0xB5,  0x0, 0x0, 0x9F,  0x0, 0x0, 0xD6,  0x0, 0x0, 0xD7,  0x0, 0x0},
+       { 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0}
+};
+
+/* 25W - PRO, LE */
+static const struct iceland_pt_defaults defaults_icelandpro = {
+       /*
+        * sviLoadLIneEn, SviLoadLineVddC,
+        * TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
+        * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,
+        * BAPM_TEMP_GRADIENT
+        */
+       1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0,
+       { 0xB7,  0x0, 0x0, 0xC3,  0x0, 0x0, 0xB5,  0x0, 0x0, 0xEA,  0x0, 0x0, 0xE6,  0x0, 0x0},
+       { 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0}
+};
+
+static void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
+{
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       struct cgs_system_info sys_info = {0};
+       uint32_t dev_id;
+
+       sys_info.size = sizeof(struct cgs_system_info);
+       sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV;
+       cgs_query_system_info(hwmgr->device, &sys_info);
+       dev_id = (uint32_t)sys_info.value;
+
+       switch (dev_id) {
+       case DEVICE_ID_VI_ICELAND_M_6900:
+       case DEVICE_ID_VI_ICELAND_M_6903:
+               smu_data->power_tune_defaults = &defaults_icelandxt;
+               break;
+
+       case DEVICE_ID_VI_ICELAND_M_6901:
+       case DEVICE_ID_VI_ICELAND_M_6902:
+               smu_data->power_tune_defaults = &defaults_icelandpro;
+               break;
+       default:
+               smu_data->power_tune_defaults = &defaults_iceland;
+               pr_warning("Unknown V.I. Device ID.\n");
+               break;
+       }
+       return;
+}
+
+static int iceland_populate_svi_load_line(struct pp_hwmgr *hwmgr)
+{
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       const struct iceland_pt_defaults *defaults = smu_data->power_tune_defaults;
+
+       smu_data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
+       smu_data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddc;
+       smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
+       smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
+
+       return 0;
+}
+
+static int iceland_populate_tdc_limit(struct pp_hwmgr *hwmgr)
+{
+       uint16_t tdc_limit;
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       const struct iceland_pt_defaults *defaults = smu_data->power_tune_defaults;
+
+       tdc_limit = (uint16_t)(hwmgr->dyn_state.cac_dtp_table->usTDC * 256);
+       smu_data->power_tune_table.TDC_VDDC_PkgLimit =
+                       CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
+       smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
+                       defaults->tdc_vddc_throttle_release_limit_perc;
+       smu_data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
+
+       return 0;
+}
+
+static int iceland_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
+{
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       const struct iceland_pt_defaults *defaults = smu_data->power_tune_defaults;
+       uint32_t temp;
+
+       if (smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       fuse_table_offset +
+                       offsetof(SMU71_Discrete_PmFuses, TdcWaterfallCtl),
+                       (uint32_t *)&temp, SMC_RAM_END))
+               PP_ASSERT_WITH_CODE(false,
+                               "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
+                               return -EINVAL);
+       else
+               smu_data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
+
+       return 0;
+}
+
+static int iceland_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
+{
+       return 0;
+}
+
+static int iceland_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
+{
+       int i;
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+
+       /* Currently not used. Set all to zero. */
+       for (i = 0; i < 8; i++)
+               smu_data->power_tune_table.GnbLPML[i] = 0;
+
+       return 0;
+}
+
+static int iceland_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
+{
+       return 0;
+}
+
+static int iceland_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
+{
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       uint16_t HiSidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd;
+       uint16_t LoSidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd;
+       struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table;
+
+       HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
+       LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
+
+       smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
+                       CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
+       smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
+                       CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
+
+       return 0;
+}
+
+static int iceland_populate_bapm_vddc_vid_sidd(struct pp_hwmgr *hwmgr)
+{
+       int i;
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       uint8_t *hi_vid = smu_data->power_tune_table.BapmVddCVidHiSidd;
+       uint8_t *lo_vid = smu_data->power_tune_table.BapmVddCVidLoSidd;
+
+       PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.cac_leakage_table,
+                           "The CAC Leakage table does not exist!", return -EINVAL);
+       PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count <= 8,
+                           "There should never be more than 8 entries for BapmVddcVid!!!", return -EINVAL);
+       PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count == hwmgr->dyn_state.vddc_dependency_on_sclk->count,
+                           "CACLeakageTable->count and VddcDependencyOnSCLk->count not equal", return -EINVAL);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EVV)) {
+               for (i = 0; (uint32_t) i < hwmgr->dyn_state.cac_leakage_table->count; i++) {
+                       lo_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc1);
+                       hi_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc2);
+               }
+       } else {
+               PP_ASSERT_WITH_CODE(false, "Iceland should always support EVV", return -EINVAL);
+       }
+
+       return 0;
+}
+
+static int iceland_populate_vddc_vid(struct pp_hwmgr *hwmgr)
+{
+       int i;
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       uint8_t *vid = smu_data->power_tune_table.VddCVid;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       PP_ASSERT_WITH_CODE(data->vddc_voltage_table.count <= 8,
+               "There should never be more than 8 entries for VddcVid!!!",
+               return -EINVAL);
+
+       for (i = 0; i < (int)data->vddc_voltage_table.count; i++) {
+               vid[i] = convert_to_vid(data->vddc_voltage_table.entries[i].value);
+       }
+
+       return 0;
+}
+
+
+
+static int iceland_populate_pm_fuses(struct pp_hwmgr *hwmgr)
+{
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t pm_fuse_table_offset;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PowerContainment)) {
+               if (smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU71_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU71_Firmware_Header, PmFuseTable),
+                               &pm_fuse_table_offset, SMC_RAM_END))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to get pm_fuse_table_offset Failed!",
+                                       return -EINVAL);
+
+               /* DW0 - DW3 */
+               if (iceland_populate_bapm_vddc_vid_sidd(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate bapm vddc vid Failed!",
+                                       return -EINVAL);
+
+               /* DW4 - DW5 */
+               if (iceland_populate_vddc_vid(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate vddc vid Failed!",
+                                       return -EINVAL);
+
+               /* DW6 */
+               if (iceland_populate_svi_load_line(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate SviLoadLine Failed!",
+                                       return -EINVAL);
+               /* DW7 */
+               if (iceland_populate_tdc_limit(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate TDCLimit Failed!", return -EINVAL);
+               /* DW8 */
+               if (iceland_populate_dw8(hwmgr, pm_fuse_table_offset))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate TdcWaterfallCtl, "
+                                       "LPMLTemperature Min and Max Failed!",
+                                       return -EINVAL);
+
+               /* DW9-DW12 */
+               if (0 != iceland_populate_temperature_scaler(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate LPMLTemperatureScaler Failed!",
+                                       return -EINVAL);
+
+               /* DW13-DW16 */
+               if (iceland_populate_gnb_lpml(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate GnbLPML Failed!",
+                                       return -EINVAL);
+
+               /* DW17 */
+               if (iceland_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate GnbLPML Min and Max Vid Failed!",
+                                       return -EINVAL);
+
+               /* DW18 */
+               if (iceland_populate_bapm_vddc_base_leakage_sidd(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate BapmVddCBaseLeakage Hi and Lo Sidd Failed!",
+                                       return -EINVAL);
+
+               if (smu7_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
+                               (uint8_t *)&smu_data->power_tune_table,
+                               sizeof(struct SMU71_Discrete_PmFuses), SMC_RAM_END))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to download PmFuseTable Failed!",
+                                       return -EINVAL);
+       }
+       return 0;
+}
+
+static int iceland_get_dependecy_volt_by_clk(struct pp_hwmgr *hwmgr,
+       struct phm_clock_voltage_dependency_table *allowed_clock_voltage_table,
+       uint32_t clock, uint32_t *vol)
+{
+       uint32_t i = 0;
+
+       /* clock - voltage dependency table is empty table */
+       if (allowed_clock_voltage_table->count == 0)
+               return -EINVAL;
+
+       for (i = 0; i < allowed_clock_voltage_table->count; i++) {
+               /* find first sclk bigger than request */
+               if (allowed_clock_voltage_table->entries[i].clk >= clock) {
+                       *vol = allowed_clock_voltage_table->entries[i].v;
+                       return 0;
+               }
+       }
+
+       /* sclk is bigger than max sclk in the dependence table */
+       *vol = allowed_clock_voltage_table->entries[i - 1].v;
+
+       return 0;
+}
+
+static int iceland_get_std_voltage_value_sidd(struct pp_hwmgr *hwmgr,
+               pp_atomctrl_voltage_table_entry *tab, uint16_t *hi,
+               uint16_t *lo)
+{
+       uint16_t v_index;
+       bool vol_found = false;
+       *hi = tab->value * VOLTAGE_SCALE;
+       *lo = tab->value * VOLTAGE_SCALE;
+
+       /* SCLK/VDDC Dependency Table has to exist. */
+       PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.vddc_dependency_on_sclk,
+                       "The SCLK/VDDC Dependency Table does not exist.\n",
+                       return -EINVAL);
+
+       if (NULL == hwmgr->dyn_state.cac_leakage_table) {
+               pr_warning("CAC Leakage Table does not exist, using vddc.\n");
+               return 0;
+       }
+
+       /*
+        * Since voltage in the sclk/vddc dependency table is not
+        * necessarily in ascending order because of ELB voltage
+        * patching, loop through entire list to find exact voltage.
+        */
+       for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) {
+               if (tab->value == hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) {
+                       vol_found = true;
+                       if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) {
+                               *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE;
+                               *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage * VOLTAGE_SCALE);
+                       } else {
+                               pr_warning("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index, using maximum index from CAC table.\n");
+                               *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE;
+                               *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE);
+                       }
+                       break;
+               }
+       }
+
+       /*
+        * If voltage is not found in the first pass, loop again to
+        * find the best match, equal or higher value.
+        */
+       if (!vol_found) {
+               for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) {
+                       if (tab->value <= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) {
+                               vol_found = true;
+                               if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) {
+                                       *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE;
+                                       *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage) * VOLTAGE_SCALE;
+                               } else {
+                                       pr_warning("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index in second look up, using maximum index from CAC table.");
+                                       *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE;
+                                       *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE);
+                               }
+                               break;
+                       }
+               }
+
+               if (!vol_found)
+                       pr_warning("Unable to get std_vddc from SCLK/VDDC Dependency Table, using vddc.\n");
+       }
+
+       return 0;
+}
+
+static int iceland_populate_smc_voltage_table(struct pp_hwmgr *hwmgr,
+               pp_atomctrl_voltage_table_entry *tab,
+               SMU71_Discrete_VoltageLevel *smc_voltage_tab)
+{
+       int result;
+
+       result = iceland_get_std_voltage_value_sidd(hwmgr, tab,
+                       &smc_voltage_tab->StdVoltageHiSidd,
+                       &smc_voltage_tab->StdVoltageLoSidd);
+       if (0 != result) {
+               smc_voltage_tab->StdVoltageHiSidd = tab->value * VOLTAGE_SCALE;
+               smc_voltage_tab->StdVoltageLoSidd = tab->value * VOLTAGE_SCALE;
+       }
+
+       smc_voltage_tab->Voltage = PP_HOST_TO_SMC_US(tab->value * VOLTAGE_SCALE);
+       CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageHiSidd);
+       CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageHiSidd);
+
+       return 0;
+}
+
+static int iceland_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
+                       SMU71_Discrete_DpmTable *table)
+{
+       unsigned int count;
+       int result;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       table->VddcLevelCount = data->vddc_voltage_table.count;
+       for (count = 0; count < table->VddcLevelCount; count++) {
+               result = iceland_populate_smc_voltage_table(hwmgr,
+                               &(data->vddc_voltage_table.entries[count]),
+                               &(table->VddcLevel[count]));
+               PP_ASSERT_WITH_CODE(0 == result, "do not populate SMC VDDC voltage table", return -EINVAL);
+
+               /* GPIO voltage control */
+               if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control)
+                       table->VddcLevel[count].Smio |= data->vddc_voltage_table.entries[count].smio_low;
+               else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control)
+                       table->VddcLevel[count].Smio = 0;
+       }
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
+
+       return 0;
+}
+
+static int iceland_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
+                       SMU71_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t count;
+       int result;
+
+       table->VddciLevelCount = data->vddci_voltage_table.count;
+
+       for (count = 0; count < table->VddciLevelCount; count++) {
+               result = iceland_populate_smc_voltage_table(hwmgr,
+                               &(data->vddci_voltage_table.entries[count]),
+                               &(table->VddciLevel[count]));
+               PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC VDDCI voltage table", return -EINVAL);
+               if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control)
+                       table->VddciLevel[count].Smio |= data->vddci_voltage_table.entries[count].smio_low;
+               else
+                       table->VddciLevel[count].Smio |= 0;
+       }
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
+
+       return 0;
+}
+
+static int iceland_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
+                       SMU71_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t count;
+       int result;
+
+       table->MvddLevelCount = data->mvdd_voltage_table.count;
+
+       for (count = 0; count < table->VddciLevelCount; count++) {
+               result = iceland_populate_smc_voltage_table(hwmgr,
+                               &(data->mvdd_voltage_table.entries[count]),
+                               &table->MvddLevel[count]);
+               PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC mvdd voltage table", return -EINVAL);
+               if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control)
+                       table->MvddLevel[count].Smio |= data->mvdd_voltage_table.entries[count].smio_low;
+               else
+                       table->MvddLevel[count].Smio |= 0;
+       }
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
+
+       return 0;
+}
+
+
+static int iceland_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
+       SMU71_Discrete_DpmTable *table)
+{
+       int result;
+
+       result = iceland_populate_smc_vddc_table(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "can not populate VDDC voltage table to SMC", return -EINVAL);
+
+       result = iceland_populate_smc_vdd_ci_table(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "can not populate VDDCI voltage table to SMC", return -EINVAL);
+
+       result = iceland_populate_smc_mvdd_table(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "can not populate MVDD voltage table to SMC", return -EINVAL);
+
+       return 0;
+}
+
+static int iceland_populate_ulv_level(struct pp_hwmgr *hwmgr,
+               struct SMU71_Discrete_Ulv *state)
+{
+       uint32_t voltage_response_time, ulv_voltage;
+       int result;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       state->CcPwrDynRm = 0;
+       state->CcPwrDynRm1 = 0;
+
+       result = pp_tables_get_response_times(hwmgr, &voltage_response_time, &ulv_voltage);
+       PP_ASSERT_WITH_CODE((0 == result), "can not get ULV voltage value", return result;);
+
+       if (ulv_voltage == 0) {
+               data->ulv_supported = false;
+               return 0;
+       }
+
+       if (data->voltage_control != SMU7_VOLTAGE_CONTROL_BY_SVID2) {
+               /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */
+               if (ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v)
+                       state->VddcOffset = 0;
+               else
+                       /* used in SMIO Mode. not implemented for now. this is backup only for CI. */
+                       state->VddcOffset = (uint16_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage);
+       } else {
+               /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */
+               if (ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v)
+                       state->VddcOffsetVid = 0;
+               else  /* used in SVI2 Mode */
+                       state->VddcOffsetVid = (uint8_t)(
+                                       (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage)
+                                               * VOLTAGE_VID_OFFSET_SCALE2
+                                               / VOLTAGE_VID_OFFSET_SCALE1);
+       }
+       state->VddcPhase = 1;
+
+       CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
+       CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
+       CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
+
+       return 0;
+}
+
+static int iceland_populate_ulv_state(struct pp_hwmgr *hwmgr,
+                SMU71_Discrete_Ulv *ulv_level)
+{
+       return iceland_populate_ulv_level(hwmgr, ulv_level);
+}
+
+static int iceland_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU71_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t i;
+
+       /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
+       for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
+               table->LinkLevel[i].PcieGenSpeed  =
+                       (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
+               table->LinkLevel[i].PcieLaneCount =
+                       (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
+               table->LinkLevel[i].EnabledForActivity =
+                       1;
+               table->LinkLevel[i].SPC =
+                       (uint8_t)(data->pcie_spc_cap & 0xff);
+               table->LinkLevel[i].DownThreshold =
+                       PP_HOST_TO_SMC_UL(5);
+               table->LinkLevel[i].UpThreshold =
+                       PP_HOST_TO_SMC_UL(30);
+       }
+
+       smu_data->smc_state_table.LinkLevelCount =
+               (uint8_t)dpm_table->pcie_speed_table.count;
+       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+               phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
+
+       return 0;
+}
+
+/**
+ * Calculates the SCLK dividers using the provided engine clock
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    engine_clock the engine clock to use to populate the structure
+ * @param    sclk        the SMC SCLK structure to be populated
+ */
+static int iceland_calculate_sclk_params(struct pp_hwmgr *hwmgr,
+               uint32_t engine_clock, SMU71_Discrete_GraphicsLevel *sclk)
+{
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       pp_atomctrl_clock_dividers_vi dividers;
+       uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+       uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+       uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+       uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+       uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+       uint32_t    reference_clock;
+       uint32_t reference_divider;
+       uint32_t fbdiv;
+       int result;
+
+       /* get the engine clock dividers for this clock value*/
+       result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock,  &dividers);
+
+       PP_ASSERT_WITH_CODE(result == 0,
+               "Error retrieving Engine Clock dividers from VBIOS.", return result);
+
+       /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
+       reference_clock = atomctrl_get_reference_clock(hwmgr);
+
+       reference_divider = 1 + dividers.uc_pll_ref_div;
+
+       /* low 14 bits is fraction and high 12 bits is divider*/
+       fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
+
+       /* SPLL_FUNC_CNTL setup*/
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+               CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div);
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+               CG_SPLL_FUNC_CNTL, SPLL_PDIV_A,  dividers.uc_pll_post_div);
+
+       /* SPLL_FUNC_CNTL_3 setup*/
+       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
+               CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv);
+
+       /* set to use fractional accumulation*/
+       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
+               CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
+               pp_atomctrl_internal_ss_info ss_info;
+
+               uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div;
+               if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) {
+                       /*
+                       * ss_info.speed_spectrum_percentage -- in unit of 0.01%
+                       * ss_info.speed_spectrum_rate -- in unit of khz
+                       */
+                       /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
+                       uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate);
+
+                       /* clkv = 2 * D * fbdiv / NS */
+                       uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000);
+
+                       cg_spll_spread_spectrum =
+                               PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS);
+                       cg_spll_spread_spectrum =
+                               PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
+                       cg_spll_spread_spectrum_2 =
+                               PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV);
+               }
+       }
+
+       sclk->SclkFrequency        = engine_clock;
+       sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
+       sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
+       sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
+       sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
+       sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
+
+       return 0;
+}
+
+static int iceland_populate_phase_value_based_on_sclk(struct pp_hwmgr *hwmgr,
+                               const struct phm_phase_shedding_limits_table *pl,
+                                       uint32_t sclk, uint32_t *p_shed)
+{
+       unsigned int i;
+
+       /* use the minimum phase shedding */
+       *p_shed = 1;
+
+       for (i = 0; i < pl->count; i++) {
+               if (sclk < pl->entries[i].Sclk) {
+                       *p_shed = i;
+                       break;
+               }
+       }
+       return 0;
+}
+
+/**
+ * Populates single SMC SCLK structure using the provided engine clock
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    engine_clock the engine clock to use to populate the structure
+ * @param    sclk        the SMC SCLK structure to be populated
+ */
+static int iceland_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
+                                               uint32_t engine_clock,
+                               uint16_t sclk_activity_level_threshold,
+                               SMU71_Discrete_GraphicsLevel *graphic_level)
+{
+       int result;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       result = iceland_calculate_sclk_params(hwmgr, engine_clock, graphic_level);
+
+       /* populate graphics levels*/
+       result = iceland_get_dependecy_volt_by_clk(hwmgr,
+               hwmgr->dyn_state.vddc_dependency_on_sclk, engine_clock,
+               &graphic_level->MinVddc);
+       PP_ASSERT_WITH_CODE((0 == result),
+               "can not find VDDC voltage value for VDDC       \
+               engine clock dependency table", return result);
+
+       /* SCLK frequency in units of 10KHz*/
+       graphic_level->SclkFrequency = engine_clock;
+       graphic_level->MinVddcPhases = 1;
+
+       if (data->vddc_phase_shed_control)
+               iceland_populate_phase_value_based_on_sclk(hwmgr,
+                               hwmgr->dyn_state.vddc_phase_shed_limits_table,
+                               engine_clock,
+                               &graphic_level->MinVddcPhases);
+
+       /* Indicates maximum activity level for this performance level. 50% for now*/
+       graphic_level->ActivityLevel = sclk_activity_level_threshold;
+
+       graphic_level->CcPwrDynRm = 0;
+       graphic_level->CcPwrDynRm1 = 0;
+       /* this level can be used if activity is high enough.*/
+       graphic_level->EnabledForActivity = 0;
+       /* this level can be used for throttling.*/
+       graphic_level->EnabledForThrottle = 1;
+       graphic_level->UpHyst = 0;
+       graphic_level->DownHyst = 100;
+       graphic_level->VoltageDownHyst = 0;
+       graphic_level->PowerThrottle = 0;
+
+       data->display_timing.min_clock_in_sr =
+                       hwmgr->display_config.min_core_set_clock_in_sr;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkDeepSleep))
+               graphic_level->DeepSleepDivId =
+                               smu7_get_sleep_divider_id_from_clock(engine_clock,
+                                               data->display_timing.min_clock_in_sr);
+
+       /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
+       graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+       if (0 == result) {
+               graphic_level->MinVddc = PP_HOST_TO_SMC_UL(graphic_level->MinVddc * VOLTAGE_SCALE);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency);
+               CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1);
+       }
+
+       return result;
+}
+
+/**
+ * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
+ *
+ * @param    hwmgr      the address of the hardware manager
+ */
+int iceland_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       uint32_t level_array_adress = smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU71_Discrete_DpmTable, GraphicsLevel);
+
+       uint32_t level_array_size = sizeof(SMU71_Discrete_GraphicsLevel) *
+                                               SMU71_MAX_LEVELS_GRAPHICS;
+
+       SMU71_Discrete_GraphicsLevel *levels = smu_data->smc_state_table.GraphicsLevel;
+
+       uint32_t i;
+       uint8_t highest_pcie_level_enabled = 0;
+       uint8_t lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0;
+       uint8_t count = 0;
+       int result = 0;
+
+       memset(levels, 0x00, level_array_size);
+
+       for (i = 0; i < dpm_table->sclk_table.count; i++) {
+               result = iceland_populate_single_graphic_level(hwmgr,
+                                       dpm_table->sclk_table.dpm_levels[i].value,
+                                       (uint16_t)smu_data->activity_target[i],
+                                       &(smu_data->smc_state_table.GraphicsLevel[i]));
+               if (result != 0)
+                       return result;
+
+               /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
+               if (i > 1)
+                       smu_data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
+       }
+
+       /* Only enable level 0 for now. */
+       smu_data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
+
+       /* set highest level watermark to high */
+       if (dpm_table->sclk_table.count > 1)
+               smu_data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark =
+                       PPSMC_DISPLAY_WATERMARK_HIGH;
+
+       smu_data->smc_state_table.GraphicsDpmLevelCount =
+               (uint8_t)dpm_table->sclk_table.count;
+       data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+               phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
+
+       while ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                               (1 << (highest_pcie_level_enabled + 1))) != 0) {
+               highest_pcie_level_enabled++;
+       }
+
+       while ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+               (1 << lowest_pcie_level_enabled)) == 0) {
+               lowest_pcie_level_enabled++;
+       }
+
+       while ((count < highest_pcie_level_enabled) &&
+                       ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                               (1 << (lowest_pcie_level_enabled + 1 + count))) == 0)) {
+               count++;
+       }
+
+       mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ?
+               (lowest_pcie_level_enabled+1+count) : highest_pcie_level_enabled;
+
+
+       /* set pcieDpmLevel to highest_pcie_level_enabled*/
+       for (i = 2; i < dpm_table->sclk_table.count; i++) {
+               smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled;
+       }
+
+       /* set pcieDpmLevel to lowest_pcie_level_enabled*/
+       smu_data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled;
+
+       /* set pcieDpmLevel to mid_pcie_level_enabled*/
+       smu_data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled;
+
+       /* level count will send to smc once at init smc table and never change*/
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr, level_array_adress,
+                               (uint8_t *)levels, (uint32_t)level_array_size,
+                                                               SMC_RAM_END);
+
+       return result;
+}
+
+/**
+ * Populates the SMC MCLK structure using the provided memory clock
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    memory_clock the memory clock to use to populate the structure
+ * @param    sclk        the SMC SCLK structure to be populated
+ */
+static int iceland_calculate_mclk_params(
+               struct pp_hwmgr *hwmgr,
+               uint32_t memory_clock,
+               SMU71_Discrete_MemoryLevel *mclk,
+               bool strobe_mode,
+               bool dllStateOn
+               )
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       uint32_t  dll_cntl = data->clock_registers.vDLL_CNTL;
+       uint32_t  mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
+       uint32_t  mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
+       uint32_t  mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
+       uint32_t  mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
+       uint32_t  mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
+       uint32_t  mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
+       uint32_t  mpll_ss1 = data->clock_registers.vMPLL_SS1;
+       uint32_t  mpll_ss2 = data->clock_registers.vMPLL_SS2;
+
+       pp_atomctrl_memory_clock_param mpll_param;
+       int result;
+
+       result = atomctrl_get_memory_pll_dividers_si(hwmgr,
+                               memory_clock, &mpll_param, strobe_mode);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Error retrieving Memory Clock Parameters from VBIOS.", return result);
+
+       /* MPLL_FUNC_CNTL setup*/
+       mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL, mpll_param.bw_ctrl);
+
+       /* MPLL_FUNC_CNTL_1 setup*/
+       mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
+                                                       MPLL_FUNC_CNTL_1, CLKF, mpll_param.mpll_fb_divider.cl_kf);
+       mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
+                                                       MPLL_FUNC_CNTL_1, CLKFRAC, mpll_param.mpll_fb_divider.clk_frac);
+       mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
+                                                       MPLL_FUNC_CNTL_1, VCO_MODE, mpll_param.vco_mode);
+
+       /* MPLL_AD_FUNC_CNTL setup*/
+       mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
+                                                       MPLL_AD_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
+
+       if (data->is_memory_gddr5) {
+               /* MPLL_DQ_FUNC_CNTL setup*/
+               mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
+                                                               MPLL_DQ_FUNC_CNTL, YCLK_SEL, mpll_param.yclk_sel);
+               mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
+                                                               MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
+       }
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
+               /*
+                ************************************
+                Fref = Reference Frequency
+                NF = Feedback divider ratio
+                NR = Reference divider ratio
+                Fnom = Nominal VCO output frequency = Fref * NF / NR
+                Fs = Spreading Rate
+                D = Percentage down-spread / 2
+                Fint = Reference input frequency to PFD = Fref / NR
+                NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
+                CLKS = NS - 1 = ISS_STEP_NUM[11:0]
+                NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
+                CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
+                *************************************
+                */
+               pp_atomctrl_internal_ss_info ss_info;
+               uint32_t freq_nom;
+               uint32_t tmp;
+               uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
+
+               /* for GDDR5 for all modes and DDR3 */
+               if (1 == mpll_param.qdr)
+                       freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
+               else
+                       freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
+
+               /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2  Note: S.I. reference_divider = 1*/
+               tmp = (freq_nom / reference_clock);
+               tmp = tmp * tmp;
+
+               if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
+                       /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
+                       /* ss.Info.speed_spectrum_rate -- in unit of khz */
+                       /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
+                       /*     = reference_clock * 5 / speed_spectrum_rate */
+                       uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
+
+                       /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
+                       /*     = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
+                       uint32_t clkv =
+                               (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
+                                                       ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
+
+                       mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
+                       mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
+               }
+       }
+
+       /* MCLK_PWRMGT_CNTL setup */
+       mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
+       mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
+       mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
+
+
+       /* Save the result data to outpupt memory level structure */
+       mclk->MclkFrequency   = memory_clock;
+       mclk->MpllFuncCntl    = mpll_func_cntl;
+       mclk->MpllFuncCntl_1  = mpll_func_cntl_1;
+       mclk->MpllFuncCntl_2  = mpll_func_cntl_2;
+       mclk->MpllAdFuncCntl  = mpll_ad_func_cntl;
+       mclk->MpllDqFuncCntl  = mpll_dq_func_cntl;
+       mclk->MclkPwrmgtCntl  = mclk_pwrmgt_cntl;
+       mclk->DllCntl         = dll_cntl;
+       mclk->MpllSs1         = mpll_ss1;
+       mclk->MpllSs2         = mpll_ss2;
+
+       return 0;
+}
+
+static uint8_t iceland_get_mclk_frequency_ratio(uint32_t memory_clock,
+               bool strobe_mode)
+{
+       uint8_t mc_para_index;
+
+       if (strobe_mode) {
+               if (memory_clock < 12500) {
+                       mc_para_index = 0x00;
+               } else if (memory_clock > 47500) {
+                       mc_para_index = 0x0f;
+               } else {
+                       mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
+               }
+       } else {
+               if (memory_clock < 65000) {
+                       mc_para_index = 0x00;
+               } else if (memory_clock > 135000) {
+                       mc_para_index = 0x0f;
+               } else {
+                       mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
+               }
+       }
+
+       return mc_para_index;
+}
+
+static uint8_t iceland_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
+{
+       uint8_t mc_para_index;
+
+       if (memory_clock < 10000) {
+               mc_para_index = 0;
+       } else if (memory_clock >= 80000) {
+               mc_para_index = 0x0f;
+       } else {
+               mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
+       }
+
+       return mc_para_index;
+}
+
+static int iceland_populate_phase_value_based_on_mclk(struct pp_hwmgr *hwmgr, const struct phm_phase_shedding_limits_table *pl,
+                                       uint32_t memory_clock, uint32_t *p_shed)
+{
+       unsigned int i;
+
+       *p_shed = 1;
+
+       for (i = 0; i < pl->count; i++) {
+               if (memory_clock < pl->entries[i].Mclk) {
+                       *p_shed = i;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int iceland_populate_single_memory_level(
+               struct pp_hwmgr *hwmgr,
+               uint32_t memory_clock,
+               SMU71_Discrete_MemoryLevel *memory_level
+               )
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       int result = 0;
+       bool dll_state_on;
+       struct cgs_display_info info = {0};
+       uint32_t mclk_edc_wr_enable_threshold = 40000;
+       uint32_t mclk_edc_enable_threshold = 40000;
+       uint32_t mclk_strobe_mode_threshold = 40000;
+
+       if (hwmgr->dyn_state.vddc_dependency_on_mclk != NULL) {
+               result = iceland_get_dependecy_volt_by_clk(hwmgr,
+                       hwmgr->dyn_state.vddc_dependency_on_mclk, memory_clock, &memory_level->MinVddc);
+               PP_ASSERT_WITH_CODE((0 == result),
+                       "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result);
+       }
+
+       if (data->vddci_control == SMU7_VOLTAGE_CONTROL_NONE) {
+               memory_level->MinVddci = memory_level->MinVddc;
+       } else if (NULL != hwmgr->dyn_state.vddci_dependency_on_mclk) {
+               result = iceland_get_dependecy_volt_by_clk(hwmgr,
+                               hwmgr->dyn_state.vddci_dependency_on_mclk,
+                               memory_clock,
+                               &memory_level->MinVddci);
+               PP_ASSERT_WITH_CODE((0 == result),
+                       "can not find MinVddci voltage value from memory VDDCI voltage dependency table", return result);
+       }
+
+       memory_level->MinVddcPhases = 1;
+
+       if (data->vddc_phase_shed_control) {
+               iceland_populate_phase_value_based_on_mclk(hwmgr, hwmgr->dyn_state.vddc_phase_shed_limits_table,
+                               memory_clock, &memory_level->MinVddcPhases);
+       }
+
+       memory_level->EnabledForThrottle = 1;
+       memory_level->EnabledForActivity = 0;
+       memory_level->UpHyst = 0;
+       memory_level->DownHyst = 100;
+       memory_level->VoltageDownHyst = 0;
+
+       /* Indicates maximum activity level for this performance level.*/
+       memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
+       memory_level->StutterEnable = 0;
+       memory_level->StrobeEnable = 0;
+       memory_level->EdcReadEnable = 0;
+       memory_level->EdcWriteEnable = 0;
+       memory_level->RttEnable = 0;
+
+       /* default set to low watermark. Highest level will be set to high later.*/
+       memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+       cgs_get_active_displays_info(hwmgr->device, &info);
+       data->display_timing.num_existing_displays = info.display_count;
+
+       /* stutter mode not support on iceland */
+
+       /* decide strobe mode*/
+       memory_level->StrobeEnable = (mclk_strobe_mode_threshold != 0) &&
+               (memory_clock <= mclk_strobe_mode_threshold);
+
+       /* decide EDC mode and memory clock ratio*/
+       if (data->is_memory_gddr5) {
+               memory_level->StrobeRatio = iceland_get_mclk_frequency_ratio(memory_clock,
+                                       memory_level->StrobeEnable);
+
+               if ((mclk_edc_enable_threshold != 0) &&
+                               (memory_clock > mclk_edc_enable_threshold)) {
+                       memory_level->EdcReadEnable = 1;
+               }
+
+               if ((mclk_edc_wr_enable_threshold != 0) &&
+                               (memory_clock > mclk_edc_wr_enable_threshold)) {
+                       memory_level->EdcWriteEnable = 1;
+               }
+
+               if (memory_level->StrobeEnable) {
+                       if (iceland_get_mclk_frequency_ratio(memory_clock, 1) >=
+                                       ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf))
+                               dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
+                       else
+                               dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
+               } else
+                       dll_state_on = data->dll_default_on;
+       } else {
+               memory_level->StrobeRatio =
+                       iceland_get_ddr3_mclk_frequency_ratio(memory_clock);
+               dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
+       }
+
+       result = iceland_calculate_mclk_params(hwmgr,
+               memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
+
+       if (0 == result) {
+               memory_level->MinVddc = PP_HOST_TO_SMC_UL(memory_level->MinVddc * VOLTAGE_SCALE);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinVddcPhases);
+               memory_level->MinVddci = PP_HOST_TO_SMC_UL(memory_level->MinVddci * VOLTAGE_SCALE);
+               memory_level->MinMvdd = PP_HOST_TO_SMC_UL(memory_level->MinMvdd * VOLTAGE_SCALE);
+               /* MCLK frequency in units of 10KHz*/
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
+               /* Indicates maximum activity level for this performance level.*/
+               CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
+       }
+
+       return result;
+}
+
+/**
+ * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
+ *
+ * @param    hwmgr      the address of the hardware manager
+ */
+
+int iceland_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       int result;
+
+       /* populate MCLK dpm table to SMU7 */
+       uint32_t level_array_adress = smu_data->smu7_data.dpm_table_start + offsetof(SMU71_Discrete_DpmTable, MemoryLevel);
+       uint32_t level_array_size = sizeof(SMU71_Discrete_MemoryLevel) * SMU71_MAX_LEVELS_MEMORY;
+       SMU71_Discrete_MemoryLevel *levels = smu_data->smc_state_table.MemoryLevel;
+       uint32_t i;
+
+       memset(levels, 0x00, level_array_size);
+
+       for (i = 0; i < dpm_table->mclk_table.count; i++) {
+               PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
+                       "can not populate memory level as memory clock is zero", return -EINVAL);
+               result = iceland_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value,
+                       &(smu_data->smc_state_table.MemoryLevel[i]));
+               if (0 != result) {
+                       return result;
+               }
+       }
+
+       /* Only enable level 0 for now.*/
+       smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
+
+       /*
+       * in order to prevent MC activity from stutter mode to push DPM up.
+       * the UVD change complements this by putting the MCLK in a higher state
+       * by default such that we are not effected by up threshold or and MCLK DPM latency.
+       */
+       smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
+       CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
+
+       smu_data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
+       data->dpm_level_enable_mask.mclk_dpm_enable_mask = phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
+       /* set highest level watermark to high*/
+       smu_data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
+
+       /* level count will send to smc once at init smc table and never change*/
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr,
+               level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size,
+               SMC_RAM_END);
+
+       return result;
+}
+
+static int iceland_populate_mvdd_value(struct pp_hwmgr *hwmgr, uint32_t mclk,
+                                       SMU71_Discrete_VoltageLevel *voltage)
+{
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       uint32_t i = 0;
+
+       if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
+               /* find mvdd value which clock is more than request */
+               for (i = 0; i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count; i++) {
+                       if (mclk <= hwmgr->dyn_state.mvdd_dependency_on_mclk->entries[i].clk) {
+                               /* Always round to higher voltage. */
+                               voltage->Voltage = data->mvdd_voltage_table.entries[i].value;
+                               break;
+                       }
+               }
+
+               PP_ASSERT_WITH_CODE(i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count,
+                       "MVDD Voltage is outside the supported range.", return -EINVAL);
+
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int iceland_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
+       SMU71_Discrete_DpmTable *table)
+{
+       int result = 0;
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       uint32_t vddc_phase_shed_control = 0;
+
+       SMU71_Discrete_VoltageLevel voltage_level;
+       uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+       uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
+       uint32_t dll_cntl          = data->clock_registers.vDLL_CNTL;
+       uint32_t mclk_pwrmgt_cntl  = data->clock_registers.vMCLK_PWRMGT_CNTL;
+
+
+       /* The ACPI state should not do DPM on DC (or ever).*/
+       table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+       if (data->acpi_vddc)
+               table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->acpi_vddc * VOLTAGE_SCALE);
+       else
+               table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->min_vddc_in_pptable * VOLTAGE_SCALE);
+
+       table->ACPILevel.MinVddcPhases = vddc_phase_shed_control ? 0 : 1;
+       /* assign zero for now*/
+       table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
+
+       /* get the engine clock dividers for this clock value*/
+       result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
+               table->ACPILevel.SclkFrequency,  &dividers);
+
+       PP_ASSERT_WITH_CODE(result == 0,
+               "Error retrieving Engine Clock dividers from VBIOS.", return result);
+
+       /* divider ID for required SCLK*/
+       table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
+       table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+       table->ACPILevel.DeepSleepDivId = 0;
+
+       spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
+                                                       CG_SPLL_FUNC_CNTL,   SPLL_PWRON,     0);
+       spll_func_cntl      = PHM_SET_FIELD(spll_func_cntl,
+                                                       CG_SPLL_FUNC_CNTL,   SPLL_RESET,     1);
+       spll_func_cntl_2    = PHM_SET_FIELD(spll_func_cntl_2,
+                                                       CG_SPLL_FUNC_CNTL_2, SCLK_MUX_SEL,   4);
+
+       table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
+       table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
+       table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+       table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+       table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+       table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+       table->ACPILevel.CcPwrDynRm = 0;
+       table->ACPILevel.CcPwrDynRm1 = 0;
+
+
+       /* For various features to be enabled/disabled while this level is active.*/
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
+       /* SCLK frequency in units of 10KHz*/
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
+
+       /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
+       table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc;
+       table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;
+
+       if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
+               table->MemoryACPILevel.MinVddci = table->MemoryACPILevel.MinVddc;
+       else {
+               if (data->acpi_vddci != 0)
+                       table->MemoryACPILevel.MinVddci = PP_HOST_TO_SMC_UL(data->acpi_vddci * VOLTAGE_SCALE);
+               else
+                       table->MemoryACPILevel.MinVddci = PP_HOST_TO_SMC_UL(data->min_vddci_in_pptable * VOLTAGE_SCALE);
+       }
+
+       if (0 == iceland_populate_mvdd_value(hwmgr, 0, &voltage_level))
+               table->MemoryACPILevel.MinMvdd =
+                       PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
+       else
+               table->MemoryACPILevel.MinMvdd = 0;
+
+       /* Force reset on DLL*/
+       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
+       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
+
+       /* Disable DLL in ACPIState*/
+       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
+       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
+
+       /* Enable DLL bypass signal*/
+       dll_cntl            = PHM_SET_FIELD(dll_cntl,
+               DLL_CNTL, MRDCK0_BYPASS, 0);
+       dll_cntl            = PHM_SET_FIELD(dll_cntl,
+               DLL_CNTL, MRDCK1_BYPASS, 0);
+
+       table->MemoryACPILevel.DllCntl            =
+               PP_HOST_TO_SMC_UL(dll_cntl);
+       table->MemoryACPILevel.MclkPwrmgtCntl     =
+               PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
+       table->MemoryACPILevel.MpllAdFuncCntl     =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
+       table->MemoryACPILevel.MpllDqFuncCntl     =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
+       table->MemoryACPILevel.MpllFuncCntl       =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
+       table->MemoryACPILevel.MpllFuncCntl_1     =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
+       table->MemoryACPILevel.MpllFuncCntl_2     =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
+       table->MemoryACPILevel.MpllSs1            =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
+       table->MemoryACPILevel.MpllSs2            =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
+
+       table->MemoryACPILevel.EnabledForThrottle = 0;
+       table->MemoryACPILevel.EnabledForActivity = 0;
+       table->MemoryACPILevel.UpHyst = 0;
+       table->MemoryACPILevel.DownHyst = 100;
+       table->MemoryACPILevel.VoltageDownHyst = 0;
+       /* Indicates maximum activity level for this performance level.*/
+       table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
+
+       table->MemoryACPILevel.StutterEnable = 0;
+       table->MemoryACPILevel.StrobeEnable = 0;
+       table->MemoryACPILevel.EdcReadEnable = 0;
+       table->MemoryACPILevel.EdcWriteEnable = 0;
+       table->MemoryACPILevel.RttEnable = 0;
+
+       return result;
+}
+
+static int iceland_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
+                                       SMU71_Discrete_DpmTable *table)
+{
+       return 0;
+}
+
+static int iceland_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
+               SMU71_Discrete_DpmTable *table)
+{
+       return 0;
+}
+
+static int iceland_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
+               SMU71_Discrete_DpmTable *table)
+{
+       return 0;
+}
+
+static int iceland_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
+       SMU71_Discrete_DpmTable *table)
+{
+       return 0;
+}
+
+static int iceland_populate_memory_timing_parameters(
+               struct pp_hwmgr *hwmgr,
+               uint32_t engine_clock,
+               uint32_t memory_clock,
+               struct SMU71_Discrete_MCArbDramTimingTableEntry *arb_regs
+               )
+{
+       uint32_t dramTiming;
+       uint32_t dramTiming2;
+       uint32_t burstTime;
+       int result;
+
+       result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
+                               engine_clock, memory_clock);
+
+       PP_ASSERT_WITH_CODE(result == 0,
+               "Error calling VBIOS to set DRAM_TIMING.", return result);
+
+       dramTiming  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+       dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+       burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+
+       arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dramTiming);
+       arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
+       arb_regs->McArbBurstTime = (uint8_t)burstTime;
+
+       return 0;
+}
+
+/**
+ * Setup parameters for the MC ARB.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ * This function is to be called from the SetPowerState table.
+ */
+static int iceland_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       int result = 0;
+       SMU71_Discrete_MCArbDramTimingTable  arb_regs;
+       uint32_t i, j;
+
+       memset(&arb_regs, 0x00, sizeof(SMU71_Discrete_MCArbDramTimingTable));
+
+       for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
+               for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
+                       result = iceland_populate_memory_timing_parameters
+                               (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
+                                data->dpm_table.mclk_table.dpm_levels[j].value,
+                                &arb_regs.entries[i][j]);
+
+                       if (0 != result) {
+                               break;
+                       }
+               }
+       }
+
+       if (0 == result) {
+               result = smu7_copy_bytes_to_smc(
+                               hwmgr->smumgr,
+                               smu_data->smu7_data.arb_table_start,
+                               (uint8_t *)&arb_regs,
+                               sizeof(SMU71_Discrete_MCArbDramTimingTable),
+                               SMC_RAM_END
+                               );
+       }
+
+       return result;
+}
+
+static int iceland_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
+                       SMU71_Discrete_DpmTable *table)
+{
+       int result = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       table->GraphicsBootLevel = 0;
+       table->MemoryBootLevel = 0;
+
+       /* find boot level from dpm table*/
+       result = phm_find_boot_level(&(data->dpm_table.sclk_table),
+                       data->vbios_boot_state.sclk_bootup_value,
+                       (uint32_t *)&(smu_data->smc_state_table.GraphicsBootLevel));
+
+       if (0 != result) {
+               smu_data->smc_state_table.GraphicsBootLevel = 0;
+               printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
+                       in dependency table. Using Graphics DPM level 0!");
+               result = 0;
+       }
+
+       result = phm_find_boot_level(&(data->dpm_table.mclk_table),
+               data->vbios_boot_state.mclk_bootup_value,
+               (uint32_t *)&(smu_data->smc_state_table.MemoryBootLevel));
+
+       if (0 != result) {
+               smu_data->smc_state_table.MemoryBootLevel = 0;
+               printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
+                       in dependency table. Using Memory DPM level 0!");
+               result = 0;
+       }
+
+       table->BootVddc = data->vbios_boot_state.vddc_bootup_value;
+       if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
+               table->BootVddci = table->BootVddc;
+       else
+               table->BootVddci = data->vbios_boot_state.vddci_bootup_value;
+
+       table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
+
+       return result;
+}
+
+static int iceland_populate_mc_reg_address(struct pp_smumgr *smumgr,
+                                SMU71_Discrete_MCRegisters *mc_reg_table)
+{
+       const struct iceland_smumgr *smu_data = (struct iceland_smumgr *)smumgr->backend;
+
+       uint32_t i, j;
+
+       for (i = 0, j = 0; j < smu_data->mc_reg_table.last; j++) {
+               if (smu_data->mc_reg_table.validflag & 1<<j) {
+                       PP_ASSERT_WITH_CODE(i < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE,
+                               "Index of mc_reg_table->address[] array out of boundary", return -EINVAL);
+                       mc_reg_table->address[i].s0 =
+                               PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s0);
+                       mc_reg_table->address[i].s1 =
+                               PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s1);
+                       i++;
+               }
+       }
+
+       mc_reg_table->last = (uint8_t)i;
+
+       return 0;
+}
+
+/*convert register values from driver to SMC format */
+static void iceland_convert_mc_registers(
+       const struct iceland_mc_reg_entry *entry,
+       SMU71_Discrete_MCRegisterSet *data,
+       uint32_t num_entries, uint32_t valid_flag)
+{
+       uint32_t i, j;
+
+       for (i = 0, j = 0; j < num_entries; j++) {
+               if (valid_flag & 1<<j) {
+                       data->value[i] = PP_HOST_TO_SMC_UL(entry->mc_data[j]);
+                       i++;
+               }
+       }
+}
+
+static int iceland_convert_mc_reg_table_entry_to_smc(
+               struct pp_smumgr *smumgr,
+               const uint32_t memory_clock,
+               SMU71_Discrete_MCRegisterSet *mc_reg_table_data
+               )
+{
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
+       uint32_t i = 0;
+
+       for (i = 0; i < smu_data->mc_reg_table.num_entries; i++) {
+               if (memory_clock <=
+                       smu_data->mc_reg_table.mc_reg_table_entry[i].mclk_max) {
+                       break;
+               }
+       }
+
+       if ((i == smu_data->mc_reg_table.num_entries) && (i > 0))
+               --i;
+
+       iceland_convert_mc_registers(&smu_data->mc_reg_table.mc_reg_table_entry[i],
+                               mc_reg_table_data, smu_data->mc_reg_table.last,
+                               smu_data->mc_reg_table.validflag);
+
+       return 0;
+}
+
+static int iceland_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
+               SMU71_Discrete_MCRegisters *mc_regs)
+{
+       int result = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       int res;
+       uint32_t i;
+
+       for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
+               res = iceland_convert_mc_reg_table_entry_to_smc(
+                               hwmgr->smumgr,
+                               data->dpm_table.mclk_table.dpm_levels[i].value,
+                               &mc_regs->data[i]
+                               );
+
+               if (0 != res)
+                       result = res;
+       }
+
+       return result;
+}
+
+static int iceland_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t address;
+       int32_t result;
+
+       if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
+               return 0;
+
+
+       memset(&smu_data->mc_regs, 0, sizeof(SMU71_Discrete_MCRegisters));
+
+       result = iceland_convert_mc_reg_table_to_smc(hwmgr, &(smu_data->mc_regs));
+
+       if (result != 0)
+               return result;
+
+
+       address = smu_data->smu7_data.mc_reg_table_start + (uint32_t)offsetof(SMU71_Discrete_MCRegisters, data[0]);
+
+       return  smu7_copy_bytes_to_smc(hwmgr->smumgr, address,
+                                (uint8_t *)&smu_data->mc_regs.data[0],
+                               sizeof(SMU71_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count,
+                               SMC_RAM_END);
+}
+
+static int iceland_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
+
+       memset(&smu_data->mc_regs, 0x00, sizeof(SMU71_Discrete_MCRegisters));
+       result = iceland_populate_mc_reg_address(smumgr, &(smu_data->mc_regs));
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize MCRegTable for the MC register addresses!", return result;);
+
+       result = iceland_convert_mc_reg_table_to_smc(hwmgr, &smu_data->mc_regs);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize MCRegTable for driver state!", return result;);
+
+       return smu7_copy_bytes_to_smc(smumgr, smu_data->smu7_data.mc_reg_table_start,
+                       (uint8_t *)&smu_data->mc_regs, sizeof(SMU71_Discrete_MCRegisters), SMC_RAM_END);
+}
+
+static int iceland_populate_smc_initial_state(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       uint8_t count, level;
+
+       count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->count);
+
+       for (level = 0; level < count; level++) {
+               if (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[level].clk
+                        >= data->vbios_boot_state.sclk_bootup_value) {
+                       smu_data->smc_state_table.GraphicsBootLevel = level;
+                       break;
+               }
+       }
+
+       count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_mclk->count);
+
+       for (level = 0; level < count; level++) {
+               if (hwmgr->dyn_state.vddc_dependency_on_mclk->entries[level].clk
+                       >= data->vbios_boot_state.mclk_bootup_value) {
+                       smu_data->smc_state_table.MemoryBootLevel = level;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int iceland_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       const struct iceland_pt_defaults *defaults = smu_data->power_tune_defaults;
+       SMU71_Discrete_DpmTable  *dpm_table = &(smu_data->smc_state_table);
+       struct phm_cac_tdp_table *cac_dtp_table = hwmgr->dyn_state.cac_dtp_table;
+       struct phm_ppm_table *ppm = hwmgr->dyn_state.ppm_parameter_table;
+       const uint16_t *def1, *def2;
+       int i, j, k;
+
+
+       /*
+        * TDP number of fraction bits are changed from 8 to 7 for Iceland
+        * as requested by SMC team
+        */
+
+       dpm_table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 256));
+       dpm_table->TargetTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
+
+
+       dpm_table->DTETjOffset = 0;
+
+       dpm_table->GpuTjMax = (uint8_t)(data->thermal_temp_setting.temperature_high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES);
+       dpm_table->GpuTjHyst = 8;
+
+       dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
+
+       /* The following are for new Iceland Multi-input fan/thermal control */
+       if (NULL != ppm) {
+               dpm_table->PPM_PkgPwrLimit = (uint16_t)ppm->dgpu_tdp * 256 / 1000;
+               dpm_table->PPM_TemperatureLimit = (uint16_t)ppm->tj_max * 256;
+       } else {
+               dpm_table->PPM_PkgPwrLimit = 0;
+               dpm_table->PPM_TemperatureLimit = 0;
+       }
+
+       CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_PkgPwrLimit);
+       CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_TemperatureLimit);
+
+       dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bamp_temp_gradient);
+       def1 = defaults->bapmti_r;
+       def2 = defaults->bapmti_rc;
+
+       for (i = 0; i < SMU71_DTE_ITERATIONS; i++) {
+               for (j = 0; j < SMU71_DTE_SOURCES; j++) {
+                       for (k = 0; k < SMU71_DTE_SINKS; k++) {
+                               dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*def1);
+                               dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*def2);
+                               def1++;
+                               def2++;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int iceland_populate_smc_svi2_config(struct pp_hwmgr *hwmgr,
+                                           SMU71_Discrete_DpmTable *tab)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control)
+               tab->SVI2Enable |= VDDC_ON_SVI2;
+
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control)
+               tab->SVI2Enable |= VDDCI_ON_SVI2;
+       else
+               tab->MergedVddci = 1;
+
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control)
+               tab->SVI2Enable |= MVDD_ON_SVI2;
+
+       PP_ASSERT_WITH_CODE(tab->SVI2Enable != (VDDC_ON_SVI2 | VDDCI_ON_SVI2 | MVDD_ON_SVI2) &&
+               (tab->SVI2Enable & VDDC_ON_SVI2), "SVI2 domain configuration is incorrect!", return -EINVAL);
+
+       return 0;
+}
+
+/**
+ * Initializes the SMC table and uploads it
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @param    pInput  the pointer to input data (PowerState)
+ * @return   always 0
+ */
+int iceland_init_smc_table(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       SMU71_Discrete_DpmTable  *table = &(smu_data->smc_state_table);
+
+
+       iceland_initialize_power_tune_defaults(hwmgr);
+       memset(&(smu_data->smc_state_table), 0x00, sizeof(smu_data->smc_state_table));
+
+       if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control) {
+               iceland_populate_smc_voltage_tables(hwmgr, table);
+       }
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_AutomaticDCTransition))
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StepVddc))
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+       if (data->is_memory_gddr5)
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+
+       if (data->ulv_supported) {
+               result = iceland_populate_ulv_state(hwmgr, &(smu_data->ulv_setting));
+               PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize ULV state!", return result;);
+
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_ULV_PARAMETER, 0x40035);
+       }
+
+       result = iceland_populate_smc_link_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize Link Level!", return result;);
+
+       result = iceland_populate_all_graphic_levels(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize Graphics Level!", return result;);
+
+       result = iceland_populate_all_memory_levels(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize Memory Level!", return result;);
+
+       result = iceland_populate_smc_acpi_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize ACPI Level!", return result;);
+
+       result = iceland_populate_smc_vce_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize VCE Level!", return result;);
+
+       result = iceland_populate_smc_acp_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize ACP Level!", return result;);
+
+       result = iceland_populate_smc_samu_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize SAMU Level!", return result;);
+
+       /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
+       /* need to populate the  ARB settings for the initial state. */
+       result = iceland_program_memory_timing_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to Write ARB settings for the initial state.", return result;);
+
+       result = iceland_populate_smc_uvd_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize UVD Level!", return result;);
+
+       table->GraphicsBootLevel = 0;
+       table->MemoryBootLevel = 0;
+
+       result = iceland_populate_smc_boot_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to initialize Boot Level!", return result;);
+
+       result = iceland_populate_smc_initial_state(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result, "Failed to initialize Boot State!", return result);
+
+       result = iceland_populate_bapm_parameters_in_dpm_table(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result, "Failed to populate BAPM Parameters!", return result);
+
+       table->GraphicsVoltageChangeEnable  = 1;
+       table->GraphicsThermThrottleEnable  = 1;
+       table->GraphicsInterval = 1;
+       table->VoltageInterval  = 1;
+       table->ThermalInterval  = 1;
+
+       table->TemperatureLimitHigh =
+               (data->thermal_temp_setting.temperature_high *
+                SMU7_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       table->TemperatureLimitLow =
+               (data->thermal_temp_setting.temperature_low *
+               SMU7_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+       table->MemoryVoltageChangeEnable  = 1;
+       table->MemoryInterval  = 1;
+       table->VoltageResponseTime  = 0;
+       table->PhaseResponseTime  = 0;
+       table->MemoryThermThrottleEnable  = 1;
+       table->PCIeBootLinkLevel = 0;
+       table->PCIeGenInterval = 1;
+
+       result = iceland_populate_smc_svi2_config(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to populate SVI2 setting!", return result);
+
+       table->ThermGpio  = 17;
+       table->SclkStepSize = 0x4000;
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcVid);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcPhase);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddciVid);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskMvddVid);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
+       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
+       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
+       CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
+       CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
+
+       table->BootVddc = PP_HOST_TO_SMC_US(table->BootVddc * VOLTAGE_SCALE);
+       table->BootVddci = PP_HOST_TO_SMC_US(table->BootVddci * VOLTAGE_SCALE);
+       table->BootMVdd = PP_HOST_TO_SMC_US(table->BootMVdd * VOLTAGE_SCALE);
+
+       /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr, smu_data->smu7_data.dpm_table_start +
+                                                                               offsetof(SMU71_Discrete_DpmTable, SystemFlags),
+                                                                               (uint8_t *)&(table->SystemFlags),
+                                                                               sizeof(SMU71_Discrete_DpmTable)-3 * sizeof(SMU71_PIDController),
+                                                                               SMC_RAM_END);
+
+       PP_ASSERT_WITH_CODE(0 == result,
+               "Failed to upload dpm data to SMC memory!", return result;);
+
+       /* Upload all ulv setting to SMC memory.(dpm level, dpm level count etc) */
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr,
+                       smu_data->smu7_data.ulv_setting_starts,
+                       (uint8_t *)&(smu_data->ulv_setting),
+                       sizeof(SMU71_Discrete_Ulv),
+                       SMC_RAM_END);
+
+
+       result = iceland_populate_initial_mc_reg_table(hwmgr);
+       PP_ASSERT_WITH_CODE((0 == result),
+               "Failed to populate initialize MC Reg table!", return result);
+
+       result = iceland_populate_pm_fuses(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to  populate PM fuses to SMC memory!", return result);
+
+       return 0;
+}
+
+/**
+* Set up the fan table to control the fan using the SMC.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_smumgr *smu7_data = (struct smu7_smumgr *)(hwmgr->smumgr->backend);
+       SMU71_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+       uint32_t duty100;
+       uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+       uint16_t fdo_min, slope1, slope2;
+       uint32_t reference_clock;
+       int res;
+       uint64_t tmp64;
+
+       if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
+               return 0;
+
+       if (0 == smu7_data->fan_table_start) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
+               return 0;
+       }
+
+       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
+
+       if (0 == duty100) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
+               return 0;
+       }
+
+       tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
+       do_div(tmp64, 10000);
+       fdo_min = (uint16_t)tmp64;
+
+       t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
+       t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
+
+       pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
+       pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
+
+       slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+       slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+       fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
+       fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
+       fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
+
+       fan_table.Slope1 = cpu_to_be16(slope1);
+       fan_table.Slope2 = cpu_to_be16(slope2);
+
+       fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+       fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
+
+       fan_table.HystUp = cpu_to_be16(1);
+
+       fan_table.HystSlope = cpu_to_be16(1);
+
+       fan_table.TempRespLim = cpu_to_be16(5);
+
+       reference_clock = smu7_get_xclk(hwmgr);
+
+       fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
+
+       fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
+
+       fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
+
+       /* fan_table.FanControl_GL_Flag = 1; */
+
+       res = smu7_copy_bytes_to_smc(hwmgr->smumgr, smu7_data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), SMC_RAM_END);
+
+       return 0;
+}
+
+
+static int iceland_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->need_update_smu7_dpm_table &
+               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+               return iceland_program_memory_timing_parameters(hwmgr);
+
+       return 0;
+}
+
+int iceland_update_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+
+       int result = 0;
+       uint32_t low_sclk_interrupt_threshold = 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkThrottleLowNotification)
+               && (hwmgr->gfx_arbiter.sclk_threshold !=
+                               data->low_sclk_interrupt_threshold)) {
+               data->low_sclk_interrupt_threshold =
+                               hwmgr->gfx_arbiter.sclk_threshold;
+               low_sclk_interrupt_threshold =
+                               data->low_sclk_interrupt_threshold;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
+
+               result = smu7_copy_bytes_to_smc(
+                               hwmgr->smumgr,
+                               smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU71_Discrete_DpmTable,
+                                       LowSclkInterruptThreshold),
+                               (uint8_t *)&low_sclk_interrupt_threshold,
+                               sizeof(uint32_t),
+                               SMC_RAM_END);
+       }
+
+       result = iceland_update_and_upload_mc_reg_table(hwmgr);
+
+       PP_ASSERT_WITH_CODE((0 == result), "Failed to upload MC reg table!", return result);
+
+       result = iceland_program_mem_timing_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE((result == 0),
+                       "Failed to program memory timing parameters!",
+                       );
+
+       return result;
+}
+
+uint32_t iceland_get_offsetof(uint32_t type, uint32_t member)
+{
+       switch (type) {
+       case SMU_SoftRegisters:
+               switch (member) {
+               case HandshakeDisables:
+                       return offsetof(SMU71_SoftRegisters, HandshakeDisables);
+               case VoltageChangeTimeout:
+                       return offsetof(SMU71_SoftRegisters, VoltageChangeTimeout);
+               case AverageGraphicsActivity:
+                       return offsetof(SMU71_SoftRegisters, AverageGraphicsActivity);
+               case PreVBlankGap:
+                       return offsetof(SMU71_SoftRegisters, PreVBlankGap);
+               case VBlankTimeout:
+                       return offsetof(SMU71_SoftRegisters, VBlankTimeout);
+               case UcodeLoadStatus:
+                       return offsetof(SMU71_SoftRegisters, UcodeLoadStatus);
+               }
+       case SMU_Discrete_DpmTable:
+               switch (member) {
+               case LowSclkInterruptThreshold:
+                       return offsetof(SMU71_Discrete_DpmTable, LowSclkInterruptThreshold);
+               }
+       }
+       printk("cant't get the offset of type %x member %x \n", type, member);
+       return 0;
+}
+
+uint32_t iceland_get_mac_definition(uint32_t value)
+{
+       switch (value) {
+       case SMU_MAX_LEVELS_GRAPHICS:
+               return SMU71_MAX_LEVELS_GRAPHICS;
+       case SMU_MAX_LEVELS_MEMORY:
+               return SMU71_MAX_LEVELS_MEMORY;
+       case SMU_MAX_LEVELS_LINK:
+               return SMU71_MAX_LEVELS_LINK;
+       case SMU_MAX_ENTRIES_SMIO:
+               return SMU71_MAX_ENTRIES_SMIO;
+       case SMU_MAX_LEVELS_VDDC:
+               return SMU71_MAX_LEVELS_VDDC;
+       case SMU_MAX_LEVELS_VDDCI:
+               return SMU71_MAX_LEVELS_VDDCI;
+       case SMU_MAX_LEVELS_MVDD:
+               return SMU71_MAX_LEVELS_MVDD;
+       }
+
+       printk("cant't get the mac of %x \n", value);
+       return 0;
+}
+
+/**
+ * Get the location of various tables inside the FW image.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int iceland_process_firmware_header(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_smumgr *smu7_data = (struct smu7_smumgr *)(hwmgr->smumgr->backend);
+
+       uint32_t tmp;
+       int result;
+       bool error = false;
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU71_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU71_Firmware_Header, DpmTable),
+                               &tmp, SMC_RAM_END);
+
+       if (0 == result) {
+               smu7_data->dpm_table_start = tmp;
+       }
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU71_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU71_Firmware_Header, SoftRegisters),
+                               &tmp, SMC_RAM_END);
+
+       if (0 == result) {
+               data->soft_regs_start = tmp;
+               smu7_data->soft_regs_start = tmp;
+       }
+
+       error |= (0 != result);
+
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU71_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU71_Firmware_Header, mcRegisterTable),
+                               &tmp, SMC_RAM_END);
+
+       if (0 == result) {
+               smu7_data->mc_reg_table_start = tmp;
+       }
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU71_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU71_Firmware_Header, FanTable),
+                               &tmp, SMC_RAM_END);
+
+       if (0 == result) {
+               smu7_data->fan_table_start = tmp;
+       }
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU71_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU71_Firmware_Header, mcArbDramTimingTable),
+                               &tmp, SMC_RAM_END);
+
+       if (0 == result) {
+               smu7_data->arb_table_start = tmp;
+       }
+
+       error |= (0 != result);
+
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU71_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU71_Firmware_Header, Version),
+                               &tmp, SMC_RAM_END);
+
+       if (0 == result) {
+               hwmgr->microcode_version_info.SMC = tmp;
+       }
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU71_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU71_Firmware_Header, UlvSettings),
+                               &tmp, SMC_RAM_END);
+
+       if (0 == result) {
+               smu7_data->ulv_setting_starts = tmp;
+       }
+
+       error |= (0 != result);
+
+       return error ? 1 : 0;
+}
+
+/*---------------------------MC----------------------------*/
+
+static uint8_t iceland_get_memory_modile_index(struct pp_hwmgr *hwmgr)
+{
+       return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
+}
+
+static bool iceland_check_s0_mc_reg_index(uint16_t in_reg, uint16_t *out_reg)
+{
+       bool result = true;
+
+       switch (in_reg) {
+       case  mmMC_SEQ_RAS_TIMING:
+               *out_reg = mmMC_SEQ_RAS_TIMING_LP;
+               break;
+
+       case  mmMC_SEQ_DLL_STBY:
+               *out_reg = mmMC_SEQ_DLL_STBY_LP;
+               break;
+
+       case  mmMC_SEQ_G5PDX_CMD0:
+               *out_reg = mmMC_SEQ_G5PDX_CMD0_LP;
+               break;
+
+       case  mmMC_SEQ_G5PDX_CMD1:
+               *out_reg = mmMC_SEQ_G5PDX_CMD1_LP;
+               break;
+
+       case  mmMC_SEQ_G5PDX_CTRL:
+               *out_reg = mmMC_SEQ_G5PDX_CTRL_LP;
+               break;
+
+       case mmMC_SEQ_CAS_TIMING:
+               *out_reg = mmMC_SEQ_CAS_TIMING_LP;
+               break;
+
+       case mmMC_SEQ_MISC_TIMING:
+               *out_reg = mmMC_SEQ_MISC_TIMING_LP;
+               break;
+
+       case mmMC_SEQ_MISC_TIMING2:
+               *out_reg = mmMC_SEQ_MISC_TIMING2_LP;
+               break;
+
+       case mmMC_SEQ_PMG_DVS_CMD:
+               *out_reg = mmMC_SEQ_PMG_DVS_CMD_LP;
+               break;
+
+       case mmMC_SEQ_PMG_DVS_CTL:
+               *out_reg = mmMC_SEQ_PMG_DVS_CTL_LP;
+               break;
+
+       case mmMC_SEQ_RD_CTL_D0:
+               *out_reg = mmMC_SEQ_RD_CTL_D0_LP;
+               break;
+
+       case mmMC_SEQ_RD_CTL_D1:
+               *out_reg = mmMC_SEQ_RD_CTL_D1_LP;
+               break;
+
+       case mmMC_SEQ_WR_CTL_D0:
+               *out_reg = mmMC_SEQ_WR_CTL_D0_LP;
+               break;
+
+       case mmMC_SEQ_WR_CTL_D1:
+               *out_reg = mmMC_SEQ_WR_CTL_D1_LP;
+               break;
+
+       case mmMC_PMG_CMD_EMRS:
+               *out_reg = mmMC_SEQ_PMG_CMD_EMRS_LP;
+               break;
+
+       case mmMC_PMG_CMD_MRS:
+               *out_reg = mmMC_SEQ_PMG_CMD_MRS_LP;
+               break;
+
+       case mmMC_PMG_CMD_MRS1:
+               *out_reg = mmMC_SEQ_PMG_CMD_MRS1_LP;
+               break;
+
+       case mmMC_SEQ_PMG_TIMING:
+               *out_reg = mmMC_SEQ_PMG_TIMING_LP;
+               break;
+
+       case mmMC_PMG_CMD_MRS2:
+               *out_reg = mmMC_SEQ_PMG_CMD_MRS2_LP;
+               break;
+
+       case mmMC_SEQ_WR_CTL_2:
+               *out_reg = mmMC_SEQ_WR_CTL_2_LP;
+               break;
+
+       default:
+               result = false;
+               break;
+       }
+
+       return result;
+}
+
+static int iceland_set_s0_mc_reg_index(struct iceland_mc_reg_table *table)
+{
+       uint32_t i;
+       uint16_t address;
+
+       for (i = 0; i < table->last; i++) {
+               table->mc_reg_address[i].s0 =
+                       iceland_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address)
+                       ? address : table->mc_reg_address[i].s1;
+       }
+       return 0;
+}
+
+static int iceland_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table,
+                                       struct iceland_mc_reg_table *ni_table)
+{
+       uint8_t i, j;
+
+       PP_ASSERT_WITH_CODE((table->last <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+               "Invalid VramInfo table.", return -EINVAL);
+       PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
+               "Invalid VramInfo table.", return -EINVAL);
+
+       for (i = 0; i < table->last; i++) {
+               ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+       }
+       ni_table->last = table->last;
+
+       for (i = 0; i < table->num_entries; i++) {
+               ni_table->mc_reg_table_entry[i].mclk_max =
+                       table->mc_reg_table_entry[i].mclk_max;
+               for (j = 0; j < table->last; j++) {
+                       ni_table->mc_reg_table_entry[i].mc_data[j] =
+                               table->mc_reg_table_entry[i].mc_data[j];
+               }
+       }
+
+       ni_table->num_entries = table->num_entries;
+
+       return 0;
+}
+
+/**
+ * VBIOS omits some information to reduce size, we need to recover them here.
+ * 1.   when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to  mmMC_PMG_CMD_EMRS /_LP[15:0].
+ *      Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
+ * 2.   when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
+ * 3.   need to set these data for each clock range
+ *
+ * @param    hwmgr the address of the powerplay hardware manager.
+ * @param    table the address of MCRegTable
+ * @return   always 0
+ */
+static int iceland_set_mc_special_registers(struct pp_hwmgr *hwmgr,
+                                       struct iceland_mc_reg_table *table)
+{
+       uint8_t i, j, k;
+       uint32_t temp_reg;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       for (i = 0, j = table->last; i < table->last; i++) {
+               PP_ASSERT_WITH_CODE((j < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                       "Invalid VramInfo table.", return -EINVAL);
+
+               switch (table->mc_reg_address[i].s1) {
+
+               case mmMC_SEQ_MISC1:
+                       temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS);
+                       table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
+                       table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
+                       for (k = 0; k < table->num_entries; k++) {
+                               table->mc_reg_table_entry[k].mc_data[j] =
+                                       ((temp_reg & 0xffff0000)) |
+                                       ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
+                       }
+                       j++;
+                       PP_ASSERT_WITH_CODE((j < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                               "Invalid VramInfo table.", return -EINVAL);
+
+                       temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
+                       table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
+                       table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
+                       for (k = 0; k < table->num_entries; k++) {
+                               table->mc_reg_table_entry[k].mc_data[j] =
+                                       (temp_reg & 0xffff0000) |
+                                       (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+
+                               if (!data->is_memory_gddr5) {
+                                       table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+                               }
+                       }
+                       j++;
+                       PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                               "Invalid VramInfo table.", return -EINVAL);
+
+                       if (!data->is_memory_gddr5) {
+                               table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
+                               table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
+                               for (k = 0; k < table->num_entries; k++) {
+                                       table->mc_reg_table_entry[k].mc_data[j] =
+                                               (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
+                               }
+                               j++;
+                               PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                                       "Invalid VramInfo table.", return -EINVAL);
+                       }
+
+                       break;
+
+               case mmMC_SEQ_RESERVE_M:
+                       temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
+                       table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
+                       table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
+                       for (k = 0; k < table->num_entries; k++) {
+                               table->mc_reg_table_entry[k].mc_data[j] =
+                                       (temp_reg & 0xffff0000) |
+                                       (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+                       }
+                       j++;
+                       PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                               "Invalid VramInfo table.", return -EINVAL);
+                       break;
+
+               default:
+                       break;
+               }
+
+       }
+
+       table->last = j;
+
+       return 0;
+}
+
+static int iceland_set_valid_flag(struct iceland_mc_reg_table *table)
+{
+       uint8_t i, j;
+       for (i = 0; i < table->last; i++) {
+               for (j = 1; j < table->num_entries; j++) {
+                       if (table->mc_reg_table_entry[j-1].mc_data[i] !=
+                               table->mc_reg_table_entry[j].mc_data[i]) {
+                               table->validflag |= (1<<i);
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smumgr->backend);
+       pp_atomctrl_mc_reg_table *table;
+       struct iceland_mc_reg_table *ni_table = &smu_data->mc_reg_table;
+       uint8_t module_index = iceland_get_memory_modile_index(hwmgr);
+
+       table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
+
+       if (NULL == table)
+               return -ENOMEM;
+
+       /* Program additional LP registers that are no longer programmed by VBIOS */
+       cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
+
+       memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
+
+       result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
+
+       if (0 == result)
+               result = iceland_copy_vbios_smc_reg_table(table, ni_table);
+
+       if (0 == result) {
+               iceland_set_s0_mc_reg_index(ni_table);
+               result = iceland_set_mc_special_registers(hwmgr, ni_table);
+       }
+
+       if (0 == result)
+               iceland_set_valid_flag(ni_table);
+
+       kfree(table);
+
+       return result;
+}
+
+bool iceland_is_dpm_running(struct pp_hwmgr *hwmgr)
+{
+       return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
+                       CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
+                       ? true : false;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.h b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.h
new file mode 100644 (file)
index 0000000..13c8dbb
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 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 _ICELAND_SMC_H
+#define _ICELAND_SMC_H
+
+#include "smumgr.h"
+
+
+int iceland_populate_all_graphic_levels(struct pp_hwmgr *hwmgr);
+int iceland_populate_all_memory_levels(struct pp_hwmgr *hwmgr);
+int iceland_init_smc_table(struct pp_hwmgr *hwmgr);
+int iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr);
+int iceland_update_sclk_threshold(struct pp_hwmgr *hwmgr);
+uint32_t iceland_get_offsetof(uint32_t type, uint32_t member);
+uint32_t iceland_get_mac_definition(uint32_t value);
+int iceland_process_firmware_header(struct pp_hwmgr *hwmgr);
+int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr);
+bool iceland_is_dpm_running(struct pp_hwmgr *hwmgr);
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c
new file mode 100644 (file)
index 0000000..eeafefc
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ *
+ * Author: Huang Rui <ray.huang@amd.com>
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+
+#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"
+#include "smu/smu_7_1_1_sh_mask.h"
+#include "cgs_common.h"
+#include "iceland_smc.h"
+
+#define ICELAND_SMC_SIZE               0x20000
+
+static int iceland_start_smc(struct pp_smumgr *smumgr)
+{
+       SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+                                 SMC_SYSCON_RESET_CNTL, rst_reg, 0);
+
+       return 0;
+}
+
+static void iceland_reset_smc(struct pp_smumgr *smumgr)
+{
+       SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+                                 SMC_SYSCON_RESET_CNTL,
+                                 rst_reg, 1);
+}
+
+
+static void iceland_stop_smc_clock(struct pp_smumgr *smumgr)
+{
+       SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+                                 SMC_SYSCON_CLOCK_CNTL_0,
+                                 ck_disable, 1);
+}
+
+static void iceland_start_smc_clock(struct pp_smumgr *smumgr)
+{
+       SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+                                 SMC_SYSCON_CLOCK_CNTL_0,
+                                 ck_disable, 0);
+}
+
+static int iceland_smu_start_smc(struct pp_smumgr *smumgr)
+{
+       /* set smc instruct start point at 0x0 */
+       smu7_program_jump_on_start(smumgr);
+
+       /* enable smc clock */
+       iceland_start_smc_clock(smumgr);
+
+       /* de-assert reset */
+       iceland_start_smc(smumgr);
+
+       SMUM_WAIT_INDIRECT_FIELD(smumgr, SMC_IND, FIRMWARE_FLAGS,
+                                INTERRUPTS_ENABLED, 1);
+
+       return 0;
+}
+
+
+static int iceland_upload_smc_firmware_data(struct pp_smumgr *smumgr,
+                                       uint32_t length, const uint8_t *src,
+                                       uint32_t limit, uint32_t start_addr)
+{
+       uint32_t byte_count = length;
+       uint32_t data;
+
+       PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area.", return -EINVAL);
+
+       cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, start_addr);
+       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
+
+       while (byte_count >= 4) {
+               data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
+               cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
+               src += 4;
+               byte_count -= 4;
+       }
+
+       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
+
+       PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be dividable by 4.", return -EINVAL);
+
+       return 0;
+}
+
+
+static int iceland_smu_upload_firmware_image(struct pp_smumgr *smumgr)
+{
+       uint32_t val;
+       struct cgs_firmware_info info = {0};
+
+       if (smumgr == NULL || smumgr->device == NULL)
+               return -EINVAL;
+
+       /* load SMC firmware */
+       cgs_get_firmware_info(smumgr->device,
+               smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
+
+       if (info.image_size & 3) {
+               pr_err("[ powerplay ] SMC ucode is not 4 bytes aligned\n");
+               return -EINVAL;
+       }
+
+       if (info.image_size > ICELAND_SMC_SIZE) {
+               pr_err("[ powerplay ] SMC address is beyond the SMC RAM area\n");
+               return -EINVAL;
+       }
+
+       /* wait for smc boot up */
+       SMUM_WAIT_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+                                        RCU_UC_EVENTS, boot_seq_done, 0);
+
+       /* clear firmware interrupt enable flag */
+       val = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC,
+                                   ixSMC_SYSCON_MISC_CNTL);
+       cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+                              ixSMC_SYSCON_MISC_CNTL, val | 1);
+
+       /* stop smc clock */
+       iceland_stop_smc_clock(smumgr);
+
+       /* reset smc */
+       iceland_reset_smc(smumgr);
+       iceland_upload_smc_firmware_data(smumgr, info.image_size,
+                               (uint8_t *)info.kptr, ICELAND_SMC_SIZE,
+                               info.ucode_start_address);
+
+       return 0;
+}
+
+static int iceland_request_smu_load_specific_fw(struct pp_smumgr *smumgr,
+                                               uint32_t firmwareType)
+{
+       return 0;
+}
+
+static int iceland_start_smu(struct pp_smumgr *smumgr)
+{
+       int result;
+
+       result = iceland_smu_upload_firmware_image(smumgr);
+       if (result)
+               return result;
+       result = iceland_smu_start_smc(smumgr);
+       if (result)
+               return result;
+
+       if (!smu7_is_smc_ram_running(smumgr)) {
+               printk("smu not running, upload firmware again \n");
+               result = iceland_smu_upload_firmware_image(smumgr);
+               if (result)
+                       return result;
+
+               result = iceland_smu_start_smc(smumgr);
+               if (result)
+                       return result;
+       }
+
+       result = smu7_request_smu_load_fw(smumgr);
+
+       return result;
+}
+
+/**
+ * Write a 32bit value to the SMC SRAM space.
+ * ALL PARAMETERS ARE IN HOST BYTE ORDER.
+ * @param    smumgr  the address of the powerplay hardware manager.
+ * @param    smcAddress the address in the SMC RAM to access.
+ * @param    value to write to the SMC SRAM.
+ */
+static int iceland_smu_init(struct pp_smumgr *smumgr)
+{
+       int i;
+       struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
+       if (smu7_init(smumgr))
+               return -EINVAL;
+
+       for (i = 0; i < SMU71_MAX_LEVELS_GRAPHICS; i++)
+               smu_data->activity_target[i] = 30;
+
+       return 0;
+}
+
+static const struct pp_smumgr_func iceland_smu_funcs = {
+       .smu_init = &iceland_smu_init,
+       .smu_fini = &smu7_smu_fini,
+       .start_smu = &iceland_start_smu,
+       .check_fw_load_finish = &smu7_check_fw_load_finish,
+       .request_smu_load_fw = &smu7_reload_firmware,
+       .request_smu_load_specific_fw = &iceland_request_smu_load_specific_fw,
+       .send_msg_to_smc = &smu7_send_msg_to_smc,
+       .send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
+       .download_pptable_settings = NULL,
+       .upload_pptable_settings = NULL,
+       .get_offsetof = iceland_get_offsetof,
+       .process_firmware_header = iceland_process_firmware_header,
+       .init_smc_table = iceland_init_smc_table,
+       .update_sclk_threshold = iceland_update_sclk_threshold,
+       .thermal_setup_fan_table = iceland_thermal_setup_fan_table,
+       .populate_all_graphic_levels = iceland_populate_all_graphic_levels,
+       .populate_all_memory_levels = iceland_populate_all_memory_levels,
+       .get_mac_definition = iceland_get_mac_definition,
+       .initialize_mc_reg_table = iceland_initialize_mc_reg_table,
+       .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/iceland_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h
new file mode 100644 (file)
index 0000000..8eae01b
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ *
+ * Author: Huang Rui <ray.huang@amd.com>
+ *
+ */
+
+#ifndef _ICELAND_SMUMGR_H_
+#define _ICELAND_SMUMGR_H_
+
+
+#include "smu7_smumgr.h"
+#include "pp_endian.h"
+#include "smu71_discrete.h"
+
+struct iceland_pt_defaults {
+       uint8_t   svi_load_line_en;
+       uint8_t   svi_load_line_vddc;
+       uint8_t   tdc_vddc_throttle_release_limit_perc;
+       uint8_t   tdc_mawt;
+       uint8_t   tdc_waterfall_ctl;
+       uint8_t   dte_ambient_temp_base;
+       uint32_t  display_cac;
+       uint32_t  bamp_temp_gradient;
+       uint16_t  bapmti_r[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS];
+       uint16_t  bapmti_rc[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS];
+};
+
+struct iceland_mc_reg_entry {
+       uint32_t mclk_max;
+       uint32_t mc_data[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct iceland_mc_reg_table {
+       uint8_t   last;               /* number of registers*/
+       uint8_t   num_entries;        /* number of entries in mc_reg_table_entry used*/
+       uint16_t  validflag;          /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
+       struct iceland_mc_reg_entry    mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+       SMU71_Discrete_MCRegisterAddress mc_reg_address[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct iceland_smumgr {
+       struct smu7_smumgr smu7_data;
+       struct SMU71_Discrete_DpmTable       smc_state_table;
+       struct SMU71_Discrete_PmFuses  power_tune_table;
+       struct SMU71_Discrete_Ulv            ulv_setting;
+       const struct iceland_pt_defaults  *power_tune_defaults;
+       SMU71_Discrete_MCRegisters      mc_regs;
+       struct iceland_mc_reg_table mc_reg_table;
+       uint32_t        activity_target[SMU71_MAX_LEVELS_GRAPHICS];
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c
new file mode 100644 (file)
index 0000000..4ccc0b7
--- /dev/null
@@ -0,0 +1,2287 @@
+/*
+ * Copyright 2015 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 "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"
+#include "pppcielanes.h"
+
+#include "smu_ucode_xfer_vi.h"
+#include "smu74_discrete.h"
+#include "smu/smu_7_1_3_d.h"
+#include "smu/smu_7_1_3_sh_mask.h"
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+#include "oss/oss_3_0_d.h"
+#include "gca/gfx_8_0_d.h"
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+#include "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+#include "polaris10_pwrvirus.h"
+#include "smu7_ppsmc.h"
+#include "smu7_smumgr.h"
+
+#define POLARIS10_SMC_SIZE 0x20000
+#define VOLTAGE_VID_OFFSET_SCALE1   625
+#define VOLTAGE_VID_OFFSET_SCALE2   100
+#define POWERTUNE_DEFAULT_SET_MAX    1
+#define VDDC_VDDCI_DELTA            200
+#define MC_CG_ARB_FREQ_F1           0x0b
+
+static const struct polaris10_pt_defaults polaris10_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
+       /* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
+        * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT */
+       { 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
+       { 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61},
+       { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 } },
+};
+
+static const sclkFcwRange_t Range_Table[NUM_SCLK_RANGE] = {
+                       {VCO_2_4, POSTDIV_DIV_BY_16,  75, 160, 112},
+                       {VCO_3_6, POSTDIV_DIV_BY_16, 112, 224, 160},
+                       {VCO_2_4, POSTDIV_DIV_BY_8,   75, 160, 112},
+                       {VCO_3_6, POSTDIV_DIV_BY_8,  112, 224, 160},
+                       {VCO_2_4, POSTDIV_DIV_BY_4,   75, 160, 112},
+                       {VCO_3_6, POSTDIV_DIV_BY_4,  112, 216, 160},
+                       {VCO_2_4, POSTDIV_DIV_BY_2,   75, 160, 108},
+                       {VCO_3_6, POSTDIV_DIV_BY_2,  112, 216, 160} };
+
+static int polaris10_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
+               struct phm_ppt_v1_clock_voltage_dependency_table *dep_table,
+               uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
+{
+       uint32_t i;
+       uint16_t vddci;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       *voltage = *mvdd = 0;
+
+       /* clock - voltage dependency table is empty table */
+       if (dep_table->count == 0)
+               return -EINVAL;
+
+       for (i = 0; i < dep_table->count; i++) {
+               /* find first sclk bigger than request */
+               if (dep_table->entries[i].clk >= clock) {
+                       *voltage |= (dep_table->entries[i].vddc *
+                                       VOLTAGE_SCALE) << VDDC_SHIFT;
+                       if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
+                               *voltage |= (data->vbios_boot_state.vddci_bootup_value *
+                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
+                       else if (dep_table->entries[i].vddci)
+                               *voltage |= (dep_table->entries[i].vddci *
+                                               VOLTAGE_SCALE) << VDDCI_SHIFT;
+                       else {
+                               vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
+                                               (dep_table->entries[i].vddc -
+                                                               (uint16_t)VDDC_VDDCI_DELTA));
+                               *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+                       }
+
+                       if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control)
+                               *mvdd = data->vbios_boot_state.mvdd_bootup_value *
+                                       VOLTAGE_SCALE;
+                       else if (dep_table->entries[i].mvdd)
+                               *mvdd = (uint32_t) dep_table->entries[i].mvdd *
+                                       VOLTAGE_SCALE;
+
+                       *voltage |= 1 << PHASES_SHIFT;
+                       return 0;
+               }
+       }
+
+       /* sclk is bigger than max sclk in the dependence table */
+       *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
+
+       if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
+               *voltage |= (data->vbios_boot_state.vddci_bootup_value *
+                               VOLTAGE_SCALE) << VDDCI_SHIFT;
+       else if (dep_table->entries[i-1].vddci) {
+               vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
+                               (dep_table->entries[i].vddc -
+                                               (uint16_t)VDDC_VDDCI_DELTA));
+               *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+       }
+
+       if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control)
+               *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
+       else if (dep_table->entries[i].mvdd)
+               *mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE;
+
+       return 0;
+}
+
+static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
+{
+       uint32_t tmp;
+       tmp = raw_setting * 4096 / 100;
+       return (uint16_t)tmp;
+}
+
+static int polaris10_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+
+       const struct polaris10_pt_defaults *defaults = smu_data->power_tune_defaults;
+       SMU74_Discrete_DpmTable  *table = &(smu_data->smc_state_table);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
+       struct pp_advance_fan_control_parameters *fan_table =
+                       &hwmgr->thermal_controller.advanceFanControlParameters;
+       int i, j, k;
+       const uint16_t *pdef1;
+       const uint16_t *pdef2;
+
+       table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 128));
+       table->TargetTdp  = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 128));
+
+       PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
+                               "Target Operating Temp is out of Range!",
+                               );
+
+       table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
+                       cac_dtp_table->usTargetOperatingTemp * 256);
+       table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
+                       cac_dtp_table->usTemperatureLimitHotspot * 256);
+       table->FanGainEdge = PP_HOST_TO_SMC_US(
+                       scale_fan_gain_settings(fan_table->usFanGainEdge));
+       table->FanGainHotspot = PP_HOST_TO_SMC_US(
+                       scale_fan_gain_settings(fan_table->usFanGainHotspot));
+
+       pdef1 = defaults->BAPMTI_R;
+       pdef2 = defaults->BAPMTI_RC;
+
+       for (i = 0; i < SMU74_DTE_ITERATIONS; i++) {
+               for (j = 0; j < SMU74_DTE_SOURCES; j++) {
+                       for (k = 0; k < SMU74_DTE_SINKS; k++) {
+                               table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*pdef1);
+                               table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*pdef2);
+                               pdef1++;
+                               pdef2++;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int polaris10_populate_svi_load_line(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       const struct polaris10_pt_defaults *defaults = smu_data->power_tune_defaults;
+
+       smu_data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
+       smu_data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
+       smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
+       smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
+
+       return 0;
+}
+
+static int polaris10_populate_tdc_limit(struct pp_hwmgr *hwmgr)
+{
+       uint16_t tdc_limit;
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       const struct polaris10_pt_defaults *defaults = smu_data->power_tune_defaults;
+
+       tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
+       smu_data->power_tune_table.TDC_VDDC_PkgLimit =
+                       CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
+       smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
+                       defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
+       smu_data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
+
+       return 0;
+}
+
+static int polaris10_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       const struct polaris10_pt_defaults *defaults = smu_data->power_tune_defaults;
+       uint32_t temp;
+
+       if (smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       fuse_table_offset +
+                       offsetof(SMU74_Discrete_PmFuses, TdcWaterfallCtl),
+                       (uint32_t *)&temp, SMC_RAM_END))
+               PP_ASSERT_WITH_CODE(false,
+                               "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
+                               return -EINVAL);
+       else {
+               smu_data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
+               smu_data->power_tune_table.LPMLTemperatureMin =
+                               (uint8_t)((temp >> 16) & 0xff);
+               smu_data->power_tune_table.LPMLTemperatureMax =
+                               (uint8_t)((temp >> 8) & 0xff);
+               smu_data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
+       }
+       return 0;
+}
+
+static int polaris10_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
+{
+       int i;
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+
+       /* Currently not used. Set all to zero. */
+       for (i = 0; i < 16; i++)
+               smu_data->power_tune_table.LPMLTemperatureScaler[i] = 0;
+
+       return 0;
+}
+
+static int polaris10_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+
+/* TO DO move to hwmgr */
+       if ((hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity & (1 << 15))
+               || 0 == hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity)
+               hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity =
+                       hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity;
+
+       smu_data->power_tune_table.FuzzyFan_PwmSetDelta = PP_HOST_TO_SMC_US(
+                               hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity);
+       return 0;
+}
+
+static int polaris10_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
+{
+       int i;
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+
+       /* Currently not used. Set all to zero. */
+       for (i = 0; i < 16; i++)
+               smu_data->power_tune_table.GnbLPML[i] = 0;
+
+       return 0;
+}
+
+static int polaris10_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
+{
+       return 0;
+}
+
+static int polaris10_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       uint16_t hi_sidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd;
+       uint16_t lo_sidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd;
+       struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
+
+       hi_sidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
+       lo_sidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
+
+       smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
+                       CONVERT_FROM_HOST_TO_SMC_US(hi_sidd);
+       smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
+                       CONVERT_FROM_HOST_TO_SMC_US(lo_sidd);
+
+       return 0;
+}
+
+static int polaris10_populate_pm_fuses(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t pm_fuse_table_offset;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PowerContainment)) {
+               if (smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU7_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU74_Firmware_Header, PmFuseTable),
+                               &pm_fuse_table_offset, SMC_RAM_END))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to get pm_fuse_table_offset Failed!",
+                                       return -EINVAL);
+
+               if (polaris10_populate_svi_load_line(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate SviLoadLine Failed!",
+                                       return -EINVAL);
+
+               if (polaris10_populate_tdc_limit(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate TDCLimit Failed!", return -EINVAL);
+
+               if (polaris10_populate_dw8(hwmgr, pm_fuse_table_offset))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate TdcWaterfallCtl, "
+                                       "LPMLTemperature Min and Max Failed!",
+                                       return -EINVAL);
+
+               if (0 != polaris10_populate_temperature_scaler(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate LPMLTemperatureScaler Failed!",
+                                       return -EINVAL);
+
+               if (polaris10_populate_fuzzy_fan(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate Fuzzy Fan Control parameters Failed!",
+                                       return -EINVAL);
+
+               if (polaris10_populate_gnb_lpml(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate GnbLPML Failed!",
+                                       return -EINVAL);
+
+               if (polaris10_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate GnbLPML Min and Max Vid Failed!",
+                                       return -EINVAL);
+
+               if (polaris10_populate_bapm_vddc_base_leakage_sidd(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate BapmVddCBaseLeakage Hi and Lo "
+                                       "Sidd Failed!", return -EINVAL);
+
+               if (smu7_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
+                               (uint8_t *)&smu_data->power_tune_table,
+                               (sizeof(struct SMU74_Discrete_PmFuses) - 92), SMC_RAM_END))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to download PmFuseTable Failed!",
+                                       return -EINVAL);
+       }
+       return 0;
+}
+
+/**
+ * Mvdd table preparation for SMC.
+ *
+ * @param    *hwmgr The address of the hardware manager.
+ * @param    *table The SMC DPM table structure to be populated.
+ * @return   0
+ */
+static int polaris10_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
+                       SMU74_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t count, level;
+
+       if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+               count = data->mvdd_voltage_table.count;
+               if (count > SMU_MAX_SMIO_LEVELS)
+                       count = SMU_MAX_SMIO_LEVELS;
+               for (level = 0; level < count; level++) {
+                       table->SmioTable2.Pattern[level].Voltage =
+                               PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE);
+                       /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
+                       table->SmioTable2.Pattern[level].Smio =
+                               (uint8_t) level;
+                       table->Smio[level] |=
+                               data->mvdd_voltage_table.entries[level].smio_low;
+               }
+               table->SmioMask2 = data->mvdd_voltage_table.mask_low;
+
+               table->MvddLevelCount = (uint32_t) PP_HOST_TO_SMC_UL(count);
+       }
+
+       return 0;
+}
+
+static int polaris10_populate_smc_vddci_table(struct pp_hwmgr *hwmgr,
+                                       struct SMU74_Discrete_DpmTable *table)
+{
+       uint32_t count, level;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       count = data->vddci_voltage_table.count;
+
+       if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+               if (count > SMU_MAX_SMIO_LEVELS)
+                       count = SMU_MAX_SMIO_LEVELS;
+               for (level = 0; level < count; ++level) {
+                       table->SmioTable1.Pattern[level].Voltage =
+                               PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[level].value * VOLTAGE_SCALE);
+                       table->SmioTable1.Pattern[level].Smio = (uint8_t) level;
+
+                       table->Smio[level] |= data->vddci_voltage_table.entries[level].smio_low;
+               }
+       }
+
+       table->SmioMask1 = data->vddci_voltage_table.mask_low;
+
+       return 0;
+}
+
+/**
+* Preparation of vddc and vddgfx CAC tables for SMC.
+*
+* @param    hwmgr  the address of the hardware manager
+* @param    table  the SMC DPM table structure to be populated
+* @return   always 0
+*/
+static int polaris10_populate_cac_table(struct pp_hwmgr *hwmgr,
+               struct SMU74_Discrete_DpmTable *table)
+{
+       uint32_t count;
+       uint8_t index;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_voltage_lookup_table *lookup_table =
+                       table_info->vddc_lookup_table;
+       /* tables is already swapped, so in order to use the value from it,
+        * we need to swap it back.
+        * We are populating vddc CAC data to BapmVddc table
+        * in split and merged mode
+        */
+       for (count = 0; count < lookup_table->count; count++) {
+               index = phm_get_voltage_index(lookup_table,
+                               data->vddc_voltage_table.entries[count].value);
+               table->BapmVddcVidLoSidd[count] = convert_to_vid(lookup_table->entries[index].us_cac_low);
+               table->BapmVddcVidHiSidd[count] = convert_to_vid(lookup_table->entries[index].us_cac_mid);
+               table->BapmVddcVidHiSidd2[count] = convert_to_vid(lookup_table->entries[index].us_cac_high);
+       }
+
+       return 0;
+}
+
+/**
+* Preparation of voltage tables for SMC.
+*
+* @param    hwmgr   the address of the hardware manager
+* @param    table   the SMC DPM table structure to be populated
+* @return   always  0
+*/
+
+static int polaris10_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
+               struct SMU74_Discrete_DpmTable *table)
+{
+       polaris10_populate_smc_vddci_table(hwmgr, table);
+       polaris10_populate_smc_mvdd_table(hwmgr, table);
+       polaris10_populate_cac_table(hwmgr, table);
+
+       return 0;
+}
+
+static int polaris10_populate_ulv_level(struct pp_hwmgr *hwmgr,
+               struct SMU74_Discrete_Ulv *state)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       state->CcPwrDynRm = 0;
+       state->CcPwrDynRm1 = 0;
+
+       state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
+       state->VddcOffsetVid = (uint8_t)(table_info->us_ulv_voltage_offset *
+                       VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
+
+       state->VddcPhase = (data->vddc_phase_shed_control) ? 0 : 1;
+
+       CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
+       CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
+       CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
+
+       return 0;
+}
+
+static int polaris10_populate_ulv_state(struct pp_hwmgr *hwmgr,
+               struct SMU74_Discrete_DpmTable *table)
+{
+       return polaris10_populate_ulv_level(hwmgr, &table->Ulv);
+}
+
+static int polaris10_populate_smc_link_level(struct pp_hwmgr *hwmgr,
+               struct SMU74_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       int i;
+
+       /* Index (dpm_table->pcie_speed_table.count)
+        * is reserved for PCIE boot level. */
+       for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
+               table->LinkLevel[i].PcieGenSpeed  =
+                               (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
+               table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width(
+                               dpm_table->pcie_speed_table.dpm_levels[i].param1);
+               table->LinkLevel[i].EnabledForActivity = 1;
+               table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff);
+               table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5);
+               table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30);
+       }
+
+       smu_data->smc_state_table.LinkLevelCount =
+                       (uint8_t)dpm_table->pcie_speed_table.count;
+
+/* To Do move to hwmgr */
+       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+                       phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
+
+       return 0;
+}
+
+
+static void polaris10_get_sclk_range_table(struct pp_hwmgr *hwmgr,
+                                  SMU74_Discrete_DpmTable  *table)
+{
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       uint32_t i, ref_clk;
+
+       struct pp_atom_ctrl_sclk_range_table range_table_from_vbios = { { {0} } };
+
+       ref_clk = smu7_get_xclk(hwmgr);
+
+       if (0 == atomctrl_get_smc_sclk_range_table(hwmgr, &range_table_from_vbios)) {
+               for (i = 0; i < NUM_SCLK_RANGE; i++) {
+                       table->SclkFcwRangeTable[i].vco_setting = range_table_from_vbios.entry[i].ucVco_setting;
+                       table->SclkFcwRangeTable[i].postdiv = range_table_from_vbios.entry[i].ucPostdiv;
+                       table->SclkFcwRangeTable[i].fcw_pcc = range_table_from_vbios.entry[i].usFcw_pcc;
+
+                       table->SclkFcwRangeTable[i].fcw_trans_upper = range_table_from_vbios.entry[i].usFcw_trans_upper;
+                       table->SclkFcwRangeTable[i].fcw_trans_lower = range_table_from_vbios.entry[i].usRcw_trans_lower;
+
+                       CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_pcc);
+                       CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_trans_upper);
+                       CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_trans_lower);
+               }
+               return;
+       }
+
+       for (i = 0; i < NUM_SCLK_RANGE; i++) {
+               smu_data->range_table[i].trans_lower_frequency = (ref_clk * Range_Table[i].fcw_trans_lower) >> Range_Table[i].postdiv;
+               smu_data->range_table[i].trans_upper_frequency = (ref_clk * Range_Table[i].fcw_trans_upper) >> Range_Table[i].postdiv;
+
+               table->SclkFcwRangeTable[i].vco_setting = Range_Table[i].vco_setting;
+               table->SclkFcwRangeTable[i].postdiv = Range_Table[i].postdiv;
+               table->SclkFcwRangeTable[i].fcw_pcc = Range_Table[i].fcw_pcc;
+
+               table->SclkFcwRangeTable[i].fcw_trans_upper = Range_Table[i].fcw_trans_upper;
+               table->SclkFcwRangeTable[i].fcw_trans_lower = Range_Table[i].fcw_trans_lower;
+
+               CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_pcc);
+               CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_trans_upper);
+               CONVERT_FROM_HOST_TO_SMC_US(table->SclkFcwRangeTable[i].fcw_trans_lower);
+       }
+}
+
+/**
+* Calculates the SCLK dividers using the provided engine clock
+*
+* @param    hwmgr  the address of the hardware manager
+* @param    clock  the engine clock to use to populate the structure
+* @param    sclk   the SMC SCLK structure to be populated
+*/
+static int polaris10_calculate_sclk_params(struct pp_hwmgr *hwmgr,
+               uint32_t clock, SMU_SclkSetting *sclk_setting)
+{
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       const SMU74_Discrete_DpmTable *table = &(smu_data->smc_state_table);
+       struct pp_atomctrl_clock_dividers_ai dividers;
+       uint32_t ref_clock;
+       uint32_t pcc_target_percent, pcc_target_freq, ss_target_percent, ss_target_freq;
+       uint8_t i;
+       int result;
+       uint64_t temp;
+
+       sclk_setting->SclkFrequency = clock;
+       /* get the engine clock dividers for this clock value */
+       result = atomctrl_get_engine_pll_dividers_ai(hwmgr, clock,  &dividers);
+       if (result == 0) {
+               sclk_setting->Fcw_int = dividers.usSclk_fcw_int;
+               sclk_setting->Fcw_frac = dividers.usSclk_fcw_frac;
+               sclk_setting->Pcc_fcw_int = dividers.usPcc_fcw_int;
+               sclk_setting->PllRange = dividers.ucSclkPllRange;
+               sclk_setting->Sclk_slew_rate = 0x400;
+               sclk_setting->Pcc_up_slew_rate = dividers.usPcc_fcw_slew_frac;
+               sclk_setting->Pcc_down_slew_rate = 0xffff;
+               sclk_setting->SSc_En = dividers.ucSscEnable;
+               sclk_setting->Fcw1_int = dividers.usSsc_fcw1_int;
+               sclk_setting->Fcw1_frac = dividers.usSsc_fcw1_frac;
+               sclk_setting->Sclk_ss_slew_rate = dividers.usSsc_fcw_slew_frac;
+               return result;
+       }
+
+       ref_clock = smu7_get_xclk(hwmgr);
+
+       for (i = 0; i < NUM_SCLK_RANGE; i++) {
+               if (clock > smu_data->range_table[i].trans_lower_frequency
+               && clock <= smu_data->range_table[i].trans_upper_frequency) {
+                       sclk_setting->PllRange = i;
+                       break;
+               }
+       }
+
+       sclk_setting->Fcw_int = (uint16_t)((clock << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv) / ref_clock);
+       temp = clock << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv;
+       temp <<= 0x10;
+       do_div(temp, ref_clock);
+       sclk_setting->Fcw_frac = temp & 0xffff;
+
+       pcc_target_percent = 10; /*  Hardcode 10% for now. */
+       pcc_target_freq = clock - (clock * pcc_target_percent / 100);
+       sclk_setting->Pcc_fcw_int = (uint16_t)((pcc_target_freq << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv) / ref_clock);
+
+       ss_target_percent = 2; /*  Hardcode 2% for now. */
+       sclk_setting->SSc_En = 0;
+       if (ss_target_percent) {
+               sclk_setting->SSc_En = 1;
+               ss_target_freq = clock - (clock * ss_target_percent / 100);
+               sclk_setting->Fcw1_int = (uint16_t)((ss_target_freq << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv) / ref_clock);
+               temp = ss_target_freq << table->SclkFcwRangeTable[sclk_setting->PllRange].postdiv;
+               temp <<= 0x10;
+               do_div(temp, ref_clock);
+               sclk_setting->Fcw1_frac = temp & 0xffff;
+       }
+
+       return 0;
+}
+
+/**
+* Populates single SMC SCLK structure using the provided engine clock
+*
+* @param    hwmgr      the address of the hardware manager
+* @param    clock the engine clock to use to populate the structure
+* @param    sclk        the SMC SCLK structure to be populated
+*/
+
+static int polaris10_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
+               uint32_t clock, uint16_t sclk_al_threshold,
+               struct SMU74_Discrete_GraphicsLevel *level)
+{
+       int result;
+       /* PP_Clocks minClocks; */
+       uint32_t mvdd;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       SMU_SclkSetting curr_sclk_setting = { 0 };
+
+       result = polaris10_calculate_sclk_params(hwmgr, clock, &curr_sclk_setting);
+
+       /* populate graphics levels */
+       result = polaris10_get_dependency_volt_by_clk(hwmgr,
+                       table_info->vdd_dep_on_sclk, clock,
+                       &level->MinVoltage, &mvdd);
+
+       PP_ASSERT_WITH_CODE((0 == result),
+                       "can not find VDDC voltage value for "
+                       "VDDC engine clock dependency table",
+                       return result);
+       level->ActivityLevel = sclk_al_threshold;
+
+       level->CcPwrDynRm = 0;
+       level->CcPwrDynRm1 = 0;
+       level->EnabledForActivity = 0;
+       level->EnabledForThrottle = 1;
+       level->UpHyst = 10;
+       level->DownHyst = 0;
+       level->VoltageDownHyst = 0;
+       level->PowerThrottle = 0;
+       data->display_timing.min_clock_in_sr = hwmgr->display_config.min_core_set_clock_in_sr;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
+               level->DeepSleepDivId = smu7_get_sleep_divider_id_from_clock(clock,
+                                                               hwmgr->display_config.min_core_set_clock_in_sr);
+
+       /* Default to slow, highest DPM level will be
+        * set to PPSMC_DISPLAY_WATERMARK_LOW later.
+        */
+       if (data->update_up_hyst)
+               level->UpHyst = (uint8_t)data->up_hyst;
+       if (data->update_down_hyst)
+               level->DownHyst = (uint8_t)data->down_hyst;
+
+       level->SclkSetting = curr_sclk_setting;
+
+       CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
+       CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
+       CONVERT_FROM_HOST_TO_SMC_UL(level->SclkSetting.SclkFrequency);
+       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Fcw_int);
+       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Fcw_frac);
+       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Pcc_fcw_int);
+       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Sclk_slew_rate);
+       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Pcc_up_slew_rate);
+       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Pcc_down_slew_rate);
+       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Fcw1_int);
+       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Fcw1_frac);
+       CONVERT_FROM_HOST_TO_SMC_US(level->SclkSetting.Sclk_ss_slew_rate);
+       return 0;
+}
+
+/**
+* Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
+*
+* @param    hwmgr      the address of the hardware manager
+*/
+int polaris10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
+{
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct smu7_hwmgr *hw_data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       struct smu7_dpm_table *dpm_table = &hw_data->dpm_table;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
+       uint8_t pcie_entry_cnt = (uint8_t) hw_data->dpm_table.pcie_speed_table.count;
+       int result = 0;
+       uint32_t array = smu_data->smu7_data.dpm_table_start +
+                       offsetof(SMU74_Discrete_DpmTable, GraphicsLevel);
+       uint32_t array_size = sizeof(struct SMU74_Discrete_GraphicsLevel) *
+                       SMU74_MAX_LEVELS_GRAPHICS;
+       struct SMU74_Discrete_GraphicsLevel *levels =
+                       smu_data->smc_state_table.GraphicsLevel;
+       uint32_t i, max_entry;
+       uint8_t hightest_pcie_level_enabled = 0,
+               lowest_pcie_level_enabled = 0,
+               mid_pcie_level_enabled = 0,
+               count = 0;
+
+       polaris10_get_sclk_range_table(hwmgr, &(smu_data->smc_state_table));
+
+       for (i = 0; i < dpm_table->sclk_table.count; i++) {
+
+               result = polaris10_populate_single_graphic_level(hwmgr,
+                               dpm_table->sclk_table.dpm_levels[i].value,
+                               (uint16_t)smu_data->activity_target[i],
+                               &(smu_data->smc_state_table.GraphicsLevel[i]));
+               if (result)
+                       return result;
+
+               /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
+               if (i > 1)
+                       levels[i].DeepSleepDivId = 0;
+       }
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_SPLLShutdownSupport))
+               smu_data->smc_state_table.GraphicsLevel[0].SclkSetting.SSc_En = 0;
+
+       smu_data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
+       smu_data->smc_state_table.GraphicsDpmLevelCount =
+                       (uint8_t)dpm_table->sclk_table.count;
+       hw_data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+                       phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
+
+
+       if (pcie_table != NULL) {
+               PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt),
+                               "There must be 1 or more PCIE levels defined in PPTable.",
+                               return -EINVAL);
+               max_entry = pcie_entry_cnt - 1;
+               for (i = 0; i < dpm_table->sclk_table.count; i++)
+                       levels[i].pcieDpmLevel =
+                                       (uint8_t) ((i < max_entry) ? i : max_entry);
+       } else {
+               while (hw_data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+                               ((hw_data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                                               (1 << (hightest_pcie_level_enabled + 1))) != 0))
+                       hightest_pcie_level_enabled++;
+
+               while (hw_data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+                               ((hw_data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                                               (1 << lowest_pcie_level_enabled)) == 0))
+                       lowest_pcie_level_enabled++;
+
+               while ((count < hightest_pcie_level_enabled) &&
+                               ((hw_data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                                               (1 << (lowest_pcie_level_enabled + 1 + count))) == 0))
+                       count++;
+
+               mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1 + count) <
+                               hightest_pcie_level_enabled ?
+                                               (lowest_pcie_level_enabled + 1 + count) :
+                                               hightest_pcie_level_enabled;
+
+               /* set pcieDpmLevel to hightest_pcie_level_enabled */
+               for (i = 2; i < dpm_table->sclk_table.count; i++)
+                       levels[i].pcieDpmLevel = hightest_pcie_level_enabled;
+
+               /* set pcieDpmLevel to lowest_pcie_level_enabled */
+               levels[0].pcieDpmLevel = lowest_pcie_level_enabled;
+
+               /* set pcieDpmLevel to mid_pcie_level_enabled */
+               levels[1].pcieDpmLevel = mid_pcie_level_enabled;
+       }
+       /* level count will send to smc once at init smc table and never change */
+       result = smu7_copy_bytes_to_smc(smumgr, array, (uint8_t *)levels,
+                       (uint32_t)array_size, SMC_RAM_END);
+
+       return result;
+}
+
+
+static int polaris10_populate_single_memory_level(struct pp_hwmgr *hwmgr,
+               uint32_t clock, struct SMU74_Discrete_MemoryLevel *mem_level)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       int result = 0;
+       struct cgs_display_info info = {0, 0, NULL};
+       uint32_t mclk_stutter_mode_threshold = 40000;
+
+       cgs_get_active_displays_info(hwmgr->device, &info);
+
+       if (table_info->vdd_dep_on_mclk) {
+               result = polaris10_get_dependency_volt_by_clk(hwmgr,
+                               table_info->vdd_dep_on_mclk, clock,
+                               &mem_level->MinVoltage, &mem_level->MinMvdd);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find MinVddc voltage value from memory "
+                               "VDDC voltage dependency table", return result);
+       }
+
+       mem_level->MclkFrequency = clock;
+       mem_level->EnabledForThrottle = 1;
+       mem_level->EnabledForActivity = 0;
+       mem_level->UpHyst = 0;
+       mem_level->DownHyst = 100;
+       mem_level->VoltageDownHyst = 0;
+       mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
+       mem_level->StutterEnable = false;
+       mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+       data->display_timing.num_existing_displays = info.display_count;
+
+       if (mclk_stutter_mode_threshold &&
+               (clock <= mclk_stutter_mode_threshold) &&
+               (SMUM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL,
+                               STUTTER_ENABLE) & 0x1))
+               mem_level->StutterEnable = true;
+
+       if (!result) {
+               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd);
+               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency);
+               CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel);
+               CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage);
+       }
+       return result;
+}
+
+/**
+* Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
+*
+* @param    hwmgr      the address of the hardware manager
+*/
+int polaris10_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
+{
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct smu7_hwmgr *hw_data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       struct smu7_dpm_table *dpm_table = &hw_data->dpm_table;
+       int result;
+       /* populate MCLK dpm table to SMU7 */
+       uint32_t array = smu_data->smu7_data.dpm_table_start +
+                       offsetof(SMU74_Discrete_DpmTable, MemoryLevel);
+       uint32_t array_size = sizeof(SMU74_Discrete_MemoryLevel) *
+                       SMU74_MAX_LEVELS_MEMORY;
+       struct SMU74_Discrete_MemoryLevel *levels =
+                       smu_data->smc_state_table.MemoryLevel;
+       uint32_t i;
+
+       for (i = 0; i < dpm_table->mclk_table.count; i++) {
+               PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
+                               "can not populate memory level as memory clock is zero",
+                               return -EINVAL);
+               result = polaris10_populate_single_memory_level(hwmgr,
+                               dpm_table->mclk_table.dpm_levels[i].value,
+                               &levels[i]);
+               if (i == dpm_table->mclk_table.count - 1) {
+                       levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
+                       levels[i].EnabledForActivity = 1;
+               }
+               if (result)
+                       return result;
+       }
+
+       /* In order to prevent MC activity from stutter mode to push DPM up,
+        * the UVD change complements this by putting the MCLK in
+        * a higher state by default such that we are not affected by
+        * up threshold or and MCLK DPM latency.
+        */
+       levels[0].ActivityLevel = 0x1f;
+       CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel);
+
+       smu_data->smc_state_table.MemoryDpmLevelCount =
+                       (uint8_t)dpm_table->mclk_table.count;
+       hw_data->dpm_level_enable_mask.mclk_dpm_enable_mask =
+                       phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
+
+       /* level count will send to smc once at init smc table and never change */
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
+                       (uint32_t)array_size, SMC_RAM_END);
+
+       return result;
+}
+
+/**
+* Populates the SMC MVDD structure using the provided memory clock.
+*
+* @param    hwmgr      the address of the hardware manager
+* @param    mclk        the MCLK value to be used in the decision if MVDD should be high or low.
+* @param    voltage     the SMC VOLTAGE structure to be populated
+*/
+static int polaris10_populate_mvdd_value(struct pp_hwmgr *hwmgr,
+               uint32_t mclk, SMIO_Pattern *smio_pat)
+{
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       uint32_t i = 0;
+
+       if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
+               /* find mvdd value which clock is more than request */
+               for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
+                       if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
+                               smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value;
+                               break;
+                       }
+               }
+               PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
+                               "MVDD Voltage is outside the supported range.",
+                               return -EINVAL);
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int polaris10_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
+               SMU74_Discrete_DpmTable *table)
+{
+       int result = 0;
+       uint32_t sclk_frequency;
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       SMIO_Pattern vol_level;
+       uint32_t mvdd;
+       uint16_t us_mvdd;
+
+       table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+       /* Get MinVoltage and Frequency from DPM0,
+        * already converted to SMC_UL */
+       sclk_frequency = data->vbios_boot_state.sclk_bootup_value;
+       result = polaris10_get_dependency_volt_by_clk(hwmgr,
+                       table_info->vdd_dep_on_sclk,
+                       sclk_frequency,
+                       &table->ACPILevel.MinVoltage, &mvdd);
+       PP_ASSERT_WITH_CODE((0 == result),
+                       "Cannot find ACPI VDDC voltage value "
+                       "in Clock Dependency Table",
+                       );
+
+       result = polaris10_calculate_sclk_params(hwmgr, sclk_frequency,  &(table->ACPILevel.SclkSetting));
+       PP_ASSERT_WITH_CODE(result == 0, "Error retrieving Engine Clock dividers from VBIOS.", return result);
+
+       table->ACPILevel.DeepSleepDivId = 0;
+       table->ACPILevel.CcPwrDynRm = 0;
+       table->ACPILevel.CcPwrDynRm1 = 0;
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkSetting.SclkFrequency);
+       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Fcw_int);
+       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Fcw_frac);
+       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Pcc_fcw_int);
+       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Sclk_slew_rate);
+       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Pcc_up_slew_rate);
+       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Pcc_down_slew_rate);
+       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Fcw1_int);
+       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Fcw1_frac);
+       CONVERT_FROM_HOST_TO_SMC_US(table->ACPILevel.SclkSetting.Sclk_ss_slew_rate);
+
+
+       /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
+       table->MemoryACPILevel.MclkFrequency = data->vbios_boot_state.mclk_bootup_value;
+       result = polaris10_get_dependency_volt_by_clk(hwmgr,
+                       table_info->vdd_dep_on_mclk,
+                       table->MemoryACPILevel.MclkFrequency,
+                       &table->MemoryACPILevel.MinVoltage, &mvdd);
+       PP_ASSERT_WITH_CODE((0 == result),
+                       "Cannot find ACPI VDDCI voltage value "
+                       "in Clock Dependency Table",
+                       );
+
+       us_mvdd = 0;
+       if ((SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) ||
+                       (data->mclk_dpm_key_disabled))
+               us_mvdd = data->vbios_boot_state.mvdd_bootup_value;
+       else {
+               if (!polaris10_populate_mvdd_value(hwmgr,
+                               data->dpm_table.mclk_table.dpm_levels[0].value,
+                               &vol_level))
+                       us_mvdd = vol_level.Voltage;
+       }
+
+       if (0 == polaris10_populate_mvdd_value(hwmgr, 0, &vol_level))
+               table->MemoryACPILevel.MinMvdd = PP_HOST_TO_SMC_UL(vol_level.Voltage);
+       else
+               table->MemoryACPILevel.MinMvdd = 0;
+
+       table->MemoryACPILevel.StutterEnable = false;
+
+       table->MemoryACPILevel.EnabledForThrottle = 0;
+       table->MemoryACPILevel.EnabledForActivity = 0;
+       table->MemoryACPILevel.UpHyst = 0;
+       table->MemoryACPILevel.DownHyst = 100;
+       table->MemoryACPILevel.VoltageDownHyst = 0;
+       table->MemoryACPILevel.ActivityLevel =
+                       PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);
+
+       return result;
+}
+
+static int polaris10_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
+               SMU74_Discrete_DpmTable *table)
+{
+       int result = -EINVAL;
+       uint8_t count;
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                       table_info->mm_dep_table;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t vddci;
+
+       table->VceLevelCount = (uint8_t)(mm_table->count);
+       table->VceBootLevel = 0;
+
+       for (count = 0; count < table->VceLevelCount; count++) {
+               table->VceLevel[count].Frequency = mm_table->entries[count].eclk;
+               table->VceLevel[count].MinVoltage = 0;
+               table->VceLevel[count].MinVoltage |=
+                               (mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
+
+               if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control)
+                       vddci = (uint32_t)phm_find_closest_vddci(&(data->vddci_voltage_table),
+                                               mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
+               else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control)
+                       vddci = mm_table->entries[count].vddc - VDDC_VDDCI_DELTA;
+               else
+                       vddci = (data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE) << VDDCI_SHIFT;
+
+
+               table->VceLevel[count].MinVoltage |=
+                               (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+               table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+               /*retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                               table->VceLevel[count].Frequency, &dividers);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find divide id for VCE engine clock",
+                               return result);
+
+               table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage);
+       }
+       return result;
+}
+
+
+static int polaris10_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
+               SMU74_Discrete_DpmTable *table)
+{
+       int result = -EINVAL;
+       uint8_t count;
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                       table_info->mm_dep_table;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t vddci;
+
+       table->SamuBootLevel = 0;
+       table->SamuLevelCount = (uint8_t)(mm_table->count);
+
+       for (count = 0; count < table->SamuLevelCount; count++) {
+               /* not sure whether we need evclk or not */
+               table->SamuLevel[count].MinVoltage = 0;
+               table->SamuLevel[count].Frequency = mm_table->entries[count].samclock;
+               table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+                               VOLTAGE_SCALE) << VDDC_SHIFT;
+
+               if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control)
+                       vddci = (uint32_t)phm_find_closest_vddci(&(data->vddci_voltage_table),
+                                               mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
+               else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control)
+                       vddci = mm_table->entries[count].vddc - VDDC_VDDCI_DELTA;
+               else
+                       vddci = (data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE) << VDDCI_SHIFT;
+
+               table->SamuLevel[count].MinVoltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+               table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+               /* retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                               table->SamuLevel[count].Frequency, &dividers);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find divide id for samu clock", return result);
+
+               table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage);
+       }
+       return result;
+}
+
+static int polaris10_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr,
+               int32_t eng_clock, int32_t mem_clock,
+               SMU74_Discrete_MCArbDramTimingTableEntry *arb_regs)
+{
+       uint32_t dram_timing;
+       uint32_t dram_timing2;
+       uint32_t burst_time;
+       int result;
+
+       result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
+                       eng_clock, mem_clock);
+       PP_ASSERT_WITH_CODE(result == 0,
+                       "Error calling VBIOS to set DRAM_TIMING.", return result);
+
+       dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+       dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+       burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+
+
+       arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dram_timing);
+       arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2);
+       arb_regs->McArbBurstTime   = (uint8_t)burst_time;
+
+       return 0;
+}
+
+static int polaris10_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct smu7_hwmgr *hw_data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       struct SMU74_Discrete_MCArbDramTimingTable arb_regs;
+       uint32_t i, j;
+       int result = 0;
+
+       for (i = 0; i < hw_data->dpm_table.sclk_table.count; i++) {
+               for (j = 0; j < hw_data->dpm_table.mclk_table.count; j++) {
+                       result = polaris10_populate_memory_timing_parameters(hwmgr,
+                                       hw_data->dpm_table.sclk_table.dpm_levels[i].value,
+                                       hw_data->dpm_table.mclk_table.dpm_levels[j].value,
+                                       &arb_regs.entries[i][j]);
+                       if (result == 0)
+                               result = atomctrl_set_ac_timing_ai(hwmgr, hw_data->dpm_table.mclk_table.dpm_levels[j].value, j);
+                       if (result != 0)
+                               return result;
+               }
+       }
+
+       result = smu7_copy_bytes_to_smc(
+                       hwmgr->smumgr,
+                       smu_data->smu7_data.arb_table_start,
+                       (uint8_t *)&arb_regs,
+                       sizeof(SMU74_Discrete_MCArbDramTimingTable),
+                       SMC_RAM_END);
+       return result;
+}
+
+static int polaris10_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
+               struct SMU74_Discrete_DpmTable *table)
+{
+       int result = -EINVAL;
+       uint8_t count;
+       struct pp_atomctrl_clock_dividers_vi dividers;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                       table_info->mm_dep_table;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t vddci;
+
+       table->UvdLevelCount = (uint8_t)(mm_table->count);
+       table->UvdBootLevel = 0;
+
+       for (count = 0; count < table->UvdLevelCount; count++) {
+               table->UvdLevel[count].MinVoltage = 0;
+               table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
+               table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
+               table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+                               VOLTAGE_SCALE) << VDDC_SHIFT;
+
+               if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control)
+                       vddci = (uint32_t)phm_find_closest_vddci(&(data->vddci_voltage_table),
+                                               mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
+               else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control)
+                       vddci = mm_table->entries[count].vddc - VDDC_VDDCI_DELTA;
+               else
+                       vddci = (data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE) << VDDCI_SHIFT;
+
+               table->UvdLevel[count].MinVoltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+               table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+               /* retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                               table->UvdLevel[count].VclkFrequency, &dividers);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find divide id for Vclk clock", return result);
+
+               table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
+
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                               table->UvdLevel[count].DclkFrequency, &dividers);
+               PP_ASSERT_WITH_CODE((0 == result),
+                               "can not find divide id for Dclk clock", return result);
+
+               table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage);
+       }
+
+       return result;
+}
+
+static int polaris10_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
+               struct SMU74_Discrete_DpmTable *table)
+{
+       int result = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       table->GraphicsBootLevel = 0;
+       table->MemoryBootLevel = 0;
+
+       /* find boot level from dpm table */
+       result = phm_find_boot_level(&(data->dpm_table.sclk_table),
+                       data->vbios_boot_state.sclk_bootup_value,
+                       (uint32_t *)&(table->GraphicsBootLevel));
+
+       result = phm_find_boot_level(&(data->dpm_table.mclk_table),
+                       data->vbios_boot_state.mclk_bootup_value,
+                       (uint32_t *)&(table->MemoryBootLevel));
+
+       table->BootVddc  = data->vbios_boot_state.vddc_bootup_value *
+                       VOLTAGE_SCALE;
+       table->BootVddci = data->vbios_boot_state.vddci_bootup_value *
+                       VOLTAGE_SCALE;
+       table->BootMVdd  = data->vbios_boot_state.mvdd_bootup_value *
+                       VOLTAGE_SCALE;
+
+       CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc);
+       CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci);
+       CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
+
+       return 0;
+}
+
+static int polaris10_populate_smc_initailial_state(struct pp_hwmgr *hwmgr)
+{
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct smu7_hwmgr *hw_data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       uint8_t count, level;
+
+       count = (uint8_t)(table_info->vdd_dep_on_sclk->count);
+
+       for (level = 0; level < count; level++) {
+               if (table_info->vdd_dep_on_sclk->entries[level].clk >=
+                               hw_data->vbios_boot_state.sclk_bootup_value) {
+                       smu_data->smc_state_table.GraphicsBootLevel = level;
+                       break;
+               }
+       }
+
+       count = (uint8_t)(table_info->vdd_dep_on_mclk->count);
+       for (level = 0; level < count; level++) {
+               if (table_info->vdd_dep_on_mclk->entries[level].clk >=
+                               hw_data->vbios_boot_state.mclk_bootup_value) {
+                       smu_data->smc_state_table.MemoryBootLevel = level;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+
+static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
+{
+       uint32_t ro, efuse, volt_without_cks, volt_with_cks, value, max, min;
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+
+       uint8_t i, stretch_amount, stretch_amount2, volt_offset = 0;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+                       table_info->vdd_dep_on_sclk;
+
+       stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
+
+       /* Read SMU_Eefuse to read and calculate RO and determine
+        * if the part is SS or FF. if RO >= 1660MHz, part is FF.
+        */
+       efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixSMU_EFUSE_0 + (67 * 4));
+       efuse &= 0xFF000000;
+       efuse = efuse >> 24;
+
+       if (hwmgr->chip_id == CHIP_POLARIS10) {
+               min = 1000;
+               max = 2300;
+       } else {
+               min = 1100;
+               max = 2100;
+       }
+
+       ro = efuse * (max - min) / 255 + min;
+
+       /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
+       for (i = 0; i < sclk_table->count; i++) {
+               smu_data->smc_state_table.Sclk_CKS_masterEn0_7 |=
+                               sclk_table->entries[i].cks_enable << i;
+               if (hwmgr->chip_id == CHIP_POLARIS10) {
+                       volt_without_cks = (uint32_t)((2753594000U + (sclk_table->entries[i].clk/100) * 136418 - (ro - 70) * 1000000) / \
+                                               (2424180 - (sclk_table->entries[i].clk/100) * 1132925/1000));
+                       volt_with_cks = (uint32_t)((2797202000U + sclk_table->entries[i].clk/100 * 3232 - (ro - 65) * 1000000) / \
+                                       (2522480 - sclk_table->entries[i].clk/100 * 115764/100));
+               } else {
+                       volt_without_cks = (uint32_t)((2416794800U + (sclk_table->entries[i].clk/100) * 1476925/10 - (ro - 50) * 1000000) / \
+                                               (2625416 - (sclk_table->entries[i].clk/100) * (12586807/10000)));
+                       volt_with_cks = (uint32_t)((2999656000U - sclk_table->entries[i].clk/100 * 392803 - (ro - 44) * 1000000) / \
+                                       (3422454 - sclk_table->entries[i].clk/100 * (18886376/10000)));
+               }
+
+               if (volt_without_cks >= volt_with_cks)
+                       volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
+                                       sclk_table->entries[i].cks_voffset) * 100 + 624) / 625);
+
+               smu_data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
+       }
+
+       smu_data->smc_state_table.LdoRefSel = (table_info->cac_dtp_table->ucCKS_LDO_REFSEL != 0) ? table_info->cac_dtp_table->ucCKS_LDO_REFSEL : 6;
+       /* Populate CKS Lookup Table */
+       if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
+               stretch_amount2 = 0;
+       else if (stretch_amount == 3 || stretch_amount == 4)
+               stretch_amount2 = 1;
+       else {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_ClockStretcher);
+               PP_ASSERT_WITH_CODE(false,
+                               "Stretch Amount in PPTable not supported\n",
+                               return -EINVAL);
+       }
+
+       value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL);
+       value &= 0xFFFFFFFE;
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value);
+
+       return 0;
+}
+
+/**
+* Populates the SMC VRConfig field in DPM table.
+*
+* @param    hwmgr   the address of the hardware manager
+* @param    table   the SMC DPM table structure to be populated
+* @return   always 0
+*/
+static int polaris10_populate_vr_config(struct pp_hwmgr *hwmgr,
+               struct SMU74_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       uint16_t config;
+
+       config = VR_MERGED_WITH_VDDC;
+       table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT);
+
+       /* Set Vddc Voltage Controller */
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+               config = VR_SVI2_PLANE_1;
+               table->VRConfig |= config;
+       } else {
+               PP_ASSERT_WITH_CODE(false,
+                               "VDDC should be on SVI2 control in merged mode!",
+                               );
+       }
+       /* Set Vddci Voltage Controller */
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
+               config = VR_SVI2_PLANE_2;  /* only in merged mode */
+               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+       } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+               config = VR_SMIO_PATTERN_1;
+               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+       } else {
+               config = VR_STATIC_VOLTAGE;
+               table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+       }
+       /* Set Mvdd Voltage Controller */
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
+               config = VR_SVI2_PLANE_2;
+               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, smu_data->smu7_data.soft_regs_start +
+                       offsetof(SMU74_SoftRegisters, AllowMvddSwitch), 0x1);
+       } else {
+               config = VR_STATIC_VOLTAGE;
+               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+       }
+
+       return 0;
+}
+
+
+static int polaris10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+
+       SMU74_Discrete_DpmTable  *table = &(smu_data->smc_state_table);
+       int result = 0;
+       struct pp_atom_ctrl__avfs_parameters avfs_params = {0};
+       AVFS_meanNsigma_t AVFS_meanNsigma = { {0} };
+       AVFS_Sclk_Offset_t AVFS_SclkOffset = { {0} };
+       uint32_t tmp, i;
+
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)hwmgr->pptable;
+       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+                       table_info->vdd_dep_on_sclk;
+
+
+       if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED)
+               return result;
+
+       result = atomctrl_get_avfs_information(hwmgr, &avfs_params);
+
+       if (0 == result) {
+               table->BTCGB_VDROOP_TABLE[0].a0  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSON_a0);
+               table->BTCGB_VDROOP_TABLE[0].a1  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSON_a1);
+               table->BTCGB_VDROOP_TABLE[0].a2  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSON_a2);
+               table->BTCGB_VDROOP_TABLE[1].a0  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a0);
+               table->BTCGB_VDROOP_TABLE[1].a1  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a1);
+               table->BTCGB_VDROOP_TABLE[1].a2  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a2);
+               table->AVFSGB_VDROOP_TABLE[0].m1 = PP_HOST_TO_SMC_UL(avfs_params.ulAVFSGB_FUSE_TABLE_CKSON_m1);
+               table->AVFSGB_VDROOP_TABLE[0].m2 = PP_HOST_TO_SMC_US(avfs_params.usAVFSGB_FUSE_TABLE_CKSON_m2);
+               table->AVFSGB_VDROOP_TABLE[0].b  = PP_HOST_TO_SMC_UL(avfs_params.ulAVFSGB_FUSE_TABLE_CKSON_b);
+               table->AVFSGB_VDROOP_TABLE[0].m1_shift = 24;
+               table->AVFSGB_VDROOP_TABLE[0].m2_shift  = 12;
+               table->AVFSGB_VDROOP_TABLE[1].m1 = PP_HOST_TO_SMC_UL(avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_m1);
+               table->AVFSGB_VDROOP_TABLE[1].m2 = PP_HOST_TO_SMC_US(avfs_params.usAVFSGB_FUSE_TABLE_CKSOFF_m2);
+               table->AVFSGB_VDROOP_TABLE[1].b  = PP_HOST_TO_SMC_UL(avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_b);
+               table->AVFSGB_VDROOP_TABLE[1].m1_shift = 24;
+               table->AVFSGB_VDROOP_TABLE[1].m2_shift  = 12;
+               table->MaxVoltage                = PP_HOST_TO_SMC_US(avfs_params.usMaxVoltage_0_25mv);
+               AVFS_meanNsigma.Aconstant[0]      = PP_HOST_TO_SMC_UL(avfs_params.ulAVFS_meanNsigma_Acontant0);
+               AVFS_meanNsigma.Aconstant[1]      = PP_HOST_TO_SMC_UL(avfs_params.ulAVFS_meanNsigma_Acontant1);
+               AVFS_meanNsigma.Aconstant[2]      = PP_HOST_TO_SMC_UL(avfs_params.ulAVFS_meanNsigma_Acontant2);
+               AVFS_meanNsigma.DC_tol_sigma      = PP_HOST_TO_SMC_US(avfs_params.usAVFS_meanNsigma_DC_tol_sigma);
+               AVFS_meanNsigma.Platform_mean     = PP_HOST_TO_SMC_US(avfs_params.usAVFS_meanNsigma_Platform_mean);
+               AVFS_meanNsigma.PSM_Age_CompFactor = PP_HOST_TO_SMC_US(avfs_params.usPSM_Age_ComFactor);
+               AVFS_meanNsigma.Platform_sigma     = PP_HOST_TO_SMC_US(avfs_params.usAVFS_meanNsigma_Platform_sigma);
+
+               for (i = 0; i < NUM_VFT_COLUMNS; i++) {
+                       AVFS_meanNsigma.Static_Voltage_Offset[i] = (uint8_t)(sclk_table->entries[i].cks_voffset * 100 / 625);
+                       AVFS_SclkOffset.Sclk_Offset[i] = PP_HOST_TO_SMC_US((uint16_t)(sclk_table->entries[i].sclk_offset) / 100);
+               }
+
+               result = smu7_read_smc_sram_dword(smumgr,
+                               SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, AvfsMeanNSigma),
+                               &tmp, SMC_RAM_END);
+
+               smu7_copy_bytes_to_smc(smumgr,
+                                       tmp,
+                                       (uint8_t *)&AVFS_meanNsigma,
+                                       sizeof(AVFS_meanNsigma_t),
+                                       SMC_RAM_END);
+
+               result = smu7_read_smc_sram_dword(smumgr,
+                               SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, AvfsSclkOffsetTable),
+                               &tmp, SMC_RAM_END);
+               smu7_copy_bytes_to_smc(smumgr,
+                                       tmp,
+                                       (uint8_t *)&AVFS_SclkOffset,
+                                       sizeof(AVFS_Sclk_Offset_t),
+                                       SMC_RAM_END);
+
+               data->avfs_vdroop_override_setting = (avfs_params.ucEnableGB_VDROOP_TABLE_CKSON << BTCGB0_Vdroop_Enable_SHIFT) |
+                                               (avfs_params.ucEnableGB_VDROOP_TABLE_CKSOFF << BTCGB1_Vdroop_Enable_SHIFT) |
+                                               (avfs_params.ucEnableGB_FUSE_TABLE_CKSON << AVFSGB0_Vdroop_Enable_SHIFT) |
+                                               (avfs_params.ucEnableGB_FUSE_TABLE_CKSOFF << AVFSGB1_Vdroop_Enable_SHIFT);
+               data->apply_avfs_cks_off_voltage = (avfs_params.ucEnableApplyAVFS_CKS_OFF_Voltage == 1) ? true : false;
+       }
+       return result;
+}
+
+
+/**
+* Initialize the ARB DRAM timing table's index field.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+static int polaris10_init_arb_table_index(struct pp_smumgr *smumgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       uint32_t tmp;
+       int result;
+
+       /* This is a read-modify-write on the first byte of the ARB table.
+        * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
+        * is the field 'current'.
+        * This solution is ugly, but we never write the whole table only
+        * individual fields in it.
+        * In reality this field should not be in that structure
+        * but in a soft register.
+        */
+       result = smu7_read_smc_sram_dword(smumgr,
+                       smu_data->smu7_data.arb_table_start, &tmp, SMC_RAM_END);
+
+       if (result)
+               return result;
+
+       tmp &= 0x00FFFFFF;
+       tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
+
+       return smu7_write_smc_sram_dword(smumgr,
+                       smu_data->smu7_data.arb_table_start, tmp, SMC_RAM_END);
+}
+
+static void polaris10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       struct  phm_ppt_v1_information *table_info =
+                       (struct  phm_ppt_v1_information *)(hwmgr->pptable);
+
+       if (table_info &&
+                       table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
+                       table_info->cac_dtp_table->usPowerTuneDataSetID)
+               smu_data->power_tune_defaults =
+                               &polaris10_power_tune_data_set_array
+                               [table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
+       else
+               smu_data->power_tune_defaults = &polaris10_power_tune_data_set_array[0];
+
+}
+
+/**
+* Initializes the SMC table and uploads it
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always 0
+*/
+int polaris10_init_smc_table(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct smu7_hwmgr *hw_data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct SMU74_Discrete_DpmTable *table = &(smu_data->smc_state_table);
+       uint8_t i;
+       struct pp_atomctrl_gpio_pin_assignment gpio_pin;
+       pp_atomctrl_clock_dividers_vi dividers;
+
+       polaris10_initialize_power_tune_defaults(hwmgr);
+
+       if (SMU7_VOLTAGE_CONTROL_NONE != hw_data->voltage_control)
+               polaris10_populate_smc_voltage_tables(hwmgr, table);
+
+       table->SystemFlags = 0;
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_AutomaticDCTransition))
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StepVddc))
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+       if (hw_data->is_memory_gddr5)
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+       if (hw_data->ulv_supported && table_info->us_ulv_voltage_offset) {
+               result = polaris10_populate_ulv_state(hwmgr, table);
+               PP_ASSERT_WITH_CODE(0 == result,
+                               "Failed to initialize ULV state!", return result);
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                               ixCG_ULV_PARAMETER, SMU7_CGULVPARAMETER_DFLT);
+       }
+
+       result = polaris10_populate_smc_link_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Link Level!", return result);
+
+       result = polaris10_populate_all_graphic_levels(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Graphics Level!", return result);
+
+       result = polaris10_populate_all_memory_levels(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Memory Level!", return result);
+
+       result = polaris10_populate_smc_acpi_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize ACPI Level!", return result);
+
+       result = polaris10_populate_smc_vce_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize VCE Level!", return result);
+
+       result = polaris10_populate_smc_samu_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize SAMU Level!", return result);
+
+       /* Since only the initial state is completely set up at this point
+        * (the other states are just copies of the boot state) we only
+        * need to populate the  ARB settings for the initial state.
+        */
+       result = polaris10_program_memory_timing_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to Write ARB settings for the initial state.", return result);
+
+       result = polaris10_populate_smc_uvd_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize UVD Level!", return result);
+
+       result = polaris10_populate_smc_boot_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Boot Level!", return result);
+
+       result = polaris10_populate_smc_initailial_state(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to initialize Boot State!", return result);
+
+       result = polaris10_populate_bapm_parameters_in_dpm_table(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to populate BAPM Parameters!", return result);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ClockStretcher)) {
+               result = polaris10_populate_clock_stretcher_data_table(hwmgr);
+               PP_ASSERT_WITH_CODE(0 == result,
+                               "Failed to populate Clock Stretcher Data Table!",
+                               return result);
+       }
+
+       result = polaris10_populate_avfs_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result, "Failed to populate AVFS Parameters!", return result;);
+
+       table->CurrSclkPllRange = 0xff;
+       table->GraphicsVoltageChangeEnable  = 1;
+       table->GraphicsThermThrottleEnable  = 1;
+       table->GraphicsInterval = 1;
+       table->VoltageInterval  = 1;
+       table->ThermalInterval  = 1;
+       table->TemperatureLimitHigh =
+                       table_info->cac_dtp_table->usTargetOperatingTemp *
+                       SMU7_Q88_FORMAT_CONVERSION_UNIT;
+       table->TemperatureLimitLow  =
+                       (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
+                       SMU7_Q88_FORMAT_CONVERSION_UNIT;
+       table->MemoryVoltageChangeEnable = 1;
+       table->MemoryInterval = 1;
+       table->VoltageResponseTime = 0;
+       table->PhaseResponseTime = 0;
+       table->MemoryThermThrottleEnable = 1;
+       table->PCIeBootLinkLevel = 0;
+       table->PCIeGenInterval = 1;
+       table->VRConfig = 0;
+
+       result = polaris10_populate_vr_config(hwmgr, table);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to populate VRConfig setting!", return result);
+
+       table->ThermGpio = 17;
+       table->SclkStepSize = 0x4000;
+
+       if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
+               table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
+       } else {
+               table->VRHotGpio = SMU7_UNUSED_GPIO_PIN;
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_RegulatorHot);
+       }
+
+       if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
+                       &gpio_pin)) {
+               table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift;
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_AutomaticDCTransition);
+       } else {
+               table->AcDcGpio = SMU7_UNUSED_GPIO_PIN;
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_AutomaticDCTransition);
+       }
+
+       /* Thermal Output GPIO */
+       if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID,
+                       &gpio_pin)) {
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_ThermalOutGPIO);
+
+               table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift;
+
+               /* For porlarity read GPIOPAD_A with assigned Gpio pin
+                * since VBIOS will program this register to set 'inactive state',
+                * driver can then determine 'active state' from this and
+                * program SMU with correct polarity
+                */
+               table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A)
+                                       & (1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0;
+               table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
+
+               /* if required, combine VRHot/PCC with thermal out GPIO */
+               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_RegulatorHot)
+               && phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_CombinePCCWithThermalSignal))
+                       table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
+       } else {
+               table->ThermOutGpio = 17;
+               table->ThermOutPolarity = 1;
+               table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
+       }
+
+       /* Populate BIF_SCLK levels into SMC DPM table */
+       for (i = 0; i <= hw_data->dpm_table.pcie_speed_table.count; i++) {
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, smu_data->bif_sclk_table[i], &dividers);
+               PP_ASSERT_WITH_CODE((result == 0), "Can not find DFS divide id for Sclk", return result);
+
+               if (i == 0)
+                       table->Ulv.BifSclkDfs = PP_HOST_TO_SMC_US((USHORT)(dividers.pll_post_divider));
+               else
+                       table->LinkLevel[i-1].BifSclkDfs = PP_HOST_TO_SMC_US((USHORT)(dividers.pll_post_divider));
+       }
+
+       for (i = 0; i < SMU74_MAX_ENTRIES_SMIO; i++)
+               table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->CurrSclkPllRange);
+       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
+       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
+       CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
+       CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
+
+       /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr,
+                       smu_data->smu7_data.dpm_table_start +
+                       offsetof(SMU74_Discrete_DpmTable, SystemFlags),
+                       (uint8_t *)&(table->SystemFlags),
+                       sizeof(SMU74_Discrete_DpmTable) - 3 * sizeof(SMU74_PIDController),
+                       SMC_RAM_END);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to upload dpm data to SMC memory!", return result);
+
+       result = polaris10_init_arb_table_index(hwmgr->smumgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to upload arb data to SMC memory!", return result);
+
+       result = polaris10_populate_pm_fuses(hwmgr);
+       PP_ASSERT_WITH_CODE(0 == result,
+                       "Failed to  populate PM fuses to SMC memory!", return result);
+       return 0;
+}
+
+static int polaris10_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->need_update_smu7_dpm_table &
+               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+               return polaris10_program_memory_timing_parameters(hwmgr);
+
+       return 0;
+}
+
+int polaris10_thermal_avfs_enable(struct pp_hwmgr *hwmgr)
+{
+       int ret;
+       struct pp_smumgr *smumgr = (struct pp_smumgr *)(hwmgr->smumgr);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED)
+               return 0;
+
+       ret = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                       PPSMC_MSG_SetGBDroopSettings, data->avfs_vdroop_override_setting);
+
+       ret = (smum_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs) == 0) ?
+                       0 : -1;
+
+       if (!ret)
+               /* If this param is not changed, this function could fire unnecessarily */
+               smu_data->avfs.avfs_btc_status = AVFS_BTC_COMPLETED_PREVIOUSLY;
+
+       return ret;
+}
+
+/**
+* Set up the fan table to control the fan using the SMC.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       SMU74_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+       uint32_t duty100;
+       uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+       uint16_t fdo_min, slope1, slope2;
+       uint32_t reference_clock;
+       int res;
+       uint64_t tmp64;
+
+       if (smu_data->smu7_data.fan_table_start == 0) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_MicrocodeFanControl);
+               return 0;
+       }
+
+       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_FDO_CTRL1, FMAX_DUTY100);
+
+       if (duty100 == 0) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_MicrocodeFanControl);
+               return 0;
+       }
+
+       tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
+                       usPWMMin * duty100;
+       do_div(tmp64, 10000);
+       fdo_min = (uint16_t)tmp64;
+
+       t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
+                       hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
+       t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
+                       hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
+
+       pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
+                       hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
+       pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
+                       hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
+
+       slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+       slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+       fan_table.TempMin = cpu_to_be16((50 + hwmgr->
+                       thermal_controller.advanceFanControlParameters.usTMin) / 100);
+       fan_table.TempMed = cpu_to_be16((50 + hwmgr->
+                       thermal_controller.advanceFanControlParameters.usTMed) / 100);
+       fan_table.TempMax = cpu_to_be16((50 + hwmgr->
+                       thermal_controller.advanceFanControlParameters.usTMax) / 100);
+
+       fan_table.Slope1 = cpu_to_be16(slope1);
+       fan_table.Slope2 = cpu_to_be16(slope2);
+
+       fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+       fan_table.HystDown = cpu_to_be16(hwmgr->
+                       thermal_controller.advanceFanControlParameters.ucTHyst);
+
+       fan_table.HystUp = cpu_to_be16(1);
+
+       fan_table.HystSlope = cpu_to_be16(1);
+
+       fan_table.TempRespLim = cpu_to_be16(5);
+
+       reference_clock = smu7_get_xclk(hwmgr);
+
+       fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
+                       thermal_controller.advanceFanControlParameters.ulCycleDelay *
+                       reference_clock) / 1600);
+
+       fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
+
+       fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
+                       hwmgr->device, CGS_IND_REG__SMC,
+                       CG_MULT_THERMAL_CTRL, TEMP_SEL);
+
+       res = smu7_copy_bytes_to_smc(hwmgr->smumgr, smu_data->smu7_data.fan_table_start,
+                       (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
+                       SMC_RAM_END);
+
+       if (!res && hwmgr->thermal_controller.
+                       advanceFanControlParameters.ucMinimumPWMLimit)
+               res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_SetFanMinPwm,
+                               hwmgr->thermal_controller.
+                               advanceFanControlParameters.ucMinimumPWMLimit);
+
+       if (!res && hwmgr->thermal_controller.
+                       advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
+               res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_SetFanSclkTarget,
+                               hwmgr->thermal_controller.
+                               advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
+
+       if (res)
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_MicrocodeFanControl);
+
+       return 0;
+}
+
+static int polaris10_update_uvd_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t mm_boot_level_offset, mm_boot_level_value;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       smu_data->smc_state_table.UvdBootLevel = 0;
+       if (table_info->mm_dep_table->count > 0)
+               smu_data->smc_state_table.UvdBootLevel =
+                               (uint8_t) (table_info->mm_dep_table->count - 1);
+       mm_boot_level_offset = smu_data->smu7_data.dpm_table_start + offsetof(SMU74_Discrete_DpmTable,
+                                               UvdBootLevel);
+       mm_boot_level_offset /= 4;
+       mm_boot_level_offset *= 4;
+       mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset);
+       mm_boot_level_value &= 0x00FFFFFF;
+       mm_boot_level_value |= smu_data->smc_state_table.UvdBootLevel << 24;
+       cgs_write_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+       if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_UVDDPM) ||
+               phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StablePState))
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_UVDDPM_SetEnabledMask,
+                               (uint32_t)(1 << smu_data->smc_state_table.UvdBootLevel));
+       return 0;
+}
+
+static int polaris10_update_vce_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t mm_boot_level_offset, mm_boot_level_value;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_StablePState))
+               smu_data->smc_state_table.VceBootLevel =
+                       (uint8_t) (table_info->mm_dep_table->count - 1);
+       else
+               smu_data->smc_state_table.VceBootLevel = 0;
+
+       mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
+                                       offsetof(SMU74_Discrete_DpmTable, VceBootLevel);
+       mm_boot_level_offset /= 4;
+       mm_boot_level_offset *= 4;
+       mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset);
+       mm_boot_level_value &= 0xFF00FFFF;
+       mm_boot_level_value |= smu_data->smc_state_table.VceBootLevel << 16;
+       cgs_write_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_VCEDPM_SetEnabledMask,
+                               (uint32_t)1 << smu_data->smc_state_table.VceBootLevel);
+       return 0;
+}
+
+static int polaris10_update_samu_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t mm_boot_level_offset, mm_boot_level_value;
+
+
+       smu_data->smc_state_table.SamuBootLevel = 0;
+       mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU74_Discrete_DpmTable, SamuBootLevel);
+
+       mm_boot_level_offset /= 4;
+       mm_boot_level_offset *= 4;
+       mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset);
+       mm_boot_level_value &= 0xFFFFFF00;
+       mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0;
+       cgs_write_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StablePState))
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_SAMUDPM_SetEnabledMask,
+                               (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel));
+       return 0;
+}
+
+
+static int polaris10_update_bif_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
+       int max_entry, i;
+
+       max_entry = (SMU74_MAX_LEVELS_LINK < pcie_table->count) ?
+                                               SMU74_MAX_LEVELS_LINK :
+                                               pcie_table->count;
+       /* Setup BIF_SCLK levels */
+       for (i = 0; i < max_entry; i++)
+               smu_data->bif_sclk_table[i] = pcie_table->entries[i].pcie_sclk;
+       return 0;
+}
+
+int polaris10_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
+{
+       switch (type) {
+       case SMU_UVD_TABLE:
+               polaris10_update_uvd_smc_table(hwmgr);
+               break;
+       case SMU_VCE_TABLE:
+               polaris10_update_vce_smc_table(hwmgr);
+               break;
+       case SMU_SAMU_TABLE:
+               polaris10_update_samu_smc_table(hwmgr);
+               break;
+       case SMU_BIF_TABLE:
+               polaris10_update_bif_smc_table(hwmgr);
+       default:
+               break;
+       }
+       return 0;
+}
+
+int polaris10_update_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+
+       int result = 0;
+       uint32_t low_sclk_interrupt_threshold = 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkThrottleLowNotification)
+               && (hwmgr->gfx_arbiter.sclk_threshold !=
+                               data->low_sclk_interrupt_threshold)) {
+               data->low_sclk_interrupt_threshold =
+                               hwmgr->gfx_arbiter.sclk_threshold;
+               low_sclk_interrupt_threshold =
+                               data->low_sclk_interrupt_threshold;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
+
+               result = smu7_copy_bytes_to_smc(
+                               hwmgr->smumgr,
+                               smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU74_Discrete_DpmTable,
+                                       LowSclkInterruptThreshold),
+                               (uint8_t *)&low_sclk_interrupt_threshold,
+                               sizeof(uint32_t),
+                               SMC_RAM_END);
+       }
+       PP_ASSERT_WITH_CODE((result == 0),
+                       "Failed to update SCLK threshold!", return result);
+
+       result = polaris10_program_mem_timing_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE((result == 0),
+                       "Failed to program memory timing parameters!",
+                       );
+
+       return result;
+}
+
+uint32_t polaris10_get_offsetof(uint32_t type, uint32_t member)
+{
+       switch (type) {
+       case SMU_SoftRegisters:
+               switch (member) {
+               case HandshakeDisables:
+                       return offsetof(SMU74_SoftRegisters, HandshakeDisables);
+               case VoltageChangeTimeout:
+                       return offsetof(SMU74_SoftRegisters, VoltageChangeTimeout);
+               case AverageGraphicsActivity:
+                       return offsetof(SMU74_SoftRegisters, AverageGraphicsActivity);
+               case PreVBlankGap:
+                       return offsetof(SMU74_SoftRegisters, PreVBlankGap);
+               case VBlankTimeout:
+                       return offsetof(SMU74_SoftRegisters, VBlankTimeout);
+               case UcodeLoadStatus:
+                       return offsetof(SMU74_SoftRegisters, UcodeLoadStatus);
+               }
+       case SMU_Discrete_DpmTable:
+               switch (member) {
+               case UvdBootLevel:
+                       return offsetof(SMU74_Discrete_DpmTable, UvdBootLevel);
+               case VceBootLevel:
+                       return offsetof(SMU74_Discrete_DpmTable, VceBootLevel);
+               case SamuBootLevel:
+                       return offsetof(SMU74_Discrete_DpmTable, SamuBootLevel);
+               case LowSclkInterruptThreshold:
+                       return offsetof(SMU74_Discrete_DpmTable, LowSclkInterruptThreshold);
+               }
+       }
+       printk("cant't get the offset of type %x member %x \n", type, member);
+       return 0;
+}
+
+uint32_t polaris10_get_mac_definition(uint32_t value)
+{
+       switch (value) {
+       case SMU_MAX_LEVELS_GRAPHICS:
+               return SMU74_MAX_LEVELS_GRAPHICS;
+       case SMU_MAX_LEVELS_MEMORY:
+               return SMU74_MAX_LEVELS_MEMORY;
+       case SMU_MAX_LEVELS_LINK:
+               return SMU74_MAX_LEVELS_LINK;
+       case SMU_MAX_ENTRIES_SMIO:
+               return SMU74_MAX_ENTRIES_SMIO;
+       case SMU_MAX_LEVELS_VDDC:
+               return SMU74_MAX_LEVELS_VDDC;
+       case SMU_MAX_LEVELS_VDDGFX:
+               return SMU74_MAX_LEVELS_VDDGFX;
+       case SMU_MAX_LEVELS_VDDCI:
+               return SMU74_MAX_LEVELS_VDDCI;
+       case SMU_MAX_LEVELS_MVDD:
+               return SMU74_MAX_LEVELS_MVDD;
+       case SMU_UVD_MCLK_HANDSHAKE_DISABLE:
+               return SMU7_UVD_MCLK_HANDSHAKE_DISABLE;
+       }
+
+       printk("cant't get the mac of %x \n", value);
+       return 0;
+}
+
+/**
+* Get the location of various tables inside the FW image.
+*
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @return   always  0
+*/
+int polaris10_process_firmware_header(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t tmp;
+       int result;
+       bool error = false;
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU74_Firmware_Header, DpmTable),
+                       &tmp, SMC_RAM_END);
+
+       if (0 == result)
+               smu_data->smu7_data.dpm_table_start = tmp;
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU74_Firmware_Header, SoftRegisters),
+                       &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.soft_regs_start = tmp;
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU74_Firmware_Header, mcRegisterTable),
+                       &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.mc_reg_table_start = tmp;
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU74_Firmware_Header, FanTable),
+                       &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.fan_table_start = tmp;
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU74_Firmware_Header, mcArbDramTimingTable),
+                       &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.arb_table_start = tmp;
+
+       error |= (0 != result);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       SMU7_FIRMWARE_HEADER_LOCATION +
+                       offsetof(SMU74_Firmware_Header, Version),
+                       &tmp, SMC_RAM_END);
+
+       if (!result)
+               hwmgr->microcode_version_info.SMC = tmp;
+
+       error |= (0 != result);
+
+       return error ? -1 : 0;
+}
+
+bool polaris10_is_dpm_running(struct pp_hwmgr *hwmgr)
+{
+       return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
+                       CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
+                       ? true : false;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.h b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.h
new file mode 100644 (file)
index 0000000..5ade3ce
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 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 POLARIS10_SMC_H
+#define POLARIS10_SMC_H
+
+#include "smumgr.h"
+
+
+int polaris10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr);
+int polaris10_populate_all_memory_levels(struct pp_hwmgr *hwmgr);
+int polaris10_init_smc_table(struct pp_hwmgr *hwmgr);
+int polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr);
+int polaris10_thermal_avfs_enable(struct pp_hwmgr *hwmgr);
+int polaris10_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type);
+int polaris10_update_sclk_threshold(struct pp_hwmgr *hwmgr);
+uint32_t polaris10_get_offsetof(uint32_t type, uint32_t member);
+uint32_t polaris10_get_mac_definition(uint32_t value);
+int polaris10_process_firmware_header(struct pp_hwmgr *hwmgr);
+bool polaris10_is_dpm_running(struct pp_hwmgr *hwmgr);
+
+#endif
+
index 5dba7c5..5c3598a 100644 (file)
 #include "ppatomctrl.h"
 #include "pp_debug.h"
 #include "cgs_common.h"
+#include "polaris10_smc.h"
+#include "smu7_ppsmc.h"
+#include "smu7_smumgr.h"
 
-#define POLARIS10_SMC_SIZE 0x20000
-#define VOLTAGE_SCALE 4
-
-/* Microcode file is stored in this buffer */
-#define BUFFER_SIZE                 80000
-#define MAX_STRING_SIZE             15
-#define BUFFER_SIZETWO              131072  /* 128 *1024 */
-
-#define SMC_RAM_END 0x40000
+#define PPPOLARIS10_TARGETACTIVITY_DFLT                     50
 
 static const SMU74_Discrete_GraphicsLevel avfs_graphics_level_polaris10[8] = {
        /*  Min      pcie   DeepSleep Activity  CgSpll      CgSpll    CcPwr  CcPwr  Sclk         Enabled      Enabled                       Voltage    Power */
@@ -62,572 +57,9 @@ static const SMU74_Discrete_GraphicsLevel avfs_graphics_level_polaris10[8] = {
        { 0xa00fa446, 0x01, 0x00, 0x3200, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 0x0a, 0x00, 0x00, 0x00, { 0xa0860100, 0x2800, 0, 0x2000, 2, 1, 0x0004, 0x0c02, 0xffff, 0x2700, 0x6433, 0x2100 } }
 };
 
-static const SMU74_Discrete_MemoryLevel avfs_memory_level_polaris10 =
-       {0x100ea446, 0, 0x30750000, 0x01, 0x01, 0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x1f00, 0x00, 0x00};
-
-/**
-* Set the address for reading/writing the SMC SRAM space.
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    smcAddress the address in the SMC RAM to access.
-*/
-static int polaris10_set_smc_sram_address(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t limit)
-{
-       PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)), "SMC address must be 4 byte aligned.", return -EINVAL);
-       PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)), "SMC addr is beyond the SMC RAM area.", return -EINVAL);
-
-       cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, smc_addr);
-       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0);
-
-       return 0;
-}
-
-/**
-* Copy bytes from SMC RAM space into driver memory.
-*
-* @param    smumgr  the address of the powerplay SMU manager.
-* @param    smc_start_address the start address in the SMC RAM to copy bytes from
-* @param    src the byte array to copy the bytes to.
-* @param    byte_count the number of bytes to copy.
-*/
-int polaris10_copy_bytes_from_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address, uint32_t *dest, uint32_t byte_count, uint32_t limit)
-{
-       uint32_t data;
-       uint32_t addr;
-       uint8_t *dest_byte;
-       uint8_t i, data_byte[4] = {0};
-       uint32_t *pdata = (uint32_t *)&data_byte;
-
-       PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -1;);
-       PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -1);
-
-       addr = smc_start_address;
-
-       while (byte_count >= 4) {
-               polaris10_read_smc_sram_dword(smumgr, addr, &data, limit);
-
-               *dest = PP_SMC_TO_HOST_UL(data);
-
-               dest += 1;
-               byte_count -= 4;
-               addr += 4;
-       }
-
-       if (byte_count) {
-               polaris10_read_smc_sram_dword(smumgr, addr, &data, limit);
-               *pdata = PP_SMC_TO_HOST_UL(data);
-       /* Cast dest into byte type in dest_byte.  This way, we don't overflow if the allocated memory is not 4-byte aligned. */
-               dest_byte = (uint8_t *)dest;
-               for (i = 0; i < byte_count; i++)
-                       dest_byte[i] = data_byte[i];
-       }
-
-       return 0;
-}
-
-/**
-* Copy bytes from an array into the SMC RAM space.
-*
-* @param    pSmuMgr  the address of the powerplay SMU manager.
-* @param    smc_start_address the start address in the SMC RAM to copy bytes to.
-* @param    src the byte array to copy the bytes from.
-* @param    byte_count the number of bytes to copy.
-*/
-int polaris10_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
-                               const uint8_t *src, uint32_t byte_count, uint32_t limit)
-{
-       int result;
-       uint32_t data = 0;
-       uint32_t original_data;
-       uint32_t addr = 0;
-       uint32_t extra_shift;
-
-       PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -1);
-       PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -1);
-
-       addr = smc_start_address;
-
-       while (byte_count >= 4) {
-       /* Bytes are written into the SMC addres space with the MSB first. */
-               data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
-
-               result = polaris10_set_smc_sram_address(smumgr, addr, limit);
-
-               if (0 != result)
-                       return result;
-
-               cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data);
-
-               src += 4;
-               byte_count -= 4;
-               addr += 4;
-       }
-
-       if (0 != byte_count) {
-
-               data = 0;
-
-               result = polaris10_set_smc_sram_address(smumgr, addr, limit);
-
-               if (0 != result)
-                       return result;
-
-
-               original_data = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11);
-
-               extra_shift = 8 * (4 - byte_count);
-
-               while (byte_count > 0) {
-                       /* Bytes are written into the SMC addres space with the MSB first. */
-                       data = (0x100 * data) + *src++;
-                       byte_count--;
-               }
-
-               data <<= extra_shift;
-
-               data |= (original_data & ~((~0UL) << extra_shift));
-
-               result = polaris10_set_smc_sram_address(smumgr, addr, limit);
-
-               if (0 != result)
-                       return result;
-
-               cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data);
-       }
-
-       return 0;
-}
-
-
-static int polaris10_program_jump_on_start(struct pp_smumgr *smumgr)
-{
-       static const unsigned char data[4] = { 0xE0, 0x00, 0x80, 0x40 };
-
-       polaris10_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data)+1);
-
-       return 0;
-}
-
-/**
-* Return if the SMC is currently running.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-*/
-bool polaris10_is_smc_ram_running(struct pp_smumgr *smumgr)
-{
-       return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
-       && (0x20100 <= cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMC_PC_C)));
-}
-
-static bool polaris10_is_hw_avfs_present(struct pp_smumgr *smumgr)
-{
-       uint32_t efuse;
-
-       efuse = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMU_EFUSE_0 + (49*4));
-       efuse &= 0x00000001;
-       if (efuse)
-               return true;
-
-       return false;
-}
-
-/**
-* Send a message to the SMC, and wait for its response.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    msg the message to send.
-* @return   The response that came from the SMC.
-*/
-int polaris10_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
-{
-       int ret;
-
-       if (!polaris10_is_smc_ram_running(smumgr))
-               return -1;
-
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-
-       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);
-
-       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-
-       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);
-
-       return 0;
-}
-
-
-/**
-* Send a message to the SMC, and do not wait for its response.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    msg the message to send.
-* @return   Always return 0.
-*/
-int polaris10_send_msg_to_smc_without_waiting(struct pp_smumgr *smumgr, uint16_t msg)
-{
-       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
-
-       return 0;
-}
-
-/**
-* Send a message to the SMC with parameter
-*
-* @param    smumgr:  the address of the powerplay hardware manager.
-* @param    msg: the message to send.
-* @param    parameter: the parameter to send
-* @return   The response that came from the SMC.
-*/
-int polaris10_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
-{
-       if (!polaris10_is_smc_ram_running(smumgr)) {
-               return -1;
-       }
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-
-       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
-
-       return polaris10_send_msg_to_smc(smumgr, msg);
-}
-
-
-/**
-* Send a message to the SMC with parameter, do not wait for response
-*
-* @param    smumgr:  the address of the powerplay hardware manager.
-* @param    msg: the message to send.
-* @param    parameter: the parameter to send
-* @return   The response that came from the SMC.
-*/
-int polaris10_send_msg_to_smc_with_parameter_without_waiting(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
-{
-       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
-
-       return polaris10_send_msg_to_smc_without_waiting(smumgr, msg);
-}
-
-int polaris10_send_msg_to_smc_offset(struct pp_smumgr *smumgr)
-{
-       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000);
-
-       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
-
-       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");
-
-       return 0;
-}
-
-/**
-* Wait until the SMC is doing nithing. Doing nothing means that the SMC is either turned off or it is sitting on the STOP instruction.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    msg the message to send.
-* @return   The response that came from the SMC.
-*/
-int polaris10_wait_for_smc_inactive(struct pp_smumgr *smumgr)
-{
-       /* If the SMC is not even on it qualifies as inactive. */
-       if (!polaris10_is_smc_ram_running(smumgr))
-               return -1;
-
-       SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, SMC_SYSCON_CLOCK_CNTL_0, cken, 0);
-       return 0;
-}
-
-
-/**
-* Upload the SMC firmware to the SMC microcontroller.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    pFirmware the data structure containing the various sections of the firmware.
-*/
-static int polaris10_upload_smc_firmware_data(struct pp_smumgr *smumgr, uint32_t length, uint32_t *src, uint32_t limit)
-{
-       uint32_t byte_count = length;
-
-       PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area.", return -1);
+static const SMU74_Discrete_MemoryLevel avfs_memory_level_polaris10 = {
+       0x100ea446, 0, 0x30750000, 0x01, 0x01, 0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x1f00, 0x00, 0x00};
 
-       cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, 0x20000);
-       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 1);
-
-       for (; byte_count >= 4; byte_count -= 4)
-               cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, *src++);
-
-       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0);
-
-       PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be dividable by 4.", return -1);
-
-       return 0;
-}
-
-static enum cgs_ucode_id polaris10_convert_fw_type_to_cgs(uint32_t fw_type)
-{
-       enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
-
-       switch (fw_type) {
-       case UCODE_ID_SMU:
-               result = CGS_UCODE_ID_SMU;
-               break;
-       case UCODE_ID_SMU_SK:
-               result = CGS_UCODE_ID_SMU_SK;
-               break;
-       case UCODE_ID_SDMA0:
-               result = CGS_UCODE_ID_SDMA0;
-               break;
-       case UCODE_ID_SDMA1:
-               result = CGS_UCODE_ID_SDMA1;
-               break;
-       case UCODE_ID_CP_CE:
-               result = CGS_UCODE_ID_CP_CE;
-               break;
-       case UCODE_ID_CP_PFP:
-               result = CGS_UCODE_ID_CP_PFP;
-               break;
-       case UCODE_ID_CP_ME:
-               result = CGS_UCODE_ID_CP_ME;
-               break;
-       case UCODE_ID_CP_MEC:
-               result = CGS_UCODE_ID_CP_MEC;
-               break;
-       case UCODE_ID_CP_MEC_JT1:
-               result = CGS_UCODE_ID_CP_MEC_JT1;
-               break;
-       case UCODE_ID_CP_MEC_JT2:
-               result = CGS_UCODE_ID_CP_MEC_JT2;
-               break;
-       case UCODE_ID_RLC_G:
-               result = CGS_UCODE_ID_RLC_G;
-               break;
-       default:
-               break;
-       }
-
-       return result;
-}
-
-static int polaris10_upload_smu_firmware_image(struct pp_smumgr *smumgr)
-{
-       int result = 0;
-       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
-
-       struct cgs_firmware_info info = {0};
-
-       if (smu_data->security_hard_key == 1)
-               cgs_get_firmware_info(smumgr->device,
-                       polaris10_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
-       else
-               cgs_get_firmware_info(smumgr->device,
-                       polaris10_convert_fw_type_to_cgs(UCODE_ID_SMU_SK), &info);
-
-       /* TO DO cgs_init_samu_load_smu(smumgr->device, (uint32_t *)info.kptr, info.image_size, smu_data->post_initial_boot);*/
-       result = polaris10_upload_smc_firmware_data(smumgr, info.image_size, (uint32_t *)info.kptr, POLARIS10_SMC_SIZE);
-
-       return result;
-}
-
-/**
-* Read a 32bit value from the SMC SRAM space.
-* ALL PARAMETERS ARE IN HOST BYTE ORDER.
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    smcAddress the address in the SMC RAM to access.
-* @param    value and output parameter for the data read from the SMC SRAM.
-*/
-int polaris10_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t *value, uint32_t limit)
-{
-       int result;
-
-       result = polaris10_set_smc_sram_address(smumgr, smc_addr, limit);
-
-       if (result)
-               return result;
-
-       *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11);
-       return 0;
-}
-
-/**
-* Write a 32bit value to the SMC SRAM space.
-* ALL PARAMETERS ARE IN HOST BYTE ORDER.
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    smc_addr the address in the SMC RAM to access.
-* @param    value to write to the SMC SRAM.
-*/
-int polaris10_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t value, uint32_t limit)
-{
-       int result;
-
-       result = polaris10_set_smc_sram_address(smumgr, smc_addr, limit);
-
-       if (result)
-               return result;
-
-       cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, value);
-
-       return 0;
-}
-
-
-int polaris10_smu_fini(struct pp_smumgr *smumgr)
-{
-       if (smumgr->backend) {
-               kfree(smumgr->backend);
-               smumgr->backend = NULL;
-       }
-       cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU);
-       return 0;
-}
-
-/* Convert the firmware type to SMU type mask. For MEC, we need to check all MEC related type */
-static uint32_t polaris10_get_mask_for_firmware_type(uint32_t fw_type)
-{
-       uint32_t result = 0;
-
-       switch (fw_type) {
-       case UCODE_ID_SDMA0:
-               result = UCODE_ID_SDMA0_MASK;
-               break;
-       case UCODE_ID_SDMA1:
-               result = UCODE_ID_SDMA1_MASK;
-               break;
-       case UCODE_ID_CP_CE:
-               result = UCODE_ID_CP_CE_MASK;
-               break;
-       case UCODE_ID_CP_PFP:
-               result = UCODE_ID_CP_PFP_MASK;
-               break;
-       case UCODE_ID_CP_ME:
-               result = UCODE_ID_CP_ME_MASK;
-               break;
-       case UCODE_ID_CP_MEC_JT1:
-       case UCODE_ID_CP_MEC_JT2:
-               result = UCODE_ID_CP_MEC_MASK;
-               break;
-       case UCODE_ID_RLC_G:
-               result = UCODE_ID_RLC_G_MASK;
-               break;
-       default:
-               printk("UCode type is out of range! \n");
-               result = 0;
-       }
-
-       return result;
-}
-
-/* Populate one firmware image to the data structure */
-
-static int polaris10_populate_single_firmware_entry(struct pp_smumgr *smumgr,
-                                               uint32_t fw_type,
-                                               struct SMU_Entry *entry)
-{
-       int result = 0;
-       struct cgs_firmware_info info = {0};
-
-       result = cgs_get_firmware_info(smumgr->device,
-                               polaris10_convert_fw_type_to_cgs(fw_type),
-                               &info);
-
-       if (!result) {
-               entry->version = info.version;
-               entry->id = (uint16_t)fw_type;
-               entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
-               entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
-               entry->meta_data_addr_high = 0;
-               entry->meta_data_addr_low = 0;
-               entry->data_size_byte = info.image_size;
-               entry->num_register_entries = 0;
-       }
-
-       if (fw_type == UCODE_ID_RLC_G)
-               entry->flags = 1;
-       else
-               entry->flags = 0;
-
-       return 0;
-}
-
-static int polaris10_request_smu_load_fw(struct pp_smumgr *smumgr)
-{
-       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
-       uint32_t fw_to_load;
-
-       int result = 0;
-       struct SMU_DRAMData_TOC *toc;
-
-       if (!smumgr->reload_fw) {
-               printk(KERN_INFO "[ powerplay ] skip reloading...\n");
-               return 0;
-       }
-
-       if (smu_data->soft_regs_start)
-               cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
-                                       smu_data->soft_regs_start + offsetof(SMU74_SoftRegisters, UcodeLoadStatus),
-                                       0x0);
-
-       polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_HI, smu_data->smu_buffer.mc_addr_high);
-       polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_LO, smu_data->smu_buffer.mc_addr_low);
-
-       toc = (struct SMU_DRAMData_TOC *)smu_data->header;
-       toc->num_entries = 0;
-       toc->structure_version = 1;
-
-       PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
-       PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
-       PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
-       PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
-       PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
-       PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
-       PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
-       PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
-       PP_ASSERT_WITH_CODE(0 == polaris10_populate_single_firmware_entry(smumgr, UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -1);
-
-       polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, smu_data->header_buffer.mc_addr_high);
-       polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, smu_data->header_buffer.mc_addr_low);
-
-       fw_to_load = 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_MASK;
-
-       if (polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_LoadUcodes, fw_to_load))
-               printk(KERN_ERR "Fail to Request SMU Load uCode");
-
-       return result;
-}
-
-/* Check if the FW has been loaded, SMU will not return if loading has not finished. */
-static int polaris10_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fw_type)
-{
-       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
-       uint32_t fw_mask = polaris10_get_mask_for_firmware_type(fw_type);
-       uint32_t ret;
-       /* Check SOFT_REGISTERS_TABLE_28.UcodeLoadStatus */
-       ret = smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX_11,
-                                       smu_data->soft_regs_start + offsetof(SMU74_SoftRegisters, UcodeLoadStatus),
-                                       fw_mask, fw_mask);
-
-       return ret;
-}
-
-static int polaris10_reload_firmware(struct pp_smumgr *smumgr)
-{
-       return smumgr->smumgr_funcs->start_smu(smumgr);
-}
 
 static int polaris10_setup_pwr_virus(struct pp_smumgr *smumgr)
 {
@@ -669,7 +101,7 @@ static int polaris10_perform_btc(struct pp_smumgr *smumgr)
        struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
 
        if (0 != smu_data->avfs.avfs_btc_param) {
-               if (0 != polaris10_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_PerformBtc, 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");
                        result = -1;
                }
@@ -697,7 +129,7 @@ int polaris10_setup_graphics_level_structure(struct pp_smumgr *smumgr)
        graphics_level_size = sizeof(avfs_graphics_level_polaris10);
        u16_boot_mvdd = PP_HOST_TO_SMC_US(1300 * VOLTAGE_SCALE);
 
-       PP_ASSERT_WITH_CODE(0 == polaris10_read_smc_sram_dword(smumgr,
+       PP_ASSERT_WITH_CODE(0 == smu7_read_smc_sram_dword(smumgr,
                                SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, DpmTable),
                                &dpm_table_start, 0x40000),
                        "[AVFS][Polaris10_SetupGfxLvlStruct] SMU could not communicate starting address of DPM table",
@@ -708,14 +140,14 @@ int polaris10_setup_graphics_level_structure(struct pp_smumgr *smumgr)
 
        vr_config_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, VRConfig);
 
-       PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, vr_config_address,
+       PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, vr_config_address,
                                (uint8_t *)&vr_config, sizeof(uint32_t), 0x40000),
                        "[AVFS][Polaris10_SetupGfxLvlStruct] Problems copying VRConfig value over to SMC",
                        return -1);
 
        graphics_level_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, GraphicsLevel);
 
-       PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, graphics_level_address,
+       PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, graphics_level_address,
                                (uint8_t *)(&avfs_graphics_level_polaris10),
                                graphics_level_size, 0x40000),
                        "[AVFS][Polaris10_SetupGfxLvlStruct] Copying of SCLK DPM table failed!",
@@ -723,7 +155,7 @@ int polaris10_setup_graphics_level_structure(struct pp_smumgr *smumgr)
 
        graphics_level_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, MemoryLevel);
 
-       PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, graphics_level_address,
+       PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, graphics_level_address,
                                (uint8_t *)(&avfs_memory_level_polaris10), sizeof(avfs_memory_level_polaris10), 0x40000),
                                "[AVFS][Polaris10_SetupGfxLvlStruct] Copying of MCLK DPM table failed!",
                        return -1);
@@ -732,7 +164,7 @@ int polaris10_setup_graphics_level_structure(struct pp_smumgr *smumgr)
 
        graphics_level_address = dpm_table_start + offsetof(SMU74_Discrete_DpmTable, BootMVdd);
 
-       PP_ASSERT_WITH_CODE(0 == polaris10_copy_bytes_to_smc(smumgr, graphics_level_address,
+       PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(smumgr, graphics_level_address,
                        (uint8_t *)(&u16_boot_mvdd), sizeof(u16_boot_mvdd), 0x40000),
                        "[AVFS][Polaris10_SetupGfxLvlStruct] Copying of DPM table failed!",
                        return -1);
@@ -793,7 +225,7 @@ static int polaris10_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
        SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
                                        SMC_SYSCON_RESET_CNTL, rst_reg, 1);
 
-       result = polaris10_upload_smu_firmware_image(smumgr);
+       result = smu7_upload_smu_firmware_image(smumgr);
        if (result != 0)
                return result;
 
@@ -812,7 +244,7 @@ static int polaris10_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
 
 
        /* Call Test SMU message with 0x20000 offset to trigger SMU start */
-       polaris10_send_msg_to_smc_offset(smumgr);
+       smu7_send_msg_to_smc_offset(smumgr);
 
        /* Wait done bit to be set */
        /* Check pass/failed indicator */
@@ -853,12 +285,12 @@ static int polaris10_start_smu_in_non_protection_mode(struct pp_smumgr *smumgr)
                                        SMC_SYSCON_RESET_CNTL,
                                        rst_reg, 1);
 
-       result = polaris10_upload_smu_firmware_image(smumgr);
+       result = smu7_upload_smu_firmware_image(smumgr);
        if (result != 0)
                return result;
 
        /* Set smc instruct start point at 0x0 */
-       polaris10_program_jump_on_start(smumgr);
+       smu7_program_jump_on_start(smumgr);
 
        SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
                                        SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
@@ -881,10 +313,10 @@ static int polaris10_start_smu(struct pp_smumgr *smumgr)
        bool SMU_VFT_INTACT;
 
        /* Only start SMC if SMC RAM is not running */
-       if (!polaris10_is_smc_ram_running(smumgr)) {
+       if (!smu7_is_smc_ram_running(smumgr)) {
                SMU_VFT_INTACT = false;
                smu_data->protected_mode = (uint8_t) (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_MODE));
-               smu_data->security_hard_key = (uint8_t) (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_SEL));
+               smu_data->smu7_data.security_hard_key = (uint8_t) (SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_SEL));
 
                /* Check if SMU is running in protected mode */
                if (smu_data->protected_mode == 0) {
@@ -894,7 +326,7 @@ static int polaris10_start_smu(struct pp_smumgr *smumgr)
 
                        /* If failed, try with different security Key. */
                        if (result != 0) {
-                               smu_data->security_hard_key ^= 1;
+                               smu_data->smu7_data.security_hard_key ^= 1;
                                result = polaris10_start_smu_in_protection_mode(smumgr);
                        }
                }
@@ -906,89 +338,69 @@ static int polaris10_start_smu(struct pp_smumgr *smumgr)
        } else
                SMU_VFT_INTACT = true; /*Driver went offline but SMU was still alive and contains the VFT table */
 
-       smu_data->post_initial_boot = true;
        polaris10_avfs_event_mgr(smumgr, SMU_VFT_INTACT);
        /* Setup SoftRegsStart here for register lookup in case DummyBackEnd is used and ProcessFirmwareHeader is not executed */
-       polaris10_read_smc_sram_dword(smumgr, SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, SoftRegisters),
-                                       &(smu_data->soft_regs_start), 0x40000);
+       smu7_read_smc_sram_dword(smumgr, SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, SoftRegisters),
+                                       &(smu_data->smu7_data.soft_regs_start), 0x40000);
 
-       result = polaris10_request_smu_load_fw(smumgr);
+       result = smu7_request_smu_load_fw(smumgr);
 
        return result;
 }
 
+static bool polaris10_is_hw_avfs_present(struct pp_smumgr *smumgr)
+{
+       uint32_t efuse;
+
+       efuse = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMU_EFUSE_0 + (49*4));
+       efuse &= 0x00000001;
+       if (efuse)
+               return true;
+
+       return false;
+}
+
 static int polaris10_smu_init(struct pp_smumgr *smumgr)
 {
-       struct polaris10_smumgr *smu_data;
-       uint8_t *internal_buf;
-       uint64_t mc_addr = 0;
-       /* Allocate memory for backend private data */
-       smu_data = (struct polaris10_smumgr *)(smumgr->backend);
-       smu_data->header_buffer.data_size =
-               ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
-       smu_data->smu_buffer.data_size = 200*4096;
-       smu_data->avfs.avfs_btc_status = AVFS_BTC_NOTSUPPORTED;
-/* Allocate FW image data structure and header buffer and
- * send the header buffer address to SMU */
-       smu_allocate_memory(smumgr->device,
-               smu_data->header_buffer.data_size,
-               CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
-               PAGE_SIZE,
-               &mc_addr,
-               &smu_data->header_buffer.kaddr,
-               &smu_data->header_buffer.handle);
-
-       smu_data->header = smu_data->header_buffer.kaddr;
-       smu_data->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
-       smu_data->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
-
-       PP_ASSERT_WITH_CODE((NULL != smu_data->header),
-               "Out of memory.",
-               kfree(smumgr->backend);
-               cgs_free_gpu_mem(smumgr->device,
-               (cgs_handle_t)smu_data->header_buffer.handle);
-               return -1);
+       struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
+       int i;
 
-/* Allocate buffer for SMU internal buffer and send the address to SMU.
- * Iceland SMU does not need internal buffer.*/
-       smu_allocate_memory(smumgr->device,
-               smu_data->smu_buffer.data_size,
-               CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
-               PAGE_SIZE,
-               &mc_addr,
-               &smu_data->smu_buffer.kaddr,
-               &smu_data->smu_buffer.handle);
-
-       internal_buf = smu_data->smu_buffer.kaddr;
-       smu_data->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
-       smu_data->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
-
-       PP_ASSERT_WITH_CODE((NULL != internal_buf),
-               "Out of memory.",
-               kfree(smumgr->backend);
-               cgs_free_gpu_mem(smumgr->device,
-               (cgs_handle_t)smu_data->smu_buffer.handle);
-               return -1;);
+       if (smu7_init(smumgr))
+               return -EINVAL;
 
        if (polaris10_is_hw_avfs_present(smumgr))
                smu_data->avfs.avfs_btc_status = AVFS_BTC_BOOT;
        else
                smu_data->avfs.avfs_btc_status = AVFS_BTC_NOTSUPPORTED;
 
+       for (i = 0; i < SMU74_MAX_LEVELS_GRAPHICS; i++)
+               smu_data->activity_target[i] = PPPOLARIS10_TARGETACTIVITY_DFLT;
+
        return 0;
 }
 
-static const struct pp_smumgr_func ellsemere_smu_funcs = {
+static const struct pp_smumgr_func polaris10_smu_funcs = {
        .smu_init = polaris10_smu_init,
-       .smu_fini = polaris10_smu_fini,
+       .smu_fini = smu7_smu_fini,
        .start_smu = polaris10_start_smu,
-       .check_fw_load_finish = polaris10_check_fw_load_finish,
-       .request_smu_load_fw = polaris10_reload_firmware,
+       .check_fw_load_finish = smu7_check_fw_load_finish,
+       .request_smu_load_fw = smu7_reload_firmware,
        .request_smu_load_specific_fw = NULL,
-       .send_msg_to_smc = polaris10_send_msg_to_smc,
-       .send_msg_to_smc_with_parameter = polaris10_send_msg_to_smc_with_parameter,
+       .send_msg_to_smc = smu7_send_msg_to_smc,
+       .send_msg_to_smc_with_parameter = smu7_send_msg_to_smc_with_parameter,
        .download_pptable_settings = NULL,
        .upload_pptable_settings = NULL,
+       .update_smc_table = polaris10_update_smc_table,
+       .get_offsetof = polaris10_get_offsetof,
+       .process_firmware_header = polaris10_process_firmware_header,
+       .init_smc_table = polaris10_init_smc_table,
+       .update_sclk_threshold = polaris10_update_sclk_threshold,
+       .thermal_avfs_enable = polaris10_thermal_avfs_enable,
+       .thermal_setup_fan_table = polaris10_thermal_setup_fan_table,
+       .populate_all_graphic_levels = polaris10_populate_all_graphic_levels,
+       .populate_all_memory_levels = polaris10_populate_all_memory_levels,
+       .get_mac_definition = polaris10_get_mac_definition,
+       .is_dpm_running = polaris10_is_dpm_running,
 };
 
 int polaris10_smum_init(struct pp_smumgr *smumgr)
@@ -998,10 +410,10 @@ int polaris10_smum_init(struct pp_smumgr *smumgr)
        polaris10_smu = kzalloc(sizeof(struct polaris10_smumgr), GFP_KERNEL);
 
        if (polaris10_smu == NULL)
-               return -1;
+               return -EINVAL;
 
        smumgr->backend = polaris10_smu;
-       smumgr->smumgr_funcs = &ellsemere_smu_funcs;
+       smumgr->smumgr_funcs = &polaris10_smu_funcs;
 
        return 0;
 }
index e5377ae..49ebf1d 100644 (file)
 #ifndef _POLARIS10_SMUMANAGER_H
 #define _POLARIS10_SMUMANAGER_H
 
-#include <polaris10_ppsmc.h>
+
 #include <pp_endian.h>
+#include "smu74.h"
+#include "smu74_discrete.h"
+#include "smu7_smumgr.h"
+
+#define SMC_RAM_END 0x40000
 
 struct polaris10_avfs {
        enum AVFS_BTC_STATUS avfs_btc_status;
        uint32_t           avfs_btc_param;
 };
 
-struct polaris10_buffer_entry {
-       uint32_t data_size;
-       uint32_t mc_addr_low;
-       uint32_t mc_addr_high;
-       void *kaddr;
-       unsigned long  handle;
+struct polaris10_pt_defaults {
+       uint8_t   SviLoadLineEn;
+       uint8_t   SviLoadLineVddC;
+       uint8_t   TDC_VDDC_ThrottleReleaseLimitPerc;
+       uint8_t   TDC_MAWt;
+       uint8_t   TdcWaterfallCtl;
+       uint8_t   DTEAmbientTempBase;
+
+       uint32_t  DisplayCac;
+       uint32_t  BAPM_TEMP_GRADIENT;
+       uint16_t  BAPMTI_R[SMU74_DTE_ITERATIONS * SMU74_DTE_SOURCES * SMU74_DTE_SINKS];
+       uint16_t  BAPMTI_RC[SMU74_DTE_ITERATIONS * SMU74_DTE_SOURCES * SMU74_DTE_SINKS];
+};
+
+
+
+struct polaris10_range_table {
+       uint32_t trans_lower_frequency; /* in 10khz */
+       uint32_t trans_upper_frequency;
 };
 
 struct polaris10_smumgr {
-       uint8_t *header;
-       uint8_t *mec_image;
-       struct polaris10_buffer_entry smu_buffer;
-       struct polaris10_buffer_entry header_buffer;
-       uint32_t soft_regs_start;
-       uint8_t *read_rrm_straps;
-       uint32_t read_drm_straps_mc_address_high;
-       uint32_t read_drm_straps_mc_address_low;
-       uint32_t acpi_optimization;
-       bool post_initial_boot;
+       struct smu7_smumgr smu7_data;
        uint8_t protected_mode;
-       uint8_t security_hard_key;
        struct polaris10_avfs  avfs;
+       SMU74_Discrete_DpmTable              smc_state_table;
+       struct SMU74_Discrete_Ulv            ulv_setting;
+       struct SMU74_Discrete_PmFuses  power_tune_table;
+       struct polaris10_range_table                range_table[NUM_SCLK_RANGE];
+       const struct polaris10_pt_defaults       *power_tune_defaults;
+       uint32_t                   activity_target[SMU74_MAX_LEVELS_GRAPHICS];
+       uint32_t                   bif_sclk_table[SMU74_MAX_LEVELS_LINK];
 };
 
 
-int polaris10_smum_init(struct pp_smumgr *smumgr);
-
-int polaris10_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t *value, uint32_t limit);
-int polaris10_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t value, uint32_t limit);
-int polaris10_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
-                               const uint8_t *src, uint32_t byte_count, uint32_t limit);
-
 #endif
-
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c
new file mode 100644 (file)
index 0000000..6af744f
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * Copyright 2015 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 "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"
+
+#define SMU7_SMC_SIZE 0x20000
+
+static int smu7_set_smc_sram_address(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t limit)
+{
+       PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)), "SMC address must be 4 byte aligned.", return -EINVAL);
+       PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)), "SMC addr is beyond the SMC RAM area.", return -EINVAL);
+
+       cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, smc_addr);
+       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0); /* on ci, SMC_IND_ACCESS_CNTL is different */
+       return 0;
+}
+
+
+int smu7_copy_bytes_from_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address, uint32_t *dest, uint32_t byte_count, uint32_t limit)
+{
+       uint32_t data;
+       uint32_t addr;
+       uint8_t *dest_byte;
+       uint8_t i, data_byte[4] = {0};
+       uint32_t *pdata = (uint32_t *)&data_byte;
+
+       PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -EINVAL);
+       PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -EINVAL);
+
+       addr = smc_start_address;
+
+       while (byte_count >= 4) {
+               smu7_read_smc_sram_dword(smumgr, addr, &data, limit);
+
+               *dest = PP_SMC_TO_HOST_UL(data);
+
+               dest += 1;
+               byte_count -= 4;
+               addr += 4;
+       }
+
+       if (byte_count) {
+               smu7_read_smc_sram_dword(smumgr, addr, &data, limit);
+               *pdata = PP_SMC_TO_HOST_UL(data);
+       /* Cast dest into byte type in dest_byte.  This way, we don't overflow if the allocated memory is not 4-byte aligned. */
+               dest_byte = (uint8_t *)dest;
+               for (i = 0; i < byte_count; i++)
+                       dest_byte[i] = data_byte[i];
+       }
+
+       return 0;
+}
+
+
+int smu7_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
+                               const uint8_t *src, uint32_t byte_count, uint32_t limit)
+{
+       int result;
+       uint32_t data = 0;
+       uint32_t original_data;
+       uint32_t addr = 0;
+       uint32_t extra_shift;
+
+       PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -EINVAL);
+       PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -EINVAL);
+
+       addr = smc_start_address;
+
+       while (byte_count >= 4) {
+       /* Bytes are written into the SMC addres space with the MSB first. */
+               data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
+
+               result = smu7_set_smc_sram_address(smumgr, addr, limit);
+
+               if (0 != result)
+                       return result;
+
+               cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data);
+
+               src += 4;
+               byte_count -= 4;
+               addr += 4;
+       }
+
+       if (0 != byte_count) {
+
+               data = 0;
+
+               result = smu7_set_smc_sram_address(smumgr, addr, limit);
+
+               if (0 != result)
+                       return result;
+
+
+               original_data = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11);
+
+               extra_shift = 8 * (4 - byte_count);
+
+               while (byte_count > 0) {
+                       /* Bytes are written into the SMC addres space with the MSB first. */
+                       data = (0x100 * data) + *src++;
+                       byte_count--;
+               }
+
+               data <<= extra_shift;
+
+               data |= (original_data & ~((~0UL) << extra_shift));
+
+               result = smu7_set_smc_sram_address(smumgr, addr, limit);
+
+               if (0 != result)
+                       return result;
+
+               cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, data);
+       }
+
+       return 0;
+}
+
+
+int smu7_program_jump_on_start(struct pp_smumgr *smumgr)
+{
+       static const unsigned char data[4] = { 0xE0, 0x00, 0x80, 0x40 };
+
+       smu7_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data)+1);
+
+       return 0;
+}
+
+bool smu7_is_smc_ram_running(struct pp_smumgr *smumgr)
+{
+       return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
+       && (0x20100 <= cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, ixSMC_PC_C)));
+}
+
+int smu7_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
+{
+       int ret;
+
+       if (!smu7_is_smc_ram_running(smumgr))
+               return -EINVAL;
+
+
+       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+       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);
+
+       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+
+       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+       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);
+
+       return 0;
+}
+
+int smu7_send_msg_to_smc_without_waiting(struct pp_smumgr *smumgr, uint16_t msg)
+{
+       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+
+       return 0;
+}
+
+int smu7_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
+{
+       if (!smu7_is_smc_ram_running(smumgr)) {
+               return -EINVAL;
+       }
+
+       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+
+       return smu7_send_msg_to_smc(smumgr, msg);
+}
+
+int smu7_send_msg_to_smc_with_parameter_without_waiting(struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
+{
+       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+
+       return smu7_send_msg_to_smc_without_waiting(smumgr, msg);
+}
+
+int smu7_send_msg_to_smc_offset(struct pp_smumgr *smumgr)
+{
+       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000);
+
+       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
+
+       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");
+
+       return 0;
+}
+
+int smu7_wait_for_smc_inactive(struct pp_smumgr *smumgr)
+{
+       if (!smu7_is_smc_ram_running(smumgr))
+               return -EINVAL;
+
+       SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, SMC_SYSCON_CLOCK_CNTL_0, cken, 0);
+       return 0;
+}
+
+
+enum cgs_ucode_id smu7_convert_fw_type_to_cgs(uint32_t fw_type)
+{
+       enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
+
+       switch (fw_type) {
+       case UCODE_ID_SMU:
+               result = CGS_UCODE_ID_SMU;
+               break;
+       case UCODE_ID_SMU_SK:
+               result = CGS_UCODE_ID_SMU_SK;
+               break;
+       case UCODE_ID_SDMA0:
+               result = CGS_UCODE_ID_SDMA0;
+               break;
+       case UCODE_ID_SDMA1:
+               result = CGS_UCODE_ID_SDMA1;
+               break;
+       case UCODE_ID_CP_CE:
+               result = CGS_UCODE_ID_CP_CE;
+               break;
+       case UCODE_ID_CP_PFP:
+               result = CGS_UCODE_ID_CP_PFP;
+               break;
+       case UCODE_ID_CP_ME:
+               result = CGS_UCODE_ID_CP_ME;
+               break;
+       case UCODE_ID_CP_MEC:
+               result = CGS_UCODE_ID_CP_MEC;
+               break;
+       case UCODE_ID_CP_MEC_JT1:
+               result = CGS_UCODE_ID_CP_MEC_JT1;
+               break;
+       case UCODE_ID_CP_MEC_JT2:
+               result = CGS_UCODE_ID_CP_MEC_JT2;
+               break;
+       case UCODE_ID_RLC_G:
+               result = CGS_UCODE_ID_RLC_G;
+               break;
+       default:
+               break;
+       }
+
+       return result;
+}
+
+
+int smu7_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t *value, uint32_t limit)
+{
+       int result;
+
+       result = smu7_set_smc_sram_address(smumgr, smc_addr, limit);
+
+       if (result)
+               return result;
+
+       *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_11);
+       return 0;
+}
+
+int smu7_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr, uint32_t value, uint32_t limit)
+{
+       int result;
+
+       result = smu7_set_smc_sram_address(smumgr, smc_addr, limit);
+
+       if (result)
+               return result;
+
+       cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, value);
+
+       return 0;
+}
+
+/* Convert the firmware type to SMU type mask. For MEC, we need to check all MEC related type */
+
+static uint32_t smu7_get_mask_for_firmware_type(uint32_t fw_type)
+{
+       uint32_t result = 0;
+
+       switch (fw_type) {
+       case UCODE_ID_SDMA0:
+               result = UCODE_ID_SDMA0_MASK;
+               break;
+       case UCODE_ID_SDMA1:
+               result = UCODE_ID_SDMA1_MASK;
+               break;
+       case UCODE_ID_CP_CE:
+               result = UCODE_ID_CP_CE_MASK;
+               break;
+       case UCODE_ID_CP_PFP:
+               result = UCODE_ID_CP_PFP_MASK;
+               break;
+       case UCODE_ID_CP_ME:
+               result = UCODE_ID_CP_ME_MASK;
+               break;
+       case UCODE_ID_CP_MEC:
+       case UCODE_ID_CP_MEC_JT1:
+       case UCODE_ID_CP_MEC_JT2:
+               result = UCODE_ID_CP_MEC_MASK;
+               break;
+       case UCODE_ID_RLC_G:
+               result = UCODE_ID_RLC_G_MASK;
+               break;
+       default:
+               printk("UCode type is out of range! \n");
+               result = 0;
+       }
+
+       return result;
+}
+
+static int smu7_populate_single_firmware_entry(struct pp_smumgr *smumgr,
+                                               uint32_t fw_type,
+                                               struct SMU_Entry *entry)
+{
+       int result = 0;
+       struct cgs_firmware_info info = {0};
+
+       result = cgs_get_firmware_info(smumgr->device,
+                               smu7_convert_fw_type_to_cgs(fw_type),
+                               &info);
+
+       if (!result) {
+               entry->version = info.version;
+               entry->id = (uint16_t)fw_type;
+               entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
+               entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
+               entry->meta_data_addr_high = 0;
+               entry->meta_data_addr_low = 0;
+               entry->data_size_byte = info.image_size;
+               entry->num_register_entries = 0;
+       }
+
+       if (fw_type == UCODE_ID_RLC_G)
+               entry->flags = 1;
+       else
+               entry->flags = 0;
+
+       return 0;
+}
+
+int smu7_request_smu_load_fw(struct pp_smumgr *smumgr)
+{
+       struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(smumgr->backend);
+       uint32_t fw_to_load;
+       int result = 0;
+       struct SMU_DRAMData_TOC *toc;
+
+       if (!smumgr->reload_fw) {
+               printk(KERN_INFO "[ powerplay ] skip reloading...\n");
+               return 0;
+       }
+
+       if (smu_data->soft_regs_start)
+               cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+                                       smu_data->soft_regs_start + smum_get_offsetof(smumgr,
+                                       SMU_SoftRegisters, UcodeLoadStatus),
+                                       0x0);
+
+       if (smumgr->chip_id > CHIP_TOPAZ) { /* add support for Topaz */
+               smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_HI, smu_data->smu_buffer.mc_addr_high);
+               smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_LO, smu_data->smu_buffer.mc_addr_low);
+               fw_to_load = 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_MASK;
+       } else {
+               fw_to_load = 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_MASK
+                          + UCODE_ID_CP_MEC_JT1_MASK
+                          + UCODE_ID_CP_MEC_JT2_MASK;
+       }
+
+       toc = (struct SMU_DRAMData_TOC *)smu_data->header;
+       toc->num_entries = 0;
+       toc->structure_version = 1;
+
+       PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
+                               UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]),
+                               "Failed to Get Firmware Entry.", return -EINVAL);
+       PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
+                               UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]),
+                               "Failed to Get Firmware Entry.", return -EINVAL);
+       PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
+                               UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
+                               "Failed to Get Firmware Entry.", return -EINVAL);
+       PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
+                               UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
+                               "Failed to Get Firmware Entry.", return -EINVAL);
+       PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
+                               UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
+                               "Failed to Get Firmware Entry.", return -EINVAL);
+       PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
+                               UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
+                               "Failed to Get Firmware Entry.", return -EINVAL);
+       PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
+                               UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
+                               "Failed to Get Firmware Entry.", return -EINVAL);
+       PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
+                               UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
+                               "Failed to Get Firmware Entry.", return -EINVAL);
+       PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(smumgr,
+                               UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
+                               "Failed to Get Firmware Entry.", return -EINVAL);
+
+       smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, smu_data->header_buffer.mc_addr_high);
+       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");
+
+       return result;
+}
+
+/* Check if the FW has been loaded, SMU will not return if loading has not finished. */
+int smu7_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fw_type)
+{
+       struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(smumgr->backend);
+       uint32_t fw_mask = smu7_get_mask_for_firmware_type(fw_type);
+       uint32_t ret;
+
+       ret = smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX_11,
+                                       smu_data->soft_regs_start + smum_get_offsetof(smumgr,
+                                       SMU_SoftRegisters, UcodeLoadStatus),
+                                       fw_mask, fw_mask);
+
+       return ret;
+}
+
+int smu7_reload_firmware(struct pp_smumgr *smumgr)
+{
+       return smumgr->smumgr_funcs->start_smu(smumgr);
+}
+
+static int smu7_upload_smc_firmware_data(struct pp_smumgr *smumgr, uint32_t length, uint32_t *src, uint32_t limit)
+{
+       uint32_t byte_count = length;
+
+       PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area.", return -EINVAL);
+
+       cgs_write_register(smumgr->device, mmSMC_IND_INDEX_11, 0x20000);
+       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 1);
+
+       for (; byte_count >= 4; byte_count -= 4)
+               cgs_write_register(smumgr->device, mmSMC_IND_DATA_11, *src++);
+
+       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0);
+
+       PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be dividable by 4.", return -EINVAL);
+
+       return 0;
+}
+
+
+int smu7_upload_smu_firmware_image(struct pp_smumgr *smumgr)
+{
+       int result = 0;
+       struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(smumgr->backend);
+
+       struct cgs_firmware_info info = {0};
+
+       if (smu_data->security_hard_key == 1)
+               cgs_get_firmware_info(smumgr->device,
+                       smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
+       else
+               cgs_get_firmware_info(smumgr->device,
+                       smu7_convert_fw_type_to_cgs(UCODE_ID_SMU_SK), &info);
+
+       result = smu7_upload_smc_firmware_data(smumgr, info.image_size, (uint32_t *)info.kptr, SMU7_SMC_SIZE);
+
+       return result;
+}
+
+
+int smu7_init(struct pp_smumgr *smumgr)
+{
+       struct smu7_smumgr *smu_data;
+       uint8_t *internal_buf;
+       uint64_t mc_addr = 0;
+
+       /* Allocate memory for backend private data */
+       smu_data = (struct smu7_smumgr *)(smumgr->backend);
+       smu_data->header_buffer.data_size =
+                       ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
+       smu_data->smu_buffer.data_size = 200*4096;
+
+/* Allocate FW image data structure and header buffer and
+ * send the header buffer address to SMU */
+       smu_allocate_memory(smumgr->device,
+               smu_data->header_buffer.data_size,
+               CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
+               PAGE_SIZE,
+               &mc_addr,
+               &smu_data->header_buffer.kaddr,
+               &smu_data->header_buffer.handle);
+
+       smu_data->header = smu_data->header_buffer.kaddr;
+       smu_data->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+       smu_data->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+       PP_ASSERT_WITH_CODE((NULL != smu_data->header),
+               "Out of memory.",
+               kfree(smumgr->backend);
+               cgs_free_gpu_mem(smumgr->device,
+               (cgs_handle_t)smu_data->header_buffer.handle);
+               return -EINVAL);
+
+       smu_allocate_memory(smumgr->device,
+               smu_data->smu_buffer.data_size,
+               CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
+               PAGE_SIZE,
+               &mc_addr,
+               &smu_data->smu_buffer.kaddr,
+               &smu_data->smu_buffer.handle);
+
+       internal_buf = smu_data->smu_buffer.kaddr;
+       smu_data->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+       smu_data->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+       PP_ASSERT_WITH_CODE((NULL != internal_buf),
+               "Out of memory.",
+               kfree(smumgr->backend);
+               cgs_free_gpu_mem(smumgr->device,
+               (cgs_handle_t)smu_data->smu_buffer.handle);
+               return -EINVAL);
+
+       return 0;
+}
+
+
+int smu7_smu_fini(struct pp_smumgr *smumgr)
+{
+       if (smumgr->backend) {
+               kfree(smumgr->backend);
+               smumgr->backend = NULL;
+       }
+       cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU);
+       return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h
new file mode 100644 (file)
index 0000000..76352f2
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015 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 _SMU7_SMUMANAGER_H
+#define _SMU7_SMUMANAGER_H
+
+
+#include <pp_endian.h>
+
+#define SMC_RAM_END 0x40000
+#define mmSMC_IND_INDEX_11                              0x01AC
+#define mmSMC_IND_DATA_11                               0x01AD
+
+struct smu7_buffer_entry {
+       uint32_t data_size;
+       uint32_t mc_addr_low;
+       uint32_t mc_addr_high;
+       void *kaddr;
+       unsigned long  handle;
+};
+
+struct smu7_smumgr {
+       uint8_t *header;
+       uint8_t *mec_image;
+       struct smu7_buffer_entry smu_buffer;
+       struct smu7_buffer_entry header_buffer;
+
+       uint32_t                             soft_regs_start;
+       uint32_t                             dpm_table_start;
+       uint32_t                             mc_reg_table_start;
+       uint32_t                             fan_table_start;
+       uint32_t                             arb_table_start;
+       uint32_t                             ulv_setting_starts;
+       uint8_t                              security_hard_key;
+       uint32_t acpi_optimization;
+};
+
+
+int smu7_copy_bytes_from_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
+                               uint32_t *dest, uint32_t byte_count, uint32_t limit);
+int smu7_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smc_start_address,
+                       const uint8_t *src, uint32_t byte_count, uint32_t limit);
+int smu7_program_jump_on_start(struct pp_smumgr *smumgr);
+bool smu7_is_smc_ram_running(struct pp_smumgr *smumgr);
+int smu7_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg);
+int smu7_send_msg_to_smc_without_waiting(struct pp_smumgr *smumgr, uint16_t msg);
+int smu7_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, uint16_t msg,
+                                               uint32_t parameter);
+int smu7_send_msg_to_smc_with_parameter_without_waiting(struct pp_smumgr *smumgr,
+                                               uint16_t msg, uint32_t parameter);
+int smu7_send_msg_to_smc_offset(struct pp_smumgr *smumgr);
+int smu7_wait_for_smc_inactive(struct pp_smumgr *smumgr);
+
+enum cgs_ucode_id smu7_convert_fw_type_to_cgs(uint32_t fw_type);
+int smu7_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
+                                               uint32_t *value, uint32_t limit);
+int smu7_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
+                                               uint32_t value, uint32_t limit);
+
+int smu7_request_smu_load_fw(struct pp_smumgr *smumgr);
+int smu7_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fw_type);
+int smu7_reload_firmware(struct pp_smumgr *smumgr);
+int smu7_upload_smu_firmware_image(struct pp_smumgr *smumgr);
+int smu7_init(struct pp_smumgr *smumgr);
+int smu7_smu_fini(struct pp_smumgr *smumgr);
+
+#endif
\ No newline at end of file
index 7723473..e5812aa 100644 (file)
 #include "smumgr.h"
 #include "cgs_common.h"
 #include "linux/delay.h"
-#include "cz_smumgr.h"
-#include "tonga_smumgr.h"
-#include "fiji_smumgr.h"
-#include "polaris10_smumgr.h"
+
 
 int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
 {
@@ -47,7 +44,6 @@ int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
        smumgr->device = pp_init->device;
        smumgr->chip_family = pp_init->chip_family;
        smumgr->chip_id = pp_init->chip_id;
-       smumgr->hw_revision = pp_init->rev_id;
        smumgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
        smumgr->reload_fw = 1;
        handle->smu_mgr = smumgr;
@@ -58,6 +54,9 @@ int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
                break;
        case AMDGPU_FAMILY_VI:
                switch (smumgr->chip_id) {
+               case CHIP_TOPAZ:
+                       iceland_smum_init(smumgr);
+                       break;
                case CHIP_TONGA:
                        tonga_smum_init(smumgr);
                        break;
@@ -87,6 +86,57 @@ int smum_fini(struct pp_smumgr *smumgr)
        return 0;
 }
 
+int smum_thermal_avfs_enable(struct pp_hwmgr *hwmgr,
+               void *input, void *output, void *storage, int result)
+{
+       if (NULL != hwmgr->smumgr->smumgr_funcs->thermal_avfs_enable)
+               return hwmgr->smumgr->smumgr_funcs->thermal_avfs_enable(hwmgr);
+
+       return 0;
+}
+
+int smum_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
+               void *input, void *output, void *storage, int result)
+{
+       if (NULL != hwmgr->smumgr->smumgr_funcs->thermal_setup_fan_table)
+               return hwmgr->smumgr->smumgr_funcs->thermal_setup_fan_table(hwmgr);
+
+       return 0;
+}
+
+int smum_update_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+
+       if (NULL != hwmgr->smumgr->smumgr_funcs->update_sclk_threshold)
+               return hwmgr->smumgr->smumgr_funcs->update_sclk_threshold(hwmgr);
+
+       return 0;
+}
+
+int smum_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
+{
+
+       if (NULL != hwmgr->smumgr->smumgr_funcs->update_smc_table)
+               return hwmgr->smumgr->smumgr_funcs->update_smc_table(hwmgr, type);
+
+       return 0;
+}
+
+uint32_t smum_get_offsetof(struct pp_smumgr *smumgr, uint32_t type, uint32_t member)
+{
+       if (NULL != smumgr->smumgr_funcs->get_offsetof)
+               return smumgr->smumgr_funcs->get_offsetof(type, member);
+
+       return 0;
+}
+
+int smum_process_firmware_header(struct pp_hwmgr *hwmgr)
+{
+       if (NULL != hwmgr->smumgr->smumgr_funcs->process_firmware_header)
+               return hwmgr->smumgr->smumgr_funcs->process_firmware_header(hwmgr);
+       return 0;
+}
+
 int smum_get_argument(struct pp_smumgr *smumgr)
 {
        if (NULL != smumgr->smumgr_funcs->get_argument)
@@ -95,13 +145,20 @@ int smum_get_argument(struct pp_smumgr *smumgr)
        return 0;
 }
 
+uint32_t smum_get_mac_definition(struct pp_smumgr *smumgr, uint32_t value)
+{
+       if (NULL != smumgr->smumgr_funcs->get_mac_definition)
+               return smumgr->smumgr_funcs->get_mac_definition(value);
+
+       return 0;
+}
+
 int smum_download_powerplay_table(struct pp_smumgr *smumgr,
                                                                void **table)
 {
        if (NULL != smumgr->smumgr_funcs->download_pptable_settings)
                return smumgr->smumgr_funcs->download_pptable_settings(smumgr,
                                                                        table);
-
        return 0;
 }
 
@@ -268,3 +325,44 @@ int smu_free_memory(void *device, void *handle)
 
        return 0;
 }
+
+int smum_init_smc_table(struct pp_hwmgr *hwmgr)
+{
+       if (NULL != hwmgr->smumgr->smumgr_funcs->init_smc_table)
+               return hwmgr->smumgr->smumgr_funcs->init_smc_table(hwmgr);
+
+       return 0;
+}
+
+int smum_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
+{
+       if (NULL != hwmgr->smumgr->smumgr_funcs->populate_all_graphic_levels)
+               return hwmgr->smumgr->smumgr_funcs->populate_all_graphic_levels(hwmgr);
+
+       return 0;
+}
+
+int smum_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
+{
+       if (NULL != hwmgr->smumgr->smumgr_funcs->populate_all_memory_levels)
+               return hwmgr->smumgr->smumgr_funcs->populate_all_memory_levels(hwmgr);
+
+       return 0;
+}
+
+/*this interface is needed by island ci/vi */
+int smum_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+       if (NULL != hwmgr->smumgr->smumgr_funcs->initialize_mc_reg_table)
+               return hwmgr->smumgr->smumgr_funcs->initialize_mc_reg_table(hwmgr);
+
+       return 0;
+}
+
+bool smum_is_dpm_running(struct pp_hwmgr *hwmgr)
+{
+       if (NULL != hwmgr->smumgr->smumgr_funcs->is_dpm_running)
+               return hwmgr->smumgr->smumgr_funcs->is_dpm_running(hwmgr);
+
+       return true;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c
new file mode 100644 (file)
index 0000000..de2a24d
--- /dev/null
@@ -0,0 +1,3206 @@
+/*
+ * Copyright 2015 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 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.
+ * 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.
+ *
+ *
+ */
+
+#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"
+#include "pppcielanes.h"
+#include "pp_endian.h"
+#include "smu7_ppsmc.h"
+
+#include "smu72_discrete.h"
+
+#include "smu/smu_7_1_2_d.h"
+#include "smu/smu_7_1_2_sh_mask.h"
+
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+
+#include "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+
+
+#define VOLTAGE_SCALE 4
+#define POWERTUNE_DEFAULT_SET_MAX    1
+#define VOLTAGE_VID_OFFSET_SCALE1   625
+#define VOLTAGE_VID_OFFSET_SCALE2   100
+#define MC_CG_ARB_FREQ_F1           0x0b
+#define VDDC_VDDCI_DELTA            200
+
+
+static const struct tonga_pt_defaults tonga_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
+/* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc,  TDC_MAWt,
+ * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,        BAPM_TEMP_GRADIENT
+ */
+       {1,               0xF,             0xFD,                0x19,
+        5,               45,                 0,              0xB0000,
+        {0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8,
+               0xC9, 0xC9, 0x2F, 0x4D, 0x61},
+        {0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203,
+               0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4}
+       },
+};
+
+/* [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
+static const uint16_t tonga_clock_stretcher_lookup_table[2][4] = {
+       {600, 1050, 3, 0},
+       {600, 1050, 6, 1}
+};
+
+/* [FF, SS] type, [] 4 voltage ranges,
+ * and [Floor Freq, Boundary Freq, VID min , VID max]
+ */
+static const uint32_t tonga_clock_stretcher_ddt_table[2][4][4] = {
+       { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
+       { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} }
+};
+
+/* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] */
+static const uint8_t tonga_clock_stretch_amount_conversion[2][6] = {
+       {0, 1, 3, 2, 4, 5},
+       {0, 2, 4, 5, 6, 5}
+};
+
+/* PPGen has the gain setting generated in x * 100 unit
+ * This function is to convert the unit to x * 4096(0x1000) unit.
+ *  This is the unit expected by SMC firmware
+ */
+
+
+static int tonga_get_dependecy_volt_by_clk(struct pp_hwmgr *hwmgr,
+       phm_ppt_v1_clock_voltage_dependency_table *allowed_clock_voltage_table,
+       uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
+{
+       uint32_t i = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info =
+                          (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       /* clock - voltage dependency table is empty table */
+       if (allowed_clock_voltage_table->count == 0)
+               return -EINVAL;
+
+       for (i = 0; i < allowed_clock_voltage_table->count; i++) {
+               /* find first sclk bigger than request */
+               if (allowed_clock_voltage_table->entries[i].clk >= clock) {
+                       voltage->VddGfx = phm_get_voltage_index(
+                                       pptable_info->vddgfx_lookup_table,
+                               allowed_clock_voltage_table->entries[i].vddgfx);
+                       voltage->Vddc = phm_get_voltage_index(
+                                               pptable_info->vddc_lookup_table,
+                                 allowed_clock_voltage_table->entries[i].vddc);
+
+                       if (allowed_clock_voltage_table->entries[i].vddci)
+                               voltage->Vddci =
+                                       phm_get_voltage_id(&data->vddci_voltage_table, allowed_clock_voltage_table->entries[i].vddci);
+                       else
+                               voltage->Vddci =
+                                       phm_get_voltage_id(&data->vddci_voltage_table,
+                                               allowed_clock_voltage_table->entries[i].vddc - VDDC_VDDCI_DELTA);
+
+
+                       if (allowed_clock_voltage_table->entries[i].mvdd)
+                               *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i].mvdd;
+
+                       voltage->Phases = 1;
+                       return 0;
+               }
+       }
+
+       /* sclk is bigger than max sclk in the dependence table */
+       voltage->VddGfx = phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
+               allowed_clock_voltage_table->entries[i-1].vddgfx);
+       voltage->Vddc = phm_get_voltage_index(pptable_info->vddc_lookup_table,
+               allowed_clock_voltage_table->entries[i-1].vddc);
+
+       if (allowed_clock_voltage_table->entries[i-1].vddci)
+               voltage->Vddci = phm_get_voltage_id(&data->vddci_voltage_table,
+                       allowed_clock_voltage_table->entries[i-1].vddci);
+
+       if (allowed_clock_voltage_table->entries[i-1].mvdd)
+               *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i-1].mvdd;
+
+       return 0;
+}
+
+
+/**
+ * Vddc table preparation for SMC.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+static int tonga_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
+                       SMU72_Discrete_DpmTable *table)
+{
+       unsigned int count;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+               table->VddcLevelCount = data->vddc_voltage_table.count;
+               for (count = 0; count < table->VddcLevelCount; count++) {
+                       table->VddcTable[count] =
+                               PP_HOST_TO_SMC_US(data->vddc_voltage_table.entries[count].value * VOLTAGE_SCALE);
+               }
+               CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
+       }
+       return 0;
+}
+
+/**
+ * VddGfx table preparation for SMC.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr *hwmgr,
+                       SMU72_Discrete_DpmTable *table)
+{
+       unsigned int count;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
+               table->VddGfxLevelCount = data->vddgfx_voltage_table.count;
+               for (count = 0; count < data->vddgfx_voltage_table.count; count++) {
+                       table->VddGfxTable[count] =
+                               PP_HOST_TO_SMC_US(data->vddgfx_voltage_table.entries[count].value * VOLTAGE_SCALE);
+               }
+               CONVERT_FROM_HOST_TO_SMC_UL(table->VddGfxLevelCount);
+       }
+       return 0;
+}
+
+/**
+ * Vddci table preparation for SMC.
+ *
+ * @param    *hwmgr The address of the hardware manager.
+ * @param    *table The SMC DPM table structure to be populated.
+ * @return   0
+ */
+static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
+                       SMU72_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t count;
+
+       table->VddciLevelCount = data->vddci_voltage_table.count;
+       for (count = 0; count < table->VddciLevelCount; count++) {
+               if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
+                       table->VddciTable[count] =
+                               PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
+               } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+                       table->SmioTable1.Pattern[count].Voltage =
+                               PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
+                       /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
+                       table->SmioTable1.Pattern[count].Smio =
+                               (uint8_t) count;
+                       table->Smio[count] |=
+                               data->vddci_voltage_table.entries[count].smio_low;
+                       table->VddciTable[count] =
+                               PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
+               }
+       }
+
+       table->SmioMask1 = data->vddci_voltage_table.mask_low;
+       CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
+
+       return 0;
+}
+
+/**
+ * Mvdd table preparation for SMC.
+ *
+ * @param    *hwmgr The address of the hardware manager.
+ * @param    *table The SMC DPM table structure to be populated.
+ * @return   0
+ */
+static int tonga_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
+                       SMU72_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t count;
+
+       if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+               table->MvddLevelCount = data->mvdd_voltage_table.count;
+               for (count = 0; count < table->MvddLevelCount; count++) {
+                       table->SmioTable2.Pattern[count].Voltage =
+                               PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE);
+                       /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
+                       table->SmioTable2.Pattern[count].Smio =
+                               (uint8_t) count;
+                       table->Smio[count] |=
+                               data->mvdd_voltage_table.entries[count].smio_low;
+               }
+               table->SmioMask2 = data->mvdd_voltage_table.mask_low;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
+       }
+
+       return 0;
+}
+
+/**
+ * Preparation of vddc and vddgfx CAC tables for SMC.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+static int tonga_populate_cac_tables(struct pp_hwmgr *hwmgr,
+                       SMU72_Discrete_DpmTable *table)
+{
+       uint32_t count;
+       uint8_t index = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table =
+                                          pptable_info->vddgfx_lookup_table;
+       struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table =
+                                               pptable_info->vddc_lookup_table;
+
+       /* table is already swapped, so in order to use the value from it
+        * we need to swap it back.
+        */
+       uint32_t vddc_level_count = PP_SMC_TO_HOST_UL(table->VddcLevelCount);
+       uint32_t vddgfx_level_count = PP_SMC_TO_HOST_UL(table->VddGfxLevelCount);
+
+       for (count = 0; count < vddc_level_count; count++) {
+               /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
+               index = phm_get_voltage_index(vddc_lookup_table,
+                       data->vddc_voltage_table.entries[count].value);
+               table->BapmVddcVidLoSidd[count] =
+                       convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
+               table->BapmVddcVidHiSidd[count] =
+                       convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
+               table->BapmVddcVidHiSidd2[count] =
+                       convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
+       }
+
+       if ((data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2)) {
+               /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
+               for (count = 0; count < vddgfx_level_count; count++) {
+                       index = phm_get_voltage_index(vddgfx_lookup_table,
+                               convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_mid));
+                       table->BapmVddGfxVidHiSidd2[count] =
+                               convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_high);
+               }
+       } else {
+               for (count = 0; count < vddc_level_count; count++) {
+                       index = phm_get_voltage_index(vddc_lookup_table,
+                               data->vddc_voltage_table.entries[count].value);
+                       table->BapmVddGfxVidLoSidd[count] =
+                               convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
+                       table->BapmVddGfxVidHiSidd[count] =
+                               convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
+                       table->BapmVddGfxVidHiSidd2[count] =
+                               convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * Preparation of voltage tables for SMC.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+
+static int tonga_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
+       SMU72_Discrete_DpmTable *table)
+{
+       int result;
+
+       result = tonga_populate_smc_vddc_table(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+                       "can not populate VDDC voltage table to SMC",
+                       return -EINVAL);
+
+       result = tonga_populate_smc_vdd_ci_table(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+                       "can not populate VDDCI voltage table to SMC",
+                       return -EINVAL);
+
+       result = tonga_populate_smc_vdd_gfx_table(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+                       "can not populate VDDGFX voltage table to SMC",
+                       return -EINVAL);
+
+       result = tonga_populate_smc_mvdd_table(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+                       "can not populate MVDD voltage table to SMC",
+                       return -EINVAL);
+
+       result = tonga_populate_cac_tables(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+                       "can not populate CAC voltage tables to SMC",
+                       return -EINVAL);
+
+       return 0;
+}
+
+static int tonga_populate_ulv_level(struct pp_hwmgr *hwmgr,
+               struct SMU72_Discrete_Ulv *state)
+{
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       state->CcPwrDynRm = 0;
+       state->CcPwrDynRm1 = 0;
+
+       state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
+       state->VddcOffsetVid = (uint8_t)(table_info->us_ulv_voltage_offset *
+                       VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
+
+       state->VddcPhase = 1;
+
+       CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
+       CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
+       CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
+
+       return 0;
+}
+
+static int tonga_populate_ulv_state(struct pp_hwmgr *hwmgr,
+               struct SMU72_Discrete_DpmTable *table)
+{
+       return tonga_populate_ulv_level(hwmgr, &table->Ulv);
+}
+
+static int tonga_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU72_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t i;
+
+       /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
+       for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
+               table->LinkLevel[i].PcieGenSpeed  =
+                       (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
+               table->LinkLevel[i].PcieLaneCount =
+                       (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
+               table->LinkLevel[i].EnabledForActivity =
+                       1;
+               table->LinkLevel[i].SPC =
+                       (uint8_t)(data->pcie_spc_cap & 0xff);
+               table->LinkLevel[i].DownThreshold =
+                       PP_HOST_TO_SMC_UL(5);
+               table->LinkLevel[i].UpThreshold =
+                       PP_HOST_TO_SMC_UL(30);
+       }
+
+       smu_data->smc_state_table.LinkLevelCount =
+               (uint8_t)dpm_table->pcie_speed_table.count;
+       data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+               phm_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
+
+       return 0;
+}
+
+/**
+ * Calculates the SCLK dividers using the provided engine clock
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    engine_clock the engine clock to use to populate the structure
+ * @param    sclk        the SMC SCLK structure to be populated
+ */
+static int tonga_calculate_sclk_params(struct pp_hwmgr *hwmgr,
+               uint32_t engine_clock, SMU72_Discrete_GraphicsLevel *sclk)
+{
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       pp_atomctrl_clock_dividers_vi dividers;
+       uint32_t spll_func_cntl            = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+       uint32_t spll_func_cntl_3          = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+       uint32_t spll_func_cntl_4          = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+       uint32_t cg_spll_spread_spectrum   = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+       uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+       uint32_t    reference_clock;
+       uint32_t reference_divider;
+       uint32_t fbdiv;
+       int result;
+
+       /* get the engine clock dividers for this clock value*/
+       result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock,  &dividers);
+
+       PP_ASSERT_WITH_CODE(result == 0,
+               "Error retrieving Engine Clock dividers from VBIOS.", return result);
+
+       /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
+       reference_clock = atomctrl_get_reference_clock(hwmgr);
+
+       reference_divider = 1 + dividers.uc_pll_ref_div;
+
+       /* low 14 bits is fraction and high 12 bits is divider*/
+       fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
+
+       /* SPLL_FUNC_CNTL setup*/
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+               CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div);
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+               CG_SPLL_FUNC_CNTL, SPLL_PDIV_A,  dividers.uc_pll_post_div);
+
+       /* SPLL_FUNC_CNTL_3 setup*/
+       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
+               CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv);
+
+       /* set to use fractional accumulation*/
+       spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
+               CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
+               pp_atomctrl_internal_ss_info ss_info;
+
+               uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div;
+               if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) {
+                       /*
+                       * ss_info.speed_spectrum_percentage -- in unit of 0.01%
+                       * ss_info.speed_spectrum_rate -- in unit of khz
+                       */
+                       /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
+                       uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate);
+
+                       /* clkv = 2 * D * fbdiv / NS */
+                       uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000);
+
+                       cg_spll_spread_spectrum =
+                               PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS);
+                       cg_spll_spread_spectrum =
+                               PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
+                       cg_spll_spread_spectrum_2 =
+                               PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV);
+               }
+       }
+
+       sclk->SclkFrequency        = engine_clock;
+       sclk->CgSpllFuncCntl3      = spll_func_cntl_3;
+       sclk->CgSpllFuncCntl4      = spll_func_cntl_4;
+       sclk->SpllSpreadSpectrum   = cg_spll_spread_spectrum;
+       sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
+       sclk->SclkDid              = (uint8_t)dividers.pll_post_divider;
+
+       return 0;
+}
+
+/**
+ * Populates single SMC SCLK structure using the provided engine clock
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    engine_clock the engine clock to use to populate the structure
+ * @param    sclk        the SMC SCLK structure to be populated
+ */
+static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
+                                               uint32_t engine_clock,
+                               uint16_t sclk_activity_level_threshold,
+                               SMU72_Discrete_GraphicsLevel *graphic_level)
+{
+       int result;
+       uint32_t mvdd;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info =
+                           (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       result = tonga_calculate_sclk_params(hwmgr, engine_clock, graphic_level);
+
+       /* populate graphics levels*/
+       result = tonga_get_dependecy_volt_by_clk(hwmgr,
+               pptable_info->vdd_dep_on_sclk, engine_clock,
+               &graphic_level->MinVoltage, &mvdd);
+       PP_ASSERT_WITH_CODE((!result),
+               "can not find VDDC voltage value for VDDC "
+               "engine clock dependency table", return result);
+
+       /* SCLK frequency in units of 10KHz*/
+       graphic_level->SclkFrequency = engine_clock;
+       /* Indicates maximum activity level for this performance level. 50% for now*/
+       graphic_level->ActivityLevel = sclk_activity_level_threshold;
+
+       graphic_level->CcPwrDynRm = 0;
+       graphic_level->CcPwrDynRm1 = 0;
+       /* this level can be used if activity is high enough.*/
+       graphic_level->EnabledForActivity = 0;
+       /* this level can be used for throttling.*/
+       graphic_level->EnabledForThrottle = 1;
+       graphic_level->UpHyst = 0;
+       graphic_level->DownHyst = 0;
+       graphic_level->VoltageDownHyst = 0;
+       graphic_level->PowerThrottle = 0;
+
+       data->display_timing.min_clock_in_sr =
+                       hwmgr->display_config.min_core_set_clock_in_sr;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkDeepSleep))
+               graphic_level->DeepSleepDivId =
+                               smu7_get_sleep_divider_id_from_clock(engine_clock,
+                                               data->display_timing.min_clock_in_sr);
+
+       /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
+       graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+       if (!result) {
+               /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
+               /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency);
+               CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm);
+               CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1);
+       }
+
+       return result;
+}
+
+/**
+ * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
+ *
+ * @param    hwmgr      the address of the hardware manager
+ */
+int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       struct phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
+       uint8_t pcie_entry_count = (uint8_t) data->dpm_table.pcie_speed_table.count;
+       uint32_t level_array_address = smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU72_Discrete_DpmTable, GraphicsLevel);
+
+       uint32_t level_array_size = sizeof(SMU72_Discrete_GraphicsLevel) *
+                                               SMU72_MAX_LEVELS_GRAPHICS;
+
+       SMU72_Discrete_GraphicsLevel *levels = smu_data->smc_state_table.GraphicsLevel;
+
+       uint32_t i, max_entry;
+       uint8_t highest_pcie_level_enabled = 0;
+       uint8_t lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0;
+       uint8_t count = 0;
+       int result = 0;
+
+       memset(levels, 0x00, level_array_size);
+
+       for (i = 0; i < dpm_table->sclk_table.count; i++) {
+               result = tonga_populate_single_graphic_level(hwmgr,
+                                       dpm_table->sclk_table.dpm_levels[i].value,
+                                       (uint16_t)smu_data->activity_target[i],
+                                       &(smu_data->smc_state_table.GraphicsLevel[i]));
+               if (result != 0)
+                       return result;
+
+               /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
+               if (i > 1)
+                       smu_data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
+       }
+
+       /* Only enable level 0 for now. */
+       smu_data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
+
+       /* set highest level watermark to high */
+       if (dpm_table->sclk_table.count > 1)
+               smu_data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark =
+                       PPSMC_DISPLAY_WATERMARK_HIGH;
+
+       smu_data->smc_state_table.GraphicsDpmLevelCount =
+               (uint8_t)dpm_table->sclk_table.count;
+       data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+               phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
+
+       if (pcie_table != NULL) {
+               PP_ASSERT_WITH_CODE((pcie_entry_count >= 1),
+                       "There must be 1 or more PCIE levels defined in PPTable.",
+                       return -EINVAL);
+               max_entry = pcie_entry_count - 1; /* for indexing, we need to decrement by 1.*/
+               for (i = 0; i < dpm_table->sclk_table.count; i++) {
+                       smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel =
+                               (uint8_t) ((i < max_entry) ? i : max_entry);
+               }
+       } else {
+               if (0 == data->dpm_level_enable_mask.pcie_dpm_enable_mask)
+                       printk(KERN_ERR "[ powerplay ] Pcie Dpm Enablemask is 0 !");
+
+               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                                       (1<<(highest_pcie_level_enabled+1))) != 0)) {
+                       highest_pcie_level_enabled++;
+               }
+
+               while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                                       (1<<lowest_pcie_level_enabled)) == 0)) {
+                       lowest_pcie_level_enabled++;
+               }
+
+               while ((count < highest_pcie_level_enabled) &&
+                               ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+                                       (1<<(lowest_pcie_level_enabled+1+count))) == 0)) {
+                       count++;
+               }
+               mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ?
+                       (lowest_pcie_level_enabled+1+count) : highest_pcie_level_enabled;
+
+
+               /* set pcieDpmLevel to highest_pcie_level_enabled*/
+               for (i = 2; i < dpm_table->sclk_table.count; i++)
+                       smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled;
+
+               /* set pcieDpmLevel to lowest_pcie_level_enabled*/
+               smu_data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled;
+
+               /* set pcieDpmLevel to mid_pcie_level_enabled*/
+               smu_data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled;
+       }
+       /* level count will send to smc once at init smc table and never change*/
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr, level_array_address,
+                               (uint8_t *)levels, (uint32_t)level_array_size,
+                                                               SMC_RAM_END);
+
+       return result;
+}
+
+/**
+ * Populates the SMC MCLK structure using the provided memory clock
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    memory_clock the memory clock to use to populate the structure
+ * @param    sclk        the SMC SCLK structure to be populated
+ */
+static int tonga_calculate_mclk_params(
+               struct pp_hwmgr *hwmgr,
+               uint32_t memory_clock,
+               SMU72_Discrete_MemoryLevel *mclk,
+               bool strobe_mode,
+               bool dllStateOn
+               )
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       uint32_t dll_cntl = data->clock_registers.vDLL_CNTL;
+       uint32_t mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
+       uint32_t mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
+       uint32_t mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
+       uint32_t mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
+       uint32_t mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
+       uint32_t mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
+       uint32_t mpll_ss1 = data->clock_registers.vMPLL_SS1;
+       uint32_t mpll_ss2 = data->clock_registers.vMPLL_SS2;
+
+       pp_atomctrl_memory_clock_param mpll_param;
+       int result;
+
+       result = atomctrl_get_memory_pll_dividers_si(hwmgr,
+                               memory_clock, &mpll_param, strobe_mode);
+       PP_ASSERT_WITH_CODE(
+                       !result,
+                       "Error retrieving Memory Clock Parameters from VBIOS.",
+                       return result);
+
+       /* MPLL_FUNC_CNTL setup*/
+       mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL,
+                                       mpll_param.bw_ctrl);
+
+       /* MPLL_FUNC_CNTL_1 setup*/
+       mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
+                                       MPLL_FUNC_CNTL_1, CLKF,
+                                       mpll_param.mpll_fb_divider.cl_kf);
+       mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
+                                       MPLL_FUNC_CNTL_1, CLKFRAC,
+                                       mpll_param.mpll_fb_divider.clk_frac);
+       mpll_func_cntl_1  = PHM_SET_FIELD(mpll_func_cntl_1,
+                                               MPLL_FUNC_CNTL_1, VCO_MODE,
+                                               mpll_param.vco_mode);
+
+       /* MPLL_AD_FUNC_CNTL setup*/
+       mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
+                                       MPLL_AD_FUNC_CNTL, YCLK_POST_DIV,
+                                       mpll_param.mpll_post_divider);
+
+       if (data->is_memory_gddr5) {
+               /* MPLL_DQ_FUNC_CNTL setup*/
+               mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
+                                               MPLL_DQ_FUNC_CNTL, YCLK_SEL,
+                                               mpll_param.yclk_sel);
+               mpll_dq_func_cntl  = PHM_SET_FIELD(mpll_dq_func_cntl,
+                                               MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV,
+                                               mpll_param.mpll_post_divider);
+       }
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
+               /*
+                ************************************
+                Fref = Reference Frequency
+                NF = Feedback divider ratio
+                NR = Reference divider ratio
+                Fnom = Nominal VCO output frequency = Fref * NF / NR
+                Fs = Spreading Rate
+                D = Percentage down-spread / 2
+                Fint = Reference input frequency to PFD = Fref / NR
+                NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
+                CLKS = NS - 1 = ISS_STEP_NUM[11:0]
+                NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
+                CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
+                *************************************
+                */
+               pp_atomctrl_internal_ss_info ss_info;
+               uint32_t freq_nom;
+               uint32_t tmp;
+               uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
+
+               /* for GDDR5 for all modes and DDR3 */
+               if (1 == mpll_param.qdr)
+                       freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
+               else
+                       freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
+
+               /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2  Note: S.I. reference_divider = 1*/
+               tmp = (freq_nom / reference_clock);
+               tmp = tmp * tmp;
+
+               if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
+                       /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
+                       /* ss.Info.speed_spectrum_rate -- in unit of khz */
+                       /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
+                       /*     = reference_clock * 5 / speed_spectrum_rate */
+                       uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
+
+                       /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
+                       /*     = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
+                       uint32_t clkv =
+                               (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
+                                                       ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
+
+                       mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
+                       mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
+               }
+       }
+
+       /* MCLK_PWRMGT_CNTL setup */
+       mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
+       mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
+       mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
+
+       /* Save the result data to outpupt memory level structure */
+       mclk->MclkFrequency   = memory_clock;
+       mclk->MpllFuncCntl    = mpll_func_cntl;
+       mclk->MpllFuncCntl_1  = mpll_func_cntl_1;
+       mclk->MpllFuncCntl_2  = mpll_func_cntl_2;
+       mclk->MpllAdFuncCntl  = mpll_ad_func_cntl;
+       mclk->MpllDqFuncCntl  = mpll_dq_func_cntl;
+       mclk->MclkPwrmgtCntl  = mclk_pwrmgt_cntl;
+       mclk->DllCntl         = dll_cntl;
+       mclk->MpllSs1         = mpll_ss1;
+       mclk->MpllSs2         = mpll_ss2;
+
+       return 0;
+}
+
+static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock,
+               bool strobe_mode)
+{
+       uint8_t mc_para_index;
+
+       if (strobe_mode) {
+               if (memory_clock < 12500)
+                       mc_para_index = 0x00;
+               else if (memory_clock > 47500)
+                       mc_para_index = 0x0f;
+               else
+                       mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
+       } else {
+               if (memory_clock < 65000)
+                       mc_para_index = 0x00;
+               else if (memory_clock > 135000)
+                       mc_para_index = 0x0f;
+               else
+                       mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
+       }
+
+       return mc_para_index;
+}
+
+static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
+{
+       uint8_t mc_para_index;
+
+       if (memory_clock < 10000)
+               mc_para_index = 0;
+       else if (memory_clock >= 80000)
+               mc_para_index = 0x0f;
+       else
+               mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
+
+       return mc_para_index;
+}
+
+
+static int tonga_populate_single_memory_level(
+               struct pp_hwmgr *hwmgr,
+               uint32_t memory_clock,
+               SMU72_Discrete_MemoryLevel *memory_level
+               )
+{
+       uint32_t mvdd = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info =
+                         (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       int result = 0;
+       bool dll_state_on;
+       struct cgs_display_info info = {0};
+       uint32_t mclk_edc_wr_enable_threshold = 40000;
+       uint32_t mclk_stutter_mode_threshold = 30000;
+       uint32_t mclk_edc_enable_threshold = 40000;
+       uint32_t mclk_strobe_mode_threshold = 40000;
+
+       if (NULL != pptable_info->vdd_dep_on_mclk) {
+               result = tonga_get_dependecy_volt_by_clk(hwmgr,
+                               pptable_info->vdd_dep_on_mclk,
+                               memory_clock,
+                               &memory_level->MinVoltage, &mvdd);
+               PP_ASSERT_WITH_CODE(
+                       !result,
+                       "can not find MinVddc voltage value from memory VDDC "
+                       "voltage dependency table",
+                       return result);
+       }
+
+       if (data->mvdd_control == SMU7_VOLTAGE_CONTROL_NONE)
+               memory_level->MinMvdd = data->vbios_boot_state.mvdd_bootup_value;
+       else
+               memory_level->MinMvdd = mvdd;
+
+       memory_level->EnabledForThrottle = 1;
+       memory_level->EnabledForActivity = 0;
+       memory_level->UpHyst = 0;
+       memory_level->DownHyst = 100;
+       memory_level->VoltageDownHyst = 0;
+
+       /* Indicates maximum activity level for this performance level.*/
+       memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
+       memory_level->StutterEnable = 0;
+       memory_level->StrobeEnable = 0;
+       memory_level->EdcReadEnable = 0;
+       memory_level->EdcWriteEnable = 0;
+       memory_level->RttEnable = 0;
+
+       /* default set to low watermark. Highest level will be set to high later.*/
+       memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+       cgs_get_active_displays_info(hwmgr->device, &info);
+       data->display_timing.num_existing_displays = info.display_count;
+
+       if ((mclk_stutter_mode_threshold != 0) &&
+           (memory_clock <= mclk_stutter_mode_threshold) &&
+           (!data->is_uvd_enabled)
+           && (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL, STUTTER_ENABLE) & 0x1)
+           && (data->display_timing.num_existing_displays <= 2)
+           && (data->display_timing.num_existing_displays != 0))
+               memory_level->StutterEnable = 1;
+
+       /* decide strobe mode*/
+       memory_level->StrobeEnable = (mclk_strobe_mode_threshold != 0) &&
+               (memory_clock <= mclk_strobe_mode_threshold);
+
+       /* decide EDC mode and memory clock ratio*/
+       if (data->is_memory_gddr5) {
+               memory_level->StrobeRatio = tonga_get_mclk_frequency_ratio(memory_clock,
+                                       memory_level->StrobeEnable);
+
+               if ((mclk_edc_enable_threshold != 0) &&
+                               (memory_clock > mclk_edc_enable_threshold)) {
+                       memory_level->EdcReadEnable = 1;
+               }
+
+               if ((mclk_edc_wr_enable_threshold != 0) &&
+                               (memory_clock > mclk_edc_wr_enable_threshold)) {
+                       memory_level->EdcWriteEnable = 1;
+               }
+
+               if (memory_level->StrobeEnable) {
+                       if (tonga_get_mclk_frequency_ratio(memory_clock, 1) >=
+                                       ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf)) {
+                               dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
+                       } else {
+                               dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
+                       }
+
+               } else {
+                       dll_state_on = data->dll_default_on;
+               }
+       } else {
+               memory_level->StrobeRatio =
+                       tonga_get_ddr3_mclk_frequency_ratio(memory_clock);
+               dll_state_on = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
+       }
+
+       result = tonga_calculate_mclk_params(hwmgr,
+               memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
+
+       if (!result) {
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinMvdd);
+               /* MCLK frequency in units of 10KHz*/
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
+               /* Indicates maximum activity level for this performance level.*/
+               CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
+               CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
+       }
+
+       return result;
+}
+
+int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct tonga_smumgr *smu_data =
+                       (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       struct smu7_dpm_table *dpm_table = &data->dpm_table;
+       int result;
+
+       /* populate MCLK dpm table to SMU7 */
+       uint32_t level_array_address =
+                               smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU72_Discrete_DpmTable, MemoryLevel);
+       uint32_t level_array_size =
+                               sizeof(SMU72_Discrete_MemoryLevel) *
+                               SMU72_MAX_LEVELS_MEMORY;
+       SMU72_Discrete_MemoryLevel *levels =
+                               smu_data->smc_state_table.MemoryLevel;
+       uint32_t i;
+
+       memset(levels, 0x00, level_array_size);
+
+       for (i = 0; i < dpm_table->mclk_table.count; i++) {
+               PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
+                       "can not populate memory level as memory clock is zero",
+                       return -EINVAL);
+               result = tonga_populate_single_memory_level(
+                               hwmgr,
+                               dpm_table->mclk_table.dpm_levels[i].value,
+                               &(smu_data->smc_state_table.MemoryLevel[i]));
+               if (result)
+                       return result;
+       }
+
+       /* Only enable level 0 for now.*/
+       smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
+
+       /*
+       * in order to prevent MC activity from stutter mode to push DPM up.
+       * the UVD change complements this by putting the MCLK in a higher state
+       * by default such that we are not effected by up threshold or and MCLK DPM latency.
+       */
+       smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
+       CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
+
+       smu_data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
+       data->dpm_level_enable_mask.mclk_dpm_enable_mask = phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
+       /* set highest level watermark to high*/
+       smu_data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
+
+       /* level count will send to smc once at init smc table and never change*/
+       result = smu7_copy_bytes_to_smc(hwmgr->smumgr,
+               level_array_address, (uint8_t *)levels, (uint32_t)level_array_size,
+               SMC_RAM_END);
+
+       return result;
+}
+
+static int tonga_populate_mvdd_value(struct pp_hwmgr *hwmgr,
+                               uint32_t mclk, SMIO_Pattern *smio_pattern)
+{
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       uint32_t i = 0;
+
+       if (SMU7_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
+               /* find mvdd value which clock is more than request */
+               for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
+                       if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
+                               /* Always round to higher voltage. */
+                               smio_pattern->Voltage =
+                                     data->mvdd_voltage_table.entries[i].value;
+                               break;
+                       }
+               }
+
+               PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
+                       "MVDD Voltage is outside the supported range.",
+                       return -EINVAL);
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+static int tonga_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
+       SMU72_Discrete_DpmTable *table)
+{
+       int result = 0;
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       const struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct pp_atomctrl_clock_dividers_vi dividers;
+
+       SMIO_Pattern voltage_level;
+       uint32_t spll_func_cntl    = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+       uint32_t spll_func_cntl_2  = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
+       uint32_t dll_cntl          = data->clock_registers.vDLL_CNTL;
+       uint32_t mclk_pwrmgt_cntl  = data->clock_registers.vMCLK_PWRMGT_CNTL;
+
+       /* The ACPI state should not do DPM on DC (or ever).*/
+       table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+       table->ACPILevel.MinVoltage =
+                       smu_data->smc_state_table.GraphicsLevel[0].MinVoltage;
+
+       /* assign zero for now*/
+       table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
+
+       /* get the engine clock dividers for this clock value*/
+       result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
+               table->ACPILevel.SclkFrequency,  &dividers);
+
+       PP_ASSERT_WITH_CODE(result == 0,
+               "Error retrieving Engine Clock dividers from VBIOS.",
+               return result);
+
+       /* divider ID for required SCLK*/
+       table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
+       table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+       table->ACPILevel.DeepSleepDivId = 0;
+
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+                                       SPLL_PWRON, 0);
+       spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+                                               SPLL_RESET, 1);
+       spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
+                                               SCLK_MUX_SEL, 4);
+
+       table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
+       table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
+       table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+       table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+       table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+       table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+       table->ACPILevel.CcPwrDynRm = 0;
+       table->ACPILevel.CcPwrDynRm1 = 0;
+
+
+       /* For various features to be enabled/disabled while this level is active.*/
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
+       /* SCLK frequency in units of 10KHz*/
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
+
+       /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
+       table->MemoryACPILevel.MinVoltage =
+                           smu_data->smc_state_table.MemoryLevel[0].MinVoltage;
+
+       /*  CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
+
+       if (0 == tonga_populate_mvdd_value(hwmgr, 0, &voltage_level))
+               table->MemoryACPILevel.MinMvdd =
+                       PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
+       else
+               table->MemoryACPILevel.MinMvdd = 0;
+
+       /* Force reset on DLL*/
+       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
+       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
+
+       /* Disable DLL in ACPIState*/
+       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
+       mclk_pwrmgt_cntl    = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+               MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
+
+       /* Enable DLL bypass signal*/
+       dll_cntl            = PHM_SET_FIELD(dll_cntl,
+               DLL_CNTL, MRDCK0_BYPASS, 0);
+       dll_cntl            = PHM_SET_FIELD(dll_cntl,
+               DLL_CNTL, MRDCK1_BYPASS, 0);
+
+       table->MemoryACPILevel.DllCntl            =
+               PP_HOST_TO_SMC_UL(dll_cntl);
+       table->MemoryACPILevel.MclkPwrmgtCntl     =
+               PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
+       table->MemoryACPILevel.MpllAdFuncCntl     =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
+       table->MemoryACPILevel.MpllDqFuncCntl     =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
+       table->MemoryACPILevel.MpllFuncCntl       =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
+       table->MemoryACPILevel.MpllFuncCntl_1     =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
+       table->MemoryACPILevel.MpllFuncCntl_2     =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
+       table->MemoryACPILevel.MpllSs1            =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
+       table->MemoryACPILevel.MpllSs2            =
+               PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
+
+       table->MemoryACPILevel.EnabledForThrottle = 0;
+       table->MemoryACPILevel.EnabledForActivity = 0;
+       table->MemoryACPILevel.UpHyst = 0;
+       table->MemoryACPILevel.DownHyst = 100;
+       table->MemoryACPILevel.VoltageDownHyst = 0;
+       /* Indicates maximum activity level for this performance level.*/
+       table->MemoryACPILevel.ActivityLevel =
+                       PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
+
+       table->MemoryACPILevel.StutterEnable = 0;
+       table->MemoryACPILevel.StrobeEnable = 0;
+       table->MemoryACPILevel.EdcReadEnable = 0;
+       table->MemoryACPILevel.EdcWriteEnable = 0;
+       table->MemoryACPILevel.RttEnable = 0;
+
+       return result;
+}
+
+static int tonga_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
+                                       SMU72_Discrete_DpmTable *table)
+{
+       int result = 0;
+
+       uint8_t count;
+       pp_atomctrl_clock_dividers_vi dividers;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info =
+                               (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                                               pptable_info->mm_dep_table;
+
+       table->UvdLevelCount = (uint8_t) (mm_table->count);
+       table->UvdBootLevel = 0;
+
+       for (count = 0; count < table->UvdLevelCount; count++) {
+               table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
+               table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
+               table->UvdLevel[count].MinVoltage.Vddc =
+                       phm_get_voltage_index(pptable_info->vddc_lookup_table,
+                                               mm_table->entries[count].vddc);
+               table->UvdLevel[count].MinVoltage.VddGfx =
+                       (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
+                       phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
+                                               mm_table->entries[count].vddgfx) : 0;
+               table->UvdLevel[count].MinVoltage.Vddci =
+                       phm_get_voltage_id(&data->vddci_voltage_table,
+                                            mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
+               table->UvdLevel[count].MinVoltage.Phases = 1;
+
+               /* retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(
+                                       hwmgr,
+                                       table->UvdLevel[count].VclkFrequency,
+                                       &dividers);
+
+               PP_ASSERT_WITH_CODE((!result),
+                                   "can not find divide id for Vclk clock",
+                                       return result);
+
+               table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
+
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                                                         table->UvdLevel[count].DclkFrequency, &dividers);
+               PP_ASSERT_WITH_CODE((!result),
+                                   "can not find divide id for Dclk clock",
+                                       return result);
+
+               table->UvdLevel[count].DclkDivider =
+                                       (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
+               CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
+       }
+
+       return result;
+
+}
+
+static int tonga_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
+               SMU72_Discrete_DpmTable *table)
+{
+       int result = 0;
+
+       uint8_t count;
+       pp_atomctrl_clock_dividers_vi dividers;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info =
+                             (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                                                    pptable_info->mm_dep_table;
+
+       table->VceLevelCount = (uint8_t) (mm_table->count);
+       table->VceBootLevel = 0;
+
+       for (count = 0; count < table->VceLevelCount; count++) {
+               table->VceLevel[count].Frequency =
+                       mm_table->entries[count].eclk;
+               table->VceLevel[count].MinVoltage.Vddc =
+                       phm_get_voltage_index(pptable_info->vddc_lookup_table,
+                               mm_table->entries[count].vddc);
+               table->VceLevel[count].MinVoltage.VddGfx =
+                       (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
+                       phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
+                               mm_table->entries[count].vddgfx) : 0;
+               table->VceLevel[count].MinVoltage.Vddci =
+                       phm_get_voltage_id(&data->vddci_voltage_table,
+                               mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
+               table->VceLevel[count].MinVoltage.Phases = 1;
+
+               /* retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                                       table->VceLevel[count].Frequency, &dividers);
+               PP_ASSERT_WITH_CODE((!result),
+                               "can not find divide id for VCE engine clock",
+                               return result);
+
+               table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
+       }
+
+       return result;
+}
+
+static int tonga_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
+               SMU72_Discrete_DpmTable *table)
+{
+       int result = 0;
+       uint8_t count;
+       pp_atomctrl_clock_dividers_vi dividers;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info =
+                            (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                                                   pptable_info->mm_dep_table;
+
+       table->AcpLevelCount = (uint8_t) (mm_table->count);
+       table->AcpBootLevel = 0;
+
+       for (count = 0; count < table->AcpLevelCount; count++) {
+               table->AcpLevel[count].Frequency =
+                       pptable_info->mm_dep_table->entries[count].aclk;
+               table->AcpLevel[count].MinVoltage.Vddc =
+                       phm_get_voltage_index(pptable_info->vddc_lookup_table,
+                       mm_table->entries[count].vddc);
+               table->AcpLevel[count].MinVoltage.VddGfx =
+                       (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
+                       phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
+                               mm_table->entries[count].vddgfx) : 0;
+               table->AcpLevel[count].MinVoltage.Vddci =
+                       phm_get_voltage_id(&data->vddci_voltage_table,
+                               mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
+               table->AcpLevel[count].MinVoltage.Phases = 1;
+
+               /* retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                       table->AcpLevel[count].Frequency, &dividers);
+               PP_ASSERT_WITH_CODE((!result),
+                       "can not find divide id for engine clock", return result);
+
+               table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
+       }
+
+       return result;
+}
+
+static int tonga_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
+               SMU72_Discrete_DpmTable *table)
+{
+       int result = 0;
+       uint8_t count;
+       pp_atomctrl_clock_dividers_vi dividers;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct phm_ppt_v1_information *pptable_info =
+                            (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+                                                   pptable_info->mm_dep_table;
+
+       table->SamuBootLevel = 0;
+       table->SamuLevelCount = (uint8_t) (mm_table->count);
+
+       for (count = 0; count < table->SamuLevelCount; count++) {
+               /* not sure whether we need evclk or not */
+               table->SamuLevel[count].Frequency =
+                       pptable_info->mm_dep_table->entries[count].samclock;
+               table->SamuLevel[count].MinVoltage.Vddc =
+                       phm_get_voltage_index(pptable_info->vddc_lookup_table,
+                               mm_table->entries[count].vddc);
+               table->SamuLevel[count].MinVoltage.VddGfx =
+                       (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ?
+                       phm_get_voltage_index(pptable_info->vddgfx_lookup_table,
+                               mm_table->entries[count].vddgfx) : 0;
+               table->SamuLevel[count].MinVoltage.Vddci =
+                       phm_get_voltage_id(&data->vddci_voltage_table,
+                               mm_table->entries[count].vddc - VDDC_VDDCI_DELTA);
+               table->SamuLevel[count].MinVoltage.Phases = 1;
+
+               /* retrieve divider value for VBIOS */
+               result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+                                       table->SamuLevel[count].Frequency, &dividers);
+               PP_ASSERT_WITH_CODE((!result),
+                       "can not find divide id for samu clock", return result);
+
+               table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
+       }
+
+       return result;
+}
+
+static int tonga_populate_memory_timing_parameters(
+               struct pp_hwmgr *hwmgr,
+               uint32_t engine_clock,
+               uint32_t memory_clock,
+               struct SMU72_Discrete_MCArbDramTimingTableEntry *arb_regs
+               )
+{
+       uint32_t dramTiming;
+       uint32_t dramTiming2;
+       uint32_t burstTime;
+       int result;
+
+       result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
+                               engine_clock, memory_clock);
+
+       PP_ASSERT_WITH_CODE(result == 0,
+               "Error calling VBIOS to set DRAM_TIMING.", return result);
+
+       dramTiming  = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+       dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+       burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+
+       arb_regs->McArbDramTiming  = PP_HOST_TO_SMC_UL(dramTiming);
+       arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
+       arb_regs->McArbBurstTime = (uint8_t)burstTime;
+
+       return 0;
+}
+
+/**
+ * Setup parameters for the MC ARB.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ * This function is to be called from the SetPowerState table.
+ */
+static int tonga_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       int result = 0;
+       SMU72_Discrete_MCArbDramTimingTable  arb_regs;
+       uint32_t i, j;
+
+       memset(&arb_regs, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable));
+
+       for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
+               for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
+                       result = tonga_populate_memory_timing_parameters
+                               (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
+                                data->dpm_table.mclk_table.dpm_levels[j].value,
+                                &arb_regs.entries[i][j]);
+
+                       if (result)
+                               break;
+               }
+       }
+
+       if (!result) {
+               result = smu7_copy_bytes_to_smc(
+                               hwmgr->smumgr,
+                               smu_data->smu7_data.arb_table_start,
+                               (uint8_t *)&arb_regs,
+                               sizeof(SMU72_Discrete_MCArbDramTimingTable),
+                               SMC_RAM_END
+                               );
+       }
+
+       return result;
+}
+
+static int tonga_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
+                       SMU72_Discrete_DpmTable *table)
+{
+       int result = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       table->GraphicsBootLevel = 0;
+       table->MemoryBootLevel = 0;
+
+       /* find boot level from dpm table*/
+       result = phm_find_boot_level(&(data->dpm_table.sclk_table),
+       data->vbios_boot_state.sclk_bootup_value,
+       (uint32_t *)&(smu_data->smc_state_table.GraphicsBootLevel));
+
+       if (result != 0) {
+               smu_data->smc_state_table.GraphicsBootLevel = 0;
+               printk(KERN_ERR "[powerplay] VBIOS did not find boot engine "
+                               "clock value in dependency table. "
+                               "Using Graphics DPM level 0 !");
+               result = 0;
+       }
+
+       result = phm_find_boot_level(&(data->dpm_table.mclk_table),
+               data->vbios_boot_state.mclk_bootup_value,
+               (uint32_t *)&(smu_data->smc_state_table.MemoryBootLevel));
+
+       if (result != 0) {
+               smu_data->smc_state_table.MemoryBootLevel = 0;
+               printk(KERN_ERR "[powerplay] VBIOS did not find boot "
+                               "engine clock value in dependency table."
+                               "Using Memory DPM level 0 !");
+               result = 0;
+       }
+
+       table->BootVoltage.Vddc =
+               phm_get_voltage_id(&(data->vddc_voltage_table),
+                       data->vbios_boot_state.vddc_bootup_value);
+       table->BootVoltage.VddGfx =
+               phm_get_voltage_id(&(data->vddgfx_voltage_table),
+                       data->vbios_boot_state.vddgfx_bootup_value);
+       table->BootVoltage.Vddci =
+               phm_get_voltage_id(&(data->vddci_voltage_table),
+                       data->vbios_boot_state.vddci_bootup_value);
+       table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
+
+       CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
+
+       return result;
+}
+
+static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
+{
+       uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
+                       volt_with_cks, value;
+       uint16_t clock_freq_u16;
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
+                       volt_offset = 0;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+                       table_info->vdd_dep_on_sclk;
+       uint32_t hw_revision, dev_id;
+       struct cgs_system_info sys_info = {0};
+
+       stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
+
+       sys_info.size = sizeof(struct cgs_system_info);
+
+       sys_info.info_id = CGS_SYSTEM_INFO_PCIE_REV;
+       cgs_query_system_info(hwmgr->device, &sys_info);
+       hw_revision = (uint32_t)sys_info.value;
+
+       sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV;
+       cgs_query_system_info(hwmgr->device, &sys_info);
+       dev_id = (uint32_t)sys_info.value;
+
+       /* Read SMU_Eefuse to read and calculate RO and determine
+        * if the part is SS or FF. if RO >= 1660MHz, part is FF.
+        */
+       efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixSMU_EFUSE_0 + (146 * 4));
+       efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixSMU_EFUSE_0 + (148 * 4));
+       efuse &= 0xFF000000;
+       efuse = efuse >> 24;
+       efuse2 &= 0xF;
+
+       if (efuse2 == 1)
+               ro = (2300 - 1350) * efuse / 255 + 1350;
+       else
+               ro = (2500 - 1000) * efuse / 255 + 1000;
+
+       if (ro >= 1660)
+               type = 0;
+       else
+               type = 1;
+
+       /* Populate Stretch amount */
+       smu_data->smc_state_table.ClockStretcherAmount = stretch_amount;
+
+
+       /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
+       for (i = 0; i < sclk_table->count; i++) {
+               smu_data->smc_state_table.Sclk_CKS_masterEn0_7 |=
+                               sclk_table->entries[i].cks_enable << i;
+               if (ASICID_IS_TONGA_P(dev_id, hw_revision)) {
+                       volt_without_cks = (uint32_t)((7732 + 60 - ro - 20838 *
+                               (sclk_table->entries[i].clk/100) / 10000) * 1000 /
+                               (8730 - (5301 * (sclk_table->entries[i].clk/100) / 1000)));
+                       volt_with_cks = (uint32_t)((5250 + 51 - ro - 2404 *
+                               (sclk_table->entries[i].clk/100) / 100000) * 1000 /
+                               (6146 - (3193 * (sclk_table->entries[i].clk/100) / 1000)));
+               } else {
+                       volt_without_cks = (uint32_t)((14041 *
+                               (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
+                               (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
+                       volt_with_cks = (uint32_t)((13946 *
+                               (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
+                               (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
+               }
+               if (volt_without_cks >= volt_with_cks)
+                       volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
+                                       sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
+               smu_data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
+       }
+
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+                       STRETCH_ENABLE, 0x0);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+                       masterReset, 0x1);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+                       staticEnable, 0x1);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+                       masterReset, 0x0);
+
+       /* Populate CKS Lookup Table */
+       if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
+               stretch_amount2 = 0;
+       else if (stretch_amount == 3 || stretch_amount == 4)
+               stretch_amount2 = 1;
+       else {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_ClockStretcher);
+               PP_ASSERT_WITH_CODE(false,
+                               "Stretch Amount in PPTable not supported\n",
+                               return -EINVAL);
+       }
+
+       value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixPWR_CKS_CNTL);
+       value &= 0xFFC2FF87;
+       smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
+                       tonga_clock_stretcher_lookup_table[stretch_amount2][0];
+       smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
+                       tonga_clock_stretcher_lookup_table[stretch_amount2][1];
+       clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(smu_data->smc_state_table.
+                       GraphicsLevel[smu_data->smc_state_table.GraphicsDpmLevelCount - 1].
+                       SclkFrequency) / 100);
+       if (tonga_clock_stretcher_lookup_table[stretch_amount2][0] <
+                       clock_freq_u16 &&
+           tonga_clock_stretcher_lookup_table[stretch_amount2][1] >
+                       clock_freq_u16) {
+               /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
+               value |= (tonga_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
+               /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
+               value |= (tonga_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
+               /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
+               value |= (tonga_clock_stretch_amount_conversion
+                               [tonga_clock_stretcher_lookup_table[stretch_amount2][3]]
+                                [stretch_amount]) << 3;
+       }
+       CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
+                       CKS_LOOKUPTableEntry[0].minFreq);
+       CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.CKS_LOOKUPTable.
+                       CKS_LOOKUPTableEntry[0].maxFreq);
+       smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
+                       tonga_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
+       smu_data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
+                       (tonga_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixPWR_CKS_CNTL, value);
+
+       /* Populate DDT Lookup Table */
+       for (i = 0; i < 4; i++) {
+               /* Assign the minimum and maximum VID stored
+                * in the last row of Clock Stretcher Voltage Table.
+                */
+               smu_data->smc_state_table.ClockStretcherDataTable.
+               ClockStretcherDataTableEntry[i].minVID =
+                               (uint8_t) tonga_clock_stretcher_ddt_table[type][i][2];
+               smu_data->smc_state_table.ClockStretcherDataTable.
+               ClockStretcherDataTableEntry[i].maxVID =
+                               (uint8_t) tonga_clock_stretcher_ddt_table[type][i][3];
+               /* Loop through each SCLK and check the frequency
+                * to see if it lies within the frequency for clock stretcher.
+                */
+               for (j = 0; j < smu_data->smc_state_table.GraphicsDpmLevelCount; j++) {
+                       cks_setting = 0;
+                       clock_freq = PP_SMC_TO_HOST_UL(
+                                       smu_data->smc_state_table.GraphicsLevel[j].SclkFrequency);
+                       /* Check the allowed frequency against the sclk level[j].
+                        *  Sclk's endianness has already been converted,
+                        *  and it's in 10Khz unit,
+                        *  as opposed to Data table, which is in Mhz unit.
+                        */
+                       if (clock_freq >= tonga_clock_stretcher_ddt_table[type][i][0] * 100) {
+                               cks_setting |= 0x2;
+                               if (clock_freq < tonga_clock_stretcher_ddt_table[type][i][1] * 100)
+                                       cks_setting |= 0x1;
+                       }
+                       smu_data->smc_state_table.ClockStretcherDataTable.
+                       ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
+               }
+               CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.
+                               ClockStretcherDataTable.
+                               ClockStretcherDataTableEntry[i].setting);
+       }
+
+       value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                                       ixPWR_CKS_CNTL);
+       value &= 0xFFFFFFFE;
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                                       ixPWR_CKS_CNTL, value);
+
+       return 0;
+}
+
+/**
+ * Populates the SMC VRConfig field in DPM table.
+ *
+ * @param    hwmgr      the address of the hardware manager
+ * @param    table     the SMC DPM table structure to be populated
+ * @return   always 0
+ */
+static int tonga_populate_vr_config(struct pp_hwmgr *hwmgr,
+                       SMU72_Discrete_DpmTable *table)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint16_t config;
+
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
+               /*  Splitted mode */
+               config = VR_SVI2_PLANE_1;
+               table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
+
+               if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+                       config = VR_SVI2_PLANE_2;
+                       table->VRConfig |= config;
+               } else {
+                       printk(KERN_ERR "[ powerplay ] VDDC and VDDGFX should "
+                               "be both on SVI2 control in splitted mode !\n");
+               }
+       } else {
+               /* Merged mode  */
+               config = VR_MERGED_WITH_VDDC;
+               table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
+
+               /* Set Vddc Voltage Controller  */
+               if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+                       config = VR_SVI2_PLANE_1;
+                       table->VRConfig |= config;
+               } else {
+                       printk(KERN_ERR "[ powerplay ] VDDC should be on "
+                                       "SVI2 control in merged mode !\n");
+               }
+       }
+
+       /* Set Vddci Voltage Controller  */
+       if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
+               config = VR_SVI2_PLANE_2;  /* only in merged mode */
+               table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
+       } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+               config = VR_SMIO_PATTERN_1;
+               table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
+       }
+
+       /* Set Mvdd Voltage Controller */
+       if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+               config = VR_SMIO_PATTERN_2;
+               table->VRConfig |= (config<<VRCONF_MVDD_SHIFT);
+       }
+
+       return 0;
+}
+
+
+/**
+ * Initialize the ARB DRAM timing table's index field.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+static int tonga_init_arb_table_index(struct pp_smumgr *smumgr)
+{
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(smumgr->backend);
+       uint32_t tmp;
+       int result;
+
+       /*
+       * This is a read-modify-write on the first byte of the ARB table.
+       * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure
+       * is the field 'current'.
+       * This solution is ugly, but we never write the whole table only
+       * individual fields in it.
+       * In reality this field should not be in that structure
+       * but in a soft register.
+       */
+       result = smu7_read_smc_sram_dword(smumgr,
+                               smu_data->smu7_data.arb_table_start, &tmp, SMC_RAM_END);
+
+       if (result != 0)
+               return result;
+
+       tmp &= 0x00FFFFFF;
+       tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
+
+       return smu7_write_smc_sram_dword(smumgr,
+                       smu_data->smu7_data.arb_table_start, tmp, SMC_RAM_END);
+}
+
+
+static int tonga_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
+       SMU72_Discrete_DpmTable  *dpm_table = &(smu_data->smc_state_table);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
+       int  i, j, k;
+       const uint16_t *pdef1, *pdef2;
+
+       dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
+                       (uint16_t)(cac_dtp_table->usTDP * 256));
+       dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
+                       (uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
+
+       PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
+                       "Target Operating Temp is out of Range !",
+                       );
+
+       dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
+       dpm_table->GpuTjHyst = 8;
+
+       dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
+
+       dpm_table->BAPM_TEMP_GRADIENT =
+                               PP_HOST_TO_SMC_UL(defaults->bamp_temp_gradient);
+       pdef1 = defaults->bapmti_r;
+       pdef2 = defaults->bapmti_rc;
+
+       for (i = 0; i < SMU72_DTE_ITERATIONS; i++) {
+               for (j = 0; j < SMU72_DTE_SOURCES; j++) {
+                       for (k = 0; k < SMU72_DTE_SINKS; k++) {
+                               dpm_table->BAPMTI_R[i][j][k] =
+                                               PP_HOST_TO_SMC_US(*pdef1);
+                               dpm_table->BAPMTI_RC[i][j][k] =
+                                               PP_HOST_TO_SMC_US(*pdef2);
+                               pdef1++;
+                               pdef2++;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int tonga_populate_svi_load_line(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
+
+       smu_data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
+       smu_data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddC;
+       smu_data->power_tune_table.SviLoadLineTrimVddC = 3;
+       smu_data->power_tune_table.SviLoadLineOffsetVddC = 0;
+
+       return 0;
+}
+
+static int tonga_populate_tdc_limit(struct pp_hwmgr *hwmgr)
+{
+       uint16_t tdc_limit;
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       /* TDC number of fraction bits are changed from 8 to 7
+        * for Fiji as requested by SMC team
+        */
+       tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 256);
+       smu_data->power_tune_table.TDC_VDDC_PkgLimit =
+                       CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
+       smu_data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
+                       defaults->tdc_vddc_throttle_release_limit_perc;
+       smu_data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
+
+       return 0;
+}
+
+static int tonga_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
+{
+       struct tonga_smumgr *smu_data =
+                       (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       const struct tonga_pt_defaults *defaults = smu_data->power_tune_defaults;
+       uint32_t temp;
+
+       if (smu7_read_smc_sram_dword(hwmgr->smumgr,
+                       fuse_table_offset +
+                       offsetof(SMU72_Discrete_PmFuses, TdcWaterfallCtl),
+                       (uint32_t *)&temp, SMC_RAM_END))
+               PP_ASSERT_WITH_CODE(false,
+                               "Attempt to read PmFuses.DW6 "
+                               "(SviLoadLineEn) from SMC Failed !",
+                               return -EINVAL);
+       else
+               smu_data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
+
+       return 0;
+}
+
+static int tonga_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
+{
+       int i;
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+
+       /* Currently not used. Set all to zero. */
+       for (i = 0; i < 16; i++)
+               smu_data->power_tune_table.LPMLTemperatureScaler[i] = 0;
+
+       return 0;
+}
+
+static int tonga_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+
+       if ((hwmgr->thermal_controller.advanceFanControlParameters.
+                       usFanOutputSensitivity & (1 << 15)) ||
+               (hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity == 0))
+               hwmgr->thermal_controller.advanceFanControlParameters.
+               usFanOutputSensitivity = hwmgr->thermal_controller.
+                       advanceFanControlParameters.usDefaultFanOutputSensitivity;
+
+       smu_data->power_tune_table.FuzzyFan_PwmSetDelta =
+                       PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
+                                       advanceFanControlParameters.usFanOutputSensitivity);
+       return 0;
+}
+
+static int tonga_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
+{
+       int i;
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+
+       /* Currently not used. Set all to zero. */
+       for (i = 0; i < 16; i++)
+               smu_data->power_tune_table.GnbLPML[i] = 0;
+
+       return 0;
+}
+
+static int tonga_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
+{
+       return 0;
+}
+
+static int tonga_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+       uint16_t hi_sidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd;
+       uint16_t lo_sidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd;
+       struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
+
+       hi_sidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
+       lo_sidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
+
+       smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd =
+                       CONVERT_FROM_HOST_TO_SMC_US(hi_sidd);
+       smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd =
+                       CONVERT_FROM_HOST_TO_SMC_US(lo_sidd);
+
+       return 0;
+}
+
+static int tonga_populate_pm_fuses(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t pm_fuse_table_offset;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_PowerContainment)) {
+               if (smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU72_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU72_Firmware_Header, PmFuseTable),
+                               &pm_fuse_table_offset, SMC_RAM_END))
+                       PP_ASSERT_WITH_CODE(false,
+                               "Attempt to get pm_fuse_table_offset Failed !",
+                               return -EINVAL);
+
+               /* DW6 */
+               if (tonga_populate_svi_load_line(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                               "Attempt to populate SviLoadLine Failed !",
+                               return -EINVAL);
+               /* DW7 */
+               if (tonga_populate_tdc_limit(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to populate TDCLimit Failed !",
+                                       return -EINVAL);
+               /* DW8 */
+               if (tonga_populate_dw8(hwmgr, pm_fuse_table_offset))
+                       PP_ASSERT_WITH_CODE(false,
+                               "Attempt to populate TdcWaterfallCtl Failed !",
+                               return -EINVAL);
+
+               /* DW9-DW12 */
+               if (tonga_populate_temperature_scaler(hwmgr) != 0)
+                       PP_ASSERT_WITH_CODE(false,
+                               "Attempt to populate LPMLTemperatureScaler Failed !",
+                               return -EINVAL);
+
+               /* DW13-DW14 */
+               if (tonga_populate_fuzzy_fan(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                               "Attempt to populate Fuzzy Fan "
+                               "Control parameters Failed !",
+                               return -EINVAL);
+
+               /* DW15-DW18 */
+               if (tonga_populate_gnb_lpml(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                               "Attempt to populate GnbLPML Failed !",
+                               return -EINVAL);
+
+               /* DW19 */
+               if (tonga_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
+                       PP_ASSERT_WITH_CODE(false,
+                               "Attempt to populate GnbLPML "
+                               "Min and Max Vid Failed !",
+                               return -EINVAL);
+
+               /* DW20 */
+               if (tonga_populate_bapm_vddc_base_leakage_sidd(hwmgr))
+                       PP_ASSERT_WITH_CODE(
+                               false,
+                               "Attempt to populate BapmVddCBaseLeakage "
+                               "Hi and Lo Sidd Failed !",
+                               return -EINVAL);
+
+               if (smu7_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
+                               (uint8_t *)&smu_data->power_tune_table,
+                               sizeof(struct SMU72_Discrete_PmFuses), SMC_RAM_END))
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to download PmFuseTable Failed !",
+                                       return -EINVAL);
+       }
+       return 0;
+}
+
+static int tonga_populate_mc_reg_address(struct pp_smumgr *smumgr,
+                                SMU72_Discrete_MCRegisters *mc_reg_table)
+{
+       const struct tonga_smumgr *smu_data = (struct tonga_smumgr *)smumgr->backend;
+
+       uint32_t i, j;
+
+       for (i = 0, j = 0; j < smu_data->mc_reg_table.last; j++) {
+               if (smu_data->mc_reg_table.validflag & 1<<j) {
+                       PP_ASSERT_WITH_CODE(
+                               i < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE,
+                               "Index of mc_reg_table->address[] array "
+                               "out of boundary",
+                               return -EINVAL);
+                       mc_reg_table->address[i].s0 =
+                               PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s0);
+                       mc_reg_table->address[i].s1 =
+                               PP_HOST_TO_SMC_US(smu_data->mc_reg_table.mc_reg_address[j].s1);
+                       i++;
+               }
+       }
+
+       mc_reg_table->last = (uint8_t)i;
+
+       return 0;
+}
+
+/*convert register values from driver to SMC format */
+static void tonga_convert_mc_registers(
+       const struct tonga_mc_reg_entry *entry,
+       SMU72_Discrete_MCRegisterSet *data,
+       uint32_t num_entries, uint32_t valid_flag)
+{
+       uint32_t i, j;
+
+       for (i = 0, j = 0; j < num_entries; j++) {
+               if (valid_flag & 1<<j) {
+                       data->value[i] = PP_HOST_TO_SMC_UL(entry->mc_data[j]);
+                       i++;
+               }
+       }
+}
+
+static int tonga_convert_mc_reg_table_entry_to_smc(
+               struct pp_smumgr *smumgr,
+               const uint32_t memory_clock,
+               SMU72_Discrete_MCRegisterSet *mc_reg_table_data
+               )
+{
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(smumgr->backend);
+       uint32_t i = 0;
+
+       for (i = 0; i < smu_data->mc_reg_table.num_entries; i++) {
+               if (memory_clock <=
+                       smu_data->mc_reg_table.mc_reg_table_entry[i].mclk_max) {
+                       break;
+               }
+       }
+
+       if ((i == smu_data->mc_reg_table.num_entries) && (i > 0))
+               --i;
+
+       tonga_convert_mc_registers(&smu_data->mc_reg_table.mc_reg_table_entry[i],
+                               mc_reg_table_data, smu_data->mc_reg_table.last,
+                               smu_data->mc_reg_table.validflag);
+
+       return 0;
+}
+
+static int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
+               SMU72_Discrete_MCRegisters *mc_regs)
+{
+       int result = 0;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       int res;
+       uint32_t i;
+
+       for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
+               res = tonga_convert_mc_reg_table_entry_to_smc(
+                               hwmgr->smumgr,
+                               data->dpm_table.mclk_table.dpm_levels[i].value,
+                               &mc_regs->data[i]
+                               );
+
+               if (0 != res)
+                       result = res;
+       }
+
+       return result;
+}
+
+static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(smumgr->backend);
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       uint32_t address;
+       int32_t result;
+
+       if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
+               return 0;
+
+
+       memset(&smu_data->mc_regs, 0, sizeof(SMU72_Discrete_MCRegisters));
+
+       result = tonga_convert_mc_reg_table_to_smc(hwmgr, &(smu_data->mc_regs));
+
+       if (result != 0)
+               return result;
+
+
+       address = smu_data->smu7_data.mc_reg_table_start +
+                       (uint32_t)offsetof(SMU72_Discrete_MCRegisters, data[0]);
+
+       return  smu7_copy_bytes_to_smc(
+                       hwmgr->smumgr, address,
+                       (uint8_t *)&smu_data->mc_regs.data[0],
+                       sizeof(SMU72_Discrete_MCRegisterSet) *
+                       data->dpm_table.mclk_table.count,
+                       SMC_RAM_END);
+}
+
+static int tonga_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       struct pp_smumgr *smumgr = hwmgr->smumgr;
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(smumgr->backend);
+
+       memset(&smu_data->mc_regs, 0x00, sizeof(SMU72_Discrete_MCRegisters));
+       result = tonga_populate_mc_reg_address(smumgr, &(smu_data->mc_regs));
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize MCRegTable for the MC register addresses !",
+               return result;);
+
+       result = tonga_convert_mc_reg_table_to_smc(hwmgr, &smu_data->mc_regs);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize MCRegTable for driver state !",
+               return result;);
+
+       return smu7_copy_bytes_to_smc(smumgr, smu_data->smu7_data.mc_reg_table_start,
+                       (uint8_t *)&smu_data->mc_regs, sizeof(SMU72_Discrete_MCRegisters), SMC_RAM_END);
+}
+
+static void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       struct  phm_ppt_v1_information *table_info =
+                       (struct  phm_ppt_v1_information *)(hwmgr->pptable);
+
+       if (table_info &&
+                       table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
+                       table_info->cac_dtp_table->usPowerTuneDataSetID)
+               smu_data->power_tune_defaults =
+                               &tonga_power_tune_data_set_array
+                               [table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
+       else
+               smu_data->power_tune_defaults = &tonga_power_tune_data_set_array[0];
+}
+
+/**
+ * Initializes the SMC table and uploads it
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @param    pInput  the pointer to input data (PowerState)
+ * @return   always 0
+ */
+int tonga_init_smc_table(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct tonga_smumgr *smu_data =
+                       (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       SMU72_Discrete_DpmTable *table = &(smu_data->smc_state_table);
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       uint8_t i;
+       pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
+
+
+       memset(&(smu_data->smc_state_table), 0x00, sizeof(smu_data->smc_state_table));
+
+       tonga_initialize_power_tune_defaults(hwmgr);
+
+       if (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control)
+               tonga_populate_smc_voltage_tables(hwmgr, table);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_AutomaticDCTransition))
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StepVddc))
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+       if (data->is_memory_gddr5)
+               table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+       i = PHM_READ_FIELD(hwmgr->device, CC_MC_MAX_CHANNEL, NOOFCHAN);
+
+       if (i == 1 || i == 0)
+               table->SystemFlags |= 0x40;
+
+       if (data->ulv_supported && table_info->us_ulv_voltage_offset) {
+               result = tonga_populate_ulv_state(hwmgr, table);
+               PP_ASSERT_WITH_CODE(!result,
+                       "Failed to initialize ULV state !",
+                       return result;);
+
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_ULV_PARAMETER, 0x40035);
+       }
+
+       result = tonga_populate_smc_link_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize Link Level !", return result);
+
+       result = tonga_populate_all_graphic_levels(hwmgr);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize Graphics Level !", return result);
+
+       result = tonga_populate_all_memory_levels(hwmgr);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize Memory Level !", return result);
+
+       result = tonga_populate_smc_acpi_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize ACPI Level !", return result);
+
+       result = tonga_populate_smc_vce_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize VCE Level !", return result);
+
+       result = tonga_populate_smc_acp_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize ACP Level !", return result);
+
+       result = tonga_populate_smc_samu_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize SAMU Level !", return result);
+
+       /* Since only the initial state is completely set up at this
+       * point (the other states are just copies of the boot state) we only
+       * need to populate the  ARB settings for the initial state.
+       */
+       result = tonga_program_memory_timing_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to Write ARB settings for the initial state.",
+               return result;);
+
+       result = tonga_populate_smc_uvd_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize UVD Level !", return result);
+
+       result = tonga_populate_smc_boot_level(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to initialize Boot Level !", return result);
+
+       tonga_populate_bapm_parameters_in_dpm_table(hwmgr);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to populate BAPM Parameters !", return result);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ClockStretcher)) {
+               result = tonga_populate_clock_stretcher_data_table(hwmgr);
+               PP_ASSERT_WITH_CODE(!result,
+                       "Failed to populate Clock Stretcher Data Table !",
+                       return result;);
+       }
+       table->GraphicsVoltageChangeEnable  = 1;
+       table->GraphicsThermThrottleEnable  = 1;
+       table->GraphicsInterval = 1;
+       table->VoltageInterval  = 1;
+       table->ThermalInterval  = 1;
+       table->TemperatureLimitHigh =
+               table_info->cac_dtp_table->usTargetOperatingTemp *
+               SMU7_Q88_FORMAT_CONVERSION_UNIT;
+       table->TemperatureLimitLow =
+               (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
+               SMU7_Q88_FORMAT_CONVERSION_UNIT;
+       table->MemoryVoltageChangeEnable  = 1;
+       table->MemoryInterval  = 1;
+       table->VoltageResponseTime  = 0;
+       table->PhaseResponseTime  = 0;
+       table->MemoryThermThrottleEnable  = 1;
+
+       /*
+       * Cail reads current link status and reports it as cap (we cannot
+       * change this due to some previous issues we had)
+       * SMC drops the link status to lowest level after enabling
+       * DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
+       * but this time Cail reads current link status which was set to low by
+       * SMC and reports it as cap to powerplay
+       * To avoid it, we set PCIeBootLinkLevel to highest dpm level
+       */
+       PP_ASSERT_WITH_CODE((1 <= data->dpm_table.pcie_speed_table.count),
+                       "There must be 1 or more PCIE levels defined in PPTable.",
+                       return -EINVAL);
+
+       table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count);
+
+       table->PCIeGenInterval  = 1;
+
+       result = tonga_populate_vr_config(hwmgr, table);
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to populate VRConfig setting !", return result);
+
+       table->ThermGpio  = 17;
+       table->SclkStepSize = 0x4000;
+
+       if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID,
+                                               &gpio_pin_assignment)) {
+               table->VRHotGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_RegulatorHot);
+       } else {
+               table->VRHotGpio = SMU7_UNUSED_GPIO_PIN;
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_RegulatorHot);
+       }
+
+       if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
+                                               &gpio_pin_assignment)) {
+               table->AcDcGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_AutomaticDCTransition);
+       } else {
+               table->AcDcGpio = SMU7_UNUSED_GPIO_PIN;
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_AutomaticDCTransition);
+       }
+
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+               PHM_PlatformCaps_Falcon_QuickTransition);
+
+       if (0) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_AutomaticDCTransition);
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_Falcon_QuickTransition);
+       }
+
+       if (atomctrl_get_pp_assign_pin(hwmgr,
+                       THERMAL_INT_OUTPUT_GPIO_PINID, &gpio_pin_assignment)) {
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ThermalOutGPIO);
+
+               table->ThermOutGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
+
+               table->ThermOutPolarity =
+                       (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
+                       (1 << gpio_pin_assignment.uc_gpio_pin_bit_shift))) ? 1 : 0;
+
+               table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
+
+               /* if required, combine VRHot/PCC with thermal out GPIO*/
+               if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_RegulatorHot) &&
+                       phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_CombinePCCWithThermalSignal)){
+                       table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
+               }
+       } else {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ThermalOutGPIO);
+
+               table->ThermOutGpio = 17;
+               table->ThermOutPolarity = 1;
+               table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
+       }
+
+       for (i = 0; i < SMU72_MAX_ENTRIES_SMIO; i++)
+               table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
+
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
+       CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
+       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
+       CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
+       CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
+       CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
+
+       /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
+       result = smu7_copy_bytes_to_smc(
+                       hwmgr->smumgr,
+                       smu_data->smu7_data.dpm_table_start + offsetof(SMU72_Discrete_DpmTable, SystemFlags),
+                       (uint8_t *)&(table->SystemFlags),
+                       sizeof(SMU72_Discrete_DpmTable) - 3 * sizeof(SMU72_PIDController),
+                       SMC_RAM_END);
+
+       PP_ASSERT_WITH_CODE(!result,
+               "Failed to upload dpm data to SMC memory !", return result;);
+
+       result = tonga_init_arb_table_index(hwmgr->smumgr);
+       PP_ASSERT_WITH_CODE(!result,
+                       "Failed to upload arb data to SMC memory !", return result);
+
+       tonga_populate_pm_fuses(hwmgr);
+       PP_ASSERT_WITH_CODE((!result),
+               "Failed to populate initialize pm fuses !", return result);
+
+       result = tonga_populate_initial_mc_reg_table(hwmgr);
+       PP_ASSERT_WITH_CODE((!result),
+               "Failed to populate initialize MC Reg table !", return result);
+
+       return 0;
+}
+
+/**
+* Set up the fan table to control the fan using the SMC.
+* @param    hwmgr  the address of the powerplay hardware manager.
+* @param    pInput the pointer to input data
+* @param    pOutput the pointer to output data
+* @param    pStorage the pointer to temporary storage
+* @param    Result the last failure code
+* @return   result from set temperature range routine
+*/
+int tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data =
+                       (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       SMU72_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+       uint32_t duty100;
+       uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+       uint16_t fdo_min, slope1, slope2;
+       uint32_t reference_clock;
+       int res;
+       uint64_t tmp64;
+
+       if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_MicrocodeFanControl))
+               return 0;
+
+       if (0 == smu_data->smu7_data.fan_table_start) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_MicrocodeFanControl);
+               return 0;
+       }
+
+       duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
+                                               CGS_IND_REG__SMC,
+                                               CG_FDO_CTRL1, FMAX_DUTY100);
+
+       if (0 == duty100) {
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                               PHM_PlatformCaps_MicrocodeFanControl);
+               return 0;
+       }
+
+       tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
+       do_div(tmp64, 10000);
+       fdo_min = (uint16_t)tmp64;
+
+       t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
+                  hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
+       t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
+                 hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
+
+       pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
+                   hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
+       pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
+                   hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
+
+       slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+       slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+       fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
+       fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
+       fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
+
+       fan_table.Slope1 = cpu_to_be16(slope1);
+       fan_table.Slope2 = cpu_to_be16(slope2);
+
+       fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+       fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
+
+       fan_table.HystUp = cpu_to_be16(1);
+
+       fan_table.HystSlope = cpu_to_be16(1);
+
+       fan_table.TempRespLim = cpu_to_be16(5);
+
+       reference_clock = smu7_get_xclk(hwmgr);
+
+       fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
+
+       fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
+
+       fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
+
+       fan_table.FanControl_GL_Flag = 1;
+
+       res = smu7_copy_bytes_to_smc(hwmgr->smumgr,
+                                       smu_data->smu7_data.fan_table_start,
+                                       (uint8_t *)&fan_table,
+                                       (uint32_t)sizeof(fan_table),
+                                       SMC_RAM_END);
+
+       return 0;
+}
+
+
+static int tonga_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       if (data->need_update_smu7_dpm_table &
+               (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+               return tonga_program_memory_timing_parameters(hwmgr);
+
+       return 0;
+}
+
+int tonga_update_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct tonga_smumgr *smu_data =
+                       (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+
+       int result = 0;
+       uint32_t low_sclk_interrupt_threshold = 0;
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkThrottleLowNotification)
+               && (hwmgr->gfx_arbiter.sclk_threshold !=
+                               data->low_sclk_interrupt_threshold)) {
+               data->low_sclk_interrupt_threshold =
+                               hwmgr->gfx_arbiter.sclk_threshold;
+               low_sclk_interrupt_threshold =
+                               data->low_sclk_interrupt_threshold;
+
+               CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
+
+               result = smu7_copy_bytes_to_smc(
+                               hwmgr->smumgr,
+                               smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU72_Discrete_DpmTable,
+                                       LowSclkInterruptThreshold),
+                               (uint8_t *)&low_sclk_interrupt_threshold,
+                               sizeof(uint32_t),
+                               SMC_RAM_END);
+       }
+
+       result = tonga_update_and_upload_mc_reg_table(hwmgr);
+
+       PP_ASSERT_WITH_CODE((!result),
+                               "Failed to upload MC reg table !",
+                               return result);
+
+       result = tonga_program_mem_timing_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE((result == 0),
+                       "Failed to program memory timing parameters !",
+                       );
+
+       return result;
+}
+
+uint32_t tonga_get_offsetof(uint32_t type, uint32_t member)
+{
+       switch (type) {
+       case SMU_SoftRegisters:
+               switch (member) {
+               case HandshakeDisables:
+                       return offsetof(SMU72_SoftRegisters, HandshakeDisables);
+               case VoltageChangeTimeout:
+                       return offsetof(SMU72_SoftRegisters, VoltageChangeTimeout);
+               case AverageGraphicsActivity:
+                       return offsetof(SMU72_SoftRegisters, AverageGraphicsActivity);
+               case PreVBlankGap:
+                       return offsetof(SMU72_SoftRegisters, PreVBlankGap);
+               case VBlankTimeout:
+                       return offsetof(SMU72_SoftRegisters, VBlankTimeout);
+               case UcodeLoadStatus:
+                       return offsetof(SMU72_SoftRegisters, UcodeLoadStatus);
+               }
+       case SMU_Discrete_DpmTable:
+               switch (member) {
+               case UvdBootLevel:
+                       return offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
+               case VceBootLevel:
+                       return offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
+               case SamuBootLevel:
+                       return offsetof(SMU72_Discrete_DpmTable, SamuBootLevel);
+               case LowSclkInterruptThreshold:
+                       return offsetof(SMU72_Discrete_DpmTable, LowSclkInterruptThreshold);
+               }
+       }
+       printk("cant't get the offset of type %x member %x\n", type, member);
+       return 0;
+}
+
+uint32_t tonga_get_mac_definition(uint32_t value)
+{
+       switch (value) {
+       case SMU_MAX_LEVELS_GRAPHICS:
+               return SMU72_MAX_LEVELS_GRAPHICS;
+       case SMU_MAX_LEVELS_MEMORY:
+               return SMU72_MAX_LEVELS_MEMORY;
+       case SMU_MAX_LEVELS_LINK:
+               return SMU72_MAX_LEVELS_LINK;
+       case SMU_MAX_ENTRIES_SMIO:
+               return SMU72_MAX_ENTRIES_SMIO;
+       case SMU_MAX_LEVELS_VDDC:
+               return SMU72_MAX_LEVELS_VDDC;
+       case SMU_MAX_LEVELS_VDDGFX:
+               return SMU72_MAX_LEVELS_VDDGFX;
+       case SMU_MAX_LEVELS_VDDCI:
+               return SMU72_MAX_LEVELS_VDDCI;
+       case SMU_MAX_LEVELS_MVDD:
+               return SMU72_MAX_LEVELS_MVDD;
+       }
+       printk("cant't get the mac value %x\n", value);
+
+       return 0;
+}
+
+
+static int tonga_update_uvd_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t mm_boot_level_offset, mm_boot_level_value;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+       smu_data->smc_state_table.UvdBootLevel = 0;
+       if (table_info->mm_dep_table->count > 0)
+               smu_data->smc_state_table.UvdBootLevel =
+                               (uint8_t) (table_info->mm_dep_table->count - 1);
+       mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
+       mm_boot_level_offset /= 4;
+       mm_boot_level_offset *= 4;
+       mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset);
+       mm_boot_level_value &= 0x00FFFFFF;
+       mm_boot_level_value |= smu_data->smc_state_table.UvdBootLevel << 24;
+       cgs_write_ind_register(hwmgr->device,
+                               CGS_IND_REG__SMC,
+                               mm_boot_level_offset, mm_boot_level_value);
+
+       if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_UVDDPM) ||
+               phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StablePState))
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_UVDDPM_SetEnabledMask,
+                               (uint32_t)(1 << smu_data->smc_state_table.UvdBootLevel));
+       return 0;
+}
+
+static int tonga_update_vce_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data =
+                               (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t mm_boot_level_offset, mm_boot_level_value;
+       struct phm_ppt_v1_information *table_info =
+                       (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+
+       smu_data->smc_state_table.VceBootLevel =
+               (uint8_t) (table_info->mm_dep_table->count - 1);
+
+       mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
+                                       offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
+       mm_boot_level_offset /= 4;
+       mm_boot_level_offset *= 4;
+       mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset);
+       mm_boot_level_value &= 0xFF00FFFF;
+       mm_boot_level_value |= smu_data->smc_state_table.VceBootLevel << 16;
+       cgs_write_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                                       PHM_PlatformCaps_StablePState))
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_VCEDPM_SetEnabledMask,
+                               (uint32_t)1 << smu_data->smc_state_table.VceBootLevel);
+       return 0;
+}
+
+static int tonga_update_samu_smc_table(struct pp_hwmgr *hwmgr)
+{
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       uint32_t mm_boot_level_offset, mm_boot_level_value;
+
+       smu_data->smc_state_table.SamuBootLevel = 0;
+       mm_boot_level_offset = smu_data->smu7_data.dpm_table_start +
+                               offsetof(SMU72_Discrete_DpmTable, SamuBootLevel);
+
+       mm_boot_level_offset /= 4;
+       mm_boot_level_offset *= 4;
+       mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset);
+       mm_boot_level_value &= 0xFFFFFF00;
+       mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0;
+       cgs_write_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_StablePState))
+               smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+                               PPSMC_MSG_SAMUDPM_SetEnabledMask,
+                               (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel));
+       return 0;
+}
+
+int tonga_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type)
+{
+       switch (type) {
+       case SMU_UVD_TABLE:
+               tonga_update_uvd_smc_table(hwmgr);
+               break;
+       case SMU_VCE_TABLE:
+               tonga_update_vce_smc_table(hwmgr);
+               break;
+       case SMU_SAMU_TABLE:
+               tonga_update_samu_smc_table(hwmgr);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+
+/**
+ * Get the location of various tables inside the FW image.
+ *
+ * @param    hwmgr  the address of the powerplay hardware manager.
+ * @return   always 0
+ */
+int tonga_process_firmware_header(struct pp_hwmgr *hwmgr)
+{
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+
+       uint32_t tmp;
+       int result;
+       bool error = false;
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU72_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU72_Firmware_Header, DpmTable),
+                               &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.dpm_table_start = tmp;
+
+       error |= (result != 0);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU72_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU72_Firmware_Header, SoftRegisters),
+                               &tmp, SMC_RAM_END);
+
+       if (!result) {
+               data->soft_regs_start = tmp;
+               smu_data->smu7_data.soft_regs_start = tmp;
+       }
+
+       error |= (result != 0);
+
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU72_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU72_Firmware_Header, mcRegisterTable),
+                               &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.mc_reg_table_start = tmp;
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU72_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU72_Firmware_Header, FanTable),
+                               &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.fan_table_start = tmp;
+
+       error |= (result != 0);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU72_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU72_Firmware_Header, mcArbDramTimingTable),
+                               &tmp, SMC_RAM_END);
+
+       if (!result)
+               smu_data->smu7_data.arb_table_start = tmp;
+
+       error |= (result != 0);
+
+       result = smu7_read_smc_sram_dword(hwmgr->smumgr,
+                               SMU72_FIRMWARE_HEADER_LOCATION +
+                               offsetof(SMU72_Firmware_Header, Version),
+                               &tmp, SMC_RAM_END);
+
+       if (!result)
+               hwmgr->microcode_version_info.SMC = tmp;
+
+       error |= (result != 0);
+
+       return error ? 1 : 0;
+}
+
+/*---------------------------MC----------------------------*/
+
+static uint8_t tonga_get_memory_modile_index(struct pp_hwmgr *hwmgr)
+{
+       return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
+}
+
+static bool tonga_check_s0_mc_reg_index(uint16_t in_reg, uint16_t *out_reg)
+{
+       bool result = true;
+
+       switch (in_reg) {
+       case  mmMC_SEQ_RAS_TIMING:
+               *out_reg = mmMC_SEQ_RAS_TIMING_LP;
+               break;
+
+       case  mmMC_SEQ_DLL_STBY:
+               *out_reg = mmMC_SEQ_DLL_STBY_LP;
+               break;
+
+       case  mmMC_SEQ_G5PDX_CMD0:
+               *out_reg = mmMC_SEQ_G5PDX_CMD0_LP;
+               break;
+
+       case  mmMC_SEQ_G5PDX_CMD1:
+               *out_reg = mmMC_SEQ_G5PDX_CMD1_LP;
+               break;
+
+       case  mmMC_SEQ_G5PDX_CTRL:
+               *out_reg = mmMC_SEQ_G5PDX_CTRL_LP;
+               break;
+
+       case mmMC_SEQ_CAS_TIMING:
+               *out_reg = mmMC_SEQ_CAS_TIMING_LP;
+               break;
+
+       case mmMC_SEQ_MISC_TIMING:
+               *out_reg = mmMC_SEQ_MISC_TIMING_LP;
+               break;
+
+       case mmMC_SEQ_MISC_TIMING2:
+               *out_reg = mmMC_SEQ_MISC_TIMING2_LP;
+               break;
+
+       case mmMC_SEQ_PMG_DVS_CMD:
+               *out_reg = mmMC_SEQ_PMG_DVS_CMD_LP;
+               break;
+
+       case mmMC_SEQ_PMG_DVS_CTL:
+               *out_reg = mmMC_SEQ_PMG_DVS_CTL_LP;
+               break;
+
+       case mmMC_SEQ_RD_CTL_D0:
+               *out_reg = mmMC_SEQ_RD_CTL_D0_LP;
+               break;
+
+       case mmMC_SEQ_RD_CTL_D1:
+               *out_reg = mmMC_SEQ_RD_CTL_D1_LP;
+               break;
+
+       case mmMC_SEQ_WR_CTL_D0:
+               *out_reg = mmMC_SEQ_WR_CTL_D0_LP;
+               break;
+
+       case mmMC_SEQ_WR_CTL_D1:
+               *out_reg = mmMC_SEQ_WR_CTL_D1_LP;
+               break;
+
+       case mmMC_PMG_CMD_EMRS:
+               *out_reg = mmMC_SEQ_PMG_CMD_EMRS_LP;
+               break;
+
+       case mmMC_PMG_CMD_MRS:
+               *out_reg = mmMC_SEQ_PMG_CMD_MRS_LP;
+               break;
+
+       case mmMC_PMG_CMD_MRS1:
+               *out_reg = mmMC_SEQ_PMG_CMD_MRS1_LP;
+               break;
+
+       case mmMC_SEQ_PMG_TIMING:
+               *out_reg = mmMC_SEQ_PMG_TIMING_LP;
+               break;
+
+       case mmMC_PMG_CMD_MRS2:
+               *out_reg = mmMC_SEQ_PMG_CMD_MRS2_LP;
+               break;
+
+       case mmMC_SEQ_WR_CTL_2:
+               *out_reg = mmMC_SEQ_WR_CTL_2_LP;
+               break;
+
+       default:
+               result = false;
+               break;
+       }
+
+       return result;
+}
+
+static int tonga_set_s0_mc_reg_index(struct tonga_mc_reg_table *table)
+{
+       uint32_t i;
+       uint16_t address;
+
+       for (i = 0; i < table->last; i++) {
+               table->mc_reg_address[i].s0 =
+                       tonga_check_s0_mc_reg_index(table->mc_reg_address[i].s1,
+                                                       &address) ?
+                                                       address :
+                                                table->mc_reg_address[i].s1;
+       }
+       return 0;
+}
+
+static int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table,
+                                       struct tonga_mc_reg_table *ni_table)
+{
+       uint8_t i, j;
+
+       PP_ASSERT_WITH_CODE((table->last <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+               "Invalid VramInfo table.", return -EINVAL);
+       PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
+               "Invalid VramInfo table.", return -EINVAL);
+
+       for (i = 0; i < table->last; i++)
+               ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+
+       ni_table->last = table->last;
+
+       for (i = 0; i < table->num_entries; i++) {
+               ni_table->mc_reg_table_entry[i].mclk_max =
+                       table->mc_reg_table_entry[i].mclk_max;
+               for (j = 0; j < table->last; j++) {
+                       ni_table->mc_reg_table_entry[i].mc_data[j] =
+                               table->mc_reg_table_entry[i].mc_data[j];
+               }
+       }
+
+       ni_table->num_entries = table->num_entries;
+
+       return 0;
+}
+
+/**
+ * VBIOS omits some information to reduce size, we need to recover them here.
+ * 1.   when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to
+ *      mmMC_PMG_CMD_EMRS /_LP[15:0]. Bit[15:0] MRS, need to be update
+ *      mmMC_PMG_CMD_MRS/_LP[15:0]
+ * 2.   when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to
+ *      mmMC_PMG_CMD_MRS1/_LP[15:0].
+ * 3.   need to set these data for each clock range
+ * @param    hwmgr the address of the powerplay hardware manager.
+ * @param    table the address of MCRegTable
+ * @return   always 0
+ */
+static int tonga_set_mc_special_registers(struct pp_hwmgr *hwmgr,
+                                       struct tonga_mc_reg_table *table)
+{
+       uint8_t i, j, k;
+       uint32_t temp_reg;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       for (i = 0, j = table->last; i < table->last; i++) {
+               PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                       "Invalid VramInfo table.", return -EINVAL);
+
+               switch (table->mc_reg_address[i].s1) {
+
+               case mmMC_SEQ_MISC1:
+                       temp_reg = cgs_read_register(hwmgr->device,
+                                                       mmMC_PMG_CMD_EMRS);
+                       table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
+                       table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
+                       for (k = 0; k < table->num_entries; k++) {
+                               table->mc_reg_table_entry[k].mc_data[j] =
+                                       ((temp_reg & 0xffff0000)) |
+                                       ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
+                       }
+                       j++;
+                       PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                               "Invalid VramInfo table.", return -EINVAL);
+
+                       temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
+                       table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
+                       table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
+                       for (k = 0; k < table->num_entries; k++) {
+                               table->mc_reg_table_entry[k].mc_data[j] =
+                                       (temp_reg & 0xffff0000) |
+                                       (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+
+                               if (!data->is_memory_gddr5)
+                                       table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+                       }
+                       j++;
+                       PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                               "Invalid VramInfo table.", return -EINVAL);
+
+                       if (!data->is_memory_gddr5) {
+                               table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
+                               table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
+                               for (k = 0; k < table->num_entries; k++)
+                                       table->mc_reg_table_entry[k].mc_data[j] =
+                                               (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
+                               j++;
+                               PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                                       "Invalid VramInfo table.", return -EINVAL);
+                       }
+
+                       break;
+
+               case mmMC_SEQ_RESERVE_M:
+                       temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
+                       table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
+                       table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
+                       for (k = 0; k < table->num_entries; k++) {
+                               table->mc_reg_table_entry[k].mc_data[j] =
+                                       (temp_reg & 0xffff0000) |
+                                       (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+                       }
+                       j++;
+                       PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+                               "Invalid VramInfo table.", return -EINVAL);
+                       break;
+
+               default:
+                       break;
+               }
+
+       }
+
+       table->last = j;
+
+       return 0;
+}
+
+static int tonga_set_valid_flag(struct tonga_mc_reg_table *table)
+{
+       uint8_t i, j;
+
+       for (i = 0; i < table->last; i++) {
+               for (j = 1; j < table->num_entries; j++) {
+                       if (table->mc_reg_table_entry[j-1].mc_data[i] !=
+                               table->mc_reg_table_entry[j].mc_data[i]) {
+                               table->validflag |= (1<<i);
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+       int result;
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+       pp_atomctrl_mc_reg_table *table;
+       struct tonga_mc_reg_table *ni_table = &smu_data->mc_reg_table;
+       uint8_t module_index = tonga_get_memory_modile_index(hwmgr);
+
+       table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
+
+       if (table == NULL)
+               return -ENOMEM;
+
+       /* Program additional LP registers that are no longer programmed by VBIOS */
+       cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP,
+                       cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP,
+                       cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP,
+                       cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP,
+                       cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
+       cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP,
+                       cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
+
+       memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
+
+       result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
+
+       if (!result)
+               result = tonga_copy_vbios_smc_reg_table(table, ni_table);
+
+       if (!result) {
+               tonga_set_s0_mc_reg_index(ni_table);
+               result = tonga_set_mc_special_registers(hwmgr, ni_table);
+       }
+
+       if (!result)
+               tonga_set_valid_flag(ni_table);
+
+       kfree(table);
+
+       return result;
+}
+
+bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr)
+{
+       return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
+                       CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
+                       ? true : false;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.h b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.h
new file mode 100644 (file)
index 0000000..8ae169f
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 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 _TONGA_SMC_H
+#define _TONGA_SMC_H
+
+#include "smumgr.h"
+#include "smu72.h"
+
+
+#define ASICID_IS_TONGA_P(wDID, bRID)   \
+       (((wDID == 0x6930) && ((bRID == 0xF0) || (bRID == 0xF1) || (bRID == 0xFF))) \
+       || ((wDID == 0x6920) && ((bRID == 0) || (bRID == 1))))
+
+
+struct tonga_pt_defaults {
+       uint8_t   svi_load_line_en;
+       uint8_t   svi_load_line_vddC;
+       uint8_t   tdc_vddc_throttle_release_limit_perc;
+       uint8_t   tdc_mawt;
+       uint8_t   tdc_waterfall_ctl;
+       uint8_t   dte_ambient_temp_base;
+       uint32_t  display_cac;
+       uint32_t  bamp_temp_gradient;
+       uint16_t  bapmti_r[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
+       uint16_t  bapmti_rc[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
+};
+
+int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr);
+int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr);
+int tonga_init_smc_table(struct pp_hwmgr *hwmgr);
+int tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr);
+int tonga_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type);
+int tonga_update_sclk_threshold(struct pp_hwmgr *hwmgr);
+uint32_t tonga_get_offsetof(uint32_t type, uint32_t member);
+uint32_t tonga_get_mac_definition(uint32_t value);
+int tonga_process_firmware_header(struct pp_hwmgr *hwmgr);
+int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr);
+bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr);
+#endif
+
index f42c536..5f91240 100644 (file)
 #include "smu/smu_7_1_2_d.h"
 #include "smu/smu_7_1_2_sh_mask.h"
 #include "cgs_common.h"
+#include "tonga_smc.h"
+#include "smu7_smumgr.h"
 
-#define TONGA_SMC_SIZE                 0x20000
-#define BUFFER_SIZE                    80000
-#define MAX_STRING_SIZE                        15
-#define BUFFER_SIZETWO              131072 /*128 *1024*/
-
-/**
-* Set the address for reading/writing the SMC SRAM space.
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    smcAddress the address in the SMC RAM to access.
-*/
-static int tonga_set_smc_sram_address(struct pp_smumgr *smumgr,
-                               uint32_t smcAddress, uint32_t limit)
-{
-       if (smumgr == NULL || smumgr->device == NULL)
-               return -EINVAL;
-       PP_ASSERT_WITH_CODE((0 == (3 & smcAddress)),
-               "SMC address must be 4 byte aligned.",
-               return -1;);
-
-       PP_ASSERT_WITH_CODE((limit > (smcAddress + 3)),
-               "SMC address is beyond the SMC RAM area.",
-               return -1;);
-
-       cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smcAddress);
-       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0);
-
-       return 0;
-}
-
-/**
-* Copy bytes from an array into the SMC RAM space.
-*
-* @param    smumgr  the address of the powerplay SMU manager.
-* @param    smcStartAddress the start address in the SMC RAM to copy bytes to.
-* @param    src the byte array to copy the bytes from.
-* @param    byteCount the number of bytes to copy.
-*/
-int tonga_copy_bytes_to_smc(struct pp_smumgr *smumgr,
-               uint32_t smcStartAddress, const uint8_t *src,
-               uint32_t byteCount, uint32_t limit)
-{
-       uint32_t addr;
-       uint32_t data, orig_data;
-       int result = 0;
-       uint32_t extra_shift;
-
-       if (smumgr == NULL || smumgr->device == NULL)
-               return -EINVAL;
-       PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)),
-               "SMC address must be 4 byte aligned.",
-               return 0;);
-
-       PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)),
-               "SMC address is beyond the SMC RAM area.",
-               return 0;);
-
-       addr = smcStartAddress;
-
-       while (byteCount >= 4) {
-               /*
-                * Bytes are written into the
-                * SMC address space with the MSB first
-                */
-               data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
-
-               result = tonga_set_smc_sram_address(smumgr, addr, limit);
-
-               if (result)
-                       goto out;
-
-               cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
-
-               src += 4;
-               byteCount -= 4;
-               addr += 4;
-       }
-
-       if (0 != byteCount) {
-               /* Now write odd bytes left, do a read modify write cycle */
-               data = 0;
-
-               result = tonga_set_smc_sram_address(smumgr, addr, limit);
-               if (result)
-                       goto out;
-
-               orig_data = cgs_read_register(smumgr->device,
-                                                       mmSMC_IND_DATA_0);
-               extra_shift = 8 * (4 - byteCount);
-
-               while (byteCount > 0) {
-                       data = (data << 8) + *src++;
-                       byteCount--;
-               }
-
-               data <<= extra_shift;
-               data |= (orig_data & ~((~0UL) << extra_shift));
-
-               result = tonga_set_smc_sram_address(smumgr, addr, limit);
-               if (result)
-                       goto out;
-
-               cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
-       }
-
-out:
-       return result;
-}
-
-
-int tonga_program_jump_on_start(struct pp_smumgr *smumgr)
-{
-       static const unsigned char pData[] = { 0xE0, 0x00, 0x80, 0x40 };
-
-       tonga_copy_bytes_to_smc(smumgr, 0x0, pData, 4, sizeof(pData)+1);
-
-       return 0;
-}
-
-/**
-* Return if the SMC is currently running.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-*/
-static int tonga_is_smc_ram_running(struct pp_smumgr *smumgr)
-{
-       return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
-                                       SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
-                       && (0x20100 <= cgs_read_ind_register(smumgr->device,
-                                       CGS_IND_REG__SMC, ixSMC_PC_C)));
-}
-
-static int tonga_send_msg_to_smc_offset(struct pp_smumgr *smumgr)
-{
-       if (smumgr == NULL || smumgr->device == NULL)
-               return -EINVAL;
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-
-       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000);
-       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-
-       return 0;
-}
-
-/**
-* Send a message to the SMC, and wait for its response.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    msg the message to send.
-* @return   The response that came from the SMC.
-*/
-static int tonga_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
-{
-       if (smumgr == NULL || smumgr->device == NULL)
-               return -EINVAL;
-
-       if (!tonga_is_smc_ram_running(smumgr))
-               return -1;
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-       PP_ASSERT_WITH_CODE(
-               1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
-               "Failed to send Previous Message.",
-               );
-
-       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-       PP_ASSERT_WITH_CODE(
-               1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
-               "Failed to send Message.",
-               );
-
-       return 0;
-}
-
-/*
-* Send a message to the SMC, and do not wait for its response.
-*
-* @param    smumgr  the address of the powerplay hardware manager.
-* @param    msg the message to send.
-* @return   The response that came from the SMC.
-*/
-static int tonga_send_msg_to_smc_without_waiting
-                               (struct pp_smumgr *smumgr, uint16_t msg)
-{
-       if (smumgr == NULL || smumgr->device == NULL)
-               return -EINVAL;
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-       PP_ASSERT_WITH_CODE(
-               1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
-               "Failed to send Previous Message.",
-               );
-       cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
-
-       return 0;
-}
-
-/*
-* Send a message to the SMC with parameter
-*
-* @param    smumgr:  the address of the powerplay hardware manager.
-* @param    msg: the message to send.
-* @param    parameter: the parameter to send
-* @return   The response that came from the SMC.
-*/
-static int tonga_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
-                               uint16_t msg, uint32_t parameter)
-{
-       if (smumgr == NULL || smumgr->device == NULL)
-               return -EINVAL;
-
-       if (!tonga_is_smc_ram_running(smumgr))
-               return PPSMC_Result_Failed;
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
-
-       return tonga_send_msg_to_smc(smumgr, msg);
-}
-
-/*
-* Send a message to the SMC with parameter, do not wait for response
-*
-* @param    smumgr:  the address of the powerplay hardware manager.
-* @param    msg: the message to send.
-* @param    parameter: the parameter to send
-* @return   The response that came from the SMC.
-*/
-static int tonga_send_msg_to_smc_with_parameter_without_waiting(
-                       struct pp_smumgr *smumgr,
-                       uint16_t msg, uint32_t parameter)
-{
-       if (smumgr == NULL || smumgr->device == NULL)
-               return -EINVAL;
-
-       SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
-
-       cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
-
-       return tonga_send_msg_to_smc_without_waiting(smumgr, msg);
-}
-
-/*
- * Read a 32bit value from the SMC SRAM space.
- * ALL PARAMETERS ARE IN HOST BYTE ORDER.
- * @param    smumgr  the address of the powerplay hardware manager.
- * @param    smcAddress the address in the SMC RAM to access.
- * @param    value and output parameter for the data read from the SMC SRAM.
- */
-int tonga_read_smc_sram_dword(struct pp_smumgr *smumgr,
-                                       uint32_t smcAddress, uint32_t *value,
-                                       uint32_t limit)
-{
-       int result;
-
-       result = tonga_set_smc_sram_address(smumgr, smcAddress, limit);
-
-       if (0 != result)
-               return result;
-
-       *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
-
-       return 0;
-}
-
-/*
- * Write a 32bit value to the SMC SRAM space.
- * ALL PARAMETERS ARE IN HOST BYTE ORDER.
- * @param    smumgr  the address of the powerplay hardware manager.
- * @param    smcAddress the address in the SMC RAM to access.
- * @param    value to write to the SMC SRAM.
- */
-int tonga_write_smc_sram_dword(struct pp_smumgr *smumgr,
-                                       uint32_t smcAddress, uint32_t value,
-                                       uint32_t limit)
-{
-       int result;
-
-       result = tonga_set_smc_sram_address(smumgr, smcAddress, limit);
-
-       if (0 != result)
-               return result;
-
-       cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value);
-
-       return 0;
-}
-
-static int tonga_smu_fini(struct pp_smumgr *smumgr)
-{
-       struct tonga_smumgr *priv = (struct tonga_smumgr *)(smumgr->backend);
-
-       smu_free_memory(smumgr->device, (void *)priv->smu_buffer.handle);
-       smu_free_memory(smumgr->device, (void *)priv->header_buffer.handle);
-
-       if (smumgr->backend != NULL) {
-               kfree(smumgr->backend);
-               smumgr->backend = NULL;
-       }
-
-       cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU);
-       return 0;
-}
-
-static enum cgs_ucode_id tonga_convert_fw_type_to_cgs(uint32_t fw_type)
-{
-       enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
-
-       switch (fw_type) {
-       case UCODE_ID_SMU:
-               result = CGS_UCODE_ID_SMU;
-               break;
-       case UCODE_ID_SDMA0:
-               result = CGS_UCODE_ID_SDMA0;
-               break;
-       case UCODE_ID_SDMA1:
-               result = CGS_UCODE_ID_SDMA1;
-               break;
-       case UCODE_ID_CP_CE:
-               result = CGS_UCODE_ID_CP_CE;
-               break;
-       case UCODE_ID_CP_PFP:
-               result = CGS_UCODE_ID_CP_PFP;
-               break;
-       case UCODE_ID_CP_ME:
-               result = CGS_UCODE_ID_CP_ME;
-               break;
-       case UCODE_ID_CP_MEC:
-               result = CGS_UCODE_ID_CP_MEC;
-               break;
-       case UCODE_ID_CP_MEC_JT1:
-               result = CGS_UCODE_ID_CP_MEC_JT1;
-               break;
-       case UCODE_ID_CP_MEC_JT2:
-               result = CGS_UCODE_ID_CP_MEC_JT2;
-               break;
-       case UCODE_ID_RLC_G:
-               result = CGS_UCODE_ID_RLC_G;
-               break;
-       default:
-               break;
-       }
-
-       return result;
-}
-
-/**
- * Convert the PPIRI firmware type to SMU type mask.
- * For MEC, we need to check all MEC related type
-*/
-static uint16_t tonga_get_mask_for_firmware_type(uint16_t firmwareType)
-{
-       uint16_t result = 0;
-
-       switch (firmwareType) {
-       case UCODE_ID_SDMA0:
-               result = UCODE_ID_SDMA0_MASK;
-               break;
-       case UCODE_ID_SDMA1:
-               result = UCODE_ID_SDMA1_MASK;
-               break;
-       case UCODE_ID_CP_CE:
-               result = UCODE_ID_CP_CE_MASK;
-               break;
-       case UCODE_ID_CP_PFP:
-               result = UCODE_ID_CP_PFP_MASK;
-               break;
-       case UCODE_ID_CP_ME:
-               result = UCODE_ID_CP_ME_MASK;
-               break;
-       case UCODE_ID_CP_MEC:
-       case UCODE_ID_CP_MEC_JT1:
-       case UCODE_ID_CP_MEC_JT2:
-               result = UCODE_ID_CP_MEC_MASK;
-               break;
-       case UCODE_ID_RLC_G:
-               result = UCODE_ID_RLC_G_MASK;
-               break;
-       default:
-               break;
-       }
-
-       return result;
-}
-
-/**
- * Check if the FW has been loaded,
- * SMU will not return if loading has not finished.
-*/
-static int tonga_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fwType)
-{
-       uint16_t fwMask = tonga_get_mask_for_firmware_type(fwType);
-
-       if (0 != SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND,
-                               SOFT_REGISTERS_TABLE_28, fwMask, fwMask)) {
-               printk(KERN_ERR "[ powerplay ] check firmware loading failed\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* Populate one firmware image to the data structure */
-static int tonga_populate_single_firmware_entry(struct pp_smumgr *smumgr,
-                               uint16_t firmware_type,
-                               struct SMU_Entry *pentry)
-{
-       int result;
-       struct cgs_firmware_info info = {0};
-
-       result = cgs_get_firmware_info(
-                               smumgr->device,
-                               tonga_convert_fw_type_to_cgs(firmware_type),
-                               &info);
-
-       if (result == 0) {
-               pentry->version = 0;
-               pentry->id = (uint16_t)firmware_type;
-               pentry->image_addr_high = smu_upper_32_bits(info.mc_addr);
-               pentry->image_addr_low = smu_lower_32_bits(info.mc_addr);
-               pentry->meta_data_addr_high = 0;
-               pentry->meta_data_addr_low = 0;
-               pentry->data_size_byte = info.image_size;
-               pentry->num_register_entries = 0;
-
-               if (firmware_type == UCODE_ID_RLC_G)
-                       pentry->flags = 1;
-               else
-                       pentry->flags = 0;
-       } else {
-               return result;
-       }
-
-       return result;
-}
-
-static int tonga_request_smu_reload_fw(struct pp_smumgr *smumgr)
-{
-       struct tonga_smumgr *tonga_smu =
-               (struct tonga_smumgr *)(smumgr->backend);
-       uint16_t fw_to_load;
-       struct SMU_DRAMData_TOC *toc;
-       /**
-        * First time this gets called during SmuMgr init,
-        * we haven't processed SMU header file yet,
-        * so Soft Register Start offset is unknown.
-        * However, for this case, UcodeLoadStatus is already 0,
-        * so we can skip this if the Soft Registers Start offset is 0.
-        */
-       cgs_write_ind_register(smumgr->device,
-               CGS_IND_REG__SMC, ixSOFT_REGISTERS_TABLE_28, 0);
-
-       tonga_send_msg_to_smc_with_parameter(smumgr,
-               PPSMC_MSG_SMU_DRAM_ADDR_HI,
-               tonga_smu->smu_buffer.mc_addr_high);
-       tonga_send_msg_to_smc_with_parameter(smumgr,
-               PPSMC_MSG_SMU_DRAM_ADDR_LO,
-               tonga_smu->smu_buffer.mc_addr_low);
-
-       toc = (struct SMU_DRAMData_TOC *)tonga_smu->pHeader;
-       toc->num_entries = 0;
-       toc->structure_version = 1;
-
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_populate_single_firmware_entry(smumgr,
-               UCODE_ID_RLC_G,
-               &toc->entry[toc->num_entries++]),
-               "Failed to Get Firmware Entry.\n",
-               return -1);
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_populate_single_firmware_entry(smumgr,
-               UCODE_ID_CP_CE,
-               &toc->entry[toc->num_entries++]),
-               "Failed to Get Firmware Entry.\n",
-               return -1);
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_populate_single_firmware_entry
-               (smumgr, UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
-               "Failed to Get Firmware Entry.\n", return -1);
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_populate_single_firmware_entry
-               (smumgr, UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
-               "Failed to Get Firmware Entry.\n", return -1);
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_populate_single_firmware_entry
-               (smumgr, UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
-               "Failed to Get Firmware Entry.\n", return -1);
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_populate_single_firmware_entry
-               (smumgr, UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
-               "Failed to Get Firmware Entry.\n", return -1);
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_populate_single_firmware_entry
-               (smumgr, UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
-               "Failed to Get Firmware Entry.\n", return -1);
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_populate_single_firmware_entry
-               (smumgr, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
-               "Failed to Get Firmware Entry.\n", return -1);
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_populate_single_firmware_entry
-               (smumgr, UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
-               "Failed to Get Firmware Entry.\n", return -1);
-
-       tonga_send_msg_to_smc_with_parameter(smumgr,
-               PPSMC_MSG_DRV_DRAM_ADDR_HI,
-               tonga_smu->header_buffer.mc_addr_high);
-       tonga_send_msg_to_smc_with_parameter(smumgr,
-               PPSMC_MSG_DRV_DRAM_ADDR_LO,
-               tonga_smu->header_buffer.mc_addr_low);
-
-       fw_to_load = 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_MASK;
-
-       PP_ASSERT_WITH_CODE(
-               0 == tonga_send_msg_to_smc_with_parameter_without_waiting(
-               smumgr, PPSMC_MSG_LoadUcodes, fw_to_load),
-               "Fail to Request SMU Load uCode", return 0);
-
-       return 0;
-}
-
-static int tonga_request_smu_load_specific_fw(struct pp_smumgr *smumgr,
-                               uint32_t firmwareType)
-{
-       return 0;
-}
-
-/**
- * Upload the SMC firmware to the SMC microcontroller.
- *
- * @param    smumgr  the address of the powerplay hardware manager.
- * @param    pFirmware the data structure containing the various sections of the firmware.
- */
-static int tonga_smu_upload_firmware_image(struct pp_smumgr *smumgr)
-{
-       const uint8_t *src;
-       uint32_t byte_count;
-       uint32_t *data;
-       struct cgs_firmware_info info = {0};
-
-       if (smumgr == NULL || smumgr->device == NULL)
-               return -EINVAL;
-
-       cgs_get_firmware_info(smumgr->device,
-               tonga_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
-
-       if (info.image_size & 3) {
-               printk(KERN_ERR "[ powerplay ] SMC ucode is not 4 bytes aligned\n");
-               return -EINVAL;
-       }
-
-       if (info.image_size > TONGA_SMC_SIZE) {
-               printk(KERN_ERR "[ powerplay ] SMC address is beyond the SMC RAM area\n");
-               return -EINVAL;
-       }
-
-       cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, 0x20000);
-       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
-
-       byte_count = info.image_size;
-       src = (const uint8_t *)info.kptr;
-
-       data = (uint32_t *)src;
-       for (; byte_count >= 4; data++, byte_count -= 4)
-               cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data[0]);
-
-       SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
-
-       return 0;
-}
 
 static int tonga_start_in_protection_mode(struct pp_smumgr *smumgr)
 {
@@ -623,7 +45,7 @@ static int tonga_start_in_protection_mode(struct pp_smumgr *smumgr)
        SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
                SMC_SYSCON_RESET_CNTL, rst_reg, 1);
 
-       result = tonga_smu_upload_firmware_image(smumgr);
+       result = smu7_upload_smu_firmware_image(smumgr);
        if (result)
                return result;
 
@@ -653,7 +75,7 @@ static int tonga_start_in_protection_mode(struct pp_smumgr *smumgr)
        /**
         * Call Test SMU message with 0x20000 offset to trigger SMU start
         */
-       tonga_send_msg_to_smc_offset(smumgr);
+       smu7_send_msg_to_smc_offset(smumgr);
 
        /* Wait for done bit to be set */
        SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
@@ -690,13 +112,13 @@ static int tonga_start_in_non_protection_mode(struct pp_smumgr *smumgr)
        SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
                SMC_SYSCON_RESET_CNTL, rst_reg, 1);
 
-       result = tonga_smu_upload_firmware_image(smumgr);
+       result = smu7_upload_smu_firmware_image(smumgr);
 
        if (result != 0)
                return result;
 
        /* Set smc instruct start point at 0x0 */
-       tonga_program_jump_on_start(smumgr);
+       smu7_program_jump_on_start(smumgr);
 
 
        SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
@@ -718,7 +140,7 @@ static int tonga_start_smu(struct pp_smumgr *smumgr)
        int result;
 
        /* Only start SMC if SMC RAM is not running */
-       if (!tonga_is_smc_ram_running(smumgr)) {
+       if (!smu7_is_smc_ram_running(smumgr)) {
                /*Check if SMU is running in protected mode*/
                if (0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
                                        SMU_FIRMWARE, SMU_MODE)) {
@@ -732,7 +154,7 @@ static int tonga_start_smu(struct pp_smumgr *smumgr)
                }
        }
 
-       result = tonga_request_smu_reload_fw(smumgr);
+       result = smu7_request_smu_load_fw(smumgr);
 
        return result;
 }
@@ -746,67 +168,41 @@ static int tonga_start_smu(struct pp_smumgr *smumgr)
  */
 static int tonga_smu_init(struct pp_smumgr *smumgr)
 {
-       struct tonga_smumgr *tonga_smu;
-       uint8_t *internal_buf;
-       uint64_t mc_addr = 0;
-       /* Allocate memory for backend private data */
-       tonga_smu = (struct tonga_smumgr *)(smumgr->backend);
-       tonga_smu->header_buffer.data_size =
-               ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
-       tonga_smu->smu_buffer.data_size = 200*4096;
-
-       smu_allocate_memory(smumgr->device,
-               tonga_smu->header_buffer.data_size,
-               CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
-               PAGE_SIZE,
-               &mc_addr,
-               &tonga_smu->header_buffer.kaddr,
-               &tonga_smu->header_buffer.handle);
-
-       tonga_smu->pHeader = tonga_smu->header_buffer.kaddr;
-       tonga_smu->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
-       tonga_smu->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
-
-       PP_ASSERT_WITH_CODE((NULL != tonga_smu->pHeader),
-               "Out of memory.",
-               kfree(smumgr->backend);
-               cgs_free_gpu_mem(smumgr->device,
-               (cgs_handle_t)tonga_smu->header_buffer.handle);
-               return -1);
-
-       smu_allocate_memory(smumgr->device,
-               tonga_smu->smu_buffer.data_size,
-               CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
-               PAGE_SIZE,
-               &mc_addr,
-               &tonga_smu->smu_buffer.kaddr,
-               &tonga_smu->smu_buffer.handle);
-
-       internal_buf = tonga_smu->smu_buffer.kaddr;
-       tonga_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
-       tonga_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
-
-       PP_ASSERT_WITH_CODE((NULL != internal_buf),
-               "Out of memory.",
-               kfree(smumgr->backend);
-               cgs_free_gpu_mem(smumgr->device,
-               (cgs_handle_t)tonga_smu->smu_buffer.handle);
-               return -1;);
+       struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(smumgr->backend);
+
+       int i;
+
+       if (smu7_init(smumgr))
+               return -EINVAL;
+
+       for (i = 0; i < SMU72_MAX_LEVELS_GRAPHICS; i++)
+               smu_data->activity_target[i] = 30;
 
        return 0;
 }
 
 static const struct pp_smumgr_func tonga_smu_funcs = {
        .smu_init = &tonga_smu_init,
-       .smu_fini = &tonga_smu_fini,
+       .smu_fini = &smu7_smu_fini,
        .start_smu = &tonga_start_smu,
-       .check_fw_load_finish = &tonga_check_fw_load_finish,
-       .request_smu_load_fw = &tonga_request_smu_reload_fw,
-       .request_smu_load_specific_fw = &tonga_request_smu_load_specific_fw,
-       .send_msg_to_smc = &tonga_send_msg_to_smc,
-       .send_msg_to_smc_with_parameter = &tonga_send_msg_to_smc_with_parameter,
+       .check_fw_load_finish = &smu7_check_fw_load_finish,
+       .request_smu_load_fw = &smu7_request_smu_load_fw,
+       .request_smu_load_specific_fw = NULL,
+       .send_msg_to_smc = &smu7_send_msg_to_smc,
+       .send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
        .download_pptable_settings = NULL,
        .upload_pptable_settings = NULL,
+       .update_smc_table = tonga_update_smc_table,
+       .get_offsetof = tonga_get_offsetof,
+       .process_firmware_header = tonga_process_firmware_header,
+       .init_smc_table = tonga_init_smc_table,
+       .update_sclk_threshold = tonga_update_sclk_threshold,
+       .thermal_setup_fan_table = tonga_thermal_setup_fan_table,
+       .populate_all_graphic_levels = tonga_populate_all_graphic_levels,
+       .populate_all_memory_levels = tonga_populate_all_memory_levels,
+       .get_mac_definition = tonga_get_mac_definition,
+       .initialize_mc_reg_table = tonga_initialize_mc_reg_table,
+       .is_dpm_running = tonga_is_dpm_running,
 };
 
 int tonga_smum_init(struct pp_smumgr *smumgr)
index 33c788d..8c4f761 100644 (file)
 #ifndef _TONGA_SMUMGR_H_
 #define _TONGA_SMUMGR_H_
 
-struct tonga_buffer_entry {
-       uint32_t data_size;
-       uint32_t mc_addr_low;
-       uint32_t mc_addr_high;
-       void *kaddr;
-       unsigned long  handle;
+#include "smu72_discrete.h"
+
+#include "smu7_smumgr.h"
+
+struct tonga_mc_reg_entry {
+       uint32_t mclk_max;
+       uint32_t mc_data[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct tonga_mc_reg_table {
+       uint8_t   last;               /* number of registers*/
+       uint8_t   num_entries;        /* number of entries in mc_reg_table_entry used*/
+       uint16_t  validflag;          /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
+       struct tonga_mc_reg_entry    mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+       SMU72_Discrete_MCRegisterAddress mc_reg_address[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
 };
 
+
 struct tonga_smumgr {
-       uint8_t *pHeader;
-       uint8_t *pMecImage;
-       uint32_t ulSoftRegsStart;
 
-       struct tonga_buffer_entry header_buffer;
-       struct tonga_buffer_entry smu_buffer;
-};
+       struct smu7_smumgr                   smu7_data;
+       struct SMU72_Discrete_DpmTable       smc_state_table;
+       struct SMU72_Discrete_Ulv            ulv_setting;
+       struct SMU72_Discrete_PmFuses  power_tune_table;
+       const struct tonga_pt_defaults  *power_tune_defaults;
+       SMU72_Discrete_MCRegisters      mc_regs;
+       struct tonga_mc_reg_table mc_reg_table;
 
-extern int tonga_smum_init(struct pp_smumgr *smumgr);
-extern int tonga_copy_bytes_to_smc(struct pp_smumgr *smumgr,
-               uint32_t smcStartAddress, const uint8_t *src,
-               uint32_t byteCount, uint32_t limit);
-extern int tonga_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
-               uint32_t *value, uint32_t limit);
-extern int tonga_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
-               uint32_t value, uint32_t limit);
+       uint32_t        activity_target[SMU72_MAX_LEVELS_GRAPHICS];
+
+};
 
 #endif
index ee0a61c..7130b04 100644 (file)
@@ -183,8 +183,6 @@ static void arc_pgu_plane_atomic_update(struct drm_plane *plane,
 }
 
 static const struct drm_plane_helper_funcs arc_pgu_plane_helper_funcs = {
-       .prepare_fb = NULL,
-       .cleanup_fb = NULL,
        .atomic_update = arc_pgu_plane_atomic_update,
 };
 
index 6d4ff34..28e6471 100644 (file)
@@ -198,8 +198,8 @@ static int arcpgu_probe(struct platform_device *pdev)
        int ret;
 
        drm = drm_dev_alloc(&arcpgu_drm_driver, &pdev->dev);
-       if (!drm)
-               return -ENOMEM;
+       if (IS_ERR(drm))
+               return PTR_ERR(drm);
 
        ret = arcpgu_load(drm);
        if (ret)
index d83b46a..fb6a418 100644 (file)
@@ -326,8 +326,8 @@ static int hdlcd_drm_bind(struct device *dev)
                return -ENOMEM;
 
        drm = drm_dev_alloc(&hdlcd_driver, dev);
-       if (!drm)
-               return -ENOMEM;
+       if (IS_ERR(drm))
+               return PTR_ERR(drm);
 
        drm->dev_private = hdlcd;
        dev_set_drvdata(dev, drm);
index 82171d2..9280358 100644 (file)
@@ -91,7 +91,8 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
 
        drm_atomic_helper_commit_modeset_disables(drm, state);
        drm_atomic_helper_commit_modeset_enables(drm, state);
-       drm_atomic_helper_commit_planes(drm, state, true);
+       drm_atomic_helper_commit_planes(drm, state,
+                                       DRM_PLANE_COMMIT_ACTIVE_ONLY);
 
        malidp_atomic_commit_hw_done(state);
 
@@ -310,8 +311,8 @@ static int malidp_bind(struct device *dev)
                return ret;
 
        drm = drm_dev_alloc(&malidp_driver, dev);
-       if (!drm) {
-               ret = -ENOMEM;
+       if (IS_ERR(drm)) {
+               ret = PTR_ERR(drm);
                goto alloc_fail;
        }
 
index 95558fd..271d2fb 100644 (file)
@@ -49,6 +49,6 @@ void malidp_de_planes_destroy(struct drm_device *drm);
 int malidp_crtc_init(struct drm_device *drm);
 
 /* often used combination of rotational bits */
-#define MALIDP_ROTATED_MASK    (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))
+#define MALIDP_ROTATED_MASK    (DRM_ROTATE_90 | DRM_ROTATE_270)
 
 #endif  /* __MALIDP_DRV_H__ */
index 725098d..82c193e 100644 (file)
@@ -108,7 +108,7 @@ static int malidp_de_plane_check(struct drm_plane *plane,
                return -EINVAL;
 
        /* packed RGB888 / BGR888 can't be rotated or flipped */
-       if (state->rotation != BIT(DRM_ROTATE_0) &&
+       if (state->rotation != DRM_ROTATE_0 &&
            (state->fb->pixel_format == DRM_FORMAT_RGB888 ||
             state->fb->pixel_format == DRM_FORMAT_BGR888))
                return -EINVAL;
@@ -188,9 +188,9 @@ 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;
-       if (plane->state->rotation & BIT(DRM_REFLECT_X))
+       if (plane->state->rotation & DRM_REFLECT_X)
                val |= LAYER_V_FLIP;
-       if (plane->state->rotation & BIT(DRM_REFLECT_Y))
+       if (plane->state->rotation & DRM_REFLECT_Y)
                val |= LAYER_H_FLIP;
 
        /* set the 'enable layer' bit */
@@ -255,12 +255,12 @@ int malidp_de_planes_init(struct drm_device *drm)
                        goto cleanup;
 
                if (!drm->mode_config.rotation_property) {
-                       unsigned long flags = BIT(DRM_ROTATE_0) |
-                                             BIT(DRM_ROTATE_90) |
-                                             BIT(DRM_ROTATE_180) |
-                                             BIT(DRM_ROTATE_270) |
-                                             BIT(DRM_REFLECT_X) |
-                                             BIT(DRM_REFLECT_Y);
+                       unsigned long flags = DRM_ROTATE_0 |
+                                             DRM_ROTATE_90 |
+                                             DRM_ROTATE_180 |
+                                             DRM_ROTATE_270 |
+                                             DRM_REFLECT_X |
+                                             DRM_REFLECT_Y;
                        drm->mode_config.rotation_property =
                                drm_mode_create_rotation_property(drm, flags);
                }
@@ -268,7 +268,7 @@ int malidp_de_planes_init(struct drm_device *drm)
                if (drm->mode_config.rotation_property && (id != DE_SMART))
                        drm_object_attach_property(&plane->base.base,
                                                   drm->mode_config.rotation_property,
-                                                  BIT(DRM_ROTATE_0));
+                                                  DRM_ROTATE_0);
 
                drm_plane_helper_add(&plane->base,
                                     &malidp_de_plane_helper_funcs);
index f5ebdd6..1e0e68f 100644 (file)
@@ -211,7 +211,7 @@ static struct drm_driver armada_drm_driver = {
        .desc                   = "Armada SoC DRM",
        .date                   = "20120730",
        .driver_features        = DRIVER_GEM | DRIVER_MODESET |
-                                 DRIVER_HAVE_IRQ | DRIVER_PRIME,
+                                 DRIVER_PRIME,
        .ioctls                 = armada_ioctls,
        .fops                   = &armada_drm_fops,
 };
index 7d03c51..ca73ad8 100644 (file)
@@ -7,7 +7,6 @@
  * published by the Free Software Foundation.
  */
 #include <linux/errno.h>
-#include <linux/fb.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 
index ff84316..8067918 100644 (file)
@@ -547,7 +547,7 @@ armada_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj,
        exp_info.flags = O_RDWR;
        exp_info.priv = obj;
 
-       return dma_buf_export(&exp_info);
+       return drm_gem_dmabuf_export(dev, &exp_info);
 }
 
 struct drm_gem_object *
index 1ee707e..152b4e7 100644 (file)
@@ -121,7 +121,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
        int ret;
 
        ret = drm_plane_helper_check_update(plane, crtc, fb, &src, &dest, &clip,
-                                           BIT(DRM_ROTATE_0),
+                                           DRM_ROTATE_0,
                                            0, INT_MAX, true, false, &visible);
        if (ret)
                return ret;
index c017a93..7a86e24 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/tty.h>
 #include <linux/sysrq.h>
 #include <linux/delay.h>
-#include <linux/fb.h>
 #include <linux/init.h>
 
 
index b29a412..608df4c 100644 (file)
@@ -150,7 +150,8 @@ static int ast_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
 {
        struct ast_bo *astbo = ast_bo(bo);
 
-       return drm_vma_node_verify_access(&astbo->gem.vma_node, filp);
+       return drm_vma_node_verify_access(&astbo->gem.vma_node,
+                                         filp->private_data);
 }
 
 static int ast_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
index d4a3d61..5f48431 100644 (file)
@@ -457,7 +457,7 @@ atmel_hlcdc_dc_atomic_complete(struct atmel_hlcdc_dc_commit *commit)
 
        /* Apply the atomic update. */
        drm_atomic_helper_commit_modeset_disables(dev, old_state);
-       drm_atomic_helper_commit_planes(dev, old_state, false);
+       drm_atomic_helper_commit_planes(dev, old_state, 0);
        drm_atomic_helper_commit_modeset_enables(dev, old_state);
 
        drm_atomic_helper_wait_for_vblanks(dev, old_state);
@@ -797,8 +797,8 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
        int ret;
 
        ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev);
-       if (!ddev)
-               return -ENOMEM;
+       if (IS_ERR(ddev))
+               return PTR_ERR(ddev);
 
        ret = atmel_hlcdc_dc_load(ddev);
        if (ret)
index 52c527f..9d4c030 100644 (file)
@@ -393,7 +393,7 @@ static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
 
        if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
             state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
-           (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
+           (state->base.rotation & (DRM_ROTATE_90 | DRM_ROTATE_270)))
                cfg |= ATMEL_HLCDC_YUV422ROT;
 
        atmel_hlcdc_layer_update_cfg(&plane->layer,
@@ -628,7 +628,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
        /*
         * Swap width and size in case of 90 or 270 degrees rotation
         */
-       if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
+       if (state->base.rotation & (DRM_ROTATE_90 | DRM_ROTATE_270)) {
                tmp = state->crtc_w;
                state->crtc_w = state->crtc_h;
                state->crtc_h = tmp;
@@ -677,7 +677,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
                        return -EINVAL;
 
                switch (state->base.rotation & DRM_ROTATE_MASK) {
-               case BIT(DRM_ROTATE_90):
+               case DRM_ROTATE_90:
                        offset = ((y_offset + state->src_y + patched_src_w - 1) /
                                  ydiv) * fb->pitches[i];
                        offset += ((x_offset + state->src_x) / xdiv) *
@@ -686,7 +686,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
                                          fb->pitches[i];
                        state->pstride[i] = -fb->pitches[i] - state->bpp[i];
                        break;
-               case BIT(DRM_ROTATE_180):
+               case DRM_ROTATE_180:
                        offset = ((y_offset + state->src_y + patched_src_h - 1) /
                                  ydiv) * fb->pitches[i];
                        offset += ((x_offset + state->src_x + patched_src_w - 1) /
@@ -695,7 +695,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
                                           state->bpp[i]) - fb->pitches[i];
                        state->pstride[i] = -2 * state->bpp[i];
                        break;
-               case BIT(DRM_ROTATE_270):
+               case DRM_ROTATE_270:
                        offset = ((y_offset + state->src_y) / ydiv) *
                                 fb->pitches[i];
                        offset += ((x_offset + state->src_x + patched_src_h - 1) /
@@ -705,7 +705,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
                                          (2 * state->bpp[i]);
                        state->pstride[i] = fb->pitches[i] - state->bpp[i];
                        break;
-               case BIT(DRM_ROTATE_0):
+               case DRM_ROTATE_0:
                default:
                        offset = ((y_offset + state->src_y) / ydiv) *
                                 fb->pitches[i];
@@ -755,7 +755,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
 }
 
 static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
-                                       const struct drm_plane_state *new_state)
+                                       struct drm_plane_state *new_state)
 {
        /*
         * FIXME: we should avoid this const -> non-const cast but it's
@@ -780,7 +780,7 @@ static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
 }
 
 static void atmel_hlcdc_plane_cleanup_fb(struct drm_plane *p,
-                               const struct drm_plane_state *old_state)
+                                        struct drm_plane_state *old_state)
 {
        /*
         * FIXME: we should avoid this const -> non-const cast but it's
@@ -905,7 +905,7 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
        if (desc->layout.xstride && desc->layout.pstride)
                drm_object_attach_property(&plane->base.base,
                                plane->base.dev->mode_config.rotation_property,
-                               BIT(DRM_ROTATE_0));
+                               DRM_ROTATE_0);
 
        if (desc->layout.csc) {
                /*
@@ -1056,10 +1056,10 @@ atmel_hlcdc_plane_create_properties(struct drm_device *dev)
 
        dev->mode_config.rotation_property =
                        drm_mode_create_rotation_property(dev,
-                                                         BIT(DRM_ROTATE_0) |
-                                                         BIT(DRM_ROTATE_90) |
-                                                         BIT(DRM_ROTATE_180) |
-                                                         BIT(DRM_ROTATE_270));
+                                                         DRM_ROTATE_0 |
+                                                         DRM_ROTATE_90 |
+                                                         DRM_ROTATE_180 |
+                                                         DRM_ROTATE_270);
        if (!dev->mode_config.rotation_property)
                return ERR_PTR(-ENOMEM);
 
index 19b5ada..32dfe41 100644 (file)
@@ -1,5 +1,4 @@
 #include <linux/io.h>
-#include <linux/fb.h>
 #include <linux/console.h>
 
 #include <drm/drmP.h>
index abace82..534227d 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <drm/drm_fb_helper.h>
 
 #include "bochs.h"
 
@@ -153,7 +154,7 @@ static int bochs_kick_out_firmware_fb(struct pci_dev *pdev)
 
        ap->ranges[0].base = pci_resource_start(pdev, 0);
        ap->ranges[0].size = pci_resource_len(pdev, 0);
-       remove_conflicting_framebuffers(ap, "bochsdrmfb", false);
+       drm_fb_helper_remove_conflicting_framebuffers(ap, "bochsdrmfb", false);
        kfree(ap);
 
        return 0;
@@ -162,8 +163,15 @@ static int bochs_kick_out_firmware_fb(struct pci_dev *pdev)
 static int bochs_pci_probe(struct pci_dev *pdev,
                           const struct pci_device_id *ent)
 {
+       unsigned long fbsize;
        int ret;
 
+       fbsize = pci_resource_len(pdev, 0);
+       if (fbsize < 4 * 1024 * 1024) {
+               DRM_ERROR("less than 4 MB video memory, ignoring device\n");
+               return -ENOMEM;
+       }
+
        ret = bochs_kick_out_firmware_fb(pdev);
        if (ret)
                return ret;
index 207a2cb..0b4e5d1 100644 (file)
@@ -178,7 +178,7 @@ static void bochs_encoder_init(struct drm_device *dev)
 }
 
 
-int bochs_connector_get_modes(struct drm_connector *connector)
+static int bochs_connector_get_modes(struct drm_connector *connector)
 {
        int count;
 
index 5c5638a..269cfca 100644 (file)
@@ -128,7 +128,8 @@ static int bochs_bo_verify_access(struct ttm_buffer_object *bo,
 {
        struct bochs_bo *bochsbo = bochs_bo(bo);
 
-       return drm_vma_node_verify_access(&bochsbo->gem.vma_node, filp);
+       return drm_vma_node_verify_access(&bochsbo->gem.vma_node,
+                                         filp->private_data);
 }
 
 static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
index b590e67..10e12e7 100644 (file)
@@ -17,6 +17,13 @@ config DRM_ANALOGIX_ANX78XX
          the HDMI output of an application processor to MyDP
          or DisplayPort.
 
+config DRM_DUMB_VGA_DAC
+       tristate "Dumb VGA DAC Bridge support"
+       depends on OF
+       select DRM_KMS_HELPER
+       help
+         Support for RGB to VGA DAC based bridges
+
 config DRM_DW_HDMI
        tristate
        select DRM_KMS_HELPER
index efdb07e..cdf3a3c 100644 (file)
@@ -1,6 +1,7 @@
 ccflags-y := -Iinclude/drm
 
 obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
+obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
 obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
 obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
index ec8fb2e..8ed3906 100644 (file)
@@ -922,15 +922,13 @@ static int adv7511_parse_dt(struct device_node *np,
        return 0;
 }
 
-static const int edid_i2c_addr = 0x7e;
-static const int packet_i2c_addr = 0x70;
-static const int cec_i2c_addr = 0x78;
-
 static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 {
        struct adv7511_link_config link_config;
        struct adv7511 *adv7511;
        struct device *dev = &i2c->dev;
+       unsigned int main_i2c_addr = i2c->addr << 1;
+       unsigned int edid_i2c_addr = main_i2c_addr + 4;
        unsigned int val;
        int ret;
 
@@ -991,8 +989,10 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
        regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
        regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
-                    packet_i2c_addr);
-       regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr);
+                    main_i2c_addr - 0xa);
+       regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
+                    main_i2c_addr - 2);
+
        adv7511_packet_disable(adv7511, 0xffff);
 
        adv7511->i2c_main = i2c;
index 5eebd15..d7f7b7c 100644 (file)
@@ -149,13 +149,12 @@ void adv7533_uninit_cec(struct adv7511 *adv)
        i2c_unregister_device(adv->i2c_cec);
 }
 
-static const int cec_i2c_addr = 0x78;
-
 int adv7533_init_cec(struct adv7511 *adv)
 {
        int ret;
 
-       adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter, cec_i2c_addr >> 1);
+       adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter,
+                                    adv->i2c_main->addr - 1);
        if (!adv->i2c_cec)
                return -ENOMEM;
 
index f9f03bc..a2a8236 100644 (file)
@@ -1001,16 +1001,11 @@ static enum drm_connector_status anx78xx_detect(struct drm_connector *connector,
        return connector_status_connected;
 }
 
-static void anx78xx_connector_destroy(struct drm_connector *connector)
-{
-       drm_connector_cleanup(connector);
-}
-
 static const struct drm_connector_funcs anx78xx_connector_funcs = {
        .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = anx78xx_detect,
-       .destroy = anx78xx_connector_destroy,
+       .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,
index 32715da..6e0447f 100644 (file)
@@ -31,6 +31,7 @@
 #include <drm/bridge/analogix_dp.h>
 
 #include "analogix_dp_core.h"
+#include "analogix_dp_reg.h"
 
 #define to_dp(nm)      container_of(nm, struct analogix_dp_device, nm)
 
@@ -97,133 +98,89 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
        return 0;
 }
 
-static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
+int analogix_dp_psr_supported(struct device *dev)
 {
-       int i;
-       unsigned char sum = 0;
-
-       for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-               sum = sum + edid_data[i];
+       struct analogix_dp_device *dp = dev_get_drvdata(dev);
 
-       return sum;
+       return dp->psr_support;
 }
+EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
 
-static int analogix_dp_read_edid(struct analogix_dp_device *dp)
+int analogix_dp_enable_psr(struct device *dev)
 {
-       unsigned char *edid = dp->edid;
-       unsigned int extend_block = 0;
-       unsigned char sum;
-       unsigned char test_vector;
-       int retval;
+       struct analogix_dp_device *dp = dev_get_drvdata(dev);
+       struct edp_vsc_psr psr_vsc;
 
-       /*
-        * EDID device address is 0x50.
-        * However, if necessary, you must have set upper address
-        * into E-EDID in I2C device, 0x30.
-        */
+       if (!dp->psr_support)
+               return -EINVAL;
 
-       /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-       retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-                                               EDID_EXTENSION_FLAG,
-                                               &extend_block);
-       if (retval)
-               return retval;
+       /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+       memset(&psr_vsc, 0, sizeof(psr_vsc));
+       psr_vsc.sdp_header.HB0 = 0;
+       psr_vsc.sdp_header.HB1 = 0x7;
+       psr_vsc.sdp_header.HB2 = 0x2;
+       psr_vsc.sdp_header.HB3 = 0x8;
 
-       if (extend_block > 0) {
-               dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-               /* Read EDID data */
-               retval = analogix_dp_read_bytes_from_i2c(dp,
-                                               I2C_EDID_DEVICE_ADDR,
-                                               EDID_HEADER_PATTERN,
-                                               EDID_BLOCK_LENGTH,
-                                               &edid[EDID_HEADER_PATTERN]);
-               if (retval != 0) {
-                       dev_err(dp->dev, "EDID Read failed!\n");
-                       return -EIO;
-               }
-               sum = analogix_dp_calc_edid_check_sum(edid);
-               if (sum != 0) {
-                       dev_err(dp->dev, "EDID bad checksum!\n");
-                       return -EIO;
-               }
+       psr_vsc.DB0 = 0;
+       psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
 
-               /* Read additional EDID data */
-               retval = analogix_dp_read_bytes_from_i2c(dp,
-                               I2C_EDID_DEVICE_ADDR,
-                               EDID_BLOCK_LENGTH,
-                               EDID_BLOCK_LENGTH,
-                               &edid[EDID_BLOCK_LENGTH]);
-               if (retval != 0) {
-                       dev_err(dp->dev, "EDID Read failed!\n");
-                       return -EIO;
-               }
-               sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
-               if (sum != 0) {
-                       dev_err(dp->dev, "EDID bad checksum!\n");
-                       return -EIO;
-               }
+       analogix_dp_send_psr_spd(dp, &psr_vsc);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
-               analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-                                               &test_vector);
-               if (test_vector & DP_TEST_LINK_EDID_READ) {
-                       analogix_dp_write_byte_to_dpcd(dp,
-                               DP_TEST_EDID_CHECKSUM,
-                               edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-                       analogix_dp_write_byte_to_dpcd(dp,
-                               DP_TEST_RESPONSE,
-                               DP_TEST_EDID_CHECKSUM_WRITE);
-               }
-       } else {
-               dev_info(dp->dev, "EDID data does not include any extensions.\n");
-
-               /* Read EDID data */
-               retval = analogix_dp_read_bytes_from_i2c(dp,
-                               I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN,
-                               EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]);
-               if (retval != 0) {
-                       dev_err(dp->dev, "EDID Read failed!\n");
-                       return -EIO;
-               }
-               sum = analogix_dp_calc_edid_check_sum(edid);
-               if (sum != 0) {
-                       dev_err(dp->dev, "EDID bad checksum!\n");
-                       return -EIO;
-               }
+int analogix_dp_disable_psr(struct device *dev)
+{
+       struct analogix_dp_device *dp = dev_get_drvdata(dev);
+       struct edp_vsc_psr psr_vsc;
 
-               analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-                                               &test_vector);
-               if (test_vector & DP_TEST_LINK_EDID_READ) {
-                       analogix_dp_write_byte_to_dpcd(dp,
-                               DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]);
-                       analogix_dp_write_byte_to_dpcd(dp,
-                               DP_TEST_RESPONSE, DP_TEST_EDID_CHECKSUM_WRITE);
-               }
-       }
+       if (!dp->psr_support)
+               return -EINVAL;
+
+       /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+       memset(&psr_vsc, 0, sizeof(psr_vsc));
+       psr_vsc.sdp_header.HB0 = 0;
+       psr_vsc.sdp_header.HB1 = 0x7;
+       psr_vsc.sdp_header.HB2 = 0x2;
+       psr_vsc.sdp_header.HB3 = 0x8;
+
+       psr_vsc.DB0 = 0;
+       psr_vsc.DB1 = 0;
 
-       dev_dbg(dp->dev, "EDID Read success!\n");
+       analogix_dp_send_psr_spd(dp, &psr_vsc);
        return 0;
 }
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
 
-static int analogix_dp_handle_edid(struct analogix_dp_device *dp)
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
 {
-       u8 buf[12];
-       int i;
-       int retval;
+       unsigned char psr_version;
 
-       /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */
-       retval = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf);
-       if (retval)
-               return retval;
+       drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version);
+       dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
 
-       /* Read EDID */
-       for (i = 0; i < 3; i++) {
-               retval = analogix_dp_read_edid(dp);
-               if (!retval)
-                       break;
-       }
+       return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
 
-       return retval;
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+       unsigned char psr_en;
+
+       /* Disable psr function */
+       drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en);
+       psr_en &= ~DP_PSR_ENABLE;
+       drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
+
+       /* Main-Link transmitter remains active during PSR active states */
+       psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+       drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
+
+       /* Enable psr function */
+       psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+                DP_PSR_CRC_VERIFICATION;
+       drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
+
+       analogix_dp_enable_psr_crc(dp);
 }
 
 static void
@@ -232,15 +189,15 @@ analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp,
 {
        u8 data;
 
-       analogix_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data);
+       drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data);
 
        if (enable)
-               analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET,
-                                              DP_LANE_COUNT_ENHANCED_FRAME_EN |
-                                              DPCD_LANE_COUNT_SET(data));
+               drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
+                                  DP_LANE_COUNT_ENHANCED_FRAME_EN |
+                                       DPCD_LANE_COUNT_SET(data));
        else
-               analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET,
-                                              DPCD_LANE_COUNT_SET(data));
+               drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
+                                  DPCD_LANE_COUNT_SET(data));
 }
 
 static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp)
@@ -248,7 +205,7 @@ static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp)
        u8 data;
        int retval;
 
-       analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data);
+       drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
        retval = DPCD_ENHANCED_FRAME_CAP(data);
 
        return retval;
@@ -267,8 +224,8 @@ static void analogix_dp_training_pattern_dis(struct analogix_dp_device *dp)
 {
        analogix_dp_set_training_pattern(dp, DP_NONE);
 
-       analogix_dp_write_byte_to_dpcd(dp, DP_TRAINING_PATTERN_SET,
-                                      DP_TRAINING_PATTERN_DISABLE);
+       drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
+                          DP_TRAINING_PATTERN_DISABLE);
 }
 
 static void
@@ -313,8 +270,8 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
        /* Setup RX configuration */
        buf[0] = dp->link_train.link_rate;
        buf[1] = dp->link_train.lane_count;
-       retval = analogix_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, 2, buf);
-       if (retval)
+       retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2);
+       if (retval < 0)
                return retval;
 
        /* Set TX pre-emphasis to minimum */
@@ -338,20 +295,22 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
        analogix_dp_set_training_pattern(dp, TRAINING_PTN1);
 
        /* Set RX training pattern */
-       retval = analogix_dp_write_byte_to_dpcd(dp,
-                       DP_TRAINING_PATTERN_SET,
-                       DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1);
-       if (retval)
+       retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
+                                   DP_LINK_SCRAMBLING_DISABLE |
+                                       DP_TRAINING_PATTERN_1);
+       if (retval < 0)
                return retval;
 
        for (lane = 0; lane < lane_count; lane++)
                buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 |
                            DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
 
-       retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET,
-                                                lane_count, buf);
+       retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf,
+                                  lane_count);
+       if (retval < 0)
+               return retval;
 
-       return retval;
+       return 0;
 }
 
 static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane)
@@ -503,25 +462,23 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp)
 
        lane_count = dp->link_train.lane_count;
 
-       retval =  analogix_dp_read_bytes_from_dpcd(dp,
-                       DP_LANE0_1_STATUS, 2, link_status);
-       if (retval)
+       retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2);
+       if (retval < 0)
                return retval;
 
-       retval =  analogix_dp_read_bytes_from_dpcd(dp,
-                       DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
-       if (retval)
+       retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1,
+                                 adjust_request, 2);
+       if (retval < 0)
                return retval;
 
        if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) {
                /* set training pattern 2 for EQ */
                analogix_dp_set_training_pattern(dp, TRAINING_PTN2);
 
-               retval = analogix_dp_write_byte_to_dpcd(dp,
-                               DP_TRAINING_PATTERN_SET,
-                               DP_LINK_SCRAMBLING_DISABLE |
-                               DP_TRAINING_PATTERN_2);
-               if (retval)
+               retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
+                                           DP_LINK_SCRAMBLING_DISABLE |
+                                               DP_TRAINING_PATTERN_2);
+               if (retval < 0)
                        return retval;
 
                dev_info(dp->dev, "Link Training Clock Recovery success\n");
@@ -559,13 +516,12 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp)
                analogix_dp_set_lane_link_training(dp,
                        dp->link_train.training_lane[lane], lane);
 
-       retval = analogix_dp_write_bytes_to_dpcd(dp,
-                       DP_TRAINING_LANE0_SET, lane_count,
-                       dp->link_train.training_lane);
-       if (retval)
+       retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
+                                  dp->link_train.training_lane, lane_count);
+       if (retval < 0)
                return retval;
 
-       return retval;
+       return 0;
 }
 
 static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
@@ -578,9 +534,8 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
 
        lane_count = dp->link_train.lane_count;
 
-       retval = analogix_dp_read_bytes_from_dpcd(dp,
-                       DP_LANE0_1_STATUS, 2, link_status);
-       if (retval)
+       retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2);
+       if (retval < 0)
                return retval;
 
        if (analogix_dp_clock_recovery_ok(link_status, lane_count)) {
@@ -588,14 +543,14 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
                return -EIO;
        }
 
-       retval = analogix_dp_read_bytes_from_dpcd(dp,
-                       DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
-       if (retval)
+       retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1,
+                                 adjust_request, 2);
+       if (retval < 0)
                return retval;
 
-       retval = analogix_dp_read_byte_from_dpcd(dp,
-                       DP_LANE_ALIGN_STATUS_UPDATED, &link_align);
-       if (retval)
+       retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED,
+                                  &link_align);
+       if (retval < 0)
                return retval;
 
        analogix_dp_get_adjust_training_lane(dp, adjust_request);
@@ -636,10 +591,12 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
                analogix_dp_set_lane_link_training(dp,
                        dp->link_train.training_lane[lane], lane);
 
-       retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET,
-                       lane_count, dp->link_train.training_lane);
+       retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
+                                  dp->link_train.training_lane, lane_count);
+       if (retval < 0)
+               return retval;
 
-       return retval;
+       return 0;
 }
 
 static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp,
@@ -653,7 +610,7 @@ static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp,
         * For DP rev.1.2, Maximum link rate of Main Link lanes
         * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps
         */
-       analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data);
+       drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data);
        *bandwidth = data;
 }
 
@@ -666,7 +623,7 @@ static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp,
         * For DP rev.1.1, Maximum number of Main Link lanes
         * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
         */
-       analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data);
+       drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
        *lane_count = DPCD_MAX_LANE_COUNT(data);
 }
 
@@ -835,19 +792,15 @@ static void analogix_dp_enable_scramble(struct analogix_dp_device *dp,
        if (enable) {
                analogix_dp_enable_scrambling(dp);
 
-               analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET,
-                                               &data);
-               analogix_dp_write_byte_to_dpcd(dp,
-                       DP_TRAINING_PATTERN_SET,
-                       (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE));
+               drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data);
+               drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
+                                  (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE));
        } else {
                analogix_dp_disable_scrambling(dp);
 
-               analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET,
-                                               &data);
-               analogix_dp_write_byte_to_dpcd(dp,
-                       DP_TRAINING_PATTERN_SET,
-                       (u8)(data | DP_LINK_SCRAMBLING_DISABLE));
+               drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data);
+               drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
+                                  (u8)(data | DP_LINK_SCRAMBLING_DISABLE));
        }
 }
 
@@ -921,21 +874,85 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
 
        /* Enable video */
        analogix_dp_start_video(dp);
+
+       dp->psr_support = analogix_dp_detect_sink_psr(dp);
+       if (dp->psr_support)
+               analogix_dp_enable_sink_psr(dp);
 }
 
-int analogix_dp_get_modes(struct drm_connector *connector)
+/*
+ * This function is a bit of a catch-all for panel preparation, hopefully
+ * simplifying the logic of functions that need to prepare/unprepare the panel
+ * below.
+ *
+ * If @prepare is true, this function will prepare the panel. Conversely, if it
+ * is false, the panel will be unprepared.
+ *
+ * If @is_modeset_prepare is true, the function will disregard the current state
+ * of the panel and either prepare/unprepare the panel based on @prepare. Once
+ * it finishes, it will update dp->panel_is_modeset to reflect the current state
+ * of the panel.
+ */
+static int analogix_dp_prepare_panel(struct analogix_dp_device *dp,
+                                    bool prepare, bool is_modeset_prepare)
 {
-       struct analogix_dp_device *dp = to_dp(connector);
-       struct edid *edid = (struct edid *)dp->edid;
-       int num_modes = 0;
+       int ret = 0;
 
-       if (analogix_dp_handle_edid(dp) == 0) {
-               drm_mode_connector_update_edid_property(&dp->connector, edid);
-               num_modes += drm_add_edid_modes(&dp->connector, edid);
-       }
+       if (!dp->plat_data->panel)
+               return 0;
 
-       if (dp->plat_data->panel)
+       mutex_lock(&dp->panel_lock);
+
+       /*
+        * Exit early if this is a temporary prepare/unprepare and we're already
+        * modeset (since we neither want to prepare twice or unprepare early).
+        */
+       if (dp->panel_is_modeset && !is_modeset_prepare)
+               goto out;
+
+       if (prepare)
+               ret = drm_panel_prepare(dp->plat_data->panel);
+       else
+               ret = drm_panel_unprepare(dp->plat_data->panel);
+
+       if (ret)
+               goto out;
+
+       if (is_modeset_prepare)
+               dp->panel_is_modeset = prepare;
+
+out:
+       mutex_unlock(&dp->panel_lock);
+       return ret;
+}
+
+static int analogix_dp_get_modes(struct drm_connector *connector)
+{
+       struct analogix_dp_device *dp = to_dp(connector);
+       struct edid *edid;
+       int ret, num_modes = 0;
+
+       if (dp->plat_data->panel) {
                num_modes += drm_panel_get_modes(dp->plat_data->panel);
+       } else {
+               ret = analogix_dp_prepare_panel(dp, true, false);
+               if (ret) {
+                       DRM_ERROR("Failed to prepare panel (%d)\n", ret);
+                       return 0;
+               }
+
+               edid = drm_get_edid(connector, &dp->aux.ddc);
+               if (edid) {
+                       drm_mode_connector_update_edid_property(&dp->connector,
+                                                               edid);
+                       num_modes += drm_add_edid_modes(&dp->connector, edid);
+                       kfree(edid);
+               }
+
+               ret = analogix_dp_prepare_panel(dp, false, false);
+               if (ret)
+                       DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
+       }
 
        if (dp->plat_data->get_modes)
                num_modes += dp->plat_data->get_modes(dp->plat_data, connector);
@@ -956,29 +973,37 @@ static const struct drm_connector_helper_funcs analogix_dp_connector_helper_func
        .best_encoder = analogix_dp_best_encoder,
 };
 
-enum drm_connector_status
+static enum drm_connector_status
 analogix_dp_detect(struct drm_connector *connector, bool force)
 {
        struct analogix_dp_device *dp = to_dp(connector);
+       enum drm_connector_status status = connector_status_disconnected;
+       int ret;
 
-       if (analogix_dp_detect_hpd(dp))
+       if (dp->plat_data->panel)
+               return connector_status_connected;
+
+       ret = analogix_dp_prepare_panel(dp, true, false);
+       if (ret) {
+               DRM_ERROR("Failed to prepare panel (%d)\n", ret);
                return connector_status_disconnected;
+       }
 
-       return connector_status_connected;
-}
+       if (!analogix_dp_detect_hpd(dp))
+               status = connector_status_connected;
 
-static void analogix_dp_connector_destroy(struct drm_connector *connector)
-{
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
+       ret = analogix_dp_prepare_panel(dp, false, false);
+       if (ret)
+               DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
 
+       return status;
 }
 
 static const struct drm_connector_funcs analogix_dp_connector_funcs = {
        .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = analogix_dp_detect,
-       .destroy = analogix_dp_connector_destroy,
+       .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,
@@ -1035,6 +1060,16 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge)
        return 0;
 }
 
+static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge)
+{
+       struct analogix_dp_device *dp = bridge->driver_private;
+       int ret;
+
+       ret = analogix_dp_prepare_panel(dp, true, true);
+       if (ret)
+               DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+}
+
 static void analogix_dp_bridge_enable(struct drm_bridge *bridge)
 {
        struct analogix_dp_device *dp = bridge->driver_private;
@@ -1058,6 +1093,7 @@ static void analogix_dp_bridge_enable(struct drm_bridge *bridge)
 static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 {
        struct analogix_dp_device *dp = bridge->driver_private;
+       int ret;
 
        if (dp->dpms_mode != DRM_MODE_DPMS_ON)
                return;
@@ -1077,6 +1113,10 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 
        pm_runtime_put_sync(dp->dev);
 
+       ret = analogix_dp_prepare_panel(dp, false, true);
+       if (ret)
+               DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+
        dp->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
@@ -1165,9 +1205,9 @@ static void analogix_dp_bridge_nop(struct drm_bridge *bridge)
 }
 
 static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
+       .pre_enable = analogix_dp_bridge_pre_enable,
        .enable = analogix_dp_bridge_enable,
        .disable = analogix_dp_bridge_disable,
-       .pre_enable = analogix_dp_bridge_nop,
        .post_disable = analogix_dp_bridge_nop,
        .mode_set = analogix_dp_bridge_mode_set,
        .attach = analogix_dp_bridge_attach,
@@ -1231,6 +1271,14 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
        return 0;
 }
 
+static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
+                                      struct drm_dp_aux_msg *msg)
+{
+       struct analogix_dp_device *dp = to_dp(aux);
+
+       return analogix_dp_transfer(dp, msg);
+}
+
 int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
                     struct analogix_dp_plat_data *plat_data)
 {
@@ -1254,6 +1302,9 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
        dp->dev = &pdev->dev;
        dp->dpms_mode = DRM_MODE_DPMS_OFF;
 
+       mutex_init(&dp->panel_lock);
+       dp->panel_is_modeset = false;
+
        /*
         * platform dp driver need containor_of the plat_data to get
         * the driver private data, so we need to store the point of
@@ -1333,13 +1384,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
        phy_power_on(dp->phy);
 
-       if (dp->plat_data->panel) {
-               if (drm_panel_prepare(dp->plat_data->panel)) {
-                       DRM_ERROR("failed to setup the panel\n");
-                       return -EBUSY;
-               }
-       }
-
        analogix_dp_init_dp(dp);
 
        ret = devm_request_threaded_irq(&pdev->dev, dp->irq,
@@ -1355,6 +1399,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
        dp->drm_dev = drm_dev;
        dp->encoder = dp->plat_data->encoder;
 
+       dp->aux.name = "DP-AUX";
+       dp->aux.transfer = analogix_dpaux_transfer;
+       dp->aux.dev = &pdev->dev;
+
+       ret = drm_dp_aux_register(&dp->aux);
+       if (ret)
+               goto err_disable_pm_runtime;
+
        ret = analogix_dp_create_bridge(drm_dev, dp);
        if (ret) {
                DRM_ERROR("failed to create bridge (%d)\n", ret);
index b456380..5c6a288 100644 (file)
 #define MAX_CR_LOOP 5
 #define MAX_EQ_LOOP 5
 
-/* I2C EDID Chip ID, Slave Address */
-#define I2C_EDID_DEVICE_ADDR                   0x50
-#define I2C_E_EDID_DEVICE_ADDR                 0x30
-
-#define EDID_BLOCK_LENGTH                      0x80
-#define EDID_HEADER_PATTERN                    0x00
-#define EDID_EXTENSION_FLAG                    0x7e
-#define EDID_CHECKSUM                          0x7f
-
 /* DP_MAX_LANE_COUNT */
 #define DPCD_ENHANCED_FRAME_CAP(x)             (((x) >> 7) & 0x1)
 #define DPCD_MAX_LANE_COUNT(x)                 ((x) & 0x1f)
@@ -166,6 +157,7 @@ struct analogix_dp_device {
        struct drm_device       *drm_dev;
        struct drm_connector    connector;
        struct drm_bridge       *bridge;
+       struct drm_dp_aux       aux;
        struct clk              *clock;
        unsigned int            irq;
        void __iomem            *reg_base;
@@ -176,7 +168,10 @@ struct analogix_dp_device {
        int                     dpms_mode;
        int                     hpd_gpio;
        bool                    force_hpd;
-       unsigned char           edid[EDID_BLOCK_LENGTH * 2];
+       bool                    psr_support;
+
+       struct mutex            panel_lock;
+       bool                    panel_is_modeset;
 
        struct analogix_dp_plat_data *plat_data;
 };
@@ -206,33 +201,6 @@ void analogix_dp_reset_aux(struct analogix_dp_device *dp);
 void analogix_dp_init_aux(struct analogix_dp_device *dp);
 int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp);
 void analogix_dp_enable_sw_function(struct analogix_dp_device *dp);
-int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp);
-int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp,
-                                  unsigned int reg_addr,
-                                  unsigned char data);
-int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp,
-                                   unsigned int reg_addr,
-                                   unsigned char *data);
-int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp,
-                                   unsigned int reg_addr,
-                                   unsigned int count,
-                                   unsigned char data[]);
-int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp,
-                                    unsigned int reg_addr,
-                                    unsigned int count,
-                                    unsigned char data[]);
-int analogix_dp_select_i2c_device(struct analogix_dp_device *dp,
-                                 unsigned int device_addr,
-                                 unsigned int reg_addr);
-int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp,
-                                  unsigned int device_addr,
-                                  unsigned int reg_addr,
-                                  unsigned int *data);
-int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp,
-                                   unsigned int device_addr,
-                                   unsigned int reg_addr,
-                                   unsigned int count,
-                                   unsigned char edid[]);
 void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype);
 void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype);
 void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count);
@@ -278,4 +246,10 @@ int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp);
 void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
+void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
+void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+                             struct edp_vsc_psr *vsc);
+ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
+                            struct drm_dp_aux_msg *msg);
+
 #endif /* _ANALOGIX_DP_CORE_H */
index 48030f0..cd37ac0 100644 (file)
@@ -585,330 +585,6 @@ int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp,
        return retval;
 }
 
-int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp,
-                                   unsigned int reg_addr,
-                                   unsigned char *data)
-{
-       u32 reg;
-       int i;
-       int retval;
-
-       for (i = 0; i < 3; i++) {
-               /* Clear AUX CH data buffer */
-               reg = BUF_CLR;
-               writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
-
-               /* Select DPCD device address */
-               reg = AUX_ADDR_7_0(reg_addr);
-               writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
-               reg = AUX_ADDR_15_8(reg_addr);
-               writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
-               reg = AUX_ADDR_19_16(reg_addr);
-               writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
-
-               /*
-                * Set DisplayPort transaction and read 1 byte
-                * If bit 3 is 1, DisplayPort transaction.
-                * If Bit 3 is 0, I2C transaction.
-                */
-               reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
-               writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
-
-               /* Start AUX transaction */
-               retval = analogix_dp_start_aux_transaction(dp);
-               if (retval == 0)
-                       break;
-
-               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
-       }
-
-       /* Read data buffer */
-       reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0);
-       *data = (unsigned char)(reg & 0xff);
-
-       return retval;
-}
-
-int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp,
-                                   unsigned int reg_addr,
-                                   unsigned int count,
-                                   unsigned char data[])
-{
-       u32 reg;
-       unsigned int start_offset;
-       unsigned int cur_data_count;
-       unsigned int cur_data_idx;
-       int i;
-       int retval = 0;
-
-       /* Clear AUX CH data buffer */
-       reg = BUF_CLR;
-       writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
-
-       start_offset = 0;
-       while (start_offset < count) {
-               /* Buffer size of AUX CH is 16 * 4bytes */
-               if ((count - start_offset) > 16)
-                       cur_data_count = 16;
-               else
-                       cur_data_count = count - start_offset;
-
-               for (i = 0; i < 3; i++) {
-                       /* Select DPCD device address */
-                       reg = AUX_ADDR_7_0(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
-                       reg = AUX_ADDR_15_8(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
-                       reg = AUX_ADDR_19_16(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
-
-                       for (cur_data_idx = 0; cur_data_idx < cur_data_count;
-                            cur_data_idx++) {
-                               reg = data[start_offset + cur_data_idx];
-                               writel(reg, dp->reg_base +
-                                      ANALOGIX_DP_BUF_DATA_0 +
-                                      4 * cur_data_idx);
-                       }
-
-                       /*
-                        * Set DisplayPort transaction and write
-                        * If bit 3 is 1, DisplayPort transaction.
-                        * If Bit 3 is 0, I2C transaction.
-                        */
-                       reg = AUX_LENGTH(cur_data_count) |
-                               AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
-                       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
-
-                       /* Start AUX transaction */
-                       retval = analogix_dp_start_aux_transaction(dp);
-                       if (retval == 0)
-                               break;
-
-                       dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-                               __func__);
-               }
-
-               start_offset += cur_data_count;
-       }
-
-       return retval;
-}
-
-int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp,
-                                    unsigned int reg_addr,
-                                    unsigned int count,
-                                    unsigned char data[])
-{
-       u32 reg;
-       unsigned int start_offset;
-       unsigned int cur_data_count;
-       unsigned int cur_data_idx;
-       int i;
-       int retval = 0;
-
-       /* Clear AUX CH data buffer */
-       reg = BUF_CLR;
-       writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
-
-       start_offset = 0;
-       while (start_offset < count) {
-               /* Buffer size of AUX CH is 16 * 4bytes */
-               if ((count - start_offset) > 16)
-                       cur_data_count = 16;
-               else
-                       cur_data_count = count - start_offset;
-
-               /* AUX CH Request Transaction process */
-               for (i = 0; i < 3; i++) {
-                       /* Select DPCD device address */
-                       reg = AUX_ADDR_7_0(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
-                       reg = AUX_ADDR_15_8(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
-                       reg = AUX_ADDR_19_16(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
-
-                       /*
-                        * Set DisplayPort transaction and read
-                        * If bit 3 is 1, DisplayPort transaction.
-                        * If Bit 3 is 0, I2C transaction.
-                        */
-                       reg = AUX_LENGTH(cur_data_count) |
-                               AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
-                       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
-
-                       /* Start AUX transaction */
-                       retval = analogix_dp_start_aux_transaction(dp);
-                       if (retval == 0)
-                               break;
-
-                       dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-                               __func__);
-               }
-
-               for (cur_data_idx = 0; cur_data_idx < cur_data_count;
-                   cur_data_idx++) {
-                       reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0
-                                                + 4 * cur_data_idx);
-                       data[start_offset + cur_data_idx] =
-                               (unsigned char)reg;
-               }
-
-               start_offset += cur_data_count;
-       }
-
-       return retval;
-}
-
-int analogix_dp_select_i2c_device(struct analogix_dp_device *dp,
-                                 unsigned int device_addr,
-                                 unsigned int reg_addr)
-{
-       u32 reg;
-       int retval;
-
-       /* Set EDID device address */
-       reg = device_addr;
-       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
-       writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
-       writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
-
-       /* Set offset from base address of EDID device */
-       writel(reg_addr, dp->reg_base + ANALOGIX_DP_BUF_DATA_0);
-
-       /*
-        * Set I2C transaction and write address
-        * If bit 3 is 1, DisplayPort transaction.
-        * If Bit 3 is 0, I2C transaction.
-        */
-       reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
-               AUX_TX_COMM_WRITE;
-       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
-
-       /* Start AUX transaction */
-       retval = analogix_dp_start_aux_transaction(dp);
-       if (retval != 0)
-               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
-
-       return retval;
-}
-
-int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp,
-                                  unsigned int device_addr,
-                                  unsigned int reg_addr,
-                                  unsigned int *data)
-{
-       u32 reg;
-       int i;
-       int retval;
-
-       for (i = 0; i < 3; i++) {
-               /* Clear AUX CH data buffer */
-               reg = BUF_CLR;
-               writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
-
-               /* Select EDID device */
-               retval = analogix_dp_select_i2c_device(dp, device_addr,
-                                                      reg_addr);
-               if (retval != 0)
-                       continue;
-
-               /*
-                * Set I2C transaction and read data
-                * If bit 3 is 1, DisplayPort transaction.
-                * If Bit 3 is 0, I2C transaction.
-                */
-               reg = AUX_TX_COMM_I2C_TRANSACTION |
-                       AUX_TX_COMM_READ;
-               writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
-
-               /* Start AUX transaction */
-               retval = analogix_dp_start_aux_transaction(dp);
-               if (retval == 0)
-                       break;
-
-               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
-       }
-
-       /* Read data */
-       if (retval == 0)
-               *data = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0);
-
-       return retval;
-}
-
-int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp,
-                                   unsigned int device_addr,
-                                   unsigned int reg_addr,
-                                   unsigned int count,
-                                   unsigned char edid[])
-{
-       u32 reg;
-       unsigned int i, j;
-       unsigned int cur_data_idx;
-       unsigned int defer = 0;
-       int retval = 0;
-
-       for (i = 0; i < count; i += 16) {
-               for (j = 0; j < 3; j++) {
-                       /* Clear AUX CH data buffer */
-                       reg = BUF_CLR;
-                       writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
-
-                       /* Set normal AUX CH command */
-                       reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
-                       reg &= ~ADDR_ONLY;
-                       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
-
-                       /*
-                        * If Rx sends defer, Tx sends only reads
-                        * request without sending address
-                        */
-                       if (!defer)
-                               retval = analogix_dp_select_i2c_device(dp,
-                                               device_addr, reg_addr + i);
-                       else
-                               defer = 0;
-
-                       if (retval == 0) {
-                               /*
-                                * Set I2C transaction and write data
-                                * If bit 3 is 1, DisplayPort transaction.
-                                * If Bit 3 is 0, I2C transaction.
-                                */
-                               reg = AUX_LENGTH(16) |
-                                       AUX_TX_COMM_I2C_TRANSACTION |
-                                       AUX_TX_COMM_READ;
-                               writel(reg, dp->reg_base +
-                                       ANALOGIX_DP_AUX_CH_CTL_1);
-
-                               /* Start AUX transaction */
-                               retval = analogix_dp_start_aux_transaction(dp);
-                               if (retval == 0)
-                                       break;
-
-                               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-                                       __func__);
-                       }
-                       /* Check if Rx sends defer */
-                       reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM);
-                       if (reg == AUX_RX_COMM_AUX_DEFER ||
-                           reg == AUX_RX_COMM_I2C_DEFER) {
-                               dev_err(dp->dev, "Defer: %d\n\n", reg);
-                               defer = 1;
-                       }
-               }
-
-               for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
-                       reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0
-                                                + 4 * cur_data_idx);
-                       edid[i + cur_data_idx] = (unsigned char)reg;
-               }
-       }
-
-       return retval;
-}
-
 void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype)
 {
        u32 reg;
@@ -1073,34 +749,22 @@ void analogix_dp_set_lane3_link_training(struct analogix_dp_device *dp,
 
 u32 analogix_dp_get_lane0_link_training(struct analogix_dp_device *dp)
 {
-       u32 reg;
-
-       reg = readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL);
-       return reg;
+       return readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL);
 }
 
 u32 analogix_dp_get_lane1_link_training(struct analogix_dp_device *dp)
 {
-       u32 reg;
-
-       reg = readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL);
-       return reg;
+       return readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL);
 }
 
 u32 analogix_dp_get_lane2_link_training(struct analogix_dp_device *dp)
 {
-       u32 reg;
-
-       reg = readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL);
-       return reg;
+       return readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL);
 }
 
 u32 analogix_dp_get_lane3_link_training(struct analogix_dp_device *dp)
 {
-       u32 reg;
-
-       reg = readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL);
-       return reg;
+       return readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL);
 }
 
 void analogix_dp_reset_macro(struct analogix_dp_device *dp)
@@ -1322,3 +986,181 @@ void analogix_dp_disable_scrambling(struct analogix_dp_device *dp)
        reg |= SCRAMBLING_DISABLE;
        writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
 }
+
+void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp)
+{
+       writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
+}
+
+void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+                             struct edp_vsc_psr *vsc)
+{
+       unsigned int val;
+
+       /* don't send info frame */
+       val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+       val &= ~IF_EN;
+       writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+       /* configure single frame update mode */
+       writel(PSR_FRAME_UP_TYPE_BURST | PSR_CRC_SEL_HARDWARE,
+              dp->reg_base + ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL);
+
+       /* configure VSC HB0~HB3 */
+       writel(vsc->sdp_header.HB0, dp->reg_base + ANALOGIX_DP_SPD_HB0);
+       writel(vsc->sdp_header.HB1, dp->reg_base + ANALOGIX_DP_SPD_HB1);
+       writel(vsc->sdp_header.HB2, dp->reg_base + ANALOGIX_DP_SPD_HB2);
+       writel(vsc->sdp_header.HB3, dp->reg_base + ANALOGIX_DP_SPD_HB3);
+
+       /* configure reused VSC PB0~PB3, magic number from vendor */
+       writel(0x00, dp->reg_base + ANALOGIX_DP_SPD_PB0);
+       writel(0x16, dp->reg_base + ANALOGIX_DP_SPD_PB1);
+       writel(0xCE, dp->reg_base + ANALOGIX_DP_SPD_PB2);
+       writel(0x5D, dp->reg_base + ANALOGIX_DP_SPD_PB3);
+
+       /* configure DB0 / DB1 values */
+       writel(vsc->DB0, dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB0);
+       writel(vsc->DB1, dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB1);
+
+       /* set reuse spd inforframe */
+       val = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);
+       val |= REUSE_SPD_EN;
+       writel(val, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);
+
+       /* mark info frame update */
+       val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+       val = (val | IF_UP) & ~IF_EN;
+       writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+       /* send info frame */
+       val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+       val |= IF_EN;
+       writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+}
+
+ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
+                            struct drm_dp_aux_msg *msg)
+{
+       u32 reg;
+       u8 *buffer = msg->buffer;
+       int timeout_loop = 0;
+       unsigned int i;
+       int num_transferred = 0;
+
+       /* Buffer size of AUX CH is 16 bytes */
+       if (WARN_ON(msg->size > 16))
+               return -E2BIG;
+
+       /* Clear AUX CH data buffer */
+       reg = BUF_CLR;
+       writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
+
+       switch (msg->request & ~DP_AUX_I2C_MOT) {
+       case DP_AUX_I2C_WRITE:
+               reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_I2C_TRANSACTION;
+               if (msg->request & DP_AUX_I2C_MOT)
+                       reg |= AUX_TX_COMM_MOT;
+               break;
+
+       case DP_AUX_I2C_READ:
+               reg = AUX_TX_COMM_READ | AUX_TX_COMM_I2C_TRANSACTION;
+               if (msg->request & DP_AUX_I2C_MOT)
+                       reg |= AUX_TX_COMM_MOT;
+               break;
+
+       case DP_AUX_NATIVE_WRITE:
+               reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_DP_TRANSACTION;
+               break;
+
+       case DP_AUX_NATIVE_READ:
+               reg = AUX_TX_COMM_READ | AUX_TX_COMM_DP_TRANSACTION;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       reg |= AUX_LENGTH(msg->size);
+       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
+
+       /* Select DPCD device address */
+       reg = AUX_ADDR_7_0(msg->address);
+       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
+       reg = AUX_ADDR_15_8(msg->address);
+       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
+       reg = AUX_ADDR_19_16(msg->address);
+       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
+
+       if (!(msg->request & DP_AUX_I2C_READ)) {
+               for (i = 0; i < msg->size; i++) {
+                       reg = buffer[i];
+                       writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0 +
+                              4 * i);
+                       num_transferred++;
+               }
+       }
+
+       /* Enable AUX CH operation */
+       reg = AUX_EN;
+
+       /* Zero-sized messages specify address-only transactions. */
+       if (msg->size < 1)
+               reg |= ADDR_ONLY;
+
+       writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
+
+       /* Is AUX CH command reply received? */
+       /* TODO: Wait for an interrupt instead of looping? */
+       reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
+       while (!(reg & RPLY_RECEIV)) {
+               timeout_loop++;
+               if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
+                       dev_err(dp->dev, "AUX CH command reply failed!\n");
+                       return -ETIMEDOUT;
+               }
+               reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
+               usleep_range(10, 11);
+       }
+
+       /* Clear interrupt source for AUX CH command reply */
+       writel(RPLY_RECEIV, dp->reg_base + ANALOGIX_DP_INT_STA);
+
+       /* Clear interrupt source for AUX CH access error */
+       reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
+       if (reg & AUX_ERR) {
+               writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA);
+               return -EREMOTEIO;
+       }
+
+       /* Check AUX CH error access status */
+       reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA);
+       if ((reg & AUX_STATUS_MASK)) {
+               dev_err(dp->dev, "AUX CH error happened: %d\n\n",
+                       reg & AUX_STATUS_MASK);
+               return -EREMOTEIO;
+       }
+
+       if (msg->request & DP_AUX_I2C_READ) {
+               for (i = 0; i < msg->size; i++) {
+                       reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 +
+                                   4 * i);
+                       buffer[i] = (unsigned char)reg;
+                       num_transferred++;
+               }
+       }
+
+       /* Check if Rx sends defer */
+       reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM);
+       if (reg == AUX_RX_COMM_AUX_DEFER)
+               msg->reply = DP_AUX_NATIVE_REPLY_DEFER;
+       else if (reg == AUX_RX_COMM_I2C_DEFER)
+               msg->reply = DP_AUX_I2C_REPLY_DEFER;
+       else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE ||
+                (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ)
+               msg->reply = DP_AUX_I2C_REPLY_ACK;
+       else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE ||
+                (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ)
+               msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+
+       return num_transferred;
+}
index cdcc6c5..40200c6 100644 (file)
@@ -22,6 +22,8 @@
 #define ANALOGIX_DP_VIDEO_CTL_8                        0x3C
 #define ANALOGIX_DP_VIDEO_CTL_10               0x44
 
+#define ANALOGIX_DP_SPDIF_AUDIO_CTL_0          0xD8
+
 #define ANALOGIX_DP_PLL_REG_1                  0xfc
 #define ANALOGIX_DP_PLL_REG_2                  0x9e4
 #define ANALOGIX_DP_PLL_REG_3                  0x9e8
 
 #define ANALOGIX_DP_PD                         0x12c
 
+#define ANALOGIX_DP_IF_TYPE                    0x244
+#define ANALOGIX_DP_IF_PKT_DB1                 0x254
+#define ANALOGIX_DP_IF_PKT_DB2                 0x258
+#define ANALOGIX_DP_SPD_HB0                    0x2F8
+#define ANALOGIX_DP_SPD_HB1                    0x2FC
+#define ANALOGIX_DP_SPD_HB2                    0x300
+#define ANALOGIX_DP_SPD_HB3                    0x304
+#define ANALOGIX_DP_SPD_PB0                    0x308
+#define ANALOGIX_DP_SPD_PB1                    0x30C
+#define ANALOGIX_DP_SPD_PB2                    0x310
+#define ANALOGIX_DP_SPD_PB3                    0x314
+#define ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL      0x318
+#define ANALOGIX_DP_VSC_SHADOW_DB0             0x31C
+#define ANALOGIX_DP_VSC_SHADOW_DB1             0x320
+
 #define ANALOGIX_DP_LANE_MAP                   0x35C
 
 #define ANALOGIX_DP_ANALOG_CTL_1               0x370
 
 #define ANALOGIX_DP_SOC_GENERAL_CTL            0x800
 
+#define ANALOGIX_DP_CRC_CON                    0x890
+
 /* ANALOGIX_DP_TX_SW_RESET */
 #define RESET_DP_TX                            (0x1 << 0)
 
 #define VID_CHK_UPDATE_TYPE_SHIFT              (4)
 #define VID_CHK_UPDATE_TYPE_1                  (0x1 << 4)
 #define VID_CHK_UPDATE_TYPE_0                  (0x0 << 4)
+#define REUSE_SPD_EN                           (0x1 << 3)
 
 /* ANALOGIX_DP_VIDEO_CTL_8 */
 #define VID_HRES_TH(x)                         (((x) & 0xf) << 4)
 #define REF_CLK_27M                            (0x0 << 0)
 #define REF_CLK_MASK                           (0x1 << 0)
 
+/* ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL */
+#define PSR_FRAME_UP_TYPE_BURST                        (0x1 << 0)
+#define PSR_FRAME_UP_TYPE_SINGLE               (0x0 << 0)
+#define PSR_CRC_SEL_HARDWARE                   (0x1 << 1)
+#define PSR_CRC_SEL_MANUALLY                   (0x0 << 1)
+
 /* ANALOGIX_DP_LANE_MAP */
 #define LANE3_MAP_LOGIC_LANE_0                 (0x0 << 6)
 #define LANE3_MAP_LOGIC_LANE_1                 (0x1 << 6)
 #define VIDEO_MODE_SLAVE_MODE                  (0x1 << 0)
 #define VIDEO_MODE_MASTER_MODE                 (0x0 << 0)
 
+/* ANALOGIX_DP_PKT_SEND_CTL */
+#define IF_UP                                  (0x1 << 4)
+#define IF_EN                                  (0x1 << 0)
+
+/* ANALOGIX_DP_CRC_CON */
+#define PSR_VID_CRC_FLUSH                      (0x1 << 2)
+#define PSR_VID_CRC_ENABLE                     (0x1 << 0)
+
 #endif /* _ANALOGIX_DP_REG_H */
diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
new file mode 100644 (file)
index 0000000..afec232
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2015-2016 Free Electrons
+ * Copyright (C) 2015-2016 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/of_graph.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+struct dumb_vga {
+       struct drm_bridge       bridge;
+       struct drm_connector    connector;
+
+       struct i2c_adapter      *ddc;
+};
+
+static inline struct dumb_vga *
+drm_bridge_to_dumb_vga(struct drm_bridge *bridge)
+{
+       return container_of(bridge, struct dumb_vga, bridge);
+}
+
+static inline struct dumb_vga *
+drm_connector_to_dumb_vga(struct drm_connector *connector)
+{
+       return container_of(connector, struct dumb_vga, connector);
+}
+
+static int dumb_vga_get_modes(struct drm_connector *connector)
+{
+       struct dumb_vga *vga = drm_connector_to_dumb_vga(connector);
+       struct edid *edid;
+       int ret;
+
+       if (IS_ERR(vga->ddc))
+               goto fallback;
+
+       edid = drm_get_edid(connector, vga->ddc);
+       if (!edid) {
+               DRM_INFO("EDID readout failed, falling back to standard modes\n");
+               goto fallback;
+       }
+
+       drm_mode_connector_update_edid_property(connector, edid);
+       return drm_add_edid_modes(connector, edid);
+
+fallback:
+       /*
+        * In case we cannot retrieve the EDIDs (broken or missing i2c
+        * bus), fallback on the XGA standards
+        */
+       ret = drm_add_modes_noedid(connector, 1920, 1200);
+
+       /* And prefer a mode pretty much anyone can handle */
+       drm_set_preferred_mode(connector, 1024, 768);
+
+       return ret;
+}
+
+static const struct drm_connector_helper_funcs dumb_vga_con_helper_funcs = {
+       .get_modes      = dumb_vga_get_modes,
+};
+
+static enum drm_connector_status
+dumb_vga_connector_detect(struct drm_connector *connector, bool force)
+{
+       struct dumb_vga *vga = drm_connector_to_dumb_vga(connector);
+
+       /*
+        * Even if we have an I2C bus, we can't assume that the cable
+        * is disconnected if drm_probe_ddc fails. Some cables don't
+        * wire the DDC pins, or the I2C bus might not be working at
+        * all.
+        */
+       if (!IS_ERR(vga->ddc) && drm_probe_ddc(vga->ddc))
+               return connector_status_connected;
+
+       return connector_status_unknown;
+}
+
+static const struct drm_connector_funcs dumb_vga_con_funcs = {
+       .dpms                   = drm_atomic_helper_connector_dpms,
+       .detect                 = dumb_vga_connector_detect,
+       .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 dumb_vga_attach(struct drm_bridge *bridge)
+{
+       struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge);
+       int ret;
+
+       if (!bridge->encoder) {
+               DRM_ERROR("Missing encoder\n");
+               return -ENODEV;
+       }
+
+       drm_connector_helper_add(&vga->connector,
+                                &dumb_vga_con_helper_funcs);
+       ret = drm_connector_init(bridge->dev, &vga->connector,
+                                &dumb_vga_con_funcs, DRM_MODE_CONNECTOR_VGA);
+       if (ret) {
+               DRM_ERROR("Failed to initialize connector\n");
+               return ret;
+       }
+
+       drm_mode_connector_attach_encoder(&vga->connector,
+                                         bridge->encoder);
+
+       return 0;
+}
+
+static const struct drm_bridge_funcs dumb_vga_bridge_funcs = {
+       .attach         = dumb_vga_attach,
+};
+
+static struct i2c_adapter *dumb_vga_retrieve_ddc(struct device *dev)
+{
+       struct device_node *end_node, *phandle, *remote;
+       struct i2c_adapter *ddc;
+
+       end_node = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
+       if (!end_node) {
+               dev_err(dev, "Missing connector endpoint\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       remote = of_graph_get_remote_port_parent(end_node);
+       of_node_put(end_node);
+       if (!remote) {
+               dev_err(dev, "Enable to parse remote node\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       phandle = of_parse_phandle(remote, "ddc-i2c-bus", 0);
+       of_node_put(remote);
+       if (!phandle)
+               return ERR_PTR(-ENODEV);
+
+       ddc = of_get_i2c_adapter_by_node(phandle);
+       of_node_put(phandle);
+       if (!ddc)
+               return ERR_PTR(-EPROBE_DEFER);
+
+       return ddc;
+}
+
+static int dumb_vga_probe(struct platform_device *pdev)
+{
+       struct dumb_vga *vga;
+       int ret;
+
+       vga = devm_kzalloc(&pdev->dev, sizeof(*vga), GFP_KERNEL);
+       if (!vga)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, vga);
+
+       vga->ddc = dumb_vga_retrieve_ddc(&pdev->dev);
+       if (IS_ERR(vga->ddc)) {
+               if (PTR_ERR(vga->ddc) == -ENODEV) {
+                       dev_dbg(&pdev->dev,
+                               "No i2c bus specified. Disabling EDID readout\n");
+               } else {
+                       dev_err(&pdev->dev, "Couldn't retrieve i2c bus\n");
+                       return PTR_ERR(vga->ddc);
+               }
+       }
+
+       vga->bridge.funcs = &dumb_vga_bridge_funcs;
+       vga->bridge.of_node = pdev->dev.of_node;
+
+       ret = drm_bridge_add(&vga->bridge);
+       if (ret && !IS_ERR(vga->ddc))
+               i2c_put_adapter(vga->ddc);
+
+       return ret;
+}
+
+static int dumb_vga_remove(struct platform_device *pdev)
+{
+       struct dumb_vga *vga = platform_get_drvdata(pdev);
+
+       drm_bridge_remove(&vga->bridge);
+
+       if (!IS_ERR(vga->ddc))
+               i2c_put_adapter(vga->ddc);
+
+       return 0;
+}
+
+static const struct of_device_id dumb_vga_match[] = {
+       { .compatible = "dumb-vga-dac" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dumb_vga_match);
+
+static struct platform_driver dumb_vga_driver = {
+       .probe  = dumb_vga_probe,
+       .remove = dumb_vga_remove,
+       .driver         = {
+               .name           = "dumb-vga-dac",
+               .of_match_table = dumb_vga_match,
+       },
+};
+module_platform_driver(dumb_vga_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Dumb VGA DAC bridge driver");
+MODULE_LICENSE("GPL");
index 122bb01..8f2d137 100644 (file)
@@ -640,7 +640,6 @@ static struct platform_driver snd_dw_hdmi_driver = {
        .remove = snd_dw_hdmi_remove,
        .driver = {
                .name = DRIVER_NAME,
-               .owner = THIS_MODULE,
                .pm = PM_OPS,
        },
 };
index 77ab473..ab7023e 100644 (file)
@@ -940,10 +940,11 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
         */
 
        /*
-        * AVI data byte 1 differences: Colorspace in bits 4,5 rather than 5,6,
-        * active aspect present in bit 6 rather than 4.
+        * AVI data byte 1 differences: Colorspace in bits 0,1 rather than 5,6,
+        * scan info in bits 4,5 rather than 0,1 and active aspect present in
+        * bit 6 rather than 4.
         */
-       val = (frame.colorspace & 3) << 4 | (frame.scan_mode & 0x3);
+       val = (frame.scan_mode & 3) << 4 | (frame.colorspace & 3);
        if (frame.active_aspect & 15)
                val |= HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT;
        if (frame.top_bar || frame.bottom_bar)
@@ -1476,12 +1477,6 @@ dw_hdmi_connector_mode_valid(struct drm_connector *connector,
        return mode_status;
 }
 
-static void dw_hdmi_connector_destroy(struct drm_connector *connector)
-{
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-}
-
 static void dw_hdmi_connector_force(struct drm_connector *connector)
 {
        struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
@@ -1498,7 +1493,7 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
        .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = dw_hdmi_connector_detect,
-       .destroy = dw_hdmi_connector_destroy,
+       .destroy = drm_connector_cleanup,
        .force = dw_hdmi_connector_force,
        .reset = drm_atomic_helper_connector_reset,
        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -1812,9 +1807,6 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
        /* Disable all interrupts */
        hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
 
-       hdmi->connector.funcs->destroy(&hdmi->connector);
-       hdmi->encoder->funcs->destroy(hdmi->encoder);
-
        clk_disable_unprepare(hdmi->iahb_clk);
        clk_disable_unprepare(hdmi->isfr_clk);
        i2c_put_adapter(hdmi->ddc);
index 93f3dac..f1a9993 100644 (file)
@@ -245,16 +245,11 @@ static enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
        return connector_status_connected;
 }
 
-static void ptn3460_connector_destroy(struct drm_connector *connector)
-{
-       drm_connector_cleanup(connector);
-}
-
 static const struct drm_connector_funcs ptn3460_connector_funcs = {
        .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = ptn3460_detect,
-       .destroy = ptn3460_connector_destroy,
+       .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,
index 583b8ce..6f7c2f9 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/backlight.h>
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <linux/fb.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
@@ -484,16 +483,11 @@ static enum drm_connector_status ps8622_detect(struct drm_connector *connector,
        return connector_status_connected;
 }
 
-static void ps8622_connector_destroy(struct drm_connector *connector)
-{
-       drm_connector_cleanup(connector);
-}
-
 static const struct drm_connector_funcs ps8622_connector_funcs = {
        .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = ps8622_detect,
-       .destroy = ps8622_connector_destroy,
+       .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,
index a09825d..44d476e 100644 (file)
@@ -1165,17 +1165,11 @@ static const struct drm_connector_helper_funcs tc_connector_helper_funcs = {
        .best_encoder = tc_connector_best_encoder,
 };
 
-static void tc_connector_destroy(struct drm_connector *connector)
-{
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-}
-
 static const struct drm_connector_funcs tc_connector_funcs = {
        .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = tc_connector_detect,
-       .destroy = tc_connector_destroy,
+       .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,
index b05f7ea..6c76d12 100644 (file)
@@ -57,7 +57,7 @@ static int cirrus_kick_out_firmware_fb(struct pci_dev *pdev)
 #ifdef CONFIG_X86
        primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 #endif
-       remove_conflicting_framebuffers(ap, "cirrusdrmfb", primary);
+       drm_fb_helper_remove_conflicting_framebuffers(ap, "cirrusdrmfb", primary);
        kfree(ap);
 
        return 0;
index 3b5be72..daecf1a 100644 (file)
@@ -13,8 +13,6 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
 
-#include <linux/fb.h>
-
 #include "cirrus_drv.h"
 
 static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
index 1cc9ee6..bb2438d 100644 (file)
@@ -150,7 +150,8 @@ static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *fi
 {
        struct cirrus_bo *cirrusbo = cirrus_bo(bo);
 
-       return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, filp);
+       return drm_vma_node_verify_access(&cirrusbo->gem.vma_node,
+                                         filp->private_data);
 }
 
 static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
index 605bd24..d621c8a 100644 (file)
@@ -430,9 +430,7 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev)
  * intact so it can still be used. It is safe to call this if AGP is disabled or
  * was already removed.
  *
- * If DRIVER_MODESET is active, nothing is done to protect the modesetting
- * resources from getting destroyed. Drivers are responsible of cleaning them up
- * during device shutdown.
+ * Cleanup is only done for drivers who have DRIVER_LEGACY set.
  */
 void drm_legacy_agp_clear(struct drm_device *dev)
 {
@@ -440,7 +438,7 @@ void drm_legacy_agp_clear(struct drm_device *dev)
 
        if (!dev->agp)
                return;
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return;
 
        list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) {
index 2a3ded4..2373960 100644 (file)
@@ -837,8 +837,9 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
        /* Check whether this plane supports the fb pixel format. */
        ret = drm_plane_check_pixel_format(plane, state->fb->pixel_format);
        if (ret) {
-               DRM_DEBUG_ATOMIC("Invalid pixel format %s\n",
-                                drm_get_format_name(state->fb->pixel_format));
+               char *format_name = drm_get_format_name(state->fb->pixel_format);
+               DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", format_name);
+               kfree(format_name);
                return ret;
        }
 
@@ -1690,7 +1691,7 @@ retry:
                                goto out;
                        }
 
-                       prop = drm_property_find(dev, prop_id);
+                       prop = drm_mode_obj_find_prop_id(obj, prop_id);
                        if (!prop) {
                                drm_mode_object_unreference(obj);
                                ret = -ENOENT;
index 20be86d..c3f8347 100644 (file)
@@ -594,7 +594,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
        struct drm_plane_state *plane_state;
        int i, ret = 0;
 
-       ret = drm_atomic_helper_normalize_zpos(dev, state);
+       ret = drm_atomic_normalize_zpos(dev, state);
        if (ret)
                return ret;
 
@@ -749,6 +749,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
                /* Right function depends upon target state. */
                if (crtc->state->enable && funcs->prepare)
                        funcs->prepare(crtc);
+               else if (funcs->atomic_disable)
+                       funcs->atomic_disable(crtc, old_crtc_state);
                else if (funcs->disable)
                        funcs->disable(crtc);
                else
@@ -886,8 +888,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
                 * Each encoder has at most one connector (since we always steal
                 * it away), so we won't call mode_set hooks twice.
                 */
-               if (funcs && funcs->mode_set)
+               if (funcs && funcs->atomic_mode_set) {
+                       funcs->atomic_mode_set(encoder, new_crtc_state,
+                                              connector->state);
+               } else if (funcs && funcs->mode_set) {
                        funcs->mode_set(encoder, mode, adjusted_mode);
+               }
 
                drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
        }
@@ -1003,29 +1009,46 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
  * drm_atomic_helper_wait_for_fences - wait for fences stashed in plane state
  * @dev: DRM device
  * @state: atomic state object with old state structures
+ * @pre_swap: if true, do an interruptible wait
  *
  * For implicit sync, driver should fish the exclusive fence out from the
  * incoming fb's and stash it in the drm_plane_state.  This is called after
  * drm_atomic_helper_swap_state() so it uses the current plane state (and
  * just uses the atomic state to find the changed planes)
+ *
+ * Returns zero if success or < 0 if fence_wait() fails.
  */
-void drm_atomic_helper_wait_for_fences(struct drm_device *dev,
-                           struct drm_atomic_state *state)
+int drm_atomic_helper_wait_for_fences(struct drm_device *dev,
+                                     struct drm_atomic_state *state,
+                                     bool pre_swap)
 {
        struct drm_plane *plane;
        struct drm_plane_state *plane_state;
-       int i;
+       int i, ret;
 
        for_each_plane_in_state(state, plane, plane_state, i) {
-               if (!plane->state->fence)
+               if (!pre_swap)
+                       plane_state = plane->state;
+
+               if (!plane_state->fence)
                        continue;
 
-               WARN_ON(!plane->state->fb);
+               WARN_ON(!plane_state->fb);
+
+               /*
+                * If waiting for fences pre-swap (ie: nonblock), userspace can
+                * still interrupt the operation. Instead of blocking until the
+                * timer expires, make the wait interruptible.
+                */
+               ret = fence_wait(plane_state->fence, pre_swap);
+               if (ret)
+                       return ret;
 
-               fence_wait(plane->state->fence, false);
-               fence_put(plane->state->fence);
-               plane->state->fence = NULL;
+               fence_put(plane_state->fence);
+               plane_state->fence = NULL;
        }
+
+       return 0;
 }
 EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences);
 
@@ -1142,7 +1165,8 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
  *
  *     drm_atomic_helper_commit_modeset_enables(dev, state);
  *
- *     drm_atomic_helper_commit_planes(dev, state, true);
+ *     drm_atomic_helper_commit_planes(dev, state,
+ *                                     DRM_PLANE_COMMIT_ACTIVE_ONLY);
  *
  * for committing the atomic update to hardware.  See the kerneldoc entries for
  * these three functions for more details.
@@ -1153,7 +1177,7 @@ void drm_atomic_helper_commit_tail(struct drm_atomic_state *state)
 
        drm_atomic_helper_commit_modeset_disables(dev, state);
 
-       drm_atomic_helper_commit_planes(dev, state, false);
+       drm_atomic_helper_commit_planes(dev, state, 0);
 
        drm_atomic_helper_commit_modeset_enables(dev, state);
 
@@ -1172,7 +1196,7 @@ static void commit_tail(struct drm_atomic_state *state)
 
        funcs = dev->mode_config.helper_private;
 
-       drm_atomic_helper_wait_for_fences(dev, state);
+       drm_atomic_helper_wait_for_fences(dev, state, false);
 
        drm_atomic_helper_wait_for_dependencies(state);
 
@@ -1231,6 +1255,12 @@ int drm_atomic_helper_commit(struct drm_device *dev,
        if (ret)
                return ret;
 
+       if (!nonblock) {
+               ret = drm_atomic_helper_wait_for_fences(dev, state, true);
+               if (ret)
+                       return ret;
+       }
+
        /*
         * This is the point of no return - everything below never fails except
         * when the hw goes bonghits. Which means we can commit the new state on
@@ -1631,6 +1661,9 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
 
                funcs = plane->helper_private;
 
+               if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc))
+                       continue;
+
                if (funcs->prepare_fb) {
                        ret = funcs->prepare_fb(plane, plane_state);
                        if (ret)
@@ -1647,18 +1680,20 @@ fail:
                if (j >= i)
                        continue;
 
+               if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc))
+                       continue;
+
                funcs = plane->helper_private;
 
                if (funcs->cleanup_fb)
                        funcs->cleanup_fb(plane, plane_state);
-
        }
 
        return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
 
-bool plane_crtc_active(struct drm_plane_state *state)
+static bool plane_crtc_active(const struct drm_plane_state *state)
 {
        return state->crtc && state->crtc->state->active;
 }
@@ -1667,7 +1702,7 @@ bool plane_crtc_active(struct drm_plane_state *state)
  * drm_atomic_helper_commit_planes - commit plane state
  * @dev: DRM device
  * @old_state: atomic state object with old state structures
- * @active_only: Only commit on active CRTC if set
+ * @flags: flags for committing plane state
  *
  * This function commits the new plane state using the plane and atomic helper
  * functions for planes and crtcs. It assumes that the atomic state has already
@@ -1687,25 +1722,34 @@ bool plane_crtc_active(struct drm_plane_state *state)
  * most drivers don't need to be immediately notified of plane updates for a
  * disabled CRTC.
  *
- * Unless otherwise needed, drivers are advised to set the @active_only
- * parameters to true in order not to receive plane update notifications related
- * to a disabled CRTC. This avoids the need to manually ignore plane updates in
+ * Unless otherwise needed, drivers are advised to set the ACTIVE_ONLY flag in
+ * @flags in order not to receive plane update notifications related to a
+ * disabled CRTC. This avoids the need to manually ignore plane updates in
  * driver code when the driver and/or hardware can't or just don't need to deal
  * with updates on disabled CRTCs, for example when supporting runtime PM.
  *
- * The drm_atomic_helper_commit() default implementation only sets @active_only
- * to false to most closely match the behaviour of the legacy helpers. This should
- * not be copied blindly by drivers.
+ * 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.
+ *
+ * The drm_atomic_helper_commit() default implementation doesn't set the
+ * ACTIVE_ONLY flag to most closely match the behaviour of the legacy helpers.
+ * This should not be copied blindly by drivers.
  */
 void drm_atomic_helper_commit_planes(struct drm_device *dev,
                                     struct drm_atomic_state *old_state,
-                                    bool active_only)
+                                    uint32_t flags)
 {
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state;
        struct drm_plane *plane;
        struct drm_plane_state *old_plane_state;
        int i;
+       bool active_only = flags & DRM_PLANE_COMMIT_ACTIVE_ONLY;
+       bool no_disable = flags & DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET;
 
        for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
                const struct drm_crtc_helper_funcs *funcs;
@@ -1749,10 +1793,19 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
                /*
                 * Special-case disabling the plane if drivers support it.
                 */
-               if (disabling && funcs->atomic_disable)
+               if (disabling && funcs->atomic_disable) {
+                       struct drm_crtc_state *crtc_state;
+
+                       crtc_state = old_plane_state->crtc->state;
+
+                       if (drm_atomic_crtc_needs_modeset(crtc_state) &&
+                           no_disable)
+                               continue;
+
                        funcs->atomic_disable(plane, old_plane_state);
-               else if (plane->state->crtc || disabling)
+               } else if (plane->state->crtc || disabling) {
                        funcs->atomic_update(plane, old_plane_state);
+               }
        }
 
        for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
@@ -1831,12 +1884,12 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
 
 /**
  * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes
- * @crtc: CRTC
+ * @old_crtc_state: atomic state object with the old CRTC state
  * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks
  *
  * Disables all planes associated with the given CRTC. This can be
- * used for instance in the CRTC helper disable callback to disable
- * all planes before shutting down the display pipeline.
+ * used for instance in the CRTC helper atomic_disable callback to disable
+ * all planes.
  *
  * If the atomic-parameter is set the function calls the CRTC's
  * atomic_begin hook before and atomic_flush hook after disabling the
@@ -1845,9 +1898,11 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
  * It is a bug to call this function without having implemented the
  * ->atomic_disable() plane hook.
  */
-void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
-                                             bool atomic)
+void
+drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state,
+                                        bool atomic)
 {
+       struct drm_crtc *crtc = old_crtc_state->crtc;
        const struct drm_crtc_helper_funcs *crtc_funcs =
                crtc->helper_private;
        struct drm_plane *plane;
@@ -1855,11 +1910,11 @@ void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
        if (atomic && crtc_funcs && crtc_funcs->atomic_begin)
                crtc_funcs->atomic_begin(crtc, NULL);
 
-       drm_for_each_plane(plane, crtc->dev) {
+       drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {
                const struct drm_plane_helper_funcs *plane_funcs =
                        plane->helper_private;
 
-               if (plane->state->crtc != crtc || !plane_funcs)
+               if (!plane_funcs)
                        continue;
 
                WARN_ON(!plane_funcs->atomic_disable);
@@ -1894,6 +1949,9 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
        for_each_plane_in_state(old_state, plane, plane_state, i) {
                const struct drm_plane_helper_funcs *funcs;
 
+               if (!drm_atomic_helper_framebuffer_changed(dev, old_state, plane_state->crtc))
+                       continue;
+
                funcs = plane->helper_private;
 
                if (funcs->cleanup_fb)
@@ -2354,7 +2412,7 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
        primary_state->crtc_h = vdisplay;
        primary_state->src_x = set->x << 16;
        primary_state->src_y = set->y << 16;
-       if (primary_state->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
+       if (primary_state->rotation & (DRM_ROTATE_90 | DRM_ROTATE_270)) {
                primary_state->src_w = vdisplay << 16;
                primary_state->src_h = hdisplay << 16;
        } else {
@@ -3039,7 +3097,7 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
 
        if (plane->state) {
                plane->state->plane = plane;
-               plane->state->rotation = BIT(DRM_ROTATE_0);
+               plane->state->rotation = DRM_ROTATE_0;
        }
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
index 4153e8a..6b14351 100644 (file)
@@ -251,7 +251,7 @@ void drm_master_release(struct drm_file *file_priv)
        if (!drm_is_current_master(file_priv))
                goto out;
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
+       if (drm_core_check_feature(dev, DRIVER_LEGACY)) {
                /*
                 * Since the master is disappearing, so is the
                 * possibility to lock.
index f3c0942..85172a9 100644 (file)
  */
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
-#include <drm/drm_crtc.h>
+#include <drm/drm_blend.h>
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/sort.h>
 
-#include "drm_internal.h"
+#include "drm_crtc_internal.h"
+
+/**
+ * DOC: overview
+ *
+ * The basic plane composition model supported by standard plane properties only
+ * has a source rectangle (in logical pixels within the &drm_framebuffer), with
+ * 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.
+ *
+ * For the atomic ioctl the following standard (atomic) properties on the plane object
+ * encode the basic plane composition model:
+ *
+ * SRC_X:
+ *     X coordinate offset for the source rectangle within the
+ *     &drm_framebuffer, in 16.16 fixed point. Must be positive.
+ * SRC_Y:
+ *     Y coordinate offset for the source rectangle within the
+ *     &drm_framebuffer, in 16.16 fixed point. Must be positive.
+ * SRC_W:
+ *     Width for the source rectangle within the &drm_framebuffer, in 16.16
+ *     fixed point. SRC_X plus SRC_W must be within the width of the source
+ *     framebuffer. Must be positive.
+ * SRC_H:
+ *     Height for the source rectangle within the &drm_framebuffer, in 16.16
+ *     fixed point. SRC_Y plus SRC_H must be within the height of the source
+ *     framebuffer. Must be positive.
+ * CRTC_X:
+ *     X coordinate offset for the destination rectangle. Can be negative.
+ * CRTC_Y:
+ *     Y coordinate offset for the destination rectangle. Can be negative.
+ * CRTC_W:
+ *     Width for the destination rectangle. CRTC_X plus CRTC_W can extend past
+ *     the currently visible horizontal area of the &drm_crtc.
+ * CRTC_H:
+ *     Height for the destination rectangle. CRTC_Y plus CRTC_H can extend past
+ *     the currently visible vertical area of the &drm_crtc.
+ * FB_ID:
+ *     Mode object ID of the &drm_framebuffer this plane should scan out.
+ * CRTC_ID:
+ *     Mode object ID of the &drm_crtc this plane should be connected to.
+ *
+ * Note that the source rectangle must fully lie within the bounds of the
+ * &drm_framebuffer. The destination rectangle can lie outside of the visible
+ * area of the current mode of the CRTC. It must be apprpriately clipped by the
+ * driver, which can be done by calling drm_plane_helper_check_update(). Drivers
+ * are also allowed to round the subpixel sampling positions appropriately, but
+ * only to the next full pixel. No pixel outside of the source rectangle may
+ * ever be sampled, which is important when applying more sophisticated
+ * filtering than just a bilinear one when scaling. The filtering mode when
+ * scaling is unspecified.
+ *
+ * On top of this basic transformation additional properties can be exposed by
+ * the driver:
+ *
+ * - Rotation is set up with drm_mode_create_rotation_property(). It adds a
+ *   rotation and reflection step between the source and destination rectangles.
+ *   Without this property the rectangle is only scaled, but not rotated or
+ *   reflected.
+ *
+ * - Z position is set up with drm_plane_create_zpos_immutable_property() and
+ *   drm_plane_create_zpos_property(). It controls the visibility of overlapping
+ *   planes. Without this property the primary plane is always below the cursor
+ *   plane, and ordering between all other planes is undefined.
+ *
+ * Note that all the property extensions described here apply either to the
+ * plane or the CRTC (e.g. for the background color, which currently is not
+ * exposed and assumed to be black).
+ */
+
+/**
+ * drm_mode_create_rotation_property - create a new rotation property
+ * @dev: DRM device
+ * @supported_rotations: bitmask of supported rotations and reflections
+ *
+ * This creates a new property with the selected support for transformations.
+ * The resulting property should be stored in @rotation_property in
+ * &drm_mode_config. It then must be attached to each plane which supports
+ * rotations using drm_object_attach_property().
+ *
+ * FIXME: Probably better if the rotation property is created on each plane,
+ * like the zpos property. Otherwise it's not possible to allow different
+ * rotation modes on different planes.
+ *
+ * Since a rotation by 180° degress is the same as reflecting both along the x
+ * and the y axis the rotation property is somewhat redundant. Drivers can use
+ * drm_rotation_simplify() to normalize values of this property.
+ *
+ * The property exposed to userspace is a bitmask property (see
+ * drm_property_create_bitmask()) called "rotation" and has the following
+ * bitmask enumaration values:
+ *
+ * DRM_ROTATE_0:
+ *     "rotate-0"
+ * DRM_ROTATE_90:
+ *     "rotate-90"
+ * DRM_ROTATE_180:
+ *     "rotate-180"
+ * DRM_ROTATE_270:
+ *     "rotate-270"
+ * DRM_REFLECT_X:
+ *     "reflect-x"
+ * DRM_REFELCT_Y:
+ *     "reflect-y"
+ *
+ * Rotation is the specified amount in degrees in counter clockwise direction,
+ * the X and Y axis are within the source rectangle, i.e.  the X/Y axis before
+ * rotation. After reflection, the rotation is applied to the image sampled from
+ * the source rectangle, before scaling it to fit the destination rectangle.
+ */
+struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
+                                                      unsigned int supported_rotations)
+{
+       static const struct drm_prop_enum_list props[] = {
+               { __builtin_ffs(DRM_ROTATE_0) - 1,   "rotate-0" },
+               { __builtin_ffs(DRM_ROTATE_90) - 1,  "rotate-90" },
+               { __builtin_ffs(DRM_ROTATE_180) - 1, "rotate-180" },
+               { __builtin_ffs(DRM_ROTATE_270) - 1, "rotate-270" },
+               { __builtin_ffs(DRM_REFLECT_X) - 1,  "reflect-x" },
+               { __builtin_ffs(DRM_REFLECT_Y) - 1,  "reflect-y" },
+       };
+
+       return drm_property_create_bitmask(dev, 0, "rotation",
+                                          props, ARRAY_SIZE(props),
+                                          supported_rotations);
+}
+EXPORT_SYMBOL(drm_mode_create_rotation_property);
+
+/**
+ * drm_rotation_simplify() - Try to simplify the rotation
+ * @rotation: Rotation to be simplified
+ * @supported_rotations: Supported rotations
+ *
+ * Attempt to simplify the rotation to a form that is supported.
+ * Eg. if the hardware supports everything except DRM_REFLECT_X
+ * one could call this function like this:
+ *
+ * drm_rotation_simplify(rotation, DRM_ROTATE_0 |
+ *                       DRM_ROTATE_90 | DRM_ROTATE_180 |
+ *                       DRM_ROTATE_270 | DRM_REFLECT_Y);
+ *
+ * to eliminate the DRM_ROTATE_X flag. Depending on what kind of
+ * transforms the hardware supports, this function may not
+ * be able to produce a supported transform, so the caller should
+ * check the result afterwards.
+ */
+unsigned int drm_rotation_simplify(unsigned int rotation,
+                                  unsigned int supported_rotations)
+{
+       if (rotation & ~supported_rotations) {
+               rotation ^= DRM_REFLECT_X | DRM_REFLECT_Y;
+               rotation = (rotation & DRM_REFLECT_MASK) |
+                          BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4);
+       }
+
+       return rotation;
+}
+EXPORT_SYMBOL(drm_rotation_simplify);
 
 /**
  * drm_plane_create_zpos_property - create mutable zpos property
  * If zpos of some planes cannot be changed (like fixed background or
  * cursor/topmost planes), driver should adjust min/max values and assign those
  * planes immutable zpos property with lower or higher values (for more
- * information, see drm_mode_create_zpos_immutable_property() function). In such
+ * information, see drm_plane_create_zpos_immutable_property() function). In such
  * case driver should also assign proper initial zpos values for all planes in
  * its plane_reset() callback, so the planes will be always sorted properly.
  *
+ * See also drm_atomic_normalize_zpos().
+ *
+ * The property exposed to userspace is called "zpos".
+ *
  * Returns:
  * Zero on success, negative errno on failure.
  */
@@ -88,7 +253,9 @@ EXPORT_SYMBOL(drm_plane_create_zpos_property);
  * support for it in drm core. Using this property driver lets userspace
  * to get the arrangement of the planes for blending operation and notifies
  * it that the hardware (or driver) doesn't support changing of the planes'
- * order.
+ * order. For mutable zpos see drm_plane_create_zpos_property().
+ *
+ * The property exposed to userspace is called "zpos".
  *
  * Returns:
  * Zero on success, negative errno on failure.
@@ -127,20 +294,6 @@ static int drm_atomic_state_zpos_cmp(const void *a, const void *b)
                return sa->plane->base.id - sb->plane->base.id;
 }
 
-/**
- * drm_atomic_helper_crtc_normalize_zpos - calculate normalized zpos values
- * @crtc: crtc with planes, which have to be considered for normalization
- * @crtc_state: new atomic state to apply
- *
- * This function checks new states of all planes assigned to given crtc and
- * calculates normalized zpos value for them. Planes are compared first by their
- * zpos values, then by plane id (if zpos equals). 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 minus one.
- *
- * RETURNS
- * Zero for success or -errno
- */
 static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,
                                          struct drm_crtc_state *crtc_state)
 {
@@ -193,20 +346,25 @@ done:
 }
 
 /**
- * drm_atomic_helper_normalize_zpos - calculate normalized zpos values for all
- *                                   crtcs
+ * drm_atomic_normalize_zpos - calculate normalized zpos values for all crtcs
  * @dev: DRM device
  * @state: atomic state of DRM device
  *
  * This function calculates normalized zpos value for all modified planes in
- * the provided atomic state of DRM device. For more information, see
- * drm_atomic_helper_crtc_normalize_zpos() function.
+ * the provided atomic state of DRM device.
+ *
+ * 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
+ * minus one.
  *
  * RETURNS
  * Zero for success or -errno
  */
-int drm_atomic_helper_normalize_zpos(struct drm_device *dev,
-                                    struct drm_atomic_state *state)
+int drm_atomic_normalize_zpos(struct drm_device *dev,
+                             struct drm_atomic_state *state)
 {
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
@@ -236,3 +394,4 @@ int drm_atomic_helper_normalize_zpos(struct drm_device *dev,
        }
        return 0;
 }
+EXPORT_SYMBOL(drm_atomic_normalize_zpos);
index 2555430..0ee052b 100644 (file)
 
 #include <linux/err.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 
-#include <drm/drm_crtc.h>
-
-#include "drm/drmP.h"
+#include <drm/drm_bridge.h>
 
 /**
  * DOC: overview
@@ -98,11 +97,11 @@ EXPORT_SYMBOL(drm_bridge_remove);
  * @dev: DRM device
  * @bridge: bridge control structure
  *
- * called by a kms driver to link one of our encoder/bridge to the given
+ * Called by a kms driver to link one of our encoder/bridge to the given
  * bridge.
  *
  * Note that setting up links between the bridge and our encoder/bridge
- * objects needs to be handled by the kms driver itself
+ * objects needs to be handled by the kms driver itself.
  *
  * RETURNS:
  * Zero on success, error code on failure
@@ -124,6 +123,31 @@ int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_attach);
 
+/**
+ * drm_bridge_detach - deassociate given bridge from its DRM device
+ *
+ * @bridge: bridge control structure
+ *
+ * Called by a kms driver to unlink the given bridge from its DRM device.
+ *
+ * Note that tearing down links between the bridge and our encoder/bridge
+ * objects needs to be handled by the kms driver itself.
+ */
+void drm_bridge_detach(struct drm_bridge *bridge)
+{
+       if (WARN_ON(!bridge))
+               return;
+
+       if (WARN_ON(!bridge->dev))
+               return;
+
+       if (bridge->funcs->detach)
+               bridge->funcs->detach(bridge);
+
+       bridge->dev = NULL;
+}
+EXPORT_SYMBOL(drm_bridge_detach);
+
 /**
  * DOC: bridge callbacks
  *
index c3a12cd..adb1dd7 100644 (file)
@@ -397,7 +397,7 @@ int drm_legacy_addmap_ioctl(struct drm_device *dev, void *data,
                return -EPERM;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        err = drm_addmap_core(dev, map->offset, map->size, map->type,
@@ -443,7 +443,7 @@ int drm_legacy_getmap_ioctl(struct drm_device *dev, void *data,
        int i;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        idx = map->offset;
@@ -545,7 +545,7 @@ EXPORT_SYMBOL(drm_legacy_rmmap_locked);
 void drm_legacy_rmmap(struct drm_device *dev, struct drm_local_map *map)
 {
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return;
 
        mutex_lock(&dev->struct_mutex);
@@ -558,7 +558,7 @@ void drm_legacy_master_rmmaps(struct drm_device *dev, struct drm_master *master)
 {
        struct drm_map_list *r_list, *list_temp;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return;
 
        mutex_lock(&dev->struct_mutex);
@@ -595,7 +595,7 @@ int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data,
        int ret;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        mutex_lock(&dev->struct_mutex);
@@ -755,7 +755,7 @@ int drm_legacy_addbufs_agp(struct drm_device *dev,
                return -EINVAL;
        }
 
-       entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
+       entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
@@ -905,14 +905,14 @@ int drm_legacy_addbufs_pci(struct drm_device *dev,
                return -EINVAL;
        }
 
-       entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
+       entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
        }
 
-       entry->seglist = kzalloc(count * sizeof(*entry->seglist), GFP_KERNEL);
+       entry->seglist = kcalloc(count, sizeof(*entry->seglist), GFP_KERNEL);
        if (!entry->seglist) {
                kfree(entry->buflist);
                mutex_unlock(&dev->struct_mutex);
@@ -923,8 +923,9 @@ int drm_legacy_addbufs_pci(struct drm_device *dev,
        /* Keep the original pagelist until we know all the allocations
         * have succeeded
         */
-       temp_pagelist = kmalloc((dma->page_count + (count << page_order)) *
-                              sizeof(*dma->pagelist), GFP_KERNEL);
+       temp_pagelist = kmalloc_array(dma->page_count + (count << page_order),
+                                     sizeof(*dma->pagelist),
+                                     GFP_KERNEL);
        if (!temp_pagelist) {
                kfree(entry->buflist);
                kfree(entry->seglist);
@@ -1116,8 +1117,7 @@ static int drm_legacy_addbufs_sg(struct drm_device *dev,
                return -EINVAL;
        }
 
-       entry->buflist = kzalloc(count * sizeof(*entry->buflist),
-                               GFP_KERNEL);
+       entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
@@ -1220,7 +1220,7 @@ int drm_legacy_addbufs(struct drm_device *dev, void *data,
        struct drm_buf_desc *request = data;
        int ret;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
@@ -1266,7 +1266,7 @@ int drm_legacy_infobufs(struct drm_device *dev, void *data,
        int i;
        int count;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
@@ -1347,7 +1347,7 @@ int drm_legacy_markbufs(struct drm_device *dev, void *data,
        int order;
        struct drm_buf_entry *entry;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
@@ -1395,7 +1395,7 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data,
        int idx;
        struct drm_buf *buf;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
@@ -1450,7 +1450,7 @@ int drm_legacy_mapbufs(struct drm_device *dev, void *data,
        struct drm_buf_map *request = data;
        int i;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
@@ -1530,7 +1530,7 @@ int drm_legacy_mapbufs(struct drm_device *dev, void *data,
 int drm_legacy_dma_ioctl(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (dev->driver->dma_ioctl)
diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c
new file mode 100644 (file)
index 0000000..d28ffdd
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_color_mgmt.h>
+
+#include "drm_crtc_internal.h"
+
+/**
+ * DOC: overview
+ *
+ * Color management or color space adjustments is supported through a set of 5
+ * properties on the &drm_crtc object. They are set up by calling
+ * drm_crtc_enable_color_mgmt().
+ *
+ * "DEGAMMA_LUT”:
+ *     Blob property to set the degamma lookup table (LUT) mapping pixel data
+ *     from the framebuffer before it is given to the transformation matrix.
+ *     The data is interpreted as an array of struct &drm_color_lut elements.
+ *     Hardware might choose not to use the full precision of the LUT elements
+ *     nor use all the elements of the LUT (for example the hardware might
+ *     choose to interpolate between LUT[0] and LUT[4]).
+ *
+ * “DEGAMMA_LUT_SIZE”:
+ *     Unsinged range property to give the size of the lookup table to be set
+ *     on the DEGAMMA_LUT property (the size depends on the underlying
+ *     hardware). If drivers support multiple LUT sizes then they should
+ *     publish the largest size, and sub-sample smaller sized LUTs (e.g. for
+ *     split-gamma modes) appropriately.
+ *
+ * “CTM”:
+ *     Blob property to set the current transformation matrix (CTM) apply to
+ *     pixel data after the lookup through the degamma LUT and before the
+ *     lookup through the gamma LUT. The data is interpreted as a struct
+ *     &drm_color_ctm.
+ *
+ * “GAMMA_LUT”:
+ *     Blob property to set the gamma lookup table (LUT) mapping pixel data
+ *     after the transformation matrix to data sent to the connector. The
+ *     data is interpreted as an array of struct &drm_color_lut elements.
+ *     Hardware might choose not to use the full precision of the LUT elements
+ *     nor use all the elements of the LUT (for example the hardware might
+ *     choose to interpolate between LUT[0] and LUT[4]).
+ *
+ * “GAMMA_LUT_SIZE”:
+ *     Unsigned range property to give the size of the lookup table to be set
+ *     on the GAMMA_LUT property (the size depends on the underlying hardware).
+ *     If drivers support multiple LUT sizes then they should publish the
+ *     largest size, and sub-sample smaller sized LUTs (e.g. for split-gamma
+ *     modes) appropriately.
+ *
+ * There is also support for a legacy gamma table, which is set up by calling
+ * drm_mode_crtc_set_gamma_size(). Drivers which support both should use
+ * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the
+ * "GAMMA_LUT" property above.
+ */
+
+/**
+ * drm_crtc_enable_color_mgmt - enable color management properties
+ * @crtc: DRM CRTC
+ * @degamma_lut_size: the size of the degamma lut (before CSC)
+ * @has_ctm: whether to attach ctm_property for CSC matrix
+ * @gamma_lut_size: the size of the gamma lut (after CSC)
+ *
+ * This function lets the driver enable the color correction
+ * properties on a CRTC. This includes 3 degamma, csc and gamma
+ * properties that userspace can set and 2 size properties to inform
+ * the userspace of the lut sizes. Each of the properties are
+ * optional. The gamma and degamma properties are only attached if
+ * their size is not 0 and ctm_property is only attached if has_ctm is
+ * true.
+ */
+void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
+                               uint degamma_lut_size,
+                               bool has_ctm,
+                               uint gamma_lut_size)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *config = &dev->mode_config;
+
+       if (degamma_lut_size) {
+               drm_object_attach_property(&crtc->base,
+                                          config->degamma_lut_property, 0);
+               drm_object_attach_property(&crtc->base,
+                                          config->degamma_lut_size_property,
+                                          degamma_lut_size);
+       }
+
+       if (has_ctm)
+               drm_object_attach_property(&crtc->base,
+                                          config->ctm_property, 0);
+
+       if (gamma_lut_size) {
+               drm_object_attach_property(&crtc->base,
+                                          config->gamma_lut_property, 0);
+               drm_object_attach_property(&crtc->base,
+                                          config->gamma_lut_size_property,
+                                          gamma_lut_size);
+       }
+}
+EXPORT_SYMBOL(drm_crtc_enable_color_mgmt);
+
+/**
+ * drm_mode_crtc_set_gamma_size - set the gamma table size
+ * @crtc: CRTC to set the gamma table size for
+ * @gamma_size: size of the gamma table
+ *
+ * Drivers which support gamma tables should set this to the supported gamma
+ * table size when initializing the CRTC. Currently the drm core only supports a
+ * fixed gamma table size.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
+                                int gamma_size)
+{
+       uint16_t *r_base, *g_base, *b_base;
+       int i;
+
+       crtc->gamma_size = gamma_size;
+
+       crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
+                                   GFP_KERNEL);
+       if (!crtc->gamma_store) {
+               crtc->gamma_size = 0;
+               return -ENOMEM;
+       }
+
+       r_base = crtc->gamma_store;
+       g_base = r_base + gamma_size;
+       b_base = g_base + gamma_size;
+       for (i = 0; i < gamma_size; i++) {
+               r_base[i] = i << 8;
+               g_base[i] = i << 8;
+               b_base[i] = i << 8;
+       }
+
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
+
+/**
+ * drm_mode_gamma_set_ioctl - set the gamma table
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * Set the gamma table of a CRTC to the one passed in by the user. Userspace can
+ * inquire the required gamma table size through drm_mode_gamma_get_ioctl.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_gamma_set_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc_lut *crtc_lut = data;
+       struct drm_crtc *crtc;
+       void *r_base, *g_base, *b_base;
+       int size;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       drm_modeset_lock_all(dev);
+       crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+       if (!crtc) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       if (crtc->funcs->gamma_set == NULL) {
+               ret = -ENOSYS;
+               goto out;
+       }
+
+       /* memcpy into gamma store */
+       if (crtc_lut->gamma_size != crtc->gamma_size) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       size = crtc_lut->gamma_size * (sizeof(uint16_t));
+       r_base = crtc->gamma_store;
+       if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       g_base = r_base + size;
+       if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       b_base = g_base + size;
+       if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size);
+
+out:
+       drm_modeset_unlock_all(dev);
+       return ret;
+
+}
+
+/**
+ * drm_mode_gamma_get_ioctl - get the gamma table
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * Copy the current gamma table into the storage provided. This also provides
+ * the gamma table size the driver expects, which can be used to size the
+ * allocated storage.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_gamma_get_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc_lut *crtc_lut = data;
+       struct drm_crtc *crtc;
+       void *r_base, *g_base, *b_base;
+       int size;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       drm_modeset_lock_all(dev);
+       crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+       if (!crtc) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       /* memcpy into gamma store */
+       if (crtc_lut->gamma_size != crtc->gamma_size) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       size = crtc_lut->gamma_size * (sizeof(uint16_t));
+       r_base = crtc->gamma_store;
+       if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       g_base = r_base + size;
+       if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       b_base = g_base + size;
+       if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+out:
+       drm_modeset_unlock_all(dev);
+       return ret;
+}
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
new file mode 100644 (file)
index 0000000..2db7fb5
--- /dev/null
@@ -0,0 +1,1123 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_edid.h>
+
+#include "drm_crtc_internal.h"
+#include "drm_internal.h"
+
+/**
+ * DOC: overview
+ *
+ * In DRM connectors are the general abstraction for display sinks, and include
+ * als fixed panels or anything else that can display pixels in some form. As
+ * opposed to all other KMS objects representing hardware (like CRTC, encoder or
+ * plane abstractions) connectors can be hotplugged and unplugged at runtime.
+ * 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().
+ *
+ * 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
+ * attached encoder.
+ *
+ * For connectors which are not fixed (like built-in panels) the driver needs to
+ * support hotplug notifications. The simplest way to do that is by using the
+ * probe helpers, see drm_kms_helper_poll_init() for connectors which don't have
+ * hardware support for hotplug interrupts. Connectors with hardware hotplug
+ * support can instead use e.g. drm_helper_hpd_irq_event().
+ */
+
+struct drm_conn_prop_enum_list {
+       int type;
+       const char *name;
+       struct ida ida;
+};
+
+/*
+ * Connector and encoder types.
+ */
+static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
+       { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
+       { DRM_MODE_CONNECTOR_VGA, "VGA" },
+       { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
+       { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
+       { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
+       { DRM_MODE_CONNECTOR_Composite, "Composite" },
+       { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
+       { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
+       { DRM_MODE_CONNECTOR_Component, "Component" },
+       { DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
+       { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
+       { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
+       { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
+       { DRM_MODE_CONNECTOR_TV, "TV" },
+       { DRM_MODE_CONNECTOR_eDP, "eDP" },
+       { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
+       { DRM_MODE_CONNECTOR_DSI, "DSI" },
+       { DRM_MODE_CONNECTOR_DPI, "DPI" },
+};
+
+void drm_connector_ida_init(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
+               ida_init(&drm_connector_enum_list[i].ida);
+}
+
+void drm_connector_ida_destroy(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
+               ida_destroy(&drm_connector_enum_list[i].ida);
+}
+
+/**
+ * drm_connector_get_cmdline_mode - reads the user's cmdline mode
+ * @connector: connector to quwery
+ *
+ * The kernel supports per-connector configuration of its consoles through
+ * use of the video= parameter. This function parses that option and
+ * extracts the user's specified mode (or enable/disable status) for a
+ * particular connector. This is typically only used during the early fbdev
+ * setup.
+ */
+static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
+{
+       struct drm_cmdline_mode *mode = &connector->cmdline_mode;
+       char *option = NULL;
+
+       if (fb_get_options(connector->name, &option))
+               return;
+
+       if (!drm_mode_parse_command_line_for_connector(option,
+                                                      connector,
+                                                      mode))
+               return;
+
+       if (mode->force) {
+               const char *s;
+
+               switch (mode->force) {
+               case DRM_FORCE_OFF:
+                       s = "OFF";
+                       break;
+               case DRM_FORCE_ON_DIGITAL:
+                       s = "ON - dig";
+                       break;
+               default:
+               case DRM_FORCE_ON:
+                       s = "ON";
+                       break;
+               }
+
+               DRM_INFO("forcing %s connector %s\n", connector->name, s);
+               connector->force = mode->force;
+       }
+
+       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+                     connector->name,
+                     mode->xres, mode->yres,
+                     mode->refresh_specified ? mode->refresh : 60,
+                     mode->rb ? " reduced blanking" : "",
+                     mode->margins ? " with margins" : "",
+                     mode->interlace ?  " interlaced" : "");
+}
+
+static void drm_connector_free(struct kref *kref)
+{
+       struct drm_connector *connector =
+               container_of(kref, struct drm_connector, base.refcount);
+       struct drm_device *dev = connector->dev;
+
+       drm_mode_object_unregister(dev, &connector->base);
+       connector->funcs->destroy(connector);
+}
+
+/**
+ * drm_connector_init - Init a preallocated connector
+ * @dev: DRM device
+ * @connector: the connector to init
+ * @funcs: callbacks for this connector
+ * @connector_type: user visible type of the connector
+ *
+ * Initialises a preallocated connector. Connectors should be
+ * subclassed as part of driver connector objects.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_connector_init(struct drm_device *dev,
+                      struct drm_connector *connector,
+                      const struct drm_connector_funcs *funcs,
+                      int connector_type)
+{
+       struct drm_mode_config *config = &dev->mode_config;
+       int ret;
+       struct ida *connector_ida =
+               &drm_connector_enum_list[connector_type].ida;
+
+       drm_modeset_lock_all(dev);
+
+       ret = drm_mode_object_get_reg(dev, &connector->base,
+                                     DRM_MODE_OBJECT_CONNECTOR,
+                                     false, drm_connector_free);
+       if (ret)
+               goto out_unlock;
+
+       connector->base.properties = &connector->properties;
+       connector->dev = dev;
+       connector->funcs = funcs;
+
+       ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL);
+       if (ret < 0)
+               goto out_put;
+       connector->index = ret;
+       ret = 0;
+
+       connector->connector_type = connector_type;
+       connector->connector_type_id =
+               ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
+       if (connector->connector_type_id < 0) {
+               ret = connector->connector_type_id;
+               goto out_put_id;
+       }
+       connector->name =
+               kasprintf(GFP_KERNEL, "%s-%d",
+                         drm_connector_enum_list[connector_type].name,
+                         connector->connector_type_id);
+       if (!connector->name) {
+               ret = -ENOMEM;
+               goto out_put_type_id;
+       }
+
+       INIT_LIST_HEAD(&connector->probed_modes);
+       INIT_LIST_HEAD(&connector->modes);
+       connector->edid_blob_ptr = NULL;
+       connector->status = connector_status_unknown;
+
+       drm_connector_get_cmdline_mode(connector);
+
+       /* We should add connectors at the end to avoid upsetting the connector
+        * index too much. */
+       list_add_tail(&connector->head, &config->connector_list);
+       config->num_connector++;
+
+       if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
+               drm_object_attach_property(&connector->base,
+                                             config->edid_property,
+                                             0);
+
+       drm_object_attach_property(&connector->base,
+                                     config->dpms_property, 0);
+
+       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+               drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
+       }
+
+       connector->debugfs_entry = NULL;
+out_put_type_id:
+       if (ret)
+               ida_simple_remove(connector_ida, connector->connector_type_id);
+out_put_id:
+       if (ret)
+               ida_simple_remove(&config->connector_ida, connector->index);
+out_put:
+       if (ret)
+               drm_mode_object_unregister(dev, &connector->base);
+
+out_unlock:
+       drm_modeset_unlock_all(dev);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_connector_init);
+
+/**
+ * drm_mode_connector_attach_encoder - attach a connector to an encoder
+ * @connector: connector to attach
+ * @encoder: encoder to attach @connector to
+ *
+ * This function links up a connector to an encoder. Note that the routing
+ * restrictions between encoders and crtcs are exposed to userspace through the
+ * possible_clones and possible_crtcs bitmasks.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_connector_attach_encoder(struct drm_connector *connector,
+                                     struct drm_encoder *encoder)
+{
+       int i;
+
+       /*
+        * In the past, drivers have attempted to model the static association
+        * of connector to encoder in simple connector/encoder devices using a
+        * direct assignment of connector->encoder = encoder. This connection
+        * is a logical one and the responsibility of the core, so drivers are
+        * expected not to mess with this.
+        *
+        * Note that the error return should've been enough here, but a large
+        * majority of drivers ignores the return value, so add in a big WARN
+        * to get people's attention.
+        */
+       if (WARN_ON(connector->encoder))
+               return -EINVAL;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0) {
+                       connector->encoder_ids[i] = encoder->base.id;
+                       return 0;
+               }
+       }
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
+
+static void drm_mode_remove(struct drm_connector *connector,
+                           struct drm_display_mode *mode)
+{
+       list_del(&mode->head);
+       drm_mode_destroy(connector->dev, mode);
+}
+
+/**
+ * drm_connector_cleanup - cleans up an initialised connector
+ * @connector: connector to cleanup
+ *
+ * Cleans up the connector but doesn't free the object.
+ */
+void drm_connector_cleanup(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_display_mode *mode, *t;
+
+       /* The connector should have been removed from userspace long before
+        * it is finally destroyed.
+        */
+       if (WARN_ON(connector->registered))
+               drm_connector_unregister(connector);
+
+       if (connector->tile_group) {
+               drm_mode_put_tile_group(dev, connector->tile_group);
+               connector->tile_group = NULL;
+       }
+
+       list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
+               drm_mode_remove(connector, mode);
+
+       list_for_each_entry_safe(mode, t, &connector->modes, head)
+               drm_mode_remove(connector, mode);
+
+       ida_simple_remove(&drm_connector_enum_list[connector->connector_type].ida,
+                         connector->connector_type_id);
+
+       ida_simple_remove(&dev->mode_config.connector_ida,
+                         connector->index);
+
+       kfree(connector->display_info.bus_formats);
+       drm_mode_object_unregister(dev, &connector->base);
+       kfree(connector->name);
+       connector->name = NULL;
+       list_del(&connector->head);
+       dev->mode_config.num_connector--;
+
+       WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
+       if (connector->state && connector->funcs->atomic_destroy_state)
+               connector->funcs->atomic_destroy_state(connector,
+                                                      connector->state);
+
+       memset(connector, 0, sizeof(*connector));
+}
+EXPORT_SYMBOL(drm_connector_cleanup);
+
+/**
+ * drm_connector_register - register a connector
+ * @connector: the connector to register
+ *
+ * Register userspace interfaces for a connector
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_connector_register(struct drm_connector *connector)
+{
+       int ret;
+
+       if (connector->registered)
+               return 0;
+
+       ret = drm_sysfs_connector_add(connector);
+       if (ret)
+               return ret;
+
+       ret = drm_debugfs_connector_add(connector);
+       if (ret) {
+               goto err_sysfs;
+       }
+
+       if (connector->funcs->late_register) {
+               ret = connector->funcs->late_register(connector);
+               if (ret)
+                       goto err_debugfs;
+       }
+
+       drm_mode_object_register(connector->dev, &connector->base);
+
+       connector->registered = true;
+       return 0;
+
+err_debugfs:
+       drm_debugfs_connector_remove(connector);
+err_sysfs:
+       drm_sysfs_connector_remove(connector);
+       return ret;
+}
+EXPORT_SYMBOL(drm_connector_register);
+
+/**
+ * drm_connector_unregister - unregister a connector
+ * @connector: the connector to unregister
+ *
+ * Unregister userspace interfaces for a connector
+ */
+void drm_connector_unregister(struct drm_connector *connector)
+{
+       if (!connector->registered)
+               return;
+
+       if (connector->funcs->early_unregister)
+               connector->funcs->early_unregister(connector);
+
+       drm_sysfs_connector_remove(connector);
+       drm_debugfs_connector_remove(connector);
+
+       connector->registered = false;
+}
+EXPORT_SYMBOL(drm_connector_unregister);
+
+void drm_connector_unregister_all(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+
+       /* FIXME: taking the mode config mutex ends up in a clash with sysfs */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               drm_connector_unregister(connector);
+}
+
+int drm_connector_register_all(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+       int ret;
+
+       /* FIXME: taking the mode config mutex ends up in a clash with
+        * fbcon/backlight registration */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               ret = drm_connector_register(connector);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       mutex_unlock(&dev->mode_config.mutex);
+       drm_connector_unregister_all(dev);
+       return ret;
+}
+
+/**
+ * drm_get_connector_status_name - return a string for connector status
+ * @status: connector status to compute name of
+ *
+ * In contrast to the other drm_get_*_name functions this one here returns a
+ * const pointer and hence is threadsafe.
+ */
+const char *drm_get_connector_status_name(enum drm_connector_status status)
+{
+       if (status == connector_status_connected)
+               return "connected";
+       else if (status == connector_status_disconnected)
+               return "disconnected";
+       else
+               return "unknown";
+}
+EXPORT_SYMBOL(drm_get_connector_status_name);
+
+static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
+       { SubPixelUnknown, "Unknown" },
+       { SubPixelHorizontalRGB, "Horizontal RGB" },
+       { SubPixelHorizontalBGR, "Horizontal BGR" },
+       { SubPixelVerticalRGB, "Vertical RGB" },
+       { SubPixelVerticalBGR, "Vertical BGR" },
+       { SubPixelNone, "None" },
+};
+
+/**
+ * drm_get_subpixel_order_name - return a string for a given subpixel enum
+ * @order: enum of subpixel_order
+ *
+ * Note you could abuse this and return something out of bounds, but that
+ * would be a caller error.  No unscrubbed user data should make it here.
+ */
+const char *drm_get_subpixel_order_name(enum subpixel_order order)
+{
+       return drm_subpixel_enum_list[order].name;
+}
+EXPORT_SYMBOL(drm_get_subpixel_order_name);
+
+static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
+       { DRM_MODE_DPMS_ON, "On" },
+       { DRM_MODE_DPMS_STANDBY, "Standby" },
+       { DRM_MODE_DPMS_SUSPEND, "Suspend" },
+       { DRM_MODE_DPMS_OFF, "Off" }
+};
+DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
+
+/**
+ * drm_display_info_set_bus_formats - set the supported bus formats
+ * @info: display info to store bus formats in
+ * @formats: array containing the supported bus formats
+ * @num_formats: the number of entries in the fmts array
+ *
+ * Store the supported bus formats in display info structure.
+ * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for
+ * a full list of available formats.
+ */
+int drm_display_info_set_bus_formats(struct drm_display_info *info,
+                                    const u32 *formats,
+                                    unsigned int num_formats)
+{
+       u32 *fmts = NULL;
+
+       if (!formats && num_formats)
+               return -EINVAL;
+
+       if (formats && num_formats) {
+               fmts = kmemdup(formats, sizeof(*formats) * num_formats,
+                              GFP_KERNEL);
+               if (!fmts)
+                       return -ENOMEM;
+       }
+
+       kfree(info->bus_formats);
+       info->bus_formats = fmts;
+       info->num_bus_formats = num_formats;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_display_info_set_bus_formats);
+
+/* Optional connector properties. */
+static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = {
+       { DRM_MODE_SCALE_NONE, "None" },
+       { DRM_MODE_SCALE_FULLSCREEN, "Full" },
+       { DRM_MODE_SCALE_CENTER, "Center" },
+       { DRM_MODE_SCALE_ASPECT, "Full aspect" },
+};
+
+static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
+       { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" },
+       { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" },
+       { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" },
+};
+
+static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
+       { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
+       { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
+};
+DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
+
+static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
+       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
+       { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
+};
+DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
+                drm_dvi_i_subconnector_enum_list)
+
+static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
+       { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
+};
+DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
+
+static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
+       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
+};
+DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
+                drm_tv_subconnector_enum_list)
+
+int drm_connector_create_standard_properties(struct drm_device *dev)
+{
+       struct drm_property *prop;
+
+       prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+                                  DRM_MODE_PROP_IMMUTABLE,
+                                  "EDID", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.edid_property = prop;
+
+       prop = drm_property_create_enum(dev, 0,
+                                  "DPMS", drm_dpms_enum_list,
+                                  ARRAY_SIZE(drm_dpms_enum_list));
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.dpms_property = prop;
+
+       prop = drm_property_create(dev,
+                                  DRM_MODE_PROP_BLOB |
+                                  DRM_MODE_PROP_IMMUTABLE,
+                                  "PATH", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.path_property = prop;
+
+       prop = drm_property_create(dev,
+                                  DRM_MODE_PROP_BLOB |
+                                  DRM_MODE_PROP_IMMUTABLE,
+                                  "TILE", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.tile_property = prop;
+
+       return 0;
+}
+
+/**
+ * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
+ * @dev: DRM device
+ *
+ * Called by a driver the first time a DVI-I connector is made.
+ */
+int drm_mode_create_dvi_i_properties(struct drm_device *dev)
+{
+       struct drm_property *dvi_i_selector;
+       struct drm_property *dvi_i_subconnector;
+
+       if (dev->mode_config.dvi_i_select_subconnector_property)
+               return 0;
+
+       dvi_i_selector =
+               drm_property_create_enum(dev, 0,
+                                   "select subconnector",
+                                   drm_dvi_i_select_enum_list,
+                                   ARRAY_SIZE(drm_dvi_i_select_enum_list));
+       dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
+
+       dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+                                   "subconnector",
+                                   drm_dvi_i_subconnector_enum_list,
+                                   ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
+       dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
+
+/**
+ * drm_create_tv_properties - create TV specific connector properties
+ * @dev: DRM device
+ * @num_modes: number of different TV formats (modes) supported
+ * @modes: array of pointers to strings containing name of each format
+ *
+ * Called by a driver's TV initialization routine, this function creates
+ * the TV specific connector properties for a given device.  Caller is
+ * responsible for allocating a list of format names and passing them to
+ * this routine.
+ */
+int drm_mode_create_tv_properties(struct drm_device *dev,
+                                 unsigned int num_modes,
+                                 const char * const modes[])
+{
+       struct drm_property *tv_selector;
+       struct drm_property *tv_subconnector;
+       unsigned int i;
+
+       if (dev->mode_config.tv_select_subconnector_property)
+               return 0;
+
+       /*
+        * Basic connector properties
+        */
+       tv_selector = drm_property_create_enum(dev, 0,
+                                         "select subconnector",
+                                         drm_tv_select_enum_list,
+                                         ARRAY_SIZE(drm_tv_select_enum_list));
+       if (!tv_selector)
+               goto nomem;
+
+       dev->mode_config.tv_select_subconnector_property = tv_selector;
+
+       tv_subconnector =
+               drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+                                   "subconnector",
+                                   drm_tv_subconnector_enum_list,
+                                   ARRAY_SIZE(drm_tv_subconnector_enum_list));
+       if (!tv_subconnector)
+               goto nomem;
+       dev->mode_config.tv_subconnector_property = tv_subconnector;
+
+       /*
+        * Other, TV specific properties: margins & TV modes.
+        */
+       dev->mode_config.tv_left_margin_property =
+               drm_property_create_range(dev, 0, "left margin", 0, 100);
+       if (!dev->mode_config.tv_left_margin_property)
+               goto nomem;
+
+       dev->mode_config.tv_right_margin_property =
+               drm_property_create_range(dev, 0, "right margin", 0, 100);
+       if (!dev->mode_config.tv_right_margin_property)
+               goto nomem;
+
+       dev->mode_config.tv_top_margin_property =
+               drm_property_create_range(dev, 0, "top margin", 0, 100);
+       if (!dev->mode_config.tv_top_margin_property)
+               goto nomem;
+
+       dev->mode_config.tv_bottom_margin_property =
+               drm_property_create_range(dev, 0, "bottom margin", 0, 100);
+       if (!dev->mode_config.tv_bottom_margin_property)
+               goto nomem;
+
+       dev->mode_config.tv_mode_property =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                   "mode", num_modes);
+       if (!dev->mode_config.tv_mode_property)
+               goto nomem;
+
+       for (i = 0; i < num_modes; i++)
+               drm_property_add_enum(dev->mode_config.tv_mode_property, i,
+                                     i, modes[i]);
+
+       dev->mode_config.tv_brightness_property =
+               drm_property_create_range(dev, 0, "brightness", 0, 100);
+       if (!dev->mode_config.tv_brightness_property)
+               goto nomem;
+
+       dev->mode_config.tv_contrast_property =
+               drm_property_create_range(dev, 0, "contrast", 0, 100);
+       if (!dev->mode_config.tv_contrast_property)
+               goto nomem;
+
+       dev->mode_config.tv_flicker_reduction_property =
+               drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
+       if (!dev->mode_config.tv_flicker_reduction_property)
+               goto nomem;
+
+       dev->mode_config.tv_overscan_property =
+               drm_property_create_range(dev, 0, "overscan", 0, 100);
+       if (!dev->mode_config.tv_overscan_property)
+               goto nomem;
+
+       dev->mode_config.tv_saturation_property =
+               drm_property_create_range(dev, 0, "saturation", 0, 100);
+       if (!dev->mode_config.tv_saturation_property)
+               goto nomem;
+
+       dev->mode_config.tv_hue_property =
+               drm_property_create_range(dev, 0, "hue", 0, 100);
+       if (!dev->mode_config.tv_hue_property)
+               goto nomem;
+
+       return 0;
+nomem:
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(drm_mode_create_tv_properties);
+
+/**
+ * drm_mode_create_scaling_mode_property - create scaling mode property
+ * @dev: DRM device
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ */
+int drm_mode_create_scaling_mode_property(struct drm_device *dev)
+{
+       struct drm_property *scaling_mode;
+
+       if (dev->mode_config.scaling_mode_property)
+               return 0;
+
+       scaling_mode =
+               drm_property_create_enum(dev, 0, "scaling mode",
+                               drm_scaling_mode_enum_list,
+                                   ARRAY_SIZE(drm_scaling_mode_enum_list));
+
+       dev->mode_config.scaling_mode_property = scaling_mode;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
+
+/**
+ * drm_mode_create_aspect_ratio_property - create aspect ratio property
+ * @dev: DRM device
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
+{
+       if (dev->mode_config.aspect_ratio_property)
+               return 0;
+
+       dev->mode_config.aspect_ratio_property =
+               drm_property_create_enum(dev, 0, "aspect ratio",
+                               drm_aspect_ratio_enum_list,
+                               ARRAY_SIZE(drm_aspect_ratio_enum_list));
+
+       if (dev->mode_config.aspect_ratio_property == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property);
+
+/**
+ * drm_mode_create_suggested_offset_properties - create suggests offset properties
+ * @dev: DRM device
+ *
+ * Create the the suggested x/y offset property for connectors.
+ */
+int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
+{
+       if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property)
+               return 0;
+
+       dev->mode_config.suggested_x_property =
+               drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff);
+
+       dev->mode_config.suggested_y_property =
+               drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff);
+
+       if (dev->mode_config.suggested_x_property == NULL ||
+           dev->mode_config.suggested_y_property == NULL)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties);
+
+/**
+ * drm_mode_connector_set_path_property - set tile property on connector
+ * @connector: connector to set property on.
+ * @path: path to use for property; must not be NULL.
+ *
+ * This creates a property to expose to userspace to specify a
+ * connector path. This is mainly used for DisplayPort MST where
+ * connectors have a topology and we want to allow userspace to give
+ * them more meaningful names.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_connector_set_path_property(struct drm_connector *connector,
+                                        const char *path)
+{
+       struct drm_device *dev = connector->dev;
+       int ret;
+
+       ret = drm_property_replace_global_blob(dev,
+                                              &connector->path_blob_ptr,
+                                              strlen(path) + 1,
+                                              path,
+                                              &connector->base,
+                                              dev->mode_config.path_property);
+       return ret;
+}
+EXPORT_SYMBOL(drm_mode_connector_set_path_property);
+
+/**
+ * drm_mode_connector_set_tile_property - set tile property on connector
+ * @connector: connector to set property on.
+ *
+ * This looks up the tile information for a connector, and creates a
+ * property for userspace to parse if it exists. The property is of
+ * the form of 8 integers using ':' as a separator.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_connector_set_tile_property(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       char tile[256];
+       int ret;
+
+       if (!connector->has_tile) {
+               ret  = drm_property_replace_global_blob(dev,
+                                                       &connector->tile_blob_ptr,
+                                                       0,
+                                                       NULL,
+                                                       &connector->base,
+                                                       dev->mode_config.tile_property);
+               return ret;
+       }
+
+       snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d",
+                connector->tile_group->id, connector->tile_is_single_monitor,
+                connector->num_h_tile, connector->num_v_tile,
+                connector->tile_h_loc, connector->tile_v_loc,
+                connector->tile_h_size, connector->tile_v_size);
+
+       ret = drm_property_replace_global_blob(dev,
+                                              &connector->tile_blob_ptr,
+                                              strlen(tile) + 1,
+                                              tile,
+                                              &connector->base,
+                                              dev->mode_config.tile_property);
+       return ret;
+}
+EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
+
+/**
+ * drm_mode_connector_update_edid_property - update the edid property of a connector
+ * @connector: drm connector
+ * @edid: new value of the edid property
+ *
+ * This function creates a new blob modeset object and assigns its id to the
+ * connector's edid property.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_connector_update_edid_property(struct drm_connector *connector,
+                                           const struct edid *edid)
+{
+       struct drm_device *dev = connector->dev;
+       size_t size = 0;
+       int ret;
+
+       /* ignore requests to set edid when overridden */
+       if (connector->override_edid)
+               return 0;
+
+       if (edid)
+               size = EDID_LENGTH * (1 + edid->extensions);
+
+       ret = drm_property_replace_global_blob(dev,
+                                              &connector->edid_blob_ptr,
+                                              size,
+                                              edid,
+                                              &connector->base,
+                                              dev->mode_config.edid_property);
+       return ret;
+}
+EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
+
+int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
+                                   struct drm_property *property,
+                                   uint64_t value)
+{
+       int ret = -EINVAL;
+       struct drm_connector *connector = obj_to_connector(obj);
+
+       /* Do DPMS ourselves */
+       if (property == connector->dev->mode_config.dpms_property) {
+               ret = (*connector->funcs->dpms)(connector, (int)value);
+       } else if (connector->funcs->set_property)
+               ret = connector->funcs->set_property(connector, property, value);
+
+       /* store the property value if successful */
+       if (!ret)
+               drm_object_property_set_value(&connector->base, property, value);
+       return ret;
+}
+
+int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
+                                      void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_connector_set_property *conn_set_prop = data;
+       struct drm_mode_obj_set_property obj_set_prop = {
+               .value = conn_set_prop->value,
+               .prop_id = conn_set_prop->prop_id,
+               .obj_id = conn_set_prop->connector_id,
+               .obj_type = DRM_MODE_OBJECT_CONNECTOR
+       };
+
+       /* It does all the locking and checking we need */
+       return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
+}
+
+static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
+{
+       /* For atomic drivers only state objects are synchronously updated and
+        * protected by modeset locks, so check those first. */
+       if (connector->state)
+               return connector->state->best_encoder;
+       return connector->encoder;
+}
+
+static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
+                                        const struct drm_file *file_priv)
+{
+       /*
+        * If user-space hasn't configured the driver to expose the stereo 3D
+        * modes, don't expose them.
+        */
+       if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode))
+               return false;
+
+       return true;
+}
+
+int drm_mode_getconnector(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+       struct drm_mode_get_connector *out_resp = data;
+       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       struct drm_display_mode *mode;
+       int mode_count = 0;
+       int encoders_count = 0;
+       int ret = 0;
+       int copied = 0;
+       int i;
+       struct drm_mode_modeinfo u_mode;
+       struct drm_mode_modeinfo __user *mode_ptr;
+       uint32_t __user *encoder_ptr;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       connector = drm_connector_lookup(dev, out_resp->connector_id);
+       if (!connector) {
+               ret = -ENOENT;
+               goto out_unlock;
+       }
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
+               if (connector->encoder_ids[i] != 0)
+                       encoders_count++;
+
+       if (out_resp->count_modes == 0) {
+               connector->funcs->fill_modes(connector,
+                                            dev->mode_config.max_width,
+                                            dev->mode_config.max_height);
+       }
+
+       /* delayed so we get modes regardless of pre-fill_modes state */
+       list_for_each_entry(mode, &connector->modes, head)
+               if (drm_mode_expose_to_userspace(mode, file_priv))
+                       mode_count++;
+
+       out_resp->connector_id = connector->base.id;
+       out_resp->connector_type = connector->connector_type;
+       out_resp->connector_type_id = connector->connector_type_id;
+       out_resp->mm_width = connector->display_info.width_mm;
+       out_resp->mm_height = connector->display_info.height_mm;
+       out_resp->subpixel = connector->display_info.subpixel_order;
+       out_resp->connection = connector->status;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+       encoder = drm_connector_get_encoder(connector);
+       if (encoder)
+               out_resp->encoder_id = encoder->base.id;
+       else
+               out_resp->encoder_id = 0;
+
+       /*
+        * This ioctl is called twice, once to determine how much space is
+        * needed, and the 2nd time to fill it.
+        */
+       if ((out_resp->count_modes >= mode_count) && mode_count) {
+               copied = 0;
+               mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
+               list_for_each_entry(mode, &connector->modes, head) {
+                       if (!drm_mode_expose_to_userspace(mode, file_priv))
+                               continue;
+
+                       drm_mode_convert_to_umode(&u_mode, mode);
+                       if (copy_to_user(mode_ptr + copied,
+                                        &u_mode, sizeof(u_mode))) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       out_resp->count_modes = mode_count;
+
+       ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic,
+                       (uint32_t __user *)(unsigned long)(out_resp->props_ptr),
+                       (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
+                       &out_resp->count_props);
+       if (ret)
+               goto out;
+
+       if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
+               copied = 0;
+               encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
+               for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+                       if (connector->encoder_ids[i] != 0) {
+                               if (put_user(connector->encoder_ids[i],
+                                            encoder_ptr + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       out_resp->count_encoders = encoders_count;
+
+out:
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
+       drm_connector_unreference(connector);
+out_unlock:
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
index 192a5f9..3c4000f 100644 (file)
@@ -54,7 +54,7 @@ struct drm_ctx_list {
 void drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
 {
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return;
 
        mutex_lock(&dev->struct_mutex);
@@ -92,7 +92,7 @@ static int drm_legacy_ctxbitmap_next(struct drm_device * dev)
 void drm_legacy_ctxbitmap_init(struct drm_device * dev)
 {
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return;
 
        idr_init(&dev->ctx_idr);
@@ -109,7 +109,7 @@ void drm_legacy_ctxbitmap_init(struct drm_device * dev)
 void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev)
 {
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return;
 
        mutex_lock(&dev->struct_mutex);
@@ -131,7 +131,7 @@ void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file)
        struct drm_ctx_list *pos, *tmp;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return;
 
        mutex_lock(&dev->ctxlist_mutex);
@@ -177,7 +177,7 @@ int drm_legacy_getsareactx(struct drm_device *dev, void *data,
        struct drm_map_list *_entry;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        mutex_lock(&dev->struct_mutex);
@@ -225,7 +225,7 @@ int drm_legacy_setsareactx(struct drm_device *dev, void *data,
        struct drm_map_list *r_list = NULL;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        mutex_lock(&dev->struct_mutex);
@@ -329,7 +329,7 @@ int drm_legacy_resctx(struct drm_device *dev, void *data,
        int i;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (res->count >= DRM_RESERVED_CONTEXTS) {
@@ -363,7 +363,7 @@ int drm_legacy_addctx(struct drm_device *dev, void *data,
        struct drm_ctx *ctx = data;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        ctx->handle = drm_legacy_ctxbitmap_next(dev);
@@ -410,7 +410,7 @@ int drm_legacy_getctx(struct drm_device *dev, void *data,
        struct drm_ctx *ctx = data;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        /* This is 0, because we don't handle any context flags */
@@ -436,7 +436,7 @@ int drm_legacy_switchctx(struct drm_device *dev, void *data,
        struct drm_ctx *ctx = data;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        DRM_DEBUG("%d\n", ctx->handle);
@@ -460,7 +460,7 @@ int drm_legacy_newctx(struct drm_device *dev, void *data,
        struct drm_ctx *ctx = data;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        DRM_DEBUG("%d\n", ctx->handle);
@@ -486,7 +486,7 @@ int drm_legacy_rmctx(struct drm_device *dev, void *data,
        struct drm_ctx *ctx = data;
 
        if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
-           drm_core_check_feature(dev, DRIVER_MODESET))
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        DRM_DEBUG("%d\n", ctx->handle);
index ddebe54..2d7bedf 100644 (file)
 #include <drm/drm_modeset_lock.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_auth.h>
+#include <drm/drm_framebuffer.h>
 
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
-static struct drm_framebuffer *
-internal_framebuffer_create(struct drm_device *dev,
-                           const struct drm_mode_fb_cmd2 *r,
-                           struct drm_file *file_priv);
-
-/* Avoid boilerplate.  I'm tired of typing. */
-#define DRM_ENUM_NAME_FN(fnname, list)                         \
-       const char *fnname(int val)                             \
-       {                                                       \
-               int i;                                          \
-               for (i = 0; i < ARRAY_SIZE(list); i++) {        \
-                       if (list[i].type == val)                \
-                               return list[i].name;            \
-               }                                               \
-               return "(unknown)";                             \
-       }
-
 /*
  * Global properties
  */
-static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
-       { DRM_MODE_DPMS_ON, "On" },
-       { DRM_MODE_DPMS_STANDBY, "Standby" },
-       { DRM_MODE_DPMS_SUSPEND, "Suspend" },
-       { DRM_MODE_DPMS_OFF, "Off" }
-};
-
-DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
-
 static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
        { DRM_PLANE_TYPE_OVERLAY, "Overlay" },
        { DRM_PLANE_TYPE_PRIMARY, "Primary" },
@@ -82,320 +57,6 @@ static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
 /*
  * Optional properties
  */
-static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = {
-       { DRM_MODE_SCALE_NONE, "None" },
-       { DRM_MODE_SCALE_FULLSCREEN, "Full" },
-       { DRM_MODE_SCALE_CENTER, "Center" },
-       { DRM_MODE_SCALE_ASPECT, "Full aspect" },
-};
-
-static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
-       { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" },
-       { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" },
-       { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" },
-};
-
-/*
- * Non-global properties, but "required" for certain connectors.
- */
-static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
-       { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
-       { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
-       { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
-};
-
-DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
-
-static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
-       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
-       { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
-       { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
-};
-
-DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
-                drm_dvi_i_subconnector_enum_list)
-
-static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
-       { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
-       { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
-       { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
-       { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
-       { DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
-};
-
-DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
-
-static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
-       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
-       { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
-       { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
-       { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
-       { DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
-};
-
-DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
-                drm_tv_subconnector_enum_list)
-
-static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
-       { DRM_MODE_DIRTY_OFF,      "Off"      },
-       { DRM_MODE_DIRTY_ON,       "On"       },
-       { DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
-};
-
-struct drm_conn_prop_enum_list {
-       int type;
-       const char *name;
-       struct ida ida;
-};
-
-/*
- * Connector and encoder types.
- */
-static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
-       { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
-       { DRM_MODE_CONNECTOR_VGA, "VGA" },
-       { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
-       { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
-       { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
-       { DRM_MODE_CONNECTOR_Composite, "Composite" },
-       { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
-       { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
-       { DRM_MODE_CONNECTOR_Component, "Component" },
-       { DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
-       { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
-       { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
-       { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
-       { DRM_MODE_CONNECTOR_TV, "TV" },
-       { DRM_MODE_CONNECTOR_eDP, "eDP" },
-       { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
-       { DRM_MODE_CONNECTOR_DSI, "DSI" },
-       { DRM_MODE_CONNECTOR_DPI, "DPI" },
-};
-
-static const struct drm_prop_enum_list drm_encoder_enum_list[] = {
-       { DRM_MODE_ENCODER_NONE, "None" },
-       { DRM_MODE_ENCODER_DAC, "DAC" },
-       { DRM_MODE_ENCODER_TMDS, "TMDS" },
-       { DRM_MODE_ENCODER_LVDS, "LVDS" },
-       { DRM_MODE_ENCODER_TVDAC, "TV" },
-       { DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
-       { DRM_MODE_ENCODER_DSI, "DSI" },
-       { DRM_MODE_ENCODER_DPMST, "DP MST" },
-       { DRM_MODE_ENCODER_DPI, "DPI" },
-};
-
-static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
-       { SubPixelUnknown, "Unknown" },
-       { SubPixelHorizontalRGB, "Horizontal RGB" },
-       { SubPixelHorizontalBGR, "Horizontal BGR" },
-       { SubPixelVerticalRGB, "Vertical RGB" },
-       { SubPixelVerticalBGR, "Vertical BGR" },
-       { SubPixelNone, "None" },
-};
-
-void drm_connector_ida_init(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
-               ida_init(&drm_connector_enum_list[i].ida);
-}
-
-void drm_connector_ida_destroy(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
-               ida_destroy(&drm_connector_enum_list[i].ida);
-}
-
-/**
- * drm_get_connector_status_name - return a string for connector status
- * @status: connector status to compute name of
- *
- * In contrast to the other drm_get_*_name functions this one here returns a
- * const pointer and hence is threadsafe.
- */
-const char *drm_get_connector_status_name(enum drm_connector_status status)
-{
-       if (status == connector_status_connected)
-               return "connected";
-       else if (status == connector_status_disconnected)
-               return "disconnected";
-       else
-               return "unknown";
-}
-EXPORT_SYMBOL(drm_get_connector_status_name);
-
-/**
- * drm_get_subpixel_order_name - return a string for a given subpixel enum
- * @order: enum of subpixel_order
- *
- * Note you could abuse this and return something out of bounds, but that
- * would be a caller error.  No unscrubbed user data should make it here.
- */
-const char *drm_get_subpixel_order_name(enum subpixel_order order)
-{
-       return drm_subpixel_enum_list[order].name;
-}
-EXPORT_SYMBOL(drm_get_subpixel_order_name);
-
-/*
- * Internal function to assign a slot in the object idr and optionally
- * register the object into the idr.
- */
-static int drm_mode_object_get_reg(struct drm_device *dev,
-                                  struct drm_mode_object *obj,
-                                  uint32_t obj_type,
-                                  bool register_obj,
-                                  void (*obj_free_cb)(struct kref *kref))
-{
-       int ret;
-
-       mutex_lock(&dev->mode_config.idr_mutex);
-       ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
-       if (ret >= 0) {
-               /*
-                * Set up the object linking under the protection of the idr
-                * lock so that other users can't see inconsistent state.
-                */
-               obj->id = ret;
-               obj->type = obj_type;
-               if (obj_free_cb) {
-                       obj->free_cb = obj_free_cb;
-                       kref_init(&obj->refcount);
-               }
-       }
-       mutex_unlock(&dev->mode_config.idr_mutex);
-
-       return ret < 0 ? ret : 0;
-}
-
-/**
- * drm_mode_object_get - allocate a new modeset identifier
- * @dev: DRM device
- * @obj: object pointer, used to generate unique ID
- * @obj_type: object type
- *
- * Create a unique identifier based on @ptr in @dev's identifier space.  Used
- * for tracking modes, CRTCs and connectors. Note that despite the _get postfix
- * modeset identifiers are _not_ reference counted. Hence don't use this for
- * reference counted modeset objects like framebuffers.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_mode_object_get(struct drm_device *dev,
-                       struct drm_mode_object *obj, uint32_t obj_type)
-{
-       return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL);
-}
-
-static void drm_mode_object_register(struct drm_device *dev,
-                                    struct drm_mode_object *obj)
-{
-       mutex_lock(&dev->mode_config.idr_mutex);
-       idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
-       mutex_unlock(&dev->mode_config.idr_mutex);
-}
-
-/**
- * drm_mode_object_unregister - free a modeset identifer
- * @dev: DRM device
- * @object: object to free
- *
- * Free @id from @dev's unique identifier pool.
- * This function can be called multiple times, and guards against
- * multiple removals.
- * These modeset identifiers are _not_ reference counted. Hence don't use this
- * for reference counted modeset objects like framebuffers.
- */
-void drm_mode_object_unregister(struct drm_device *dev,
-                        struct drm_mode_object *object)
-{
-       mutex_lock(&dev->mode_config.idr_mutex);
-       if (object->id) {
-               idr_remove(&dev->mode_config.crtc_idr, object->id);
-               object->id = 0;
-       }
-       mutex_unlock(&dev->mode_config.idr_mutex);
-}
-
-static struct drm_mode_object *_object_find(struct drm_device *dev,
-               uint32_t id, uint32_t type)
-{
-       struct drm_mode_object *obj = NULL;
-
-       mutex_lock(&dev->mode_config.idr_mutex);
-       obj = idr_find(&dev->mode_config.crtc_idr, id);
-       if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
-               obj = NULL;
-       if (obj && obj->id != id)
-               obj = NULL;
-
-       if (obj && obj->free_cb) {
-               if (!kref_get_unless_zero(&obj->refcount))
-                       obj = NULL;
-       }
-       mutex_unlock(&dev->mode_config.idr_mutex);
-
-       return obj;
-}
-
-/**
- * drm_mode_object_find - look up a drm object with static lifetime
- * @dev: drm device
- * @id: id of the mode object
- * @type: type of the mode object
- *
- * This function is used to look up a modeset object. It will acquire a
- * reference for reference counted objects. This reference must be dropped again
- * by callind drm_mode_object_unreference().
- */
-struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
-               uint32_t id, uint32_t type)
-{
-       struct drm_mode_object *obj = NULL;
-
-       obj = _object_find(dev, id, type);
-       return obj;
-}
-EXPORT_SYMBOL(drm_mode_object_find);
-
-/**
- * drm_mode_object_unreference - decr the object refcnt
- * @obj: mode_object
- *
- * This functions decrements the object's refcount if it is a refcounted modeset
- * object. It is a no-op on any other object. This is used to drop references
- * acquired with drm_mode_object_reference().
- */
-void drm_mode_object_unreference(struct drm_mode_object *obj)
-{
-       if (obj->free_cb) {
-               DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
-               kref_put(&obj->refcount, obj->free_cb);
-       }
-}
-EXPORT_SYMBOL(drm_mode_object_unreference);
-
-/**
- * drm_mode_object_reference - incr the object refcnt
- * @obj: mode_object
- *
- * This functions increments the object's refcount if it is a refcounted modeset
- * object. It is a no-op on any other object. References should be dropped again
- * by calling drm_mode_object_unreference().
- */
-void drm_mode_object_reference(struct drm_mode_object *obj)
-{
-       if (obj->free_cb) {
-               DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
-               kref_get(&obj->refcount);
-       }
-}
-EXPORT_SYMBOL(drm_mode_object_reference);
-
 /**
  * drm_crtc_force_disable - Forcibly turn off a CRTC
  * @crtc: CRTC to turn off
@@ -441,199 +102,6 @@ out:
 }
 EXPORT_SYMBOL(drm_crtc_force_disable_all);
 
-static void drm_framebuffer_free(struct kref *kref)
-{
-       struct drm_framebuffer *fb =
-                       container_of(kref, struct drm_framebuffer, base.refcount);
-       struct drm_device *dev = fb->dev;
-
-       /*
-        * The lookup idr holds a weak reference, which has not necessarily been
-        * removed at this point. Check for that.
-        */
-       drm_mode_object_unregister(dev, &fb->base);
-
-       fb->funcs->destroy(fb);
-}
-
-/**
- * drm_framebuffer_init - initialize a framebuffer
- * @dev: DRM device
- * @fb: framebuffer to be initialized
- * @funcs: ... with these functions
- *
- * Allocates an ID for the framebuffer's parent mode object, sets its mode
- * functions & device file and adds it to the master fd list.
- *
- * IMPORTANT:
- * This functions publishes the fb and makes it available for concurrent access
- * by other users. Which means by this point the fb _must_ be fully set up -
- * since all the fb attributes are invariant over its lifetime, no further
- * locking but only correct reference counting is required.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
-                        const struct drm_framebuffer_funcs *funcs)
-{
-       int ret;
-
-       INIT_LIST_HEAD(&fb->filp_head);
-       fb->dev = dev;
-       fb->funcs = funcs;
-
-       ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB,
-                                     false, drm_framebuffer_free);
-       if (ret)
-               goto out;
-
-       mutex_lock(&dev->mode_config.fb_lock);
-       dev->mode_config.num_fb++;
-       list_add(&fb->head, &dev->mode_config.fb_list);
-       mutex_unlock(&dev->mode_config.fb_lock);
-
-       drm_mode_object_register(dev, &fb->base);
-out:
-       return ret;
-}
-EXPORT_SYMBOL(drm_framebuffer_init);
-
-/**
- * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
- * @dev: drm device
- * @id: id of the fb object
- *
- * If successful, this grabs an additional reference to the framebuffer -
- * callers need to make sure to eventually unreference the returned framebuffer
- * again, using @drm_framebuffer_unreference.
- */
-struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
-                                              uint32_t id)
-{
-       struct drm_mode_object *obj;
-       struct drm_framebuffer *fb = NULL;
-
-       obj = _object_find(dev, id, DRM_MODE_OBJECT_FB);
-       if (obj)
-               fb = obj_to_fb(obj);
-       return fb;
-}
-EXPORT_SYMBOL(drm_framebuffer_lookup);
-
-/**
- * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
- * @fb: fb to unregister
- *
- * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
- * those used for fbdev. Note that the caller must hold a reference of it's own,
- * i.e. the object may not be destroyed through this call (since it'll lead to a
- * locking inversion).
- */
-void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
-{
-       struct drm_device *dev;
-
-       if (!fb)
-               return;
-
-       dev = fb->dev;
-
-       /* Mark fb as reaped and drop idr ref. */
-       drm_mode_object_unregister(dev, &fb->base);
-}
-EXPORT_SYMBOL(drm_framebuffer_unregister_private);
-
-/**
- * drm_framebuffer_cleanup - remove a framebuffer object
- * @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.
- *
- * Note that this function does not remove the fb from active usuage - 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.
- *
- * Also, the framebuffer will not be removed from the lookup idr - for
- * user-created framebuffers this will happen in in the rmfb ioctl. For
- * driver-private objects (e.g. for fbdev) drivers need to explicitly call
- * drm_framebuffer_unregister_private.
- */
-void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
-{
-       struct drm_device *dev = fb->dev;
-
-       mutex_lock(&dev->mode_config.fb_lock);
-       list_del(&fb->head);
-       dev->mode_config.num_fb--;
-       mutex_unlock(&dev->mode_config.fb_lock);
-}
-EXPORT_SYMBOL(drm_framebuffer_cleanup);
-
-/**
- * drm_framebuffer_remove - remove and unreference a framebuffer object
- * @fb: framebuffer to remove
- *
- * Scans all the CRTCs and planes in @dev's mode_config.  If they're
- * using @fb, removes it, setting it to NULL. Then drops the reference to the
- * passed-in framebuffer. Might take the modeset locks.
- *
- * Note that this function optimizes the cleanup away if the caller holds the
- * last reference to the framebuffer. It is also guaranteed to not take the
- * modeset locks in this case.
- */
-void drm_framebuffer_remove(struct drm_framebuffer *fb)
-{
-       struct drm_device *dev;
-       struct drm_crtc *crtc;
-       struct drm_plane *plane;
-
-       if (!fb)
-               return;
-
-       dev = fb->dev;
-
-       WARN_ON(!list_empty(&fb->filp_head));
-
-       /*
-        * drm ABI mandates that we remove any deleted framebuffers from active
-        * useage. But since most sane clients only remove framebuffers they no
-        * longer need, try to optimize this away.
-        *
-        * Since we're holding a reference ourselves, observing a refcount of 1
-        * means that we're the last holder and can skip it. Also, the refcount
-        * can never increase from 1 again, so we don't need any barriers or
-        * locks.
-        *
-        * Note that userspace could try to race with use and instate a new
-        * usage _after_ we've cleared all current ones. End result will be an
-        * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot
-        * in this manner.
-        */
-       if (drm_framebuffer_read_refcount(fb) > 1) {
-               drm_modeset_lock_all(dev);
-               /* remove from any CRTC */
-               drm_for_each_crtc(crtc, dev) {
-                       if (crtc->primary->fb == fb) {
-                               /* should turn off the crtc */
-                               if (drm_crtc_force_disable(crtc))
-                                       DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
-                       }
-               }
-
-               drm_for_each_plane(plane, dev) {
-                       if (plane->fb == fb)
-                               drm_plane_force_disable(plane);
-               }
-               drm_modeset_unlock_all(dev);
-       }
-
-       drm_framebuffer_unreference(fb);
-}
-EXPORT_SYMBOL(drm_framebuffer_remove);
-
 DEFINE_WW_CLASS(crtc_ww_class);
 
 static unsigned int drm_num_crtcs(struct drm_device *dev)
@@ -683,7 +151,11 @@ static void drm_crtc_unregister_all(struct drm_device *dev)
  * @funcs: callbacks for the new CRTC
  * @name: printf style format string for the CRTC name, or NULL for default name
  *
- * Inits a new object created as base part of a driver crtc object.
+ * Inits a new object created as base part of a driver crtc object. Drivers
+ * should use this function instead of drm_crtc_init(), which is only provided
+ * for backwards compatibility with drivers which do not yet support universal
+ * planes). For really simple hardware which has only 1 plane look at
+ * drm_simple_display_pipe_init() instead.
  *
  * Returns:
  * Zero on success, error code on failure.
@@ -783,4713 +255,650 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_cleanup);
 
-/*
- * drm_mode_remove - remove and free a mode
- * @connector: connector list to modify
- * @mode: mode to remove
- *
- * Remove @mode from @connector's mode list, then free it.
- */
-static void drm_mode_remove(struct drm_connector *connector,
-                           struct drm_display_mode *mode)
+int drm_modeset_register_all(struct drm_device *dev)
 {
-       list_del(&mode->head);
-       drm_mode_destroy(connector->dev, mode);
-}
+       int ret;
 
-/**
- * drm_display_info_set_bus_formats - set the supported bus formats
- * @info: display info to store bus formats in
- * @formats: array containing the supported bus formats
- * @num_formats: the number of entries in the fmts array
- *
- * Store the supported bus formats in display info structure.
- * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for
- * a full list of available formats.
- */
-int drm_display_info_set_bus_formats(struct drm_display_info *info,
-                                    const u32 *formats,
-                                    unsigned int num_formats)
-{
-       u32 *fmts = NULL;
+       ret = drm_plane_register_all(dev);
+       if (ret)
+               goto err_plane;
 
-       if (!formats && num_formats)
-               return -EINVAL;
+       ret = drm_crtc_register_all(dev);
+       if  (ret)
+               goto err_crtc;
 
-       if (formats && num_formats) {
-               fmts = kmemdup(formats, sizeof(*formats) * num_formats,
-                              GFP_KERNEL);
-               if (!fmts)
-                       return -ENOMEM;
-       }
+       ret = drm_encoder_register_all(dev);
+       if (ret)
+               goto err_encoder;
 
-       kfree(info->bus_formats);
-       info->bus_formats = fmts;
-       info->num_bus_formats = num_formats;
+       ret = drm_connector_register_all(dev);
+       if (ret)
+               goto err_connector;
 
        return 0;
+
+err_connector:
+       drm_encoder_unregister_all(dev);
+err_encoder:
+       drm_crtc_unregister_all(dev);
+err_crtc:
+       drm_plane_unregister_all(dev);
+err_plane:
+       return ret;
 }
-EXPORT_SYMBOL(drm_display_info_set_bus_formats);
 
-/**
- * drm_connector_get_cmdline_mode - reads the user's cmdline mode
- * @connector: connector to quwery
- *
- * The kernel supports per-connector configration of its consoles through
- * use of the video= parameter. This function parses that option and
- * extracts the user's specified mode (or enable/disable status) for a
- * particular connector. This is typically only used during the early fbdev
- * setup.
- */
-static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
+void drm_modeset_unregister_all(struct drm_device *dev)
 {
-       struct drm_cmdline_mode *mode = &connector->cmdline_mode;
-       char *option = NULL;
-
-       if (fb_get_options(connector->name, &option))
-               return;
-
-       if (!drm_mode_parse_command_line_for_connector(option,
-                                                      connector,
-                                                      mode))
-               return;
-
-       if (mode->force) {
-               const char *s;
-
-               switch (mode->force) {
-               case DRM_FORCE_OFF:
-                       s = "OFF";
-                       break;
-               case DRM_FORCE_ON_DIGITAL:
-                       s = "ON - dig";
-                       break;
-               default:
-               case DRM_FORCE_ON:
-                       s = "ON";
-                       break;
-               }
-
-               DRM_INFO("forcing %s connector %s\n", connector->name, s);
-               connector->force = mode->force;
-       }
-
-       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
-                     connector->name,
-                     mode->xres, mode->yres,
-                     mode->refresh_specified ? mode->refresh : 60,
-                     mode->rb ? " reduced blanking" : "",
-                     mode->margins ? " with margins" : "",
-                     mode->interlace ?  " interlaced" : "");
+       drm_connector_unregister_all(dev);
+       drm_encoder_unregister_all(dev);
+       drm_crtc_unregister_all(dev);
+       drm_plane_unregister_all(dev);
 }
 
-static void drm_connector_free(struct kref *kref)
+static int drm_mode_create_standard_properties(struct drm_device *dev)
 {
-       struct drm_connector *connector =
-               container_of(kref, struct drm_connector, base.refcount);
-       struct drm_device *dev = connector->dev;
-
-       drm_mode_object_unregister(dev, &connector->base);
-       connector->funcs->destroy(connector);
-}
+       struct drm_property *prop;
+       int ret;
 
-/**
- * drm_connector_init - Init a preallocated connector
- * @dev: DRM device
- * @connector: the connector to init
- * @funcs: callbacks for this connector
- * @connector_type: user visible type of the connector
- *
- * Initialises a preallocated connector. Connectors should be
- * subclassed as part of driver connector objects.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_connector_init(struct drm_device *dev,
-                      struct drm_connector *connector,
-                      const struct drm_connector_funcs *funcs,
-                      int connector_type)
-{
-       struct drm_mode_config *config = &dev->mode_config;
-       int ret;
-       struct ida *connector_ida =
-               &drm_connector_enum_list[connector_type].ida;
-
-       drm_modeset_lock_all(dev);
-
-       ret = drm_mode_object_get_reg(dev, &connector->base,
-                                     DRM_MODE_OBJECT_CONNECTOR,
-                                     false, drm_connector_free);
-       if (ret)
-               goto out_unlock;
-
-       connector->base.properties = &connector->properties;
-       connector->dev = dev;
-       connector->funcs = funcs;
-
-       ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL);
-       if (ret < 0)
-               goto out_put;
-       connector->index = ret;
-       ret = 0;
-
-       connector->connector_type = connector_type;
-       connector->connector_type_id =
-               ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
-       if (connector->connector_type_id < 0) {
-               ret = connector->connector_type_id;
-               goto out_put_id;
-       }
-       connector->name =
-               kasprintf(GFP_KERNEL, "%s-%d",
-                         drm_connector_enum_list[connector_type].name,
-                         connector->connector_type_id);
-       if (!connector->name) {
-               ret = -ENOMEM;
-               goto out_put_type_id;
-       }
-
-       INIT_LIST_HEAD(&connector->probed_modes);
-       INIT_LIST_HEAD(&connector->modes);
-       connector->edid_blob_ptr = NULL;
-       connector->status = connector_status_unknown;
-
-       drm_connector_get_cmdline_mode(connector);
-
-       /* We should add connectors at the end to avoid upsetting the connector
-        * index too much. */
-       list_add_tail(&connector->head, &config->connector_list);
-       config->num_connector++;
-
-       if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
-               drm_object_attach_property(&connector->base,
-                                             config->edid_property,
-                                             0);
-
-       drm_object_attach_property(&connector->base,
-                                     config->dpms_property, 0);
-
-       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
-               drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
-       }
-
-       connector->debugfs_entry = NULL;
-out_put_type_id:
-       if (ret)
-               ida_remove(connector_ida, connector->connector_type_id);
-out_put_id:
-       if (ret)
-               ida_remove(&config->connector_ida, connector->index);
-out_put:
-       if (ret)
-               drm_mode_object_unregister(dev, &connector->base);
-
-out_unlock:
-       drm_modeset_unlock_all(dev);
-
-       return ret;
-}
-EXPORT_SYMBOL(drm_connector_init);
-
-/**
- * drm_connector_cleanup - cleans up an initialised connector
- * @connector: connector to cleanup
- *
- * Cleans up the connector but doesn't free the object.
- */
-void drm_connector_cleanup(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_display_mode *mode, *t;
-
-       /* The connector should have been removed from userspace long before
-        * it is finally destroyed.
-        */
-       if (WARN_ON(connector->registered))
-               drm_connector_unregister(connector);
-
-       if (connector->tile_group) {
-               drm_mode_put_tile_group(dev, connector->tile_group);
-               connector->tile_group = NULL;
-       }
-
-       list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
-               drm_mode_remove(connector, mode);
-
-       list_for_each_entry_safe(mode, t, &connector->modes, head)
-               drm_mode_remove(connector, mode);
-
-       ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
-                  connector->connector_type_id);
-
-       ida_remove(&dev->mode_config.connector_ida,
-                  connector->index);
-
-       kfree(connector->display_info.bus_formats);
-       drm_mode_object_unregister(dev, &connector->base);
-       kfree(connector->name);
-       connector->name = NULL;
-       list_del(&connector->head);
-       dev->mode_config.num_connector--;
-
-       WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
-       if (connector->state && connector->funcs->atomic_destroy_state)
-               connector->funcs->atomic_destroy_state(connector,
-                                                      connector->state);
-
-       memset(connector, 0, sizeof(*connector));
-}
-EXPORT_SYMBOL(drm_connector_cleanup);
-
-/**
- * drm_connector_register - register a connector
- * @connector: the connector to register
- *
- * Register userspace interfaces for a connector
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_connector_register(struct drm_connector *connector)
-{
-       int ret;
-
-       if (connector->registered)
-               return 0;
-
-       ret = drm_sysfs_connector_add(connector);
+       ret = drm_connector_create_standard_properties(dev);
        if (ret)
                return ret;
 
-       ret = drm_debugfs_connector_add(connector);
-       if (ret) {
-               goto err_sysfs;
-       }
-
-       if (connector->funcs->late_register) {
-               ret = connector->funcs->late_register(connector);
-               if (ret)
-                       goto err_debugfs;
-       }
-
-       drm_mode_object_register(connector->dev, &connector->base);
-
-       connector->registered = true;
-       return 0;
-
-err_debugfs:
-       drm_debugfs_connector_remove(connector);
-err_sysfs:
-       drm_sysfs_connector_remove(connector);
-       return ret;
-}
-EXPORT_SYMBOL(drm_connector_register);
-
-/**
- * drm_connector_unregister - unregister a connector
- * @connector: the connector to unregister
- *
- * Unregister userspace interfaces for a connector
- */
-void drm_connector_unregister(struct drm_connector *connector)
-{
-       if (!connector->registered)
-               return;
-
-       if (connector->funcs->early_unregister)
-               connector->funcs->early_unregister(connector);
-
-       drm_sysfs_connector_remove(connector);
-       drm_debugfs_connector_remove(connector);
-
-       connector->registered = false;
-}
-EXPORT_SYMBOL(drm_connector_unregister);
-
-static void drm_connector_unregister_all(struct drm_device *dev)
-{
-       struct drm_connector *connector;
-
-       /* FIXME: taking the mode config mutex ends up in a clash with sysfs */
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
-               drm_connector_unregister(connector);
-}
-
-static int drm_connector_register_all(struct drm_device *dev)
-{
-       struct drm_connector *connector;
-       int ret;
-
-       /* FIXME: taking the mode config mutex ends up in a clash with
-        * fbcon/backlight registration */
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               ret = drm_connector_register(connector);
-               if (ret)
-                       goto err;
-       }
-
-       return 0;
-
-err:
-       mutex_unlock(&dev->mode_config.mutex);
-       drm_connector_unregister_all(dev);
-       return ret;
-}
-
-static int drm_encoder_register_all(struct drm_device *dev)
-{
-       struct drm_encoder *encoder;
-       int ret = 0;
-
-       drm_for_each_encoder(encoder, dev) {
-               if (encoder->funcs->late_register)
-                       ret = encoder->funcs->late_register(encoder);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
+       prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+                                       "type", drm_plane_type_enum_list,
+                                       ARRAY_SIZE(drm_plane_type_enum_list));
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.plane_type_property = prop;
 
-static void drm_encoder_unregister_all(struct drm_device *dev)
-{
-       struct drm_encoder *encoder;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "SRC_X", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_src_x = prop;
 
-       drm_for_each_encoder(encoder, dev) {
-               if (encoder->funcs->early_unregister)
-                       encoder->funcs->early_unregister(encoder);
-       }
-}
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "SRC_Y", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_src_y = prop;
 
-/**
- * drm_encoder_init - Init a preallocated encoder
- * @dev: drm device
- * @encoder: the encoder to init
- * @funcs: callbacks for this encoder
- * @encoder_type: user visible type of the encoder
- * @name: printf style format string for the encoder name, or NULL for default name
- *
- * Initialises a preallocated encoder. Encoder should be
- * subclassed as part of driver encoder objects.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_encoder_init(struct drm_device *dev,
-                     struct drm_encoder *encoder,
-                     const struct drm_encoder_funcs *funcs,
-                     int encoder_type, const char *name, ...)
-{
-       int ret;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "SRC_W", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_src_w = prop;
 
-       drm_modeset_lock_all(dev);
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "SRC_H", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_src_h = prop;
 
-       ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
-       if (ret)
-               goto out_unlock;
+       prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_X", INT_MIN, INT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_x = prop;
 
-       encoder->dev = dev;
-       encoder->encoder_type = encoder_type;
-       encoder->funcs = funcs;
-       if (name) {
-               va_list ap;
+       prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_Y", INT_MIN, INT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_y = prop;
 
-               va_start(ap, name);
-               encoder->name = kvasprintf(GFP_KERNEL, name, ap);
-               va_end(ap);
-       } else {
-               encoder->name = kasprintf(GFP_KERNEL, "%s-%d",
-                                         drm_encoder_enum_list[encoder_type].name,
-                                         encoder->base.id);
-       }
-       if (!encoder->name) {
-               ret = -ENOMEM;
-               goto out_put;
-       }
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_W", 0, INT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_w = prop;
 
-       list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
-       encoder->index = dev->mode_config.num_encoder++;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_H", 0, INT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_h = prop;
 
-out_put:
-       if (ret)
-               drm_mode_object_unregister(dev, &encoder->base);
+       prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
+                       "FB_ID", DRM_MODE_OBJECT_FB);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_fb_id = prop;
 
-out_unlock:
-       drm_modeset_unlock_all(dev);
+       prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_ID", DRM_MODE_OBJECT_CRTC);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_id = prop;
 
-       return ret;
-}
-EXPORT_SYMBOL(drm_encoder_init);
+       prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
+                       "ACTIVE");
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_active = prop;
 
-/**
- * drm_encoder_cleanup - cleans up an initialised encoder
- * @encoder: encoder to cleanup
- *
- * Cleans up the encoder but doesn't free the object.
- */
-void drm_encoder_cleanup(struct drm_encoder *encoder)
-{
-       struct drm_device *dev = encoder->dev;
+       prop = drm_property_create(dev,
+                       DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
+                       "MODE_ID", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_mode_id = prop;
 
-       /* Note that the encoder_list is considered to be static; should we
-        * remove the drm_encoder at runtime we would have to decrement all
-        * the indices on the drm_encoder after us in the encoder_list.
-        */
+       prop = drm_property_create(dev,
+                       DRM_MODE_PROP_BLOB,
+                       "DEGAMMA_LUT", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.degamma_lut_property = prop;
 
-       drm_modeset_lock_all(dev);
-       drm_mode_object_unregister(dev, &encoder->base);
-       kfree(encoder->name);
-       list_del(&encoder->head);
-       dev->mode_config.num_encoder--;
-       drm_modeset_unlock_all(dev);
+       prop = drm_property_create_range(dev,
+                       DRM_MODE_PROP_IMMUTABLE,
+                       "DEGAMMA_LUT_SIZE", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.degamma_lut_size_property = prop;
 
-       memset(encoder, 0, sizeof(*encoder));
-}
-EXPORT_SYMBOL(drm_encoder_cleanup);
+       prop = drm_property_create(dev,
+                       DRM_MODE_PROP_BLOB,
+                       "CTM", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.ctm_property = prop;
 
-static unsigned int drm_num_planes(struct drm_device *dev)
-{
-       unsigned int num = 0;
-       struct drm_plane *tmp;
+       prop = drm_property_create(dev,
+                       DRM_MODE_PROP_BLOB,
+                       "GAMMA_LUT", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.gamma_lut_property = prop;
 
-       drm_for_each_plane(tmp, dev) {
-               num++;
-       }
+       prop = drm_property_create_range(dev,
+                       DRM_MODE_PROP_IMMUTABLE,
+                       "GAMMA_LUT_SIZE", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.gamma_lut_size_property = prop;
 
-       return num;
+       return 0;
 }
 
 /**
- * drm_universal_plane_init - Initialize a new universal plane object
- * @dev: DRM device
- * @plane: plane object to init
- * @possible_crtcs: bitmask of possible CRTCs
- * @funcs: callbacks for the new plane
- * @formats: array of supported formats (%DRM_FORMAT_*)
- * @format_count: number of elements in @formats
- * @type: type of plane (overlay, primary, cursor)
- * @name: printf style format string for the plane name, or NULL for default name
- *
- * Initializes a plane object of type @type.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
-                            unsigned long possible_crtcs,
-                            const struct drm_plane_funcs *funcs,
-                            const uint32_t *formats, unsigned int format_count,
-                            enum drm_plane_type type,
-                            const char *name, ...)
-{
-       struct drm_mode_config *config = &dev->mode_config;
-       int ret;
-
-       ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
-       if (ret)
-               return ret;
-
-       drm_modeset_lock_init(&plane->mutex);
-
-       plane->base.properties = &plane->properties;
-       plane->dev = dev;
-       plane->funcs = funcs;
-       plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
-                                           GFP_KERNEL);
-       if (!plane->format_types) {
-               DRM_DEBUG_KMS("out of memory when allocating plane\n");
-               drm_mode_object_unregister(dev, &plane->base);
-               return -ENOMEM;
-       }
-
-       if (name) {
-               va_list ap;
-
-               va_start(ap, name);
-               plane->name = kvasprintf(GFP_KERNEL, name, ap);
-               va_end(ap);
-       } else {
-               plane->name = kasprintf(GFP_KERNEL, "plane-%d",
-                                       drm_num_planes(dev));
-       }
-       if (!plane->name) {
-               kfree(plane->format_types);
-               drm_mode_object_unregister(dev, &plane->base);
-               return -ENOMEM;
-       }
-
-       memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
-       plane->format_count = format_count;
-       plane->possible_crtcs = possible_crtcs;
-       plane->type = type;
-
-       list_add_tail(&plane->head, &config->plane_list);
-       plane->index = config->num_total_plane++;
-       if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-               config->num_overlay_plane++;
-
-       drm_object_attach_property(&plane->base,
-                                  config->plane_type_property,
-                                  plane->type);
-
-       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
-               drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
-               drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
-               drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
-               drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
-               drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
-               drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
-               drm_object_attach_property(&plane->base, config->prop_src_x, 0);
-               drm_object_attach_property(&plane->base, config->prop_src_y, 0);
-               drm_object_attach_property(&plane->base, config->prop_src_w, 0);
-               drm_object_attach_property(&plane->base, config->prop_src_h, 0);
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(drm_universal_plane_init);
-
-static int drm_plane_register_all(struct drm_device *dev)
-{
-       struct drm_plane *plane;
-       int ret = 0;
-
-       drm_for_each_plane(plane, dev) {
-               if (plane->funcs->late_register)
-                       ret = plane->funcs->late_register(plane);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static void drm_plane_unregister_all(struct drm_device *dev)
-{
-       struct drm_plane *plane;
-
-       drm_for_each_plane(plane, dev) {
-               if (plane->funcs->early_unregister)
-                       plane->funcs->early_unregister(plane);
-       }
-}
-
-/**
- * drm_plane_init - Initialize a legacy plane
- * @dev: DRM device
- * @plane: plane object to init
- * @possible_crtcs: bitmask of possible CRTCs
- * @funcs: callbacks for the new plane
- * @formats: array of supported formats (%DRM_FORMAT_*)
- * @format_count: number of elements in @formats
- * @is_primary: plane type (primary vs overlay)
- *
- * Legacy API to initialize a DRM plane.
- *
- * New drivers should call drm_universal_plane_init() instead.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
-                  unsigned long possible_crtcs,
-                  const struct drm_plane_funcs *funcs,
-                  const uint32_t *formats, unsigned int format_count,
-                  bool is_primary)
-{
-       enum drm_plane_type type;
-
-       type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
-       return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
-                                       formats, format_count, type, NULL);
-}
-EXPORT_SYMBOL(drm_plane_init);
-
-/**
- * drm_plane_cleanup - Clean up the core plane usage
- * @plane: plane to cleanup
- *
- * This function cleans up @plane and removes it from the DRM mode setting
- * core. Note that the function does *not* free the plane structure itself,
- * this is the responsibility of the caller.
- */
-void drm_plane_cleanup(struct drm_plane *plane)
-{
-       struct drm_device *dev = plane->dev;
-
-       drm_modeset_lock_all(dev);
-       kfree(plane->format_types);
-       drm_mode_object_unregister(dev, &plane->base);
-
-       BUG_ON(list_empty(&plane->head));
-
-       /* Note that the plane_list is considered to be static; should we
-        * remove the drm_plane at runtime we would have to decrement all
-        * the indices on the drm_plane after us in the plane_list.
-        */
-
-       list_del(&plane->head);
-       dev->mode_config.num_total_plane--;
-       if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-               dev->mode_config.num_overlay_plane--;
-       drm_modeset_unlock_all(dev);
-
-       WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
-       if (plane->state && plane->funcs->atomic_destroy_state)
-               plane->funcs->atomic_destroy_state(plane, plane->state);
-
-       kfree(plane->name);
-
-       memset(plane, 0, sizeof(*plane));
-}
-EXPORT_SYMBOL(drm_plane_cleanup);
-
-/**
- * drm_plane_from_index - find the registered plane at an index
- * @dev: DRM device
- * @idx: index of registered plane to find for
- *
- * Given a plane index, return the registered plane from DRM device's
- * list of planes with matching index.
- */
-struct drm_plane *
-drm_plane_from_index(struct drm_device *dev, int idx)
-{
-       struct drm_plane *plane;
-
-       drm_for_each_plane(plane, dev)
-               if (idx == plane->index)
-                       return plane;
-
-       return NULL;
-}
-EXPORT_SYMBOL(drm_plane_from_index);
-
-/**
- * drm_plane_force_disable - Forcibly disable a plane
- * @plane: plane to disable
- *
- * Forces the plane to be disabled.
- *
- * Used when the plane's current framebuffer is destroyed,
- * and when restoring fbdev mode.
- */
-void drm_plane_force_disable(struct drm_plane *plane)
-{
-       int ret;
-
-       if (!plane->fb)
-               return;
-
-       plane->old_fb = plane->fb;
-       ret = plane->funcs->disable_plane(plane);
-       if (ret) {
-               DRM_ERROR("failed to disable plane with busy fb\n");
-               plane->old_fb = NULL;
-               return;
-       }
-       /* disconnect the plane from the fb and crtc: */
-       drm_framebuffer_unreference(plane->old_fb);
-       plane->old_fb = NULL;
-       plane->fb = NULL;
-       plane->crtc = NULL;
-}
-EXPORT_SYMBOL(drm_plane_force_disable);
-
-int drm_modeset_register_all(struct drm_device *dev)
-{
-       int ret;
-
-       ret = drm_plane_register_all(dev);
-       if (ret)
-               goto err_plane;
-
-       ret = drm_crtc_register_all(dev);
-       if  (ret)
-               goto err_crtc;
-
-       ret = drm_encoder_register_all(dev);
-       if (ret)
-               goto err_encoder;
-
-       ret = drm_connector_register_all(dev);
-       if (ret)
-               goto err_connector;
-
-       return 0;
-
-err_connector:
-       drm_encoder_unregister_all(dev);
-err_encoder:
-       drm_crtc_unregister_all(dev);
-err_crtc:
-       drm_plane_unregister_all(dev);
-err_plane:
-       return ret;
-}
-
-void drm_modeset_unregister_all(struct drm_device *dev)
-{
-       drm_connector_unregister_all(dev);
-       drm_encoder_unregister_all(dev);
-       drm_crtc_unregister_all(dev);
-       drm_plane_unregister_all(dev);
-}
-
-static int drm_mode_create_standard_properties(struct drm_device *dev)
-{
-       struct drm_property *prop;
-
-       /*
-        * Standard properties (apply to all connectors)
-        */
-       prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
-                                  DRM_MODE_PROP_IMMUTABLE,
-                                  "EDID", 0);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.edid_property = prop;
-
-       prop = drm_property_create_enum(dev, 0,
-                                  "DPMS", drm_dpms_enum_list,
-                                  ARRAY_SIZE(drm_dpms_enum_list));
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.dpms_property = prop;
-
-       prop = drm_property_create(dev,
-                                  DRM_MODE_PROP_BLOB |
-                                  DRM_MODE_PROP_IMMUTABLE,
-                                  "PATH", 0);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.path_property = prop;
-
-       prop = drm_property_create(dev,
-                                  DRM_MODE_PROP_BLOB |
-                                  DRM_MODE_PROP_IMMUTABLE,
-                                  "TILE", 0);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.tile_property = prop;
-
-       prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
-                                       "type", drm_plane_type_enum_list,
-                                       ARRAY_SIZE(drm_plane_type_enum_list));
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.plane_type_property = prop;
-
-       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
-                       "SRC_X", 0, UINT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_src_x = prop;
-
-       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
-                       "SRC_Y", 0, UINT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_src_y = prop;
-
-       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
-                       "SRC_W", 0, UINT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_src_w = prop;
-
-       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
-                       "SRC_H", 0, UINT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_src_h = prop;
-
-       prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
-                       "CRTC_X", INT_MIN, INT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_crtc_x = prop;
-
-       prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
-                       "CRTC_Y", INT_MIN, INT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_crtc_y = prop;
-
-       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
-                       "CRTC_W", 0, INT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_crtc_w = prop;
-
-       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
-                       "CRTC_H", 0, INT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_crtc_h = prop;
-
-       prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
-                       "FB_ID", DRM_MODE_OBJECT_FB);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_fb_id = prop;
-
-       prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
-                       "CRTC_ID", DRM_MODE_OBJECT_CRTC);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_crtc_id = prop;
-
-       prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
-                       "ACTIVE");
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_active = prop;
-
-       prop = drm_property_create(dev,
-                       DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
-                       "MODE_ID", 0);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.prop_mode_id = prop;
-
-       prop = drm_property_create(dev,
-                       DRM_MODE_PROP_BLOB,
-                       "DEGAMMA_LUT", 0);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.degamma_lut_property = prop;
-
-       prop = drm_property_create_range(dev,
-                       DRM_MODE_PROP_IMMUTABLE,
-                       "DEGAMMA_LUT_SIZE", 0, UINT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.degamma_lut_size_property = prop;
-
-       prop = drm_property_create(dev,
-                       DRM_MODE_PROP_BLOB,
-                       "CTM", 0);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.ctm_property = prop;
-
-       prop = drm_property_create(dev,
-                       DRM_MODE_PROP_BLOB,
-                       "GAMMA_LUT", 0);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.gamma_lut_property = prop;
-
-       prop = drm_property_create_range(dev,
-                       DRM_MODE_PROP_IMMUTABLE,
-                       "GAMMA_LUT_SIZE", 0, UINT_MAX);
-       if (!prop)
-               return -ENOMEM;
-       dev->mode_config.gamma_lut_size_property = prop;
-
-       return 0;
-}
-
-/**
- * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
- * @dev: DRM device
- *
- * Called by a driver the first time a DVI-I connector is made.
- */
-int drm_mode_create_dvi_i_properties(struct drm_device *dev)
-{
-       struct drm_property *dvi_i_selector;
-       struct drm_property *dvi_i_subconnector;
-
-       if (dev->mode_config.dvi_i_select_subconnector_property)
-               return 0;
-
-       dvi_i_selector =
-               drm_property_create_enum(dev, 0,
-                                   "select subconnector",
-                                   drm_dvi_i_select_enum_list,
-                                   ARRAY_SIZE(drm_dvi_i_select_enum_list));
-       dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
-
-       dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
-                                   "subconnector",
-                                   drm_dvi_i_subconnector_enum_list,
-                                   ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
-       dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
-
-       return 0;
-}
-EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
-
-/**
- * drm_create_tv_properties - create TV specific connector properties
- * @dev: DRM device
- * @num_modes: number of different TV formats (modes) supported
- * @modes: array of pointers to strings containing name of each format
- *
- * Called by a driver's TV initialization routine, this function creates
- * the TV specific connector properties for a given device.  Caller is
- * responsible for allocating a list of format names and passing them to
- * this routine.
- */
-int drm_mode_create_tv_properties(struct drm_device *dev,
-                                 unsigned int num_modes,
-                                 const char * const modes[])
-{
-       struct drm_property *tv_selector;
-       struct drm_property *tv_subconnector;
-       unsigned int i;
-
-       if (dev->mode_config.tv_select_subconnector_property)
-               return 0;
-
-       /*
-        * Basic connector properties
-        */
-       tv_selector = drm_property_create_enum(dev, 0,
-                                         "select subconnector",
-                                         drm_tv_select_enum_list,
-                                         ARRAY_SIZE(drm_tv_select_enum_list));
-       if (!tv_selector)
-               goto nomem;
-
-       dev->mode_config.tv_select_subconnector_property = tv_selector;
-
-       tv_subconnector =
-               drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
-                                   "subconnector",
-                                   drm_tv_subconnector_enum_list,
-                                   ARRAY_SIZE(drm_tv_subconnector_enum_list));
-       if (!tv_subconnector)
-               goto nomem;
-       dev->mode_config.tv_subconnector_property = tv_subconnector;
-
-       /*
-        * Other, TV specific properties: margins & TV modes.
-        */
-       dev->mode_config.tv_left_margin_property =
-               drm_property_create_range(dev, 0, "left margin", 0, 100);
-       if (!dev->mode_config.tv_left_margin_property)
-               goto nomem;
-
-       dev->mode_config.tv_right_margin_property =
-               drm_property_create_range(dev, 0, "right margin", 0, 100);
-       if (!dev->mode_config.tv_right_margin_property)
-               goto nomem;
-
-       dev->mode_config.tv_top_margin_property =
-               drm_property_create_range(dev, 0, "top margin", 0, 100);
-       if (!dev->mode_config.tv_top_margin_property)
-               goto nomem;
-
-       dev->mode_config.tv_bottom_margin_property =
-               drm_property_create_range(dev, 0, "bottom margin", 0, 100);
-       if (!dev->mode_config.tv_bottom_margin_property)
-               goto nomem;
-
-       dev->mode_config.tv_mode_property =
-               drm_property_create(dev, DRM_MODE_PROP_ENUM,
-                                   "mode", num_modes);
-       if (!dev->mode_config.tv_mode_property)
-               goto nomem;
-
-       for (i = 0; i < num_modes; i++)
-               drm_property_add_enum(dev->mode_config.tv_mode_property, i,
-                                     i, modes[i]);
-
-       dev->mode_config.tv_brightness_property =
-               drm_property_create_range(dev, 0, "brightness", 0, 100);
-       if (!dev->mode_config.tv_brightness_property)
-               goto nomem;
-
-       dev->mode_config.tv_contrast_property =
-               drm_property_create_range(dev, 0, "contrast", 0, 100);
-       if (!dev->mode_config.tv_contrast_property)
-               goto nomem;
-
-       dev->mode_config.tv_flicker_reduction_property =
-               drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
-       if (!dev->mode_config.tv_flicker_reduction_property)
-               goto nomem;
-
-       dev->mode_config.tv_overscan_property =
-               drm_property_create_range(dev, 0, "overscan", 0, 100);
-       if (!dev->mode_config.tv_overscan_property)
-               goto nomem;
-
-       dev->mode_config.tv_saturation_property =
-               drm_property_create_range(dev, 0, "saturation", 0, 100);
-       if (!dev->mode_config.tv_saturation_property)
-               goto nomem;
-
-       dev->mode_config.tv_hue_property =
-               drm_property_create_range(dev, 0, "hue", 0, 100);
-       if (!dev->mode_config.tv_hue_property)
-               goto nomem;
-
-       return 0;
-nomem:
-       return -ENOMEM;
-}
-EXPORT_SYMBOL(drm_mode_create_tv_properties);
-
-/**
- * drm_mode_create_scaling_mode_property - create scaling mode property
- * @dev: DRM device
- *
- * Called by a driver the first time it's needed, must be attached to desired
- * connectors.
- */
-int drm_mode_create_scaling_mode_property(struct drm_device *dev)
-{
-       struct drm_property *scaling_mode;
-
-       if (dev->mode_config.scaling_mode_property)
-               return 0;
-
-       scaling_mode =
-               drm_property_create_enum(dev, 0, "scaling mode",
-                               drm_scaling_mode_enum_list,
-                                   ARRAY_SIZE(drm_scaling_mode_enum_list));
-
-       dev->mode_config.scaling_mode_property = scaling_mode;
-
-       return 0;
-}
-EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
-
-/**
- * drm_mode_create_aspect_ratio_property - create aspect ratio property
- * @dev: DRM device
- *
- * Called by a driver the first time it's needed, must be attached to desired
- * connectors.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
-{
-       if (dev->mode_config.aspect_ratio_property)
-               return 0;
-
-       dev->mode_config.aspect_ratio_property =
-               drm_property_create_enum(dev, 0, "aspect ratio",
-                               drm_aspect_ratio_enum_list,
-                               ARRAY_SIZE(drm_aspect_ratio_enum_list));
-
-       if (dev->mode_config.aspect_ratio_property == NULL)
-               return -ENOMEM;
-
-       return 0;
-}
-EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property);
-
-/**
- * drm_mode_create_dirty_property - create dirty property
- * @dev: DRM device
- *
- * Called by a driver the first time it's needed, must be attached to desired
- * connectors.
- */
-int drm_mode_create_dirty_info_property(struct drm_device *dev)
-{
-       struct drm_property *dirty_info;
-
-       if (dev->mode_config.dirty_info_property)
-               return 0;
-
-       dirty_info =
-               drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
-                                   "dirty",
-                                   drm_dirty_info_enum_list,
-                                   ARRAY_SIZE(drm_dirty_info_enum_list));
-       dev->mode_config.dirty_info_property = dirty_info;
-
-       return 0;
-}
-EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
-
-/**
- * drm_mode_create_suggested_offset_properties - create suggests offset properties
- * @dev: DRM device
- *
- * Create the the suggested x/y offset property for connectors.
- */
-int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
-{
-       if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property)
-               return 0;
-
-       dev->mode_config.suggested_x_property =
-               drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff);
-
-       dev->mode_config.suggested_y_property =
-               drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff);
-
-       if (dev->mode_config.suggested_x_property == NULL ||
-           dev->mode_config.suggested_y_property == NULL)
-               return -ENOMEM;
-       return 0;
-}
-EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties);
-
-/**
- * drm_mode_getresources - get graphics configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Construct a set of configuration description structures and return
- * them to the user, including CRTC, connector and framebuffer configuration.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_getresources(struct drm_device *dev, void *data,
-                         struct drm_file *file_priv)
-{
-       struct drm_mode_card_res *card_res = data;
-       struct list_head *lh;
-       struct drm_framebuffer *fb;
-       struct drm_connector *connector;
-       struct drm_crtc *crtc;
-       struct drm_encoder *encoder;
-       int ret = 0;
-       int connector_count = 0;
-       int crtc_count = 0;
-       int fb_count = 0;
-       int encoder_count = 0;
-       int copied = 0;
-       uint32_t __user *fb_id;
-       uint32_t __user *crtc_id;
-       uint32_t __user *connector_id;
-       uint32_t __user *encoder_id;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-
-       mutex_lock(&file_priv->fbs_lock);
-       /*
-        * For the non-control nodes we need to limit the list of resources
-        * by IDs in the group list for this node
-        */
-       list_for_each(lh, &file_priv->fbs)
-               fb_count++;
-
-       /* handle this in 4 parts */
-       /* FBs */
-       if (card_res->count_fbs >= fb_count) {
-               copied = 0;
-               fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
-               list_for_each_entry(fb, &file_priv->fbs, filp_head) {
-                       if (put_user(fb->base.id, fb_id + copied)) {
-                               mutex_unlock(&file_priv->fbs_lock);
-                               return -EFAULT;
-                       }
-                       copied++;
-               }
-       }
-       card_res->count_fbs = fb_count;
-       mutex_unlock(&file_priv->fbs_lock);
-
-       /* mode_config.mutex protects the connector list against e.g. DP MST
-        * connector hot-adding. CRTC/Plane lists are invariant. */
-       mutex_lock(&dev->mode_config.mutex);
-       drm_for_each_crtc(crtc, dev)
-               crtc_count++;
-
-       drm_for_each_connector(connector, dev)
-               connector_count++;
-
-       drm_for_each_encoder(encoder, dev)
-               encoder_count++;
-
-       card_res->max_height = dev->mode_config.max_height;
-       card_res->min_height = dev->mode_config.min_height;
-       card_res->max_width = dev->mode_config.max_width;
-       card_res->min_width = dev->mode_config.min_width;
-
-       /* CRTCs */
-       if (card_res->count_crtcs >= crtc_count) {
-               copied = 0;
-               crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
-               drm_for_each_crtc(crtc, dev) {
-                       if (put_user(crtc->base.id, crtc_id + copied)) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-                       copied++;
-               }
-       }
-       card_res->count_crtcs = crtc_count;
-
-       /* Encoders */
-       if (card_res->count_encoders >= encoder_count) {
-               copied = 0;
-               encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
-               drm_for_each_encoder(encoder, dev) {
-                       if (put_user(encoder->base.id, encoder_id +
-                                    copied)) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-                       copied++;
-               }
-       }
-       card_res->count_encoders = encoder_count;
-
-       /* Connectors */
-       if (card_res->count_connectors >= connector_count) {
-               copied = 0;
-               connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
-               drm_for_each_connector(connector, dev) {
-                       if (put_user(connector->base.id,
-                                    connector_id + copied)) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-                       copied++;
-               }
-       }
-       card_res->count_connectors = connector_count;
-
-out:
-       mutex_unlock(&dev->mode_config.mutex);
-       return ret;
-}
-
-/**
- * drm_mode_getcrtc - get CRTC configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Construct a CRTC configuration structure to return to the user.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_getcrtc(struct drm_device *dev,
-                    void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_crtc *crtc_resp = data;
-       struct drm_crtc *crtc;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
-       if (!crtc)
-               return -ENOENT;
-
-       drm_modeset_lock_crtc(crtc, crtc->primary);
-       crtc_resp->gamma_size = crtc->gamma_size;
-       if (crtc->primary->fb)
-               crtc_resp->fb_id = crtc->primary->fb->base.id;
-       else
-               crtc_resp->fb_id = 0;
-
-       if (crtc->state) {
-               crtc_resp->x = crtc->primary->state->src_x >> 16;
-               crtc_resp->y = crtc->primary->state->src_y >> 16;
-               if (crtc->state->enable) {
-                       drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
-                       crtc_resp->mode_valid = 1;
-
-               } else {
-                       crtc_resp->mode_valid = 0;
-               }
-       } else {
-               crtc_resp->x = crtc->x;
-               crtc_resp->y = crtc->y;
-               if (crtc->enabled) {
-                       drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode);
-                       crtc_resp->mode_valid = 1;
-
-               } else {
-                       crtc_resp->mode_valid = 0;
-               }
-       }
-       drm_modeset_unlock_crtc(crtc);
-
-       return 0;
-}
-
-static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
-                                        const struct drm_file *file_priv)
-{
-       /*
-        * If user-space hasn't configured the driver to expose the stereo 3D
-        * modes, don't expose them.
-        */
-       if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode))
-               return false;
-
-       return true;
-}
-
-static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
-{
-       /* For atomic drivers only state objects are synchronously updated and
-        * protected by modeset locks, so check those first. */
-       if (connector->state)
-               return connector->state->best_encoder;
-       return connector->encoder;
-}
-
-/* helper for getconnector and getproperties ioctls */
-static int get_properties(struct drm_mode_object *obj, bool atomic,
-               uint32_t __user *prop_ptr, uint64_t __user *prop_values,
-               uint32_t *arg_count_props)
-{
-       int props_count;
-       int i, ret, copied;
-
-       props_count = obj->properties->count;
-       if (!atomic)
-               props_count -= obj->properties->atomic_count;
-
-       if ((*arg_count_props >= props_count) && props_count) {
-               for (i = 0, copied = 0; copied < props_count; i++) {
-                       struct drm_property *prop = obj->properties->properties[i];
-                       uint64_t val;
-
-                       if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
-                               continue;
-
-                       ret = drm_object_property_get_value(obj, prop, &val);
-                       if (ret)
-                               return ret;
-
-                       if (put_user(prop->base.id, prop_ptr + copied))
-                               return -EFAULT;
-
-                       if (put_user(val, prop_values + copied))
-                               return -EFAULT;
-
-                       copied++;
-               }
-       }
-       *arg_count_props = props_count;
-
-       return 0;
-}
-
-/**
- * drm_mode_getconnector - get connector configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Construct a connector configuration structure to return to the user.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_getconnector(struct drm_device *dev, void *data,
-                         struct drm_file *file_priv)
-{
-       struct drm_mode_get_connector *out_resp = data;
-       struct drm_connector *connector;
-       struct drm_encoder *encoder;
-       struct drm_display_mode *mode;
-       int mode_count = 0;
-       int encoders_count = 0;
-       int ret = 0;
-       int copied = 0;
-       int i;
-       struct drm_mode_modeinfo u_mode;
-       struct drm_mode_modeinfo __user *mode_ptr;
-       uint32_t __user *encoder_ptr;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
-
-       mutex_lock(&dev->mode_config.mutex);
-
-       connector = drm_connector_lookup(dev, out_resp->connector_id);
-       if (!connector) {
-               ret = -ENOENT;
-               goto out_unlock;
-       }
-
-       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
-               if (connector->encoder_ids[i] != 0)
-                       encoders_count++;
-
-       if (out_resp->count_modes == 0) {
-               connector->funcs->fill_modes(connector,
-                                            dev->mode_config.max_width,
-                                            dev->mode_config.max_height);
-       }
-
-       /* delayed so we get modes regardless of pre-fill_modes state */
-       list_for_each_entry(mode, &connector->modes, head)
-               if (drm_mode_expose_to_userspace(mode, file_priv))
-                       mode_count++;
-
-       out_resp->connector_id = connector->base.id;
-       out_resp->connector_type = connector->connector_type;
-       out_resp->connector_type_id = connector->connector_type_id;
-       out_resp->mm_width = connector->display_info.width_mm;
-       out_resp->mm_height = connector->display_info.height_mm;
-       out_resp->subpixel = connector->display_info.subpixel_order;
-       out_resp->connection = connector->status;
-
-       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       encoder = drm_connector_get_encoder(connector);
-       if (encoder)
-               out_resp->encoder_id = encoder->base.id;
-       else
-               out_resp->encoder_id = 0;
-
-       /*
-        * This ioctl is called twice, once to determine how much space is
-        * needed, and the 2nd time to fill it.
-        */
-       if ((out_resp->count_modes >= mode_count) && mode_count) {
-               copied = 0;
-               mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
-               list_for_each_entry(mode, &connector->modes, head) {
-                       if (!drm_mode_expose_to_userspace(mode, file_priv))
-                               continue;
-
-                       drm_mode_convert_to_umode(&u_mode, mode);
-                       if (copy_to_user(mode_ptr + copied,
-                                        &u_mode, sizeof(u_mode))) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-                       copied++;
-               }
-       }
-       out_resp->count_modes = mode_count;
-
-       ret = get_properties(&connector->base, file_priv->atomic,
-                       (uint32_t __user *)(unsigned long)(out_resp->props_ptr),
-                       (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
-                       &out_resp->count_props);
-       if (ret)
-               goto out;
-
-       if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
-               copied = 0;
-               encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
-               for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-                       if (connector->encoder_ids[i] != 0) {
-                               if (put_user(connector->encoder_ids[i],
-                                            encoder_ptr + copied)) {
-                                       ret = -EFAULT;
-                                       goto out;
-                               }
-                               copied++;
-                       }
-               }
-       }
-       out_resp->count_encoders = encoders_count;
-
-out:
-       drm_modeset_unlock(&dev->mode_config.connection_mutex);
-
-       drm_connector_unreference(connector);
-out_unlock:
-       mutex_unlock(&dev->mode_config.mutex);
-
-       return ret;
-}
-
-static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
-{
-       struct drm_connector *connector;
-       struct drm_device *dev = encoder->dev;
-       bool uses_atomic = false;
-
-       /* For atomic drivers only state objects are synchronously updated and
-        * protected by modeset locks, so check those first. */
-       drm_for_each_connector(connector, dev) {
-               if (!connector->state)
-                       continue;
-
-               uses_atomic = true;
-
-               if (connector->state->best_encoder != encoder)
-                       continue;
-
-               return connector->state->crtc;
-       }
-
-       /* Don't return stale data (e.g. pending async disable). */
-       if (uses_atomic)
-               return NULL;
-
-       return encoder->crtc;
-}
-
-/**
- * drm_mode_getencoder - get encoder configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Construct a encoder configuration structure to return to the user.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_getencoder(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv)
-{
-       struct drm_mode_get_encoder *enc_resp = data;
-       struct drm_encoder *encoder;
-       struct drm_crtc *crtc;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       encoder = drm_encoder_find(dev, enc_resp->encoder_id);
-       if (!encoder)
-               return -ENOENT;
-
-       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       crtc = drm_encoder_get_crtc(encoder);
-       if (crtc)
-               enc_resp->crtc_id = crtc->base.id;
-       else
-               enc_resp->crtc_id = 0;
-       drm_modeset_unlock(&dev->mode_config.connection_mutex);
-
-       enc_resp->encoder_type = encoder->encoder_type;
-       enc_resp->encoder_id = encoder->base.id;
-       enc_resp->possible_crtcs = encoder->possible_crtcs;
-       enc_resp->possible_clones = encoder->possible_clones;
-
-       return 0;
-}
-
-/**
- * drm_mode_getplane_res - enumerate all plane resources
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
- *
- * Construct a list of plane ids to return to the user.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_getplane_res(struct drm_device *dev, void *data,
-                         struct drm_file *file_priv)
-{
-       struct drm_mode_get_plane_res *plane_resp = data;
-       struct drm_mode_config *config;
-       struct drm_plane *plane;
-       uint32_t __user *plane_ptr;
-       int copied = 0;
-       unsigned num_planes;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       config = &dev->mode_config;
-
-       if (file_priv->universal_planes)
-               num_planes = config->num_total_plane;
-       else
-               num_planes = config->num_overlay_plane;
-
-       /*
-        * This ioctl is called twice, once to determine how much space is
-        * needed, and the 2nd time to fill it.
-        */
-       if (num_planes &&
-           (plane_resp->count_planes >= num_planes)) {
-               plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
-
-               /* Plane lists are invariant, no locking needed. */
-               drm_for_each_plane(plane, dev) {
-                       /*
-                        * Unless userspace set the 'universal planes'
-                        * capability bit, only advertise overlays.
-                        */
-                       if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
-                           !file_priv->universal_planes)
-                               continue;
-
-                       if (put_user(plane->base.id, plane_ptr + copied))
-                               return -EFAULT;
-                       copied++;
-               }
-       }
-       plane_resp->count_planes = num_planes;
-
-       return 0;
-}
-
-/**
- * drm_mode_getplane - get plane configuration
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
- *
- * Construct a plane configuration structure to return to the user.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_getplane(struct drm_device *dev, void *data,
-                     struct drm_file *file_priv)
-{
-       struct drm_mode_get_plane *plane_resp = data;
-       struct drm_plane *plane;
-       uint32_t __user *format_ptr;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       plane = drm_plane_find(dev, plane_resp->plane_id);
-       if (!plane)
-               return -ENOENT;
-
-       drm_modeset_lock(&plane->mutex, NULL);
-       if (plane->crtc)
-               plane_resp->crtc_id = plane->crtc->base.id;
-       else
-               plane_resp->crtc_id = 0;
-
-       if (plane->fb)
-               plane_resp->fb_id = plane->fb->base.id;
-       else
-               plane_resp->fb_id = 0;
-       drm_modeset_unlock(&plane->mutex);
-
-       plane_resp->plane_id = plane->base.id;
-       plane_resp->possible_crtcs = plane->possible_crtcs;
-       plane_resp->gamma_size = 0;
-
-       /*
-        * This ioctl is called twice, once to determine how much space is
-        * needed, and the 2nd time to fill it.
-        */
-       if (plane->format_count &&
-           (plane_resp->count_format_types >= plane->format_count)) {
-               format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
-               if (copy_to_user(format_ptr,
-                                plane->format_types,
-                                sizeof(uint32_t) * plane->format_count)) {
-                       return -EFAULT;
-               }
-       }
-       plane_resp->count_format_types = plane->format_count;
-
-       return 0;
-}
-
-/**
- * drm_plane_check_pixel_format - Check if the plane supports the pixel format
- * @plane: plane to check for format support
- * @format: the pixel format
- *
- * Returns:
- * Zero of @plane has @format in its list of supported pixel formats, -EINVAL
- * otherwise.
- */
-int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
-{
-       unsigned int i;
-
-       for (i = 0; i < plane->format_count; i++) {
-               if (format == plane->format_types[i])
-                       return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int check_src_coords(uint32_t src_x, uint32_t src_y,
-                           uint32_t src_w, uint32_t src_h,
-                           const struct drm_framebuffer *fb)
-{
-       unsigned int fb_width, fb_height;
-
-       fb_width = fb->width << 16;
-       fb_height = fb->height << 16;
-
-       /* Make sure source coordinates are inside the fb. */
-       if (src_w > fb_width ||
-           src_x > fb_width - src_w ||
-           src_h > fb_height ||
-           src_y > fb_height - src_h) {
-               DRM_DEBUG_KMS("Invalid source coordinates "
-                             "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
-                             src_w >> 16, ((src_w & 0xffff) * 15625) >> 10,
-                             src_h >> 16, ((src_h & 0xffff) * 15625) >> 10,
-                             src_x >> 16, ((src_x & 0xffff) * 15625) >> 10,
-                             src_y >> 16, ((src_y & 0xffff) * 15625) >> 10);
-               return -ENOSPC;
-       }
-
-       return 0;
-}
-
-/*
- * setplane_internal - setplane handler for internal callers
- *
- * Note that we assume an extra reference has already been taken on fb.  If the
- * update fails, this reference will be dropped before return; if it succeeds,
- * the previous framebuffer (if any) will be unreferenced instead.
- *
- * src_{x,y,w,h} are provided in 16.16 fixed point format
- */
-static int __setplane_internal(struct drm_plane *plane,
-                              struct drm_crtc *crtc,
-                              struct drm_framebuffer *fb,
-                              int32_t crtc_x, int32_t crtc_y,
-                              uint32_t crtc_w, uint32_t crtc_h,
-                              /* src_{x,y,w,h} values are 16.16 fixed point */
-                              uint32_t src_x, uint32_t src_y,
-                              uint32_t src_w, uint32_t src_h)
-{
-       int ret = 0;
-
-       /* No fb means shut it down */
-       if (!fb) {
-               plane->old_fb = plane->fb;
-               ret = plane->funcs->disable_plane(plane);
-               if (!ret) {
-                       plane->crtc = NULL;
-                       plane->fb = NULL;
-               } else {
-                       plane->old_fb = NULL;
-               }
-               goto out;
-       }
-
-       /* Check whether this plane is usable on this CRTC */
-       if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
-               DRM_DEBUG_KMS("Invalid crtc for plane\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /* Check whether this plane supports the fb pixel format. */
-       ret = drm_plane_check_pixel_format(plane, fb->pixel_format);
-       if (ret) {
-               DRM_DEBUG_KMS("Invalid pixel format %s\n",
-                             drm_get_format_name(fb->pixel_format));
-               goto out;
-       }
-
-       /* Give drivers some help against integer overflows */
-       if (crtc_w > INT_MAX ||
-           crtc_x > INT_MAX - (int32_t) crtc_w ||
-           crtc_h > INT_MAX ||
-           crtc_y > INT_MAX - (int32_t) crtc_h) {
-               DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
-                             crtc_w, crtc_h, crtc_x, crtc_y);
-               ret = -ERANGE;
-               goto out;
-       }
-
-       ret = check_src_coords(src_x, src_y, src_w, src_h, fb);
-       if (ret)
-               goto out;
-
-       plane->old_fb = plane->fb;
-       ret = plane->funcs->update_plane(plane, crtc, fb,
-                                        crtc_x, crtc_y, crtc_w, crtc_h,
-                                        src_x, src_y, src_w, src_h);
-       if (!ret) {
-               plane->crtc = crtc;
-               plane->fb = fb;
-               fb = NULL;
-       } else {
-               plane->old_fb = NULL;
-       }
-
-out:
-       if (fb)
-               drm_framebuffer_unreference(fb);
-       if (plane->old_fb)
-               drm_framebuffer_unreference(plane->old_fb);
-       plane->old_fb = NULL;
-
-       return ret;
-}
-
-static int setplane_internal(struct drm_plane *plane,
-                            struct drm_crtc *crtc,
-                            struct drm_framebuffer *fb,
-                            int32_t crtc_x, int32_t crtc_y,
-                            uint32_t crtc_w, uint32_t crtc_h,
-                            /* src_{x,y,w,h} values are 16.16 fixed point */
-                            uint32_t src_x, uint32_t src_y,
-                            uint32_t src_w, uint32_t src_h)
-{
-       int ret;
-
-       drm_modeset_lock_all(plane->dev);
-       ret = __setplane_internal(plane, crtc, fb,
-                                 crtc_x, crtc_y, crtc_w, crtc_h,
-                                 src_x, src_y, src_w, src_h);
-       drm_modeset_unlock_all(plane->dev);
-
-       return ret;
-}
-
-/**
- * drm_mode_setplane - configure a plane's configuration
- * @dev: DRM device
- * @data: ioctl data*
- * @file_priv: DRM file info
- *
- * Set plane configuration, including placement, fb, scaling, and other factors.
- * Or pass a NULL fb to disable (planes may be disabled without providing a
- * valid crtc).
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_setplane(struct drm_device *dev, void *data,
-                     struct drm_file *file_priv)
-{
-       struct drm_mode_set_plane *plane_req = data;
-       struct drm_plane *plane;
-       struct drm_crtc *crtc = NULL;
-       struct drm_framebuffer *fb = NULL;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       /*
-        * First, find the plane, crtc, and fb objects.  If not available,
-        * we don't bother to call the driver.
-        */
-       plane = drm_plane_find(dev, plane_req->plane_id);
-       if (!plane) {
-               DRM_DEBUG_KMS("Unknown plane ID %d\n",
-                             plane_req->plane_id);
-               return -ENOENT;
-       }
-
-       if (plane_req->fb_id) {
-               fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
-               if (!fb) {
-                       DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
-                                     plane_req->fb_id);
-                       return -ENOENT;
-               }
-
-               crtc = drm_crtc_find(dev, plane_req->crtc_id);
-               if (!crtc) {
-                       DRM_DEBUG_KMS("Unknown crtc ID %d\n",
-                                     plane_req->crtc_id);
-                       return -ENOENT;
-               }
-       }
-
-       /*
-        * setplane_internal will take care of deref'ing either the old or new
-        * framebuffer depending on success.
-        */
-       return setplane_internal(plane, crtc, fb,
-                                plane_req->crtc_x, plane_req->crtc_y,
-                                plane_req->crtc_w, plane_req->crtc_h,
-                                plane_req->src_x, plane_req->src_y,
-                                plane_req->src_w, plane_req->src_h);
-}
-
-/**
- * drm_mode_set_config_internal - helper to call ->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.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_set_config_internal(struct drm_mode_set *set)
-{
-       struct drm_crtc *crtc = set->crtc;
-       struct drm_framebuffer *fb;
-       struct drm_crtc *tmp;
-       int ret;
-
-       /*
-        * NOTE: ->set_config can also disable other crtcs (if we steal all
-        * connectors from it), hence we need to refcount the fbs across all
-        * crtcs. Atomic modeset will have saner semantics ...
-        */
-       drm_for_each_crtc(tmp, crtc->dev)
-               tmp->primary->old_fb = tmp->primary->fb;
-
-       fb = set->fb;
-
-       ret = crtc->funcs->set_config(set);
-       if (ret == 0) {
-               crtc->primary->crtc = crtc;
-               crtc->primary->fb = fb;
-       }
-
-       drm_for_each_crtc(tmp, crtc->dev) {
-               if (tmp->primary->fb)
-                       drm_framebuffer_reference(tmp->primary->fb);
-               if (tmp->primary->old_fb)
-                       drm_framebuffer_unreference(tmp->primary->old_fb);
-               tmp->primary->old_fb = NULL;
-       }
-
-       return ret;
-}
-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
- * @x: x panning
- * @y: y panning
- * @mode: mode that framebuffer will be displayed under
- * @fb: framebuffer to check size of
- */
-int drm_crtc_check_viewport(const struct drm_crtc *crtc,
-                           int x, int y,
-                           const struct drm_display_mode *mode,
-                           const struct drm_framebuffer *fb)
-
-{
-       int hdisplay, vdisplay;
-
-       drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
-
-       if (crtc->state &&
-           crtc->primary->state->rotation & (BIT(DRM_ROTATE_90) |
-                                             BIT(DRM_ROTATE_270)))
-               swap(hdisplay, vdisplay);
-
-       return check_src_coords(x << 16, y << 16,
-                               hdisplay << 16, vdisplay << 16, fb);
-}
-EXPORT_SYMBOL(drm_crtc_check_viewport);
-
-/**
- * drm_mode_setcrtc - set CRTC configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Build a new CRTC configuration based on user request.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_setcrtc(struct drm_device *dev, void *data,
-                    struct drm_file *file_priv)
-{
-       struct drm_mode_config *config = &dev->mode_config;
-       struct drm_mode_crtc *crtc_req = data;
-       struct drm_crtc *crtc;
-       struct drm_connector **connector_set = NULL, *connector;
-       struct drm_framebuffer *fb = NULL;
-       struct drm_display_mode *mode = NULL;
-       struct drm_mode_set set;
-       uint32_t __user *set_connectors_ptr;
-       int ret;
-       int i;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       /*
-        * Universal plane src offsets are only 16.16, prevent havoc for
-        * drivers using universal plane code internally.
-        */
-       if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000)
-               return -ERANGE;
-
-       drm_modeset_lock_all(dev);
-       crtc = drm_crtc_find(dev, crtc_req->crtc_id);
-       if (!crtc) {
-               DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
-               ret = -ENOENT;
-               goto out;
-       }
-       DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
-
-       if (crtc_req->mode_valid) {
-               /* If we have a mode we need a framebuffer. */
-               /* If we pass -1, set the mode with the currently bound fb */
-               if (crtc_req->fb_id == -1) {
-                       if (!crtc->primary->fb) {
-                               DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
-                               ret = -EINVAL;
-                               goto out;
-                       }
-                       fb = crtc->primary->fb;
-                       /* Make refcounting symmetric with the lookup path. */
-                       drm_framebuffer_reference(fb);
-               } else {
-                       fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
-                       if (!fb) {
-                               DRM_DEBUG_KMS("Unknown FB ID%d\n",
-                                               crtc_req->fb_id);
-                               ret = -ENOENT;
-                               goto out;
-                       }
-               }
-
-               mode = drm_mode_create(dev);
-               if (!mode) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               ret = drm_mode_convert_umode(mode, &crtc_req->mode);
-               if (ret) {
-                       DRM_DEBUG_KMS("Invalid mode\n");
-                       goto out;
-               }
-
-               /*
-                * Check whether the primary plane supports the fb pixel format.
-                * Drivers not implementing the universal planes API use a
-                * default formats list provided by the DRM core which doesn't
-                * match real hardware capabilities. Skip the check in that
-                * case.
-                */
-               if (!crtc->primary->format_default) {
-                       ret = drm_plane_check_pixel_format(crtc->primary,
-                                                          fb->pixel_format);
-                       if (ret) {
-                               DRM_DEBUG_KMS("Invalid pixel format %s\n",
-                                       drm_get_format_name(fb->pixel_format));
-                               goto out;
-                       }
-               }
-
-               ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
-                                             mode, fb);
-               if (ret)
-                       goto out;
-
-       }
-
-       if (crtc_req->count_connectors == 0 && mode) {
-               DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
-               DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
-                         crtc_req->count_connectors);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (crtc_req->count_connectors > 0) {
-               u32 out_id;
-
-               /* Avoid unbounded kernel memory allocation */
-               if (crtc_req->count_connectors > config->num_connector) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               connector_set = kmalloc_array(crtc_req->count_connectors,
-                                             sizeof(struct drm_connector *),
-                                             GFP_KERNEL);
-               if (!connector_set) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               for (i = 0; i < crtc_req->count_connectors; i++) {
-                       connector_set[i] = NULL;
-                       set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
-                       if (get_user(out_id, &set_connectors_ptr[i])) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-
-                       connector = drm_connector_lookup(dev, out_id);
-                       if (!connector) {
-                               DRM_DEBUG_KMS("Connector id %d unknown\n",
-                                               out_id);
-                               ret = -ENOENT;
-                               goto out;
-                       }
-                       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                                       connector->base.id,
-                                       connector->name);
-
-                       connector_set[i] = connector;
-               }
-       }
-
-       set.crtc = crtc;
-       set.x = crtc_req->x;
-       set.y = crtc_req->y;
-       set.mode = mode;
-       set.connectors = connector_set;
-       set.num_connectors = crtc_req->count_connectors;
-       set.fb = fb;
-       ret = drm_mode_set_config_internal(&set);
-
-out:
-       if (fb)
-               drm_framebuffer_unreference(fb);
-
-       if (connector_set) {
-               for (i = 0; i < crtc_req->count_connectors; i++) {
-                       if (connector_set[i])
-                               drm_connector_unreference(connector_set[i]);
-               }
-       }
-       kfree(connector_set);
-       drm_mode_destroy(dev, mode);
-       drm_modeset_unlock_all(dev);
-       return ret;
-}
-
-/**
- * drm_mode_cursor_universal - translate legacy cursor ioctl call into a
- *     universal plane handler call
- * @crtc: crtc to update cursor for
- * @req: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Legacy cursor ioctl's work directly with driver buffer handles.  To
- * translate legacy ioctl calls into universal plane handler calls, we need to
- * wrap the native buffer handle in a drm_framebuffer.
- *
- * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB
- * buffer with a pitch of 4*width; the universal plane interface should be used
- * directly in cases where the hardware can support other buffer settings and
- * userspace wants to make use of these capabilities.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-static int drm_mode_cursor_universal(struct drm_crtc *crtc,
-                                    struct drm_mode_cursor2 *req,
-                                    struct drm_file *file_priv)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_framebuffer *fb = NULL;
-       struct drm_mode_fb_cmd2 fbreq = {
-               .width = req->width,
-               .height = req->height,
-               .pixel_format = DRM_FORMAT_ARGB8888,
-               .pitches = { req->width * 4 },
-               .handles = { req->handle },
-       };
-       int32_t crtc_x, crtc_y;
-       uint32_t crtc_w = 0, crtc_h = 0;
-       uint32_t src_w = 0, src_h = 0;
-       int ret = 0;
-
-       BUG_ON(!crtc->cursor);
-       WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL);
-
-       /*
-        * Obtain fb we'll be using (either new or existing) and take an extra
-        * reference to it if fb != null.  setplane will take care of dropping
-        * the reference if the plane update fails.
-        */
-       if (req->flags & DRM_MODE_CURSOR_BO) {
-               if (req->handle) {
-                       fb = internal_framebuffer_create(dev, &fbreq, file_priv);
-                       if (IS_ERR(fb)) {
-                               DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
-                               return PTR_ERR(fb);
-                       }
-                       fb->hot_x = req->hot_x;
-                       fb->hot_y = req->hot_y;
-               } else {
-                       fb = NULL;
-               }
-       } else {
-               fb = crtc->cursor->fb;
-               if (fb)
-                       drm_framebuffer_reference(fb);
-       }
-
-       if (req->flags & DRM_MODE_CURSOR_MOVE) {
-               crtc_x = req->x;
-               crtc_y = req->y;
-       } else {
-               crtc_x = crtc->cursor_x;
-               crtc_y = crtc->cursor_y;
-       }
-
-       if (fb) {
-               crtc_w = fb->width;
-               crtc_h = fb->height;
-               src_w = fb->width << 16;
-               src_h = fb->height << 16;
-       }
-
-       /*
-        * setplane_internal will take care of deref'ing either the old or new
-        * framebuffer depending on success.
-        */
-       ret = __setplane_internal(crtc->cursor, crtc, fb,
-                               crtc_x, crtc_y, crtc_w, crtc_h,
-                               0, 0, src_w, src_h);
-
-       /* Update successful; save new cursor position, if necessary */
-       if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
-               crtc->cursor_x = req->x;
-               crtc->cursor_y = req->y;
-       }
-
-       return ret;
-}
-
-static int drm_mode_cursor_common(struct drm_device *dev,
-                                 struct drm_mode_cursor2 *req,
-                                 struct drm_file *file_priv)
-{
-       struct drm_crtc *crtc;
-       int ret = 0;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
-               return -EINVAL;
-
-       crtc = drm_crtc_find(dev, req->crtc_id);
-       if (!crtc) {
-               DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
-               return -ENOENT;
-       }
-
-       /*
-        * If this crtc has a universal cursor plane, call that plane's update
-        * handler rather than using legacy cursor handlers.
-        */
-       drm_modeset_lock_crtc(crtc, crtc->cursor);
-       if (crtc->cursor) {
-               ret = drm_mode_cursor_universal(crtc, req, file_priv);
-               goto out;
-       }
-
-       if (req->flags & DRM_MODE_CURSOR_BO) {
-               if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
-                       ret = -ENXIO;
-                       goto out;
-               }
-               /* Turns off the cursor if handle is 0 */
-               if (crtc->funcs->cursor_set2)
-                       ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
-                                                     req->width, req->height, req->hot_x, req->hot_y);
-               else
-                       ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
-                                                     req->width, req->height);
-       }
-
-       if (req->flags & DRM_MODE_CURSOR_MOVE) {
-               if (crtc->funcs->cursor_move) {
-                       ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
-               } else {
-                       ret = -EFAULT;
-                       goto out;
-               }
-       }
-out:
-       drm_modeset_unlock_crtc(crtc);
-
-       return ret;
-
-}
-
-
-/**
- * drm_mode_cursor_ioctl - set CRTC's cursor configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Set the cursor configuration based on user request.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_cursor_ioctl(struct drm_device *dev,
-                         void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_cursor *req = data;
-       struct drm_mode_cursor2 new_req;
-
-       memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
-       new_req.hot_x = new_req.hot_y = 0;
-
-       return drm_mode_cursor_common(dev, &new_req, file_priv);
-}
-
-/**
- * drm_mode_cursor2_ioctl - set CRTC's cursor configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Set the cursor configuration based on user request. This implements the 2nd
- * version of the cursor ioctl, which allows userspace to additionally specify
- * the hotspot of the pointer.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_cursor2_ioctl(struct drm_device *dev,
-                          void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_cursor2 *req = data;
-
-       return drm_mode_cursor_common(dev, req, file_priv);
-}
-
-/**
- * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
- * @bpp: bits per pixels
- * @depth: bit depth per pixel
- *
- * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
- * Useful in fbdev emulation code, since that deals in those values.
- */
-uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
-{
-       uint32_t fmt;
-
-       switch (bpp) {
-       case 8:
-               fmt = DRM_FORMAT_C8;
-               break;
-       case 16:
-               if (depth == 15)
-                       fmt = DRM_FORMAT_XRGB1555;
-               else
-                       fmt = DRM_FORMAT_RGB565;
-               break;
-       case 24:
-               fmt = DRM_FORMAT_RGB888;
-               break;
-       case 32:
-               if (depth == 24)
-                       fmt = DRM_FORMAT_XRGB8888;
-               else if (depth == 30)
-                       fmt = DRM_FORMAT_XRGB2101010;
-               else
-                       fmt = DRM_FORMAT_ARGB8888;
-               break;
-       default:
-               DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
-               fmt = DRM_FORMAT_XRGB8888;
-               break;
-       }
-
-       return fmt;
-}
-EXPORT_SYMBOL(drm_mode_legacy_fb_format);
-
-/**
- * drm_mode_addfb - add an FB to the graphics configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Add a new FB to the specified CRTC, given a user request. This is the
- * original addfb ioctl which only supported RGB formats.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_addfb(struct drm_device *dev,
-                  void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_fb_cmd *or = data;
-       struct drm_mode_fb_cmd2 r = {};
-       int ret;
-
-       /* convert to new format and call new ioctl */
-       r.fb_id = or->fb_id;
-       r.width = or->width;
-       r.height = or->height;
-       r.pitches[0] = or->pitch;
-       r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
-       r.handles[0] = or->handle;
-
-       ret = drm_mode_addfb2(dev, &r, file_priv);
-       if (ret)
-               return ret;
-
-       or->fb_id = r.fb_id;
-
-       return 0;
-}
-
-static int format_check(const struct drm_mode_fb_cmd2 *r)
-{
-       uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
-
-       switch (format) {
-       case DRM_FORMAT_C8:
-       case DRM_FORMAT_RGB332:
-       case DRM_FORMAT_BGR233:
-       case DRM_FORMAT_XRGB4444:
-       case DRM_FORMAT_XBGR4444:
-       case DRM_FORMAT_RGBX4444:
-       case DRM_FORMAT_BGRX4444:
-       case DRM_FORMAT_ARGB4444:
-       case DRM_FORMAT_ABGR4444:
-       case DRM_FORMAT_RGBA4444:
-       case DRM_FORMAT_BGRA4444:
-       case DRM_FORMAT_XRGB1555:
-       case DRM_FORMAT_XBGR1555:
-       case DRM_FORMAT_RGBX5551:
-       case DRM_FORMAT_BGRX5551:
-       case DRM_FORMAT_ARGB1555:
-       case DRM_FORMAT_ABGR1555:
-       case DRM_FORMAT_RGBA5551:
-       case DRM_FORMAT_BGRA5551:
-       case DRM_FORMAT_RGB565:
-       case DRM_FORMAT_BGR565:
-       case DRM_FORMAT_RGB888:
-       case DRM_FORMAT_BGR888:
-       case DRM_FORMAT_XRGB8888:
-       case DRM_FORMAT_XBGR8888:
-       case DRM_FORMAT_RGBX8888:
-       case DRM_FORMAT_BGRX8888:
-       case DRM_FORMAT_ARGB8888:
-       case DRM_FORMAT_ABGR8888:
-       case DRM_FORMAT_RGBA8888:
-       case DRM_FORMAT_BGRA8888:
-       case DRM_FORMAT_XRGB2101010:
-       case DRM_FORMAT_XBGR2101010:
-       case DRM_FORMAT_RGBX1010102:
-       case DRM_FORMAT_BGRX1010102:
-       case DRM_FORMAT_ARGB2101010:
-       case DRM_FORMAT_ABGR2101010:
-       case DRM_FORMAT_RGBA1010102:
-       case DRM_FORMAT_BGRA1010102:
-       case DRM_FORMAT_YUYV:
-       case DRM_FORMAT_YVYU:
-       case DRM_FORMAT_UYVY:
-       case DRM_FORMAT_VYUY:
-       case DRM_FORMAT_AYUV:
-       case DRM_FORMAT_NV12:
-       case DRM_FORMAT_NV21:
-       case DRM_FORMAT_NV16:
-       case DRM_FORMAT_NV61:
-       case DRM_FORMAT_NV24:
-       case DRM_FORMAT_NV42:
-       case DRM_FORMAT_YUV410:
-       case DRM_FORMAT_YVU410:
-       case DRM_FORMAT_YUV411:
-       case DRM_FORMAT_YVU411:
-       case DRM_FORMAT_YUV420:
-       case DRM_FORMAT_YVU420:
-       case DRM_FORMAT_YUV422:
-       case DRM_FORMAT_YVU422:
-       case DRM_FORMAT_YUV444:
-       case DRM_FORMAT_YVU444:
-               return 0;
-       default:
-               DRM_DEBUG_KMS("invalid pixel format %s\n",
-                             drm_get_format_name(r->pixel_format));
-               return -EINVAL;
-       }
-}
-
-static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
-{
-       int ret, hsub, vsub, num_planes, i;
-
-       ret = format_check(r);
-       if (ret) {
-               DRM_DEBUG_KMS("bad framebuffer format %s\n",
-                             drm_get_format_name(r->pixel_format));
-               return ret;
-       }
-
-       hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
-       vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
-       num_planes = drm_format_num_planes(r->pixel_format);
-
-       if (r->width == 0 || r->width % hsub) {
-               DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
-               return -EINVAL;
-       }
-
-       if (r->height == 0 || r->height % vsub) {
-               DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < num_planes; i++) {
-               unsigned int width = r->width / (i != 0 ? hsub : 1);
-               unsigned int height = r->height / (i != 0 ? vsub : 1);
-               unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
-
-               if (!r->handles[i]) {
-                       DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
-                       return -EINVAL;
-               }
-
-               if ((uint64_t) width * cpp > UINT_MAX)
-                       return -ERANGE;
-
-               if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
-                       return -ERANGE;
-
-               if (r->pitches[i] < width * cpp) {
-                       DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
-                       return -EINVAL;
-               }
-
-               if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
-                       DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n",
-                                     r->modifier[i], i);
-                       return -EINVAL;
-               }
-
-               /* modifier specific checks: */
-               switch (r->modifier[i]) {
-               case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
-                       /* NOTE: the pitch restriction may be lifted later if it turns
-                        * out that no hw has this restriction:
-                        */
-                       if (r->pixel_format != DRM_FORMAT_NV12 ||
-                                       width % 128 || height % 32 ||
-                                       r->pitches[i] % 128) {
-                               DRM_DEBUG_KMS("bad modifier data for plane %d\n", i);
-                               return -EINVAL;
-                       }
-                       break;
-
-               default:
-                       break;
-               }
-       }
-
-       for (i = num_planes; i < 4; i++) {
-               if (r->modifier[i]) {
-                       DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i);
-                       return -EINVAL;
-               }
-
-               /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */
-               if (!(r->flags & DRM_MODE_FB_MODIFIERS))
-                       continue;
-
-               if (r->handles[i]) {
-                       DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i);
-                       return -EINVAL;
-               }
-
-               if (r->pitches[i]) {
-                       DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i);
-                       return -EINVAL;
-               }
-
-               if (r->offsets[i]) {
-                       DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i);
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-
-static struct drm_framebuffer *
-internal_framebuffer_create(struct drm_device *dev,
-                           const struct drm_mode_fb_cmd2 *r,
-                           struct drm_file *file_priv)
-{
-       struct drm_mode_config *config = &dev->mode_config;
-       struct drm_framebuffer *fb;
-       int ret;
-
-       if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
-               DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
-               return ERR_PTR(-EINVAL);
-       }
-
-       if ((config->min_width > r->width) || (r->width > config->max_width)) {
-               DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
-                         r->width, config->min_width, config->max_width);
-               return ERR_PTR(-EINVAL);
-       }
-       if ((config->min_height > r->height) || (r->height > config->max_height)) {
-               DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
-                         r->height, config->min_height, config->max_height);
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (r->flags & DRM_MODE_FB_MODIFIERS &&
-           !dev->mode_config.allow_fb_modifiers) {
-               DRM_DEBUG_KMS("driver does not support fb modifiers\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       ret = framebuffer_check(r);
-       if (ret)
-               return ERR_PTR(ret);
-
-       fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
-       if (IS_ERR(fb)) {
-               DRM_DEBUG_KMS("could not create framebuffer\n");
-               return fb;
-       }
-
-       return fb;
-}
-
-/**
- * drm_mode_addfb2 - add an FB to the graphics configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Add a new FB to the specified CRTC, given a user request with format. This is
- * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
- * and uses fourcc codes as pixel format specifiers.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_addfb2(struct drm_device *dev,
-                   void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_fb_cmd2 *r = data;
-       struct drm_framebuffer *fb;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       fb = internal_framebuffer_create(dev, r, file_priv);
-       if (IS_ERR(fb))
-               return PTR_ERR(fb);
-
-       DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
-       r->fb_id = fb->base.id;
-
-       /* Transfer ownership to the filp for reaping on close */
-       mutex_lock(&file_priv->fbs_lock);
-       list_add(&fb->filp_head, &file_priv->fbs);
-       mutex_unlock(&file_priv->fbs_lock);
-
-       return 0;
-}
-
-struct drm_mode_rmfb_work {
-       struct work_struct work;
-       struct list_head fbs;
-};
-
-static void drm_mode_rmfb_work_fn(struct work_struct *w)
-{
-       struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work);
-
-       while (!list_empty(&arg->fbs)) {
-               struct drm_framebuffer *fb =
-                       list_first_entry(&arg->fbs, typeof(*fb), filp_head);
-
-               list_del_init(&fb->filp_head);
-               drm_framebuffer_remove(fb);
-       }
-}
-
-/**
- * drm_mode_rmfb - remove an FB from the configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Remove the FB specified by the user.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_rmfb(struct drm_device *dev,
-                  void *data, struct drm_file *file_priv)
-{
-       struct drm_framebuffer *fb = NULL;
-       struct drm_framebuffer *fbl = NULL;
-       uint32_t *id = data;
-       int found = 0;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       fb = drm_framebuffer_lookup(dev, *id);
-       if (!fb)
-               return -ENOENT;
-
-       mutex_lock(&file_priv->fbs_lock);
-       list_for_each_entry(fbl, &file_priv->fbs, filp_head)
-               if (fb == fbl)
-                       found = 1;
-       if (!found) {
-               mutex_unlock(&file_priv->fbs_lock);
-               goto fail_unref;
-       }
-
-       list_del_init(&fb->filp_head);
-       mutex_unlock(&file_priv->fbs_lock);
-
-       /* drop the reference we picked up in framebuffer lookup */
-       drm_framebuffer_unreference(fb);
-
-       /*
-        * we now own the reference that was stored in the fbs list
-        *
-        * drm_framebuffer_remove may fail with -EINTR on pending signals,
-        * so run this in a separate stack as there's no way to correctly
-        * handle this after the fb is already removed from the lookup table.
-        */
-       if (drm_framebuffer_read_refcount(fb) > 1) {
-               struct drm_mode_rmfb_work arg;
-
-               INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn);
-               INIT_LIST_HEAD(&arg.fbs);
-               list_add_tail(&fb->filp_head, &arg.fbs);
-
-               schedule_work(&arg.work);
-               flush_work(&arg.work);
-               destroy_work_on_stack(&arg.work);
-       } else
-               drm_framebuffer_unreference(fb);
-
-       return 0;
-
-fail_unref:
-       drm_framebuffer_unreference(fb);
-       return -ENOENT;
-}
-
-/**
- * drm_mode_getfb - get FB info
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Lookup the FB given its ID and return info about it.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_getfb(struct drm_device *dev,
-                  void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_fb_cmd *r = data;
-       struct drm_framebuffer *fb;
-       int ret;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       fb = drm_framebuffer_lookup(dev, r->fb_id);
-       if (!fb)
-               return -ENOENT;
-
-       r->height = fb->height;
-       r->width = fb->width;
-       r->depth = fb->depth;
-       r->bpp = fb->bits_per_pixel;
-       r->pitch = fb->pitches[0];
-       if (fb->funcs->create_handle) {
-               if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) ||
-                   drm_is_control_client(file_priv)) {
-                       ret = fb->funcs->create_handle(fb, file_priv,
-                                                      &r->handle);
-               } else {
-                       /* GET_FB() is an unprivileged ioctl so we must not
-                        * return a buffer-handle to non-master processes! For
-                        * backwards-compatibility reasons, we cannot make
-                        * GET_FB() privileged, so just return an invalid handle
-                        * for non-masters. */
-                       r->handle = 0;
-                       ret = 0;
-               }
-       } else {
-               ret = -ENODEV;
-       }
-
-       drm_framebuffer_unreference(fb);
-
-       return ret;
-}
-
-/**
- * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Lookup the FB and flush out the damaged area supplied by userspace as a clip
- * rectangle list. Generic userspace which does frontbuffer rendering must call
- * this ioctl to flush out the changes on manual-update display outputs, e.g.
- * 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.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
-                          void *data, struct drm_file *file_priv)
-{
-       struct drm_clip_rect __user *clips_ptr;
-       struct drm_clip_rect *clips = NULL;
-       struct drm_mode_fb_dirty_cmd *r = data;
-       struct drm_framebuffer *fb;
-       unsigned flags;
-       int num_clips;
-       int ret;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       fb = drm_framebuffer_lookup(dev, r->fb_id);
-       if (!fb)
-               return -ENOENT;
-
-       num_clips = r->num_clips;
-       clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
-
-       if (!num_clips != !clips_ptr) {
-               ret = -EINVAL;
-               goto out_err1;
-       }
-
-       flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
-
-       /* If userspace annotates copy, clips must come in pairs */
-       if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
-               ret = -EINVAL;
-               goto out_err1;
-       }
-
-       if (num_clips && clips_ptr) {
-               if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
-                       ret = -EINVAL;
-                       goto out_err1;
-               }
-               clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
-               if (!clips) {
-                       ret = -ENOMEM;
-                       goto out_err1;
-               }
-
-               ret = copy_from_user(clips, clips_ptr,
-                                    num_clips * sizeof(*clips));
-               if (ret) {
-                       ret = -EFAULT;
-                       goto out_err2;
-               }
-       }
-
-       if (fb->funcs->dirty) {
-               ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
-                                      clips, num_clips);
-       } else {
-               ret = -ENOSYS;
-       }
-
-out_err2:
-       kfree(clips);
-out_err1:
-       drm_framebuffer_unreference(fb);
-
-       return ret;
-}
-
-/**
- * drm_fb_release - remove and free the FBs on this file
- * @priv: drm file for the ioctl
- *
- * Destroy all the FBs associated with @filp.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-void drm_fb_release(struct drm_file *priv)
-{
-       struct drm_framebuffer *fb, *tfb;
-       struct drm_mode_rmfb_work arg;
-
-       INIT_LIST_HEAD(&arg.fbs);
-
-       /*
-        * When the file gets released that means no one else can access the fb
-        * list any more, so no need to grab fpriv->fbs_lock. And we need to
-        * avoid upsetting lockdep since the universal cursor code adds a
-        * framebuffer while holding mutex locks.
-        *
-        * Note that a real deadlock between fpriv->fbs_lock and the modeset
-        * locks is impossible here since no one else but this function can get
-        * at it any more.
-        */
-       list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
-               if (drm_framebuffer_read_refcount(fb) > 1) {
-                       list_move_tail(&fb->filp_head, &arg.fbs);
-               } else {
-                       list_del_init(&fb->filp_head);
-
-                       /* This drops the fpriv->fbs reference. */
-                       drm_framebuffer_unreference(fb);
-               }
-       }
-
-       if (!list_empty(&arg.fbs)) {
-               INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn);
-
-               schedule_work(&arg.work);
-               flush_work(&arg.work);
-               destroy_work_on_stack(&arg.work);
-       }
-}
-
-static bool drm_property_type_valid(struct drm_property *property)
-{
-       if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
-               return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
-       return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
-}
-
-/**
- * drm_property_create - create a new property type
- * @dev: drm device
- * @flags: flags specifying the property type
- * @name: name of the property
- * @num_values: number of pre-defined values
- *
- * This creates a new generic drm property which can then be attached to a drm
- * object with drm_object_attach_property. The returned property object must be
- * freed with drm_property_destroy.
- *
- * Note that the DRM core keeps a per-device list of properties and that, if
- * drm_mode_config_cleanup() is called, it will destroy all properties created
- * by the driver.
- *
- * Returns:
- * A pointer to the newly created property on success, NULL on failure.
- */
-struct drm_property *drm_property_create(struct drm_device *dev, int flags,
-                                        const char *name, int num_values)
-{
-       struct drm_property *property = NULL;
-       int ret;
-
-       property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
-       if (!property)
-               return NULL;
-
-       property->dev = dev;
-
-       if (num_values) {
-               property->values = kcalloc(num_values, sizeof(uint64_t),
-                                          GFP_KERNEL);
-               if (!property->values)
-                       goto fail;
-       }
-
-       ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
-       if (ret)
-               goto fail;
-
-       property->flags = flags;
-       property->num_values = num_values;
-       INIT_LIST_HEAD(&property->enum_list);
-
-       if (name) {
-               strncpy(property->name, name, DRM_PROP_NAME_LEN);
-               property->name[DRM_PROP_NAME_LEN-1] = '\0';
-       }
-
-       list_add_tail(&property->head, &dev->mode_config.property_list);
-
-       WARN_ON(!drm_property_type_valid(property));
-
-       return property;
-fail:
-       kfree(property->values);
-       kfree(property);
-       return NULL;
-}
-EXPORT_SYMBOL(drm_property_create);
-
-/**
- * drm_property_create_enum - create a new enumeration property type
- * @dev: drm device
- * @flags: flags specifying the property type
- * @name: name of the property
- * @props: enumeration lists with property values
- * @num_values: number of pre-defined values
- *
- * This creates a new generic drm property which can then be attached to a drm
- * object with drm_object_attach_property. The returned property object must be
- * freed with drm_property_destroy.
- *
- * Userspace is only allowed to set one of the predefined values for enumeration
- * properties.
- *
- * Returns:
- * A pointer to the newly created property on success, NULL on failure.
- */
-struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
-                                        const char *name,
-                                        const struct drm_prop_enum_list *props,
-                                        int num_values)
-{
-       struct drm_property *property;
-       int i, ret;
-
-       flags |= DRM_MODE_PROP_ENUM;
-
-       property = drm_property_create(dev, flags, name, num_values);
-       if (!property)
-               return NULL;
-
-       for (i = 0; i < num_values; i++) {
-               ret = drm_property_add_enum(property, i,
-                                     props[i].type,
-                                     props[i].name);
-               if (ret) {
-                       drm_property_destroy(dev, property);
-                       return NULL;
-               }
-       }
-
-       return property;
-}
-EXPORT_SYMBOL(drm_property_create_enum);
-
-/**
- * drm_property_create_bitmask - create a new bitmask property type
- * @dev: drm device
- * @flags: flags specifying the property type
- * @name: name of the property
- * @props: enumeration lists with property bitflags
- * @num_props: size of the @props array
- * @supported_bits: bitmask of all supported enumeration values
- *
- * This creates a new bitmask drm property which can then be attached to a drm
- * object with drm_object_attach_property. The returned property object must be
- * freed with drm_property_destroy.
- *
- * Compared to plain enumeration properties userspace is allowed to set any
- * or'ed together combination of the predefined property bitflag values
- *
- * Returns:
- * A pointer to the newly created property on success, NULL on failure.
- */
-struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
-                                        int flags, const char *name,
-                                        const struct drm_prop_enum_list *props,
-                                        int num_props,
-                                        uint64_t supported_bits)
-{
-       struct drm_property *property;
-       int i, ret, index = 0;
-       int num_values = hweight64(supported_bits);
-
-       flags |= DRM_MODE_PROP_BITMASK;
-
-       property = drm_property_create(dev, flags, name, num_values);
-       if (!property)
-               return NULL;
-       for (i = 0; i < num_props; i++) {
-               if (!(supported_bits & (1ULL << props[i].type)))
-                       continue;
-
-               if (WARN_ON(index >= num_values)) {
-                       drm_property_destroy(dev, property);
-                       return NULL;
-               }
-
-               ret = drm_property_add_enum(property, index++,
-                                     props[i].type,
-                                     props[i].name);
-               if (ret) {
-                       drm_property_destroy(dev, property);
-                       return NULL;
-               }
-       }
-
-       return property;
-}
-EXPORT_SYMBOL(drm_property_create_bitmask);
-
-static struct drm_property *property_create_range(struct drm_device *dev,
-                                        int flags, const char *name,
-                                        uint64_t min, uint64_t max)
-{
-       struct drm_property *property;
-
-       property = drm_property_create(dev, flags, name, 2);
-       if (!property)
-               return NULL;
-
-       property->values[0] = min;
-       property->values[1] = max;
-
-       return property;
-}
-
-/**
- * drm_property_create_range - create a new unsigned ranged property type
- * @dev: drm device
- * @flags: flags specifying the property type
- * @name: name of the property
- * @min: minimum value of the property
- * @max: maximum value of the property
- *
- * This creates a new generic drm property which can then be attached to a drm
- * object with drm_object_attach_property. The returned property object must be
- * freed with drm_property_destroy.
- *
- * Userspace is allowed to set any unsigned integer value in the (min, max)
- * range inclusive.
- *
- * Returns:
- * A pointer to the newly created property on success, NULL on failure.
- */
-struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
-                                        const char *name,
-                                        uint64_t min, uint64_t max)
-{
-       return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
-                       name, min, max);
-}
-EXPORT_SYMBOL(drm_property_create_range);
-
-/**
- * drm_property_create_signed_range - create a new signed ranged property type
- * @dev: drm device
- * @flags: flags specifying the property type
- * @name: name of the property
- * @min: minimum value of the property
- * @max: maximum value of the property
- *
- * This creates a new generic drm property which can then be attached to a drm
- * object with drm_object_attach_property. The returned property object must be
- * freed with drm_property_destroy.
- *
- * Userspace is allowed to set any signed integer value in the (min, max)
- * range inclusive.
- *
- * Returns:
- * A pointer to the newly created property on success, NULL on failure.
- */
-struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
-                                        int flags, const char *name,
-                                        int64_t min, int64_t max)
-{
-       return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
-                       name, I642U64(min), I642U64(max));
-}
-EXPORT_SYMBOL(drm_property_create_signed_range);
-
-/**
- * drm_property_create_object - create a new object property type
- * @dev: drm device
- * @flags: flags specifying the property type
- * @name: name of the property
- * @type: object type from DRM_MODE_OBJECT_* defines
- *
- * This creates a new generic drm property which can then be attached to a drm
- * object with drm_object_attach_property. The returned property object must be
- * freed with drm_property_destroy.
- *
- * Userspace is only allowed to set this to any property value of the given
- * @type. Only useful for atomic properties, which is enforced.
- *
- * Returns:
- * A pointer to the newly created property on success, NULL on failure.
- */
-struct drm_property *drm_property_create_object(struct drm_device *dev,
-                                        int flags, const char *name, uint32_t type)
-{
-       struct drm_property *property;
-
-       flags |= DRM_MODE_PROP_OBJECT;
-
-       if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
-               return NULL;
-
-       property = drm_property_create(dev, flags, name, 1);
-       if (!property)
-               return NULL;
-
-       property->values[0] = type;
-
-       return property;
-}
-EXPORT_SYMBOL(drm_property_create_object);
-
-/**
- * drm_property_create_bool - create a new boolean property type
- * @dev: drm device
- * @flags: flags specifying the property type
- * @name: name of the property
- *
- * This creates a new generic drm property which can then be attached to a drm
- * object with drm_object_attach_property. The returned property object must be
- * freed with drm_property_destroy.
- *
- * This is implemented as a ranged property with only {0, 1} as valid values.
- *
- * Returns:
- * A pointer to the newly created property on success, NULL on failure.
- */
-struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
-                                        const char *name)
-{
-       return drm_property_create_range(dev, flags, name, 0, 1);
-}
-EXPORT_SYMBOL(drm_property_create_bool);
-
-/**
- * drm_property_add_enum - add a possible value to an enumeration property
- * @property: enumeration property to change
- * @index: index of the new enumeration
- * @value: value of the new enumeration
- * @name: symbolic name of the new enumeration
- *
- * This functions adds enumerations to a property.
- *
- * It's use is deprecated, drivers should use one of the more specific helpers
- * to directly create the property with all enumerations already attached.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_property_add_enum(struct drm_property *property, int index,
-                         uint64_t value, const char *name)
-{
-       struct drm_property_enum *prop_enum;
-
-       if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
-                       drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
-               return -EINVAL;
-
-       /*
-        * Bitmask enum properties have the additional constraint of values
-        * from 0 to 63
-        */
-       if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
-                       (value > 63))
-               return -EINVAL;
-
-       if (!list_empty(&property->enum_list)) {
-               list_for_each_entry(prop_enum, &property->enum_list, head) {
-                       if (prop_enum->value == value) {
-                               strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
-                               prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
-                               return 0;
-                       }
-               }
-       }
-
-       prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
-       if (!prop_enum)
-               return -ENOMEM;
-
-       strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
-       prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
-       prop_enum->value = value;
-
-       property->values[index] = value;
-       list_add_tail(&prop_enum->head, &property->enum_list);
-       return 0;
-}
-EXPORT_SYMBOL(drm_property_add_enum);
-
-/**
- * drm_property_destroy - destroy a drm property
- * @dev: drm device
- * @property: property to destry
- *
- * This function frees a property including any attached resources like
- * enumeration values.
- */
-void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
-{
-       struct drm_property_enum *prop_enum, *pt;
-
-       list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
-               list_del(&prop_enum->head);
-               kfree(prop_enum);
-       }
-
-       if (property->num_values)
-               kfree(property->values);
-       drm_mode_object_unregister(dev, &property->base);
-       list_del(&property->head);
-       kfree(property);
-}
-EXPORT_SYMBOL(drm_property_destroy);
-
-/**
- * drm_object_attach_property - attach a property to a modeset object
- * @obj: drm modeset object
- * @property: property to attach
- * @init_val: initial value of the property
- *
- * This attaches the given property to the modeset object with the given initial
- * value. Currently this function cannot fail since the properties are stored in
- * a statically sized array.
- */
-void drm_object_attach_property(struct drm_mode_object *obj,
-                               struct drm_property *property,
-                               uint64_t init_val)
-{
-       int count = obj->properties->count;
-
-       if (count == DRM_OBJECT_MAX_PROPERTY) {
-               WARN(1, "Failed to attach object property (type: 0x%x). Please "
-                       "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
-                       "you see this message on the same object type.\n",
-                       obj->type);
-               return;
-       }
-
-       obj->properties->properties[count] = property;
-       obj->properties->values[count] = init_val;
-       obj->properties->count++;
-       if (property->flags & DRM_MODE_PROP_ATOMIC)
-               obj->properties->atomic_count++;
-}
-EXPORT_SYMBOL(drm_object_attach_property);
-
-/**
- * drm_object_property_set_value - set the value of a property
- * @obj: drm mode object to set property value for
- * @property: property to set
- * @val: value the property should be set to
- *
- * This functions sets a given property on a given object. This function only
- * changes the software state of the property, it does not call into the
- * driver's ->set_property callback.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_object_property_set_value(struct drm_mode_object *obj,
-                                 struct drm_property *property, uint64_t val)
-{
-       int i;
-
-       for (i = 0; i < obj->properties->count; i++) {
-               if (obj->properties->properties[i] == property) {
-                       obj->properties->values[i] = val;
-                       return 0;
-               }
-       }
-
-       return -EINVAL;
-}
-EXPORT_SYMBOL(drm_object_property_set_value);
-
-/**
- * drm_object_property_get_value - retrieve the value of a property
- * @obj: drm mode object to get property value from
- * @property: property to retrieve
- * @val: storage for the property value
- *
- * This function retrieves the softare state of the given property for the given
- * property. Since there is no driver callback to retrieve the current property
- * value this might be out of sync with the hardware, depending upon the driver
- * and property.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_object_property_get_value(struct drm_mode_object *obj,
-                                 struct drm_property *property, uint64_t *val)
-{
-       int i;
-
-       /* read-only properties bypass atomic mechanism and still store
-        * their value in obj->properties->values[].. mostly to avoid
-        * having to deal w/ EDID and similar props in atomic paths:
-        */
-       if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) &&
-                       !(property->flags & DRM_MODE_PROP_IMMUTABLE))
-               return drm_atomic_get_property(obj, property, val);
-
-       for (i = 0; i < obj->properties->count; i++) {
-               if (obj->properties->properties[i] == property) {
-                       *val = obj->properties->values[i];
-                       return 0;
-               }
-       }
-
-       return -EINVAL;
-}
-EXPORT_SYMBOL(drm_object_property_get_value);
-
-/**
- * drm_mode_getproperty_ioctl - get the property metadata
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
- *
- * This function retrieves the metadata for a given property, like the different
- * possible values for an enum property or the limits for a range property.
- *
- * Blob properties are special
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_getproperty_ioctl(struct drm_device *dev,
-                              void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_get_property *out_resp = data;
-       struct drm_property *property;
-       int enum_count = 0;
-       int value_count = 0;
-       int ret = 0, i;
-       int copied;
-       struct drm_property_enum *prop_enum;
-       struct drm_mode_property_enum __user *enum_ptr;
-       uint64_t __user *values_ptr;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       drm_modeset_lock_all(dev);
-       property = drm_property_find(dev, out_resp->prop_id);
-       if (!property) {
-               ret = -ENOENT;
-               goto done;
-       }
-
-       if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
-                       drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
-               list_for_each_entry(prop_enum, &property->enum_list, head)
-                       enum_count++;
-       }
-
-       value_count = property->num_values;
-
-       strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
-       out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
-       out_resp->flags = property->flags;
-
-       if ((out_resp->count_values >= value_count) && value_count) {
-               values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr;
-               for (i = 0; i < value_count; i++) {
-                       if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
-                               ret = -EFAULT;
-                               goto done;
-                       }
-               }
-       }
-       out_resp->count_values = value_count;
-
-       if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
-                       drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
-               if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
-                       copied = 0;
-                       enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
-                       list_for_each_entry(prop_enum, &property->enum_list, head) {
-
-                               if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
-                                       ret = -EFAULT;
-                                       goto done;
-                               }
-
-                               if (copy_to_user(&enum_ptr[copied].name,
-                                                &prop_enum->name, DRM_PROP_NAME_LEN)) {
-                                       ret = -EFAULT;
-                                       goto done;
-                               }
-                               copied++;
-                       }
-               }
-               out_resp->count_enum_blobs = enum_count;
-       }
-
-       /*
-        * NOTE: The idea seems to have been to use this to read all the blob
-        * property values. But nothing ever added them to the corresponding
-        * list, userspace always used the special-purpose get_blob ioctl to
-        * read the value for a blob property. It also doesn't make a lot of
-        * sense to return values here when everything else is just metadata for
-        * the property itself.
-        */
-       if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
-               out_resp->count_enum_blobs = 0;
-done:
-       drm_modeset_unlock_all(dev);
-       return ret;
-}
-
-static void drm_property_free_blob(struct kref *kref)
-{
-       struct drm_property_blob *blob =
-               container_of(kref, struct drm_property_blob, base.refcount);
-
-       mutex_lock(&blob->dev->mode_config.blob_lock);
-       list_del(&blob->head_global);
-       mutex_unlock(&blob->dev->mode_config.blob_lock);
-
-       drm_mode_object_unregister(blob->dev, &blob->base);
-
-       kfree(blob);
-}
-
-/**
- * drm_property_create_blob - Create new blob property
- *
- * Creates a new blob property for a specified DRM device, optionally
- * copying data.
- *
- * @dev: DRM device to create property for
- * @length: Length to allocate for blob data
- * @data: If specified, copies data into blob
- *
- * Returns:
- * New blob property with a single reference on success, or an ERR_PTR
- * value on failure.
- */
-struct drm_property_blob *
-drm_property_create_blob(struct drm_device *dev, size_t length,
-                        const void *data)
-{
-       struct drm_property_blob *blob;
-       int ret;
-
-       if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob))
-               return ERR_PTR(-EINVAL);
-
-       blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
-       if (!blob)
-               return ERR_PTR(-ENOMEM);
-
-       /* This must be explicitly initialised, so we can safely call list_del
-        * on it in the removal handler, even if it isn't in a file list. */
-       INIT_LIST_HEAD(&blob->head_file);
-       blob->length = length;
-       blob->dev = dev;
-
-       if (data)
-               memcpy(blob->data, data, length);
-
-       ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
-                                     true, drm_property_free_blob);
-       if (ret) {
-               kfree(blob);
-               return ERR_PTR(-EINVAL);
-       }
-
-       mutex_lock(&dev->mode_config.blob_lock);
-       list_add_tail(&blob->head_global,
-                     &dev->mode_config.property_blob_list);
-       mutex_unlock(&dev->mode_config.blob_lock);
-
-       return blob;
-}
-EXPORT_SYMBOL(drm_property_create_blob);
-
-/**
- * drm_property_unreference_blob - Unreference a blob property
- *
- * Drop a reference on a blob property. May free the object.
- *
- * @blob: Pointer to blob property
- */
-void drm_property_unreference_blob(struct drm_property_blob *blob)
-{
-       if (!blob)
-               return;
-
-       drm_mode_object_unreference(&blob->base);
-}
-EXPORT_SYMBOL(drm_property_unreference_blob);
-
-/**
- * drm_property_destroy_user_blobs - destroy all blobs created by this client
- * @dev:       DRM device
- * @file_priv: destroy all blobs owned by this file handle
- */
-void drm_property_destroy_user_blobs(struct drm_device *dev,
-                                    struct drm_file *file_priv)
-{
-       struct drm_property_blob *blob, *bt;
-
-       /*
-        * When the file gets released that means no one else can access the
-        * blob list any more, so no need to grab dev->blob_lock.
-        */
-       list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
-               list_del_init(&blob->head_file);
-               drm_property_unreference_blob(blob);
-       }
-}
-
-/**
- * drm_property_reference_blob - Take a reference on an existing property
- *
- * Take a new reference on an existing blob property.
- *
- * @blob: Pointer to blob property
- */
-struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob)
-{
-       drm_mode_object_reference(&blob->base);
-       return blob;
-}
-EXPORT_SYMBOL(drm_property_reference_blob);
-
-/**
- * drm_property_lookup_blob - look up a blob property and take a reference
- * @dev: drm device
- * @id: id of the blob property
- *
- * If successful, this takes an additional reference to the blob property.
- * callers need to make sure to eventually unreference the returned property
- * again, using @drm_property_unreference_blob.
- */
-struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
-                                                  uint32_t id)
-{
-       struct drm_mode_object *obj;
-       struct drm_property_blob *blob = NULL;
-
-       obj = _object_find(dev, id, DRM_MODE_OBJECT_BLOB);
-       if (obj)
-               blob = obj_to_blob(obj);
-       return blob;
-}
-EXPORT_SYMBOL(drm_property_lookup_blob);
-
-/**
- * drm_property_replace_global_blob - atomically replace existing blob property
- * @dev: drm device
- * @replace: location of blob property pointer to be replaced
- * @length: length of data for new blob, or 0 for no data
- * @data: content for new blob, or NULL for no data
- * @obj_holds_id: optional object for property holding blob ID
- * @prop_holds_id: optional property holding blob ID
- * @return 0 on success or error on failure
- *
- * This function will atomically replace a global property in the blob list,
- * optionally updating a property which holds the ID of that property. It is
- * guaranteed to be atomic: no caller will be allowed to see intermediate
- * results, and either the entire operation will succeed and clean up the
- * previous property, or it will fail and the state will be unchanged.
- *
- * If length is 0 or data is NULL, no new blob will be created, and the holding
- * property, if specified, will be set to 0.
- *
- * Access to the replace pointer is assumed to be protected by the caller, e.g.
- * by holding the relevant modesetting object lock for its parent.
- *
- * For example, a drm_connector has a 'PATH' property, which contains the ID
- * of a blob property with the value of the MST path information. Calling this
- * function with replace pointing to the connector's path_blob_ptr, length and
- * data set for the new path information, obj_holds_id set to the connector's
- * base object, and prop_holds_id set to the path property name, will perform
- * a completely atomic update. The access to path_blob_ptr is protected by the
- * caller holding a lock on the connector.
- */
-static int drm_property_replace_global_blob(struct drm_device *dev,
-                                            struct drm_property_blob **replace,
-                                            size_t length,
-                                            const void *data,
-                                            struct drm_mode_object *obj_holds_id,
-                                            struct drm_property *prop_holds_id)
-{
-       struct drm_property_blob *new_blob = NULL;
-       struct drm_property_blob *old_blob = NULL;
-       int ret;
-
-       WARN_ON(replace == NULL);
-
-       old_blob = *replace;
-
-       if (length && data) {
-               new_blob = drm_property_create_blob(dev, length, data);
-               if (IS_ERR(new_blob))
-                       return PTR_ERR(new_blob);
-       }
-
-       /* This does not need to be synchronised with blob_lock, as the
-        * get_properties ioctl locks all modesetting objects, and
-        * obj_holds_id must be locked before calling here, so we cannot
-        * have its value out of sync with the list membership modified
-        * below under blob_lock. */
-       if (obj_holds_id) {
-               ret = drm_object_property_set_value(obj_holds_id,
-                                                   prop_holds_id,
-                                                   new_blob ?
-                                                       new_blob->base.id : 0);
-               if (ret != 0)
-                       goto err_created;
-       }
-
-       drm_property_unreference_blob(old_blob);
-       *replace = new_blob;
-
-       return 0;
-
-err_created:
-       drm_property_unreference_blob(new_blob);
-       return ret;
-}
-
-/**
- * drm_mode_getblob_ioctl - get the contents of a blob property value
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
- *
- * This function retrieves the contents of a blob property. The value stored in
- * an object's blob property is just a normal modeset object id.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_getblob_ioctl(struct drm_device *dev,
-                          void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_get_blob *out_resp = data;
-       struct drm_property_blob *blob;
-       int ret = 0;
-       void __user *blob_ptr;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       blob = drm_property_lookup_blob(dev, out_resp->blob_id);
-       if (!blob)
-               return -ENOENT;
-
-       if (out_resp->length == blob->length) {
-               blob_ptr = (void __user *)(unsigned long)out_resp->data;
-               if (copy_to_user(blob_ptr, blob->data, blob->length)) {
-                       ret = -EFAULT;
-                       goto unref;
-               }
-       }
-       out_resp->length = blob->length;
-unref:
-       drm_property_unreference_blob(blob);
-
-       return ret;
-}
-
-/**
- * drm_mode_createblob_ioctl - create a new blob property
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
- *
- * This function creates a new blob property with user-defined values. In order
- * to give us sensible validation and checking when creating, rather than at
- * every potential use, we also require a type to be provided upfront.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_createblob_ioctl(struct drm_device *dev,
-                             void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_create_blob *out_resp = data;
-       struct drm_property_blob *blob;
-       void __user *blob_ptr;
-       int ret = 0;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       blob = drm_property_create_blob(dev, out_resp->length, NULL);
-       if (IS_ERR(blob))
-               return PTR_ERR(blob);
-
-       blob_ptr = (void __user *)(unsigned long)out_resp->data;
-       if (copy_from_user(blob->data, blob_ptr, out_resp->length)) {
-               ret = -EFAULT;
-               goto out_blob;
-       }
-
-       /* Dropping the lock between create_blob and our access here is safe
-        * as only the same file_priv can remove the blob; at this point, it is
-        * not associated with any file_priv. */
-       mutex_lock(&dev->mode_config.blob_lock);
-       out_resp->blob_id = blob->base.id;
-       list_add_tail(&blob->head_file, &file_priv->blobs);
-       mutex_unlock(&dev->mode_config.blob_lock);
-
-       return 0;
-
-out_blob:
-       drm_property_unreference_blob(blob);
-       return ret;
-}
-
-/**
- * drm_mode_destroyblob_ioctl - destroy a user blob property
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
- *
- * Destroy an existing user-defined blob property.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_destroyblob_ioctl(struct drm_device *dev,
-                              void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_destroy_blob *out_resp = data;
-       struct drm_property_blob *blob = NULL, *bt;
-       bool found = false;
-       int ret = 0;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       blob = drm_property_lookup_blob(dev, out_resp->blob_id);
-       if (!blob)
-               return -ENOENT;
-
-       mutex_lock(&dev->mode_config.blob_lock);
-       /* Ensure the property was actually created by this user. */
-       list_for_each_entry(bt, &file_priv->blobs, head_file) {
-               if (bt == blob) {
-                       found = true;
-                       break;
-               }
-       }
-
-       if (!found) {
-               ret = -EPERM;
-               goto err;
-       }
-
-       /* We must drop head_file here, because we may not be the last
-        * reference on the blob. */
-       list_del_init(&blob->head_file);
-       mutex_unlock(&dev->mode_config.blob_lock);
-
-       /* One reference from lookup, and one from the filp. */
-       drm_property_unreference_blob(blob);
-       drm_property_unreference_blob(blob);
-
-       return 0;
-
-err:
-       mutex_unlock(&dev->mode_config.blob_lock);
-       drm_property_unreference_blob(blob);
-
-       return ret;
-}
-
-/**
- * drm_mode_connector_set_path_property - set tile property on connector
- * @connector: connector to set property on.
- * @path: path to use for property; must not be NULL.
- *
- * This creates a property to expose to userspace to specify a
- * connector path. This is mainly used for DisplayPort MST where
- * connectors have a topology and we want to allow userspace to give
- * them more meaningful names.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_connector_set_path_property(struct drm_connector *connector,
-                                        const char *path)
-{
-       struct drm_device *dev = connector->dev;
-       int ret;
-
-       ret = drm_property_replace_global_blob(dev,
-                                              &connector->path_blob_ptr,
-                                              strlen(path) + 1,
-                                              path,
-                                              &connector->base,
-                                              dev->mode_config.path_property);
-       return ret;
-}
-EXPORT_SYMBOL(drm_mode_connector_set_path_property);
-
-/**
- * drm_mode_connector_set_tile_property - set tile property on connector
- * @connector: connector to set property on.
- *
- * This looks up the tile information for a connector, and creates a
- * property for userspace to parse if it exists. The property is of
- * the form of 8 integers using ':' as a separator.
- *
- * Returns:
- * Zero on success, errno on failure.
- */
-int drm_mode_connector_set_tile_property(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       char tile[256];
-       int ret;
-
-       if (!connector->has_tile) {
-               ret  = drm_property_replace_global_blob(dev,
-                                                       &connector->tile_blob_ptr,
-                                                       0,
-                                                       NULL,
-                                                       &connector->base,
-                                                       dev->mode_config.tile_property);
-               return ret;
-       }
-
-       snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d",
-                connector->tile_group->id, connector->tile_is_single_monitor,
-                connector->num_h_tile, connector->num_v_tile,
-                connector->tile_h_loc, connector->tile_v_loc,
-                connector->tile_h_size, connector->tile_v_size);
-
-       ret = drm_property_replace_global_blob(dev,
-                                              &connector->tile_blob_ptr,
-                                              strlen(tile) + 1,
-                                              tile,
-                                              &connector->base,
-                                              dev->mode_config.tile_property);
-       return ret;
-}
-EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
-
-/**
- * drm_mode_connector_update_edid_property - update the edid property of a connector
- * @connector: drm connector
- * @edid: new value of the edid property
- *
- * This function creates a new blob modeset object and assigns its id to the
- * connector's edid property.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_connector_update_edid_property(struct drm_connector *connector,
-                                           const struct edid *edid)
-{
-       struct drm_device *dev = connector->dev;
-       size_t size = 0;
-       int ret;
-
-       /* ignore requests to set edid when overridden */
-       if (connector->override_edid)
-               return 0;
-
-       if (edid)
-               size = EDID_LENGTH * (1 + edid->extensions);
-
-       ret = drm_property_replace_global_blob(dev,
-                                              &connector->edid_blob_ptr,
-                                              size,
-                                              edid,
-                                              &connector->base,
-                                              dev->mode_config.edid_property);
-       return ret;
-}
-EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
-
-/* Some properties could refer to dynamic refcnt'd objects, or things that
- * need special locking to handle lifetime issues (ie. to ensure the prop
- * value doesn't become invalid part way through the property update due to
- * race).  The value returned by reference via 'obj' should be passed back
- * to drm_property_change_valid_put() after the property is set (and the
- * object to which the property is attached has a chance to take it's own
- * reference).
- */
-bool drm_property_change_valid_get(struct drm_property *property,
-                                        uint64_t value, struct drm_mode_object **ref)
-{
-       int i;
-
-       if (property->flags & DRM_MODE_PROP_IMMUTABLE)
-               return false;
-
-       *ref = NULL;
-
-       if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
-               if (value < property->values[0] || value > property->values[1])
-                       return false;
-               return true;
-       } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
-               int64_t svalue = U642I64(value);
-
-               if (svalue < U642I64(property->values[0]) ||
-                               svalue > U642I64(property->values[1]))
-                       return false;
-               return true;
-       } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
-               uint64_t valid_mask = 0;
-
-               for (i = 0; i < property->num_values; i++)
-                       valid_mask |= (1ULL << property->values[i]);
-               return !(value & ~valid_mask);
-       } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
-               struct drm_property_blob *blob;
-
-               if (value == 0)
-                       return true;
-
-               blob = drm_property_lookup_blob(property->dev, value);
-               if (blob) {
-                       *ref = &blob->base;
-                       return true;
-               } else {
-                       return false;
-               }
-       } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
-               /* a zero value for an object property translates to null: */
-               if (value == 0)
-                       return true;
-
-               *ref = _object_find(property->dev, value, property->values[0]);
-               return *ref != NULL;
-       }
-
-       for (i = 0; i < property->num_values; i++)
-               if (property->values[i] == value)
-                       return true;
-       return false;
-}
-
-void drm_property_change_valid_put(struct drm_property *property,
-               struct drm_mode_object *ref)
-{
-       if (!ref)
-               return;
-
-       if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
-               drm_mode_object_unreference(ref);
-       } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
-               drm_property_unreference_blob(obj_to_blob(ref));
-}
-
-/**
- * drm_mode_connector_property_set_ioctl - set the current value of a connector property
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
- *
- * This function sets the current value for a connectors's property. It also
- * calls into a driver's ->set_property callback to update the hardware state
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
-                                      void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_connector_set_property *conn_set_prop = data;
-       struct drm_mode_obj_set_property obj_set_prop = {
-               .value = conn_set_prop->value,
-               .prop_id = conn_set_prop->prop_id,
-               .obj_id = conn_set_prop->connector_id,
-               .obj_type = DRM_MODE_OBJECT_CONNECTOR
-       };
-
-       /* It does all the locking and checking we need */
-       return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
-}
-
-static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
-                                          struct drm_property *property,
-                                          uint64_t value)
-{
-       int ret = -EINVAL;
-       struct drm_connector *connector = obj_to_connector(obj);
-
-       /* Do DPMS ourselves */
-       if (property == connector->dev->mode_config.dpms_property) {
-               ret = (*connector->funcs->dpms)(connector, (int)value);
-       } else if (connector->funcs->set_property)
-               ret = connector->funcs->set_property(connector, property, value);
-
-       /* store the property value if successful */
-       if (!ret)
-               drm_object_property_set_value(&connector->base, property, value);
-       return ret;
-}
-
-static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
-                                     struct drm_property *property,
-                                     uint64_t value)
-{
-       int ret = -EINVAL;
-       struct drm_crtc *crtc = obj_to_crtc(obj);
-
-       if (crtc->funcs->set_property)
-               ret = crtc->funcs->set_property(crtc, property, value);
-       if (!ret)
-               drm_object_property_set_value(obj, property, value);
-
-       return ret;
-}
-
-/**
- * drm_mode_plane_set_obj_prop - set the value of a property
- * @plane: drm plane object to set property value for
- * @property: property to set
- * @value: value the property should be set to
- *
- * This functions sets a given property on a given plane object. This function
- * calls the driver's ->set_property callback and changes the software state of
- * the property if the callback succeeds.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
-                               struct drm_property *property,
-                               uint64_t value)
-{
-       int ret = -EINVAL;
-       struct drm_mode_object *obj = &plane->base;
-
-       if (plane->funcs->set_property)
-               ret = plane->funcs->set_property(plane, property, value);
-       if (!ret)
-               drm_object_property_set_value(obj, property, value);
-
-       return ret;
-}
-EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
-
-/**
- * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
+ * drm_mode_getresources - get graphics configuration
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
- * This function retrieves the current value for an object's property. Compared
- * to the connector specific ioctl this one is extended to also work on crtc and
- * plane objects.
+ * Construct a set of configuration description structures and return
+ * them to the user, including CRTC, connector and framebuffer configuration.
  *
  * Called by the user via ioctl.
  *
  * Returns:
  * Zero on success, negative errno on failure.
  */
-int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
-                                     struct drm_file *file_priv)
+int drm_mode_getresources(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
 {
-       struct drm_mode_obj_get_properties *arg = data;
-       struct drm_mode_object *obj;
+       struct drm_mode_card_res *card_res = data;
+       struct list_head *lh;
+       struct drm_framebuffer *fb;
+       struct drm_connector *connector;
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
        int ret = 0;
+       int connector_count = 0;
+       int crtc_count = 0;
+       int fb_count = 0;
+       int encoder_count = 0;
+       int copied = 0;
+       uint32_t __user *fb_id;
+       uint32_t __user *crtc_id;
+       uint32_t __user *connector_id;
+       uint32_t __user *encoder_id;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
 
-       obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
-       if (!obj) {
-               ret = -ENOENT;
-               goto out;
+       mutex_lock(&file_priv->fbs_lock);
+       /*
+        * For the non-control nodes we need to limit the list of resources
+        * by IDs in the group list for this node
+        */
+       list_for_each(lh, &file_priv->fbs)
+               fb_count++;
+
+       /* handle this in 4 parts */
+       /* FBs */
+       if (card_res->count_fbs >= fb_count) {
+               copied = 0;
+               fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
+               list_for_each_entry(fb, &file_priv->fbs, filp_head) {
+                       if (put_user(fb->base.id, fb_id + copied)) {
+                               mutex_unlock(&file_priv->fbs_lock);
+                               return -EFAULT;
+                       }
+                       copied++;
+               }
        }
-       if (!obj->properties) {
-               ret = -EINVAL;
-               goto out_unref;
+       card_res->count_fbs = fb_count;
+       mutex_unlock(&file_priv->fbs_lock);
+
+       /* mode_config.mutex protects the connector list against e.g. DP MST
+        * connector hot-adding. CRTC/Plane lists are invariant. */
+       mutex_lock(&dev->mode_config.mutex);
+       drm_for_each_crtc(crtc, dev)
+               crtc_count++;
+
+       drm_for_each_connector(connector, dev)
+               connector_count++;
+
+       drm_for_each_encoder(encoder, dev)
+               encoder_count++;
+
+       card_res->max_height = dev->mode_config.max_height;
+       card_res->min_height = dev->mode_config.min_height;
+       card_res->max_width = dev->mode_config.max_width;
+       card_res->min_width = dev->mode_config.min_width;
+
+       /* CRTCs */
+       if (card_res->count_crtcs >= crtc_count) {
+               copied = 0;
+               crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
+               drm_for_each_crtc(crtc, dev) {
+                       if (put_user(crtc->base.id, crtc_id + copied)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       card_res->count_crtcs = crtc_count;
+
+       /* Encoders */
+       if (card_res->count_encoders >= encoder_count) {
+               copied = 0;
+               encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
+               drm_for_each_encoder(encoder, dev) {
+                       if (put_user(encoder->base.id, encoder_id +
+                                    copied)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
        }
+       card_res->count_encoders = encoder_count;
 
-       ret = get_properties(obj, file_priv->atomic,
-                       (uint32_t __user *)(unsigned long)(arg->props_ptr),
-                       (uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
-                       &arg->count_props);
+       /* Connectors */
+       if (card_res->count_connectors >= connector_count) {
+               copied = 0;
+               connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
+               drm_for_each_connector(connector, dev) {
+                       if (put_user(connector->base.id,
+                                    connector_id + copied)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       card_res->count_connectors = connector_count;
 
-out_unref:
-       drm_mode_object_unreference(obj);
 out:
-       drm_modeset_unlock_all(dev);
+       mutex_unlock(&dev->mode_config.mutex);
        return ret;
 }
 
 /**
- * drm_mode_obj_set_property_ioctl - set the current value of an object's property
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
+ * drm_mode_getcrtc - get CRTC configuration
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
- * This function sets the current value for an object's property. It also calls
- * into a driver's ->set_property callback to update the hardware state.
- * Compared to the connector specific ioctl this one is extended to also work on
- * crtc and plane objects.
+ * Construct a CRTC configuration structure to return to the user.
  *
  * Called by the user via ioctl.
  *
  * Returns:
  * Zero on success, negative errno on failure.
  */
-int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv)
+int drm_mode_getcrtc(struct drm_device *dev,
+                    void *data, struct drm_file *file_priv)
 {
-       struct drm_mode_obj_set_property *arg = data;
-       struct drm_mode_object *arg_obj;
-       struct drm_mode_object *prop_obj;
-       struct drm_property *property;
-       int i, ret = -EINVAL;
-       struct drm_mode_object *ref;
+       struct drm_mode_crtc *crtc_resp = data;
+       struct drm_crtc *crtc;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
+       crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
+       if (!crtc)
+               return -ENOENT;
 
-       arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
-       if (!arg_obj) {
-               ret = -ENOENT;
-               goto out;
-       }
-       if (!arg_obj->properties)
-               goto out_unref;
+       drm_modeset_lock_crtc(crtc, crtc->primary);
+       crtc_resp->gamma_size = crtc->gamma_size;
+       if (crtc->primary->fb)
+               crtc_resp->fb_id = crtc->primary->fb->base.id;
+       else
+               crtc_resp->fb_id = 0;
 
-       for (i = 0; i < arg_obj->properties->count; i++)
-               if (arg_obj->properties->properties[i]->base.id == arg->prop_id)
-                       break;
+       if (crtc->state) {
+               crtc_resp->x = crtc->primary->state->src_x >> 16;
+               crtc_resp->y = crtc->primary->state->src_y >> 16;
+               if (crtc->state->enable) {
+                       drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
+                       crtc_resp->mode_valid = 1;
 
-       if (i == arg_obj->properties->count)
-               goto out_unref;
+               } else {
+                       crtc_resp->mode_valid = 0;
+               }
+       } else {
+               crtc_resp->x = crtc->x;
+               crtc_resp->y = crtc->y;
+               if (crtc->enabled) {
+                       drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode);
+                       crtc_resp->mode_valid = 1;
 
-       prop_obj = drm_mode_object_find(dev, arg->prop_id,
-                                       DRM_MODE_OBJECT_PROPERTY);
-       if (!prop_obj) {
-               ret = -ENOENT;
-               goto out_unref;
-       }
-       property = obj_to_property(prop_obj);
-
-       if (!drm_property_change_valid_get(property, arg->value, &ref))
-               goto out_unref;
-
-       switch (arg_obj->type) {
-       case DRM_MODE_OBJECT_CONNECTOR:
-               ret = drm_mode_connector_set_obj_prop(arg_obj, property,
-                                                     arg->value);
-               break;
-       case DRM_MODE_OBJECT_CRTC:
-               ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
-               break;
-       case DRM_MODE_OBJECT_PLANE:
-               ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj),
-                                                 property, arg->value);
-               break;
+               } else {
+                       crtc_resp->mode_valid = 0;
+               }
        }
+       drm_modeset_unlock_crtc(crtc);
 
-       drm_property_change_valid_put(property, ref);
-
-out_unref:
-       drm_mode_object_unreference(arg_obj);
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       return 0;
 }
 
 /**
- * drm_mode_connector_attach_encoder - attach a connector to an encoder
- * @connector: connector to attach
- * @encoder: encoder to attach @connector to
+ * drm_mode_set_config_internal - helper to call ->set_config
+ * @set: modeset config to set
  *
- * This function links up a connector to an encoder. Note that the routing
- * restrictions between encoders and crtcs are exposed to userspace through the
- * possible_clones and possible_crtcs bitmasks.
+ * This is a little helper to wrap internal calls to the ->set_config driver
+ * interface. The only thing it adds is correct refcounting dance.
  *
  * Returns:
  * Zero on success, negative errno on failure.
  */
-int drm_mode_connector_attach_encoder(struct drm_connector *connector,
-                                     struct drm_encoder *encoder)
+int drm_mode_set_config_internal(struct drm_mode_set *set)
 {
-       int i;
+       struct drm_crtc *crtc = set->crtc;
+       struct drm_framebuffer *fb;
+       struct drm_crtc *tmp;
+       int ret;
 
        /*
-        * In the past, drivers have attempted to model the static association
-        * of connector to encoder in simple connector/encoder devices using a
-        * direct assignment of connector->encoder = encoder. This connection
-        * is a logical one and the responsibility of the core, so drivers are
-        * expected not to mess with this.
-        *
-        * Note that the error return should've been enough here, but a large
-        * majority of drivers ignores the return value, so add in a big WARN
-        * to get people's attention.
+        * NOTE: ->set_config can also disable other crtcs (if we steal all
+        * connectors from it), hence we need to refcount the fbs across all
+        * crtcs. Atomic modeset will have saner semantics ...
         */
-       if (WARN_ON(connector->encoder))
-               return -EINVAL;
-
-       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-               if (connector->encoder_ids[i] == 0) {
-                       connector->encoder_ids[i] = encoder->base.id;
-                       return 0;
-               }
-       }
-       return -ENOMEM;
-}
-EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
-
-/**
- * drm_mode_crtc_set_gamma_size - set the gamma table size
- * @crtc: CRTC to set the gamma table size for
- * @gamma_size: size of the gamma table
- *
- * Drivers which support gamma tables should set this to the supported gamma
- * table size when initializing the CRTC. Currently the drm core only supports a
- * fixed gamma table size.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
-                                int gamma_size)
-{
-       uint16_t *r_base, *g_base, *b_base;
-       int i;
+       drm_for_each_crtc(tmp, crtc->dev)
+               tmp->primary->old_fb = tmp->primary->fb;
 
-       crtc->gamma_size = gamma_size;
+       fb = set->fb;
 
-       crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
-                                   GFP_KERNEL);
-       if (!crtc->gamma_store) {
-               crtc->gamma_size = 0;
-               return -ENOMEM;
+       ret = crtc->funcs->set_config(set);
+       if (ret == 0) {
+               crtc->primary->crtc = crtc;
+               crtc->primary->fb = fb;
        }
 
-       r_base = crtc->gamma_store;
-       g_base = r_base + gamma_size;
-       b_base = g_base + gamma_size;
-       for (i = 0; i < gamma_size; i++) {
-               r_base[i] = i << 8;
-               g_base[i] = i << 8;
-               b_base[i] = i << 8;
+       drm_for_each_crtc(tmp, crtc->dev) {
+               if (tmp->primary->fb)
+                       drm_framebuffer_reference(tmp->primary->fb);
+               if (tmp->primary->old_fb)
+                       drm_framebuffer_unreference(tmp->primary->old_fb);
+               tmp->primary->old_fb = NULL;
        }
 
-
-       return 0;
+       return ret;
 }
-EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
+EXPORT_SYMBOL(drm_mode_set_config_internal);
 
 /**
- * drm_mode_gamma_set_ioctl - set the gamma table
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
- *
- * Set the gamma table of a CRTC to the one passed in by the user. Userspace can
- * inquire the required gamma table size through drm_mode_gamma_get_ioctl.
- *
- * Called by the user via ioctl.
+ * 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
  *
- * Returns:
- * Zero on success, negative errno on failure.
+ * The vdisplay value will be doubled if the specified mode is a stereo mode of
+ * the appropriate layout.
  */
-int drm_mode_gamma_set_ioctl(struct drm_device *dev,
-                            void *data, struct drm_file *file_priv)
+void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
+                           int *hdisplay, int *vdisplay)
 {
-       struct drm_mode_crtc_lut *crtc_lut = data;
-       struct drm_crtc *crtc;
-       void *r_base, *g_base, *b_base;
-       int size;
-       int ret = 0;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       drm_modeset_lock_all(dev);
-       crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
-       if (!crtc) {
-               ret = -ENOENT;
-               goto out;
-       }
-
-       if (crtc->funcs->gamma_set == NULL) {
-               ret = -ENOSYS;
-               goto out;
-       }
-
-       /* memcpy into gamma store */
-       if (crtc_lut->gamma_size != crtc->gamma_size) {
-               ret = -EINVAL;
-               goto out;
-       }
+       struct drm_display_mode adjusted;
 
-       size = crtc_lut->gamma_size * (sizeof(uint16_t));
-       r_base = crtc->gamma_store;
-       if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
-               ret = -EFAULT;
-               goto out;
-       }
+       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);
 
-       g_base = r_base + size;
-       if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
-               ret = -EFAULT;
-               goto out;
-       }
+/**
+ * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
+ *     CRTC viewport
+ * @crtc: CRTC that framebuffer will be displayed on
+ * @x: x panning
+ * @y: y panning
+ * @mode: mode that framebuffer will be displayed under
+ * @fb: framebuffer to check size of
+ */
+int drm_crtc_check_viewport(const struct drm_crtc *crtc,
+                           int x, int y,
+                           const struct drm_display_mode *mode,
+                           const struct drm_framebuffer *fb)
 
-       b_base = g_base + size;
-       if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
-               ret = -EFAULT;
-               goto out;
-       }
+{
+       int hdisplay, vdisplay;
 
-       ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size);
+       drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
 
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       if (crtc->state &&
+           crtc->primary->state->rotation & (DRM_ROTATE_90 |
+                                             DRM_ROTATE_270))
+               swap(hdisplay, vdisplay);
 
+       return drm_framebuffer_check_src_coords(x << 16, y << 16,
+                                               hdisplay << 16, vdisplay << 16,
+                                               fb);
 }
+EXPORT_SYMBOL(drm_crtc_check_viewport);
 
 /**
- * drm_mode_gamma_get_ioctl - get the gamma table
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
+ * drm_mode_setcrtc - set CRTC configuration
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
- * Copy the current gamma table into the storage provided. This also provides
- * the gamma table size the driver expects, which can be used to size the
- * allocated storage.
+ * Build a new CRTC configuration based on user request.
  *
  * Called by the user via ioctl.
  *
  * Returns:
  * Zero on success, negative errno on failure.
  */
-int drm_mode_gamma_get_ioctl(struct drm_device *dev,
-                            void *data, struct drm_file *file_priv)
+int drm_mode_setcrtc(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
 {
-       struct drm_mode_crtc_lut *crtc_lut = data;
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_mode_crtc *crtc_req = data;
        struct drm_crtc *crtc;
-       void *r_base, *g_base, *b_base;
-       int size;
-       int ret = 0;
+       struct drm_connector **connector_set = NULL, *connector;
+       struct drm_framebuffer *fb = NULL;
+       struct drm_display_mode *mode = NULL;
+       struct drm_mode_set set;
+       uint32_t __user *set_connectors_ptr;
+       int ret;
+       int i;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
+       /*
+        * Universal plane src offsets are only 16.16, prevent havoc for
+        * drivers using universal plane code internally.
+        */
+       if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000)
+               return -ERANGE;
+
        drm_modeset_lock_all(dev);
-       crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+       crtc = drm_crtc_find(dev, crtc_req->crtc_id);
        if (!crtc) {
+               DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
                ret = -ENOENT;
                goto out;
        }
+       DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
 
-       /* memcpy into gamma store */
-       if (crtc_lut->gamma_size != crtc->gamma_size) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       size = crtc_lut->gamma_size * (sizeof(uint16_t));
-       r_base = crtc->gamma_store;
-       if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
-               ret = -EFAULT;
-               goto out;
-       }
-
-       g_base = r_base + size;
-       if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
-               ret = -EFAULT;
-               goto out;
-       }
-
-       b_base = g_base + size;
-       if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
-               ret = -EFAULT;
-               goto out;
-       }
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
-}
-
-/**
- * drm_mode_page_flip_ioctl - schedule an asynchronous fb update
- * @dev: DRM device
- * @data: ioctl data
- * @file_priv: DRM file info
- *
- * This schedules an asynchronous update on a given CRTC, called page flip.
- * Optionally a drm event is generated to signal the completion of the event.
- * Generic drivers cannot assume that a pageflip with changed framebuffer
- * properties (including driver specific metadata like tiling layout) will work,
- * but some drivers support e.g. pixel format changes through the pageflip
- * ioctl.
- *
- * Called by the user via ioctl.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int drm_mode_page_flip_ioctl(struct drm_device *dev,
-                            void *data, struct drm_file *file_priv)
-{
-       struct drm_mode_crtc_page_flip *page_flip = data;
-       struct drm_crtc *crtc;
-       struct drm_framebuffer *fb = NULL;
-       struct drm_pending_vblank_event *e = NULL;
-       int ret = -EINVAL;
-
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
-           page_flip->reserved != 0)
-               return -EINVAL;
+       if (crtc_req->mode_valid) {
+               /* If we have a mode we need a framebuffer. */
+               /* If we pass -1, set the mode with the currently bound fb */
+               if (crtc_req->fb_id == -1) {
+                       if (!crtc->primary->fb) {
+                               DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       fb = crtc->primary->fb;
+                       /* Make refcounting symmetric with the lookup path. */
+                       drm_framebuffer_reference(fb);
+               } else {
+                       fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
+                       if (!fb) {
+                               DRM_DEBUG_KMS("Unknown FB ID%d\n",
+                                               crtc_req->fb_id);
+                               ret = -ENOENT;
+                               goto out;
+                       }
+               }
 
-       if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
-               return -EINVAL;
+               mode = drm_mode_create(dev);
+               if (!mode) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
 
-       crtc = drm_crtc_find(dev, page_flip->crtc_id);
-       if (!crtc)
-               return -ENOENT;
+               ret = drm_mode_convert_umode(mode, &crtc_req->mode);
+               if (ret) {
+                       DRM_DEBUG_KMS("Invalid mode\n");
+                       goto out;
+               }
 
-       drm_modeset_lock_crtc(crtc, crtc->primary);
-       if (crtc->primary->fb == NULL) {
-               /* The framebuffer is currently unbound, presumably
-                * due to a hotplug event, that userspace has not
-                * yet discovered.
+               /*
+                * Check whether the primary plane supports the fb pixel format.
+                * Drivers not implementing the universal planes API use a
+                * default formats list provided by the DRM core which doesn't
+                * match real hardware capabilities. Skip the check in that
+                * case.
                 */
-               ret = -EBUSY;
-               goto out;
-       }
+               if (!crtc->primary->format_default) {
+                       ret = drm_plane_check_pixel_format(crtc->primary,
+                                                          fb->pixel_format);
+                       if (ret) {
+                               char *format_name = drm_get_format_name(fb->pixel_format);
+                               DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name);
+                               kfree(format_name);
+                               goto out;
+                       }
+               }
 
-       if (crtc->funcs->page_flip == NULL)
-               goto out;
+               ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
+                                             mode, fb);
+               if (ret)
+                       goto out;
 
-       fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
-       if (!fb) {
-               ret = -ENOENT;
-               goto out;
        }
 
-       if (crtc->state) {
-               const struct drm_plane_state *state = crtc->primary->state;
-
-               ret = check_src_coords(state->src_x, state->src_y,
-                                      state->src_w, state->src_h, fb);
-       } else {
-               ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
-       }
-       if (ret)
+       if (crtc_req->count_connectors == 0 && mode) {
+               DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
+               ret = -EINVAL;
                goto out;
+       }
 
-       if (crtc->primary->fb->pixel_format != fb->pixel_format) {
-               DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
+       if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
+               DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
+                         crtc_req->count_connectors);
                ret = -EINVAL;
                goto out;
        }
 
-       if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
-               e = kzalloc(sizeof *e, GFP_KERNEL);
-               if (!e) {
-                       ret = -ENOMEM;
+       if (crtc_req->count_connectors > 0) {
+               u32 out_id;
+
+               /* Avoid unbounded kernel memory allocation */
+               if (crtc_req->count_connectors > config->num_connector) {
+                       ret = -EINVAL;
                        goto out;
                }
-               e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
-               e->event.base.length = sizeof(e->event);
-               e->event.user_data = page_flip->user_data;
-               ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
-               if (ret) {
-                       kfree(e);
+
+               connector_set = kmalloc_array(crtc_req->count_connectors,
+                                             sizeof(struct drm_connector *),
+                                             GFP_KERNEL);
+               if (!connector_set) {
+                       ret = -ENOMEM;
                        goto out;
                }
-       }
 
-       crtc->primary->old_fb = crtc->primary->fb;
-       ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
-       if (ret) {
-               if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
-                       drm_event_cancel_free(dev, &e->base);
-               /* Keep the old fb, don't unref it. */
-               crtc->primary->old_fb = NULL;
-       } else {
-               crtc->primary->fb = fb;
-               /* Unref only the old framebuffer. */
-               fb = NULL;
+               for (i = 0; i < crtc_req->count_connectors; i++) {
+                       connector_set[i] = NULL;
+                       set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
+                       if (get_user(out_id, &set_connectors_ptr[i])) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+
+                       connector = drm_connector_lookup(dev, out_id);
+                       if (!connector) {
+                               DRM_DEBUG_KMS("Connector id %d unknown\n",
+                                               out_id);
+                               ret = -ENOENT;
+                               goto out;
+                       }
+                       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                                       connector->base.id,
+                                       connector->name);
+
+                       connector_set[i] = connector;
+               }
        }
 
+       set.crtc = crtc;
+       set.x = crtc_req->x;
+       set.y = crtc_req->y;
+       set.mode = mode;
+       set.connectors = connector_set;
+       set.num_connectors = crtc_req->count_connectors;
+       set.fb = fb;
+       ret = drm_mode_set_config_internal(&set);
+
 out:
        if (fb)
                drm_framebuffer_unreference(fb);
-       if (crtc->primary->old_fb)
-               drm_framebuffer_unreference(crtc->primary->old_fb);
-       crtc->primary->old_fb = NULL;
-       drm_modeset_unlock_crtc(crtc);
+
+       if (connector_set) {
+               for (i = 0; i < crtc_req->count_connectors; i++) {
+                       if (connector_set[i])
+                               drm_connector_unreference(connector_set[i]);
+               }
+       }
+       kfree(connector_set);
+       drm_mode_destroy(dev, mode);
+       drm_modeset_unlock_all(dev);
+       return ret;
+}
+
+int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
+                              struct drm_property *property,
+                              uint64_t value)
+{
+       int ret = -EINVAL;
+       struct drm_crtc *crtc = obj_to_crtc(obj);
+
+       if (crtc->funcs->set_property)
+               ret = crtc->funcs->set_property(crtc, property, value);
+       if (!ret)
+               drm_object_property_set_value(obj, property, value);
 
        return ret;
 }
@@ -5638,37 +1047,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
        return dev->driver->dumb_destroy(file_priv, dev, args->handle);
 }
 
-/**
- * drm_rotation_simplify() - Try to simplify the rotation
- * @rotation: Rotation to be simplified
- * @supported_rotations: Supported rotations
- *
- * Attempt to simplify the rotation to a form that is supported.
- * Eg. if the hardware supports everything except DRM_REFLECT_X
- * one could call this function like this:
- *
- * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) |
- *                       BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) |
- *                       BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y));
- *
- * to eliminate the DRM_ROTATE_X flag. Depending on what kind of
- * transforms the hardware supports, this function may not
- * be able to produce a supported transform, so the caller should
- * check the result afterwards.
- */
-unsigned int drm_rotation_simplify(unsigned int rotation,
-                                  unsigned int supported_rotations)
-{
-       if (rotation & ~supported_rotations) {
-               rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y);
-               rotation = (rotation & DRM_REFLECT_MASK) |
-                          BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4);
-       }
-
-       return rotation;
-}
-EXPORT_SYMBOL(drm_rotation_simplify);
-
 /**
  * drm_mode_config_init - initialize DRM mode_configuration structure
  * @dev: DRM device
@@ -5785,24 +1163,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_mode_config_cleanup);
 
-struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
-                                                      unsigned int supported_rotations)
-{
-       static const struct drm_prop_enum_list props[] = {
-               { DRM_ROTATE_0,   "rotate-0" },
-               { DRM_ROTATE_90,  "rotate-90" },
-               { DRM_ROTATE_180, "rotate-180" },
-               { DRM_ROTATE_270, "rotate-270" },
-               { DRM_REFLECT_X,  "reflect-x" },
-               { DRM_REFLECT_Y,  "reflect-y" },
-       };
-
-       return drm_property_create_bitmask(dev, 0, "rotation",
-                                          props, ARRAY_SIZE(props),
-                                          supported_rotations);
-}
-EXPORT_SYMBOL(drm_mode_create_rotation_property);
-
 /**
  * DOC: Tile group
  *
@@ -5901,48 +1261,3 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
        return tg;
 }
 EXPORT_SYMBOL(drm_mode_create_tile_group);
-
-/**
- * drm_crtc_enable_color_mgmt - enable color management properties
- * @crtc: DRM CRTC
- * @degamma_lut_size: the size of the degamma lut (before CSC)
- * @has_ctm: whether to attach ctm_property for CSC matrix
- * @gamma_lut_size: the size of the gamma lut (after CSC)
- *
- * This function lets the driver enable the color correction
- * properties on a CRTC. This includes 3 degamma, csc and gamma
- * properties that userspace can set and 2 size properties to inform
- * the userspace of the lut sizes. Each of the properties are
- * optional. The gamma and degamma properties are only attached if
- * their size is not 0 and ctm_property is only attached if has_ctm is
- * true.
- */
-void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
-                               uint degamma_lut_size,
-                               bool has_ctm,
-                               uint gamma_lut_size)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_mode_config *config = &dev->mode_config;
-
-       if (degamma_lut_size) {
-               drm_object_attach_property(&crtc->base,
-                                          config->degamma_lut_property, 0);
-               drm_object_attach_property(&crtc->base,
-                                          config->degamma_lut_size_property,
-                                          degamma_lut_size);
-       }
-
-       if (has_ctm)
-               drm_object_attach_property(&crtc->base,
-                                          config->ctm_property, 0);
-
-       if (gamma_lut_size) {
-               drm_object_attach_property(&crtc->base,
-                                          config->gamma_lut_property, 0);
-               drm_object_attach_property(&crtc->base,
-                                          config->gamma_lut_size_property,
-                                          gamma_lut_size);
-       }
-}
-EXPORT_SYMBOL(drm_crtc_enable_color_mgmt);
index 604d3ef..5d2cb13 100644 (file)
  * &drm_connector_helper_funcs.
  */
 
-/**
- * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
- *                                             connector list
- * @dev: drm device to operate on
- *
- * Some userspace presumes that the first connected connector is the main
- * display, where it's supposed to display e.g. the login screen. For
- * laptops, this should be the main panel. Use this function to sort all
- * (eDP/LVDS) panels to the front of the connector list, instead of
- * painstakingly trying to initialize them in the right order.
- */
-void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
-{
-       struct drm_connector *connector, *tmp;
-       struct list_head panel_list;
-
-       INIT_LIST_HEAD(&panel_list);
-
-       list_for_each_entry_safe(connector, tmp,
-                                &dev->mode_config.connector_list, head) {
-               if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
-                   connector->connector_type == DRM_MODE_CONNECTOR_eDP)
-                       list_move_tail(&connector->head, &panel_list);
-       }
-
-       list_splice(&panel_list, &dev->mode_config.connector_list);
-}
-EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
-
 /**
  * drm_helper_encoder_in_use - check if a given encoder is in use
  * @encoder: encoder to check
@@ -912,33 +883,6 @@ int drm_helper_connector_dpms(struct drm_connector *connector, int mode)
 }
 EXPORT_SYMBOL(drm_helper_connector_dpms);
 
-/**
- * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata
- * @fb: drm_framebuffer object to fill out
- * @mode_cmd: metadata from the userspace fb creation request
- *
- * This helper can be used in a drivers fb_create callback to pre-fill the fb's
- * metadata fields.
- */
-void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
-                                   const struct drm_mode_fb_cmd2 *mode_cmd)
-{
-       int i;
-
-       fb->width = mode_cmd->width;
-       fb->height = mode_cmd->height;
-       for (i = 0; i < 4; i++) {
-               fb->pitches[i] = mode_cmd->pitches[i];
-               fb->offsets[i] = mode_cmd->offsets[i];
-               fb->modifier[i] = mode_cmd->modifier[i];
-       }
-       drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
-                                   &fb->bits_per_pixel);
-       fb->pixel_format = mode_cmd->pixel_format;
-       fb->flags = mode_cmd->flags;
-}
-EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
-
 /**
  * drm_helper_resume_force_mode - force-restore mode setting configuration
  * @dev: drm_device which should be restored
diff --git a/drivers/gpu/drm/drm_crtc_helper_internal.h b/drivers/gpu/drm/drm_crtc_helper_internal.h
new file mode 100644 (file)
index 0000000..28295e5
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2016 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 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.
+ */
+
+/*
+ * This header file contains mode setting related functions and definitions
+ * which are only used within the drm kms helper module as internal
+ * implementation details and are not exported to drivers.
+ */
+
+#include <drm/drm_dp_helper.h>
+
+/* drm_fb_helper.c */
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+int drm_fb_helper_modinit(void);
+#else
+static inline int drm_fb_helper_modinit(void)
+{
+       return 0;
+}
+#endif
+
+/* drm_dp_aux_dev.c */
+#ifdef CONFIG_DRM_DP_AUX_CHARDEV
+int drm_dp_aux_dev_init(void);
+void drm_dp_aux_dev_exit(void);
+int drm_dp_aux_register_devnode(struct drm_dp_aux *aux);
+void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux);
+#else
+static inline int drm_dp_aux_dev_init(void)
+{
+       return 0;
+}
+
+static inline void drm_dp_aux_dev_exit(void)
+{
+}
+
+static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
+{
+       return 0;
+}
+
+static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
+{
+}
+#endif
index 0c34e6d..c48ba02 100644 (file)
 
 
 /* drm_crtc.c */
-void drm_connector_ida_init(void);
-void drm_connector_ida_destroy(void);
-int drm_mode_object_get(struct drm_device *dev,
-                       struct drm_mode_object *obj, uint32_t obj_type);
-void drm_mode_object_unregister(struct drm_device *dev,
-                               struct drm_mode_object *object);
-bool drm_property_change_valid_get(struct drm_property *property,
-                                  uint64_t value,
-                                  struct drm_mode_object **ref);
-void drm_property_change_valid_put(struct drm_property *property,
-                                  struct drm_mode_object *ref);
-
-int drm_plane_check_pixel_format(const struct drm_plane *plane,
-                                u32 format);
+int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
+                              struct drm_property *property,
+                              uint64_t value);
 int drm_crtc_check_viewport(const struct drm_crtc *crtc,
                            int x, int y,
                            const struct drm_display_mode *mode,
                            const struct drm_framebuffer *fb);
 
 void drm_fb_release(struct drm_file *file_priv);
-void drm_property_destroy_user_blobs(struct drm_device *dev,
-                                    struct drm_file *file_priv);
 
 /* dumb buffer support IOCTLs */
 int drm_mode_create_dumb_ioctl(struct drm_device *dev,
@@ -64,42 +51,32 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
 int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
                                void *data, struct drm_file *file_priv);
 
-/* framebuffer IOCTLs */
-extern int drm_mode_addfb(struct drm_device *dev,
-                         void *data, struct drm_file *file_priv);
-extern int drm_mode_addfb2(struct drm_device *dev,
-                          void *data, struct drm_file *file_priv);
-int drm_mode_rmfb(struct drm_device *dev,
-                        void *data, struct drm_file *file_priv);
-int drm_mode_getfb(struct drm_device *dev,
-                  void *data, struct drm_file *file_priv);
-int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
-                          void *data, struct drm_file *file_priv);
-
 /* IOCTLs */
-int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
-                                     struct drm_file *file_priv);
-int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv);
-
 int drm_mode_getresources(struct drm_device *dev,
                          void *data, struct drm_file *file_priv);
-int drm_mode_getplane_res(struct drm_device *dev, void *data,
-                         struct drm_file *file_priv);
 int drm_mode_getcrtc(struct drm_device *dev,
                     void *data, struct drm_file *file_priv);
-int drm_mode_getconnector(struct drm_device *dev,
-                         void *data, struct drm_file *file_priv);
 int drm_mode_setcrtc(struct drm_device *dev,
                     void *data, struct drm_file *file_priv);
-int drm_mode_getplane(struct drm_device *dev,
-                     void *data, struct drm_file *file_priv);
-int drm_mode_setplane(struct drm_device *dev,
-                     void *data, struct drm_file *file_priv);
-int drm_mode_cursor_ioctl(struct drm_device *dev,
-                         void *data, struct drm_file *file_priv);
-int drm_mode_cursor2_ioctl(struct drm_device *dev,
-                          void *data, struct drm_file *file_priv);
+
+/* drm_color_mgmt.c */
+
+/* IOCTLs */
+int drm_mode_gamma_get_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv);
+int drm_mode_gamma_set_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv);
+
+/* drm_property.c */
+void drm_property_destroy_user_blobs(struct drm_device *dev,
+                                    struct drm_file *file_priv);
+bool drm_property_change_valid_get(struct drm_property *property,
+                                  uint64_t value,
+                                  struct drm_mode_object **ref);
+void drm_property_change_valid_put(struct drm_property *property,
+                                  struct drm_mode_object *ref);
+
+/* IOCTL */
 int drm_mode_getproperty_ioctl(struct drm_device *dev,
                               void *data, struct drm_file *file_priv);
 int drm_mode_getblob_ioctl(struct drm_device *dev,
@@ -108,17 +85,80 @@ int drm_mode_createblob_ioctl(struct drm_device *dev,
                              void *data, struct drm_file *file_priv);
 int drm_mode_destroyblob_ioctl(struct drm_device *dev,
                               void *data, struct drm_file *file_priv);
-int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
-                                         void *data, struct drm_file *file_priv);
+
+/* drm_mode_object.c */
+int drm_mode_object_get_reg(struct drm_device *dev,
+                           struct drm_mode_object *obj,
+                           uint32_t obj_type,
+                           bool register_obj,
+                           void (*obj_free_cb)(struct kref *kref));
+void drm_mode_object_register(struct drm_device *dev,
+                             struct drm_mode_object *obj);
+int drm_mode_object_get(struct drm_device *dev,
+                       struct drm_mode_object *obj, uint32_t obj_type);
+struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
+                                              uint32_t id, uint32_t type);
+void drm_mode_object_unregister(struct drm_device *dev,
+                               struct drm_mode_object *object);
+int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
+                                  uint32_t __user *prop_ptr,
+                                  uint64_t __user *prop_values,
+                                  uint32_t *arg_count_props);
+struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj,
+                                              uint32_t prop_id);
+
+/* IOCTL */
+
+int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
+                                     struct drm_file *file_priv);
+int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
+
+/* drm_encoder.c */
+int drm_encoder_register_all(struct drm_device *dev);
+void drm_encoder_unregister_all(struct drm_device *dev);
+
+/* IOCTL */
 int drm_mode_getencoder(struct drm_device *dev,
                        void *data, struct drm_file *file_priv);
-int drm_mode_gamma_get_ioctl(struct drm_device *dev,
-                            void *data, struct drm_file *file_priv);
-int drm_mode_gamma_set_ioctl(struct drm_device *dev,
-                            void *data, struct drm_file *file_priv);
 
-int drm_mode_page_flip_ioctl(struct drm_device *dev,
-                            void *data, struct drm_file *file_priv);
+/* drm_connector.c */
+void drm_connector_ida_init(void);
+void drm_connector_ida_destroy(void);
+void drm_connector_unregister_all(struct drm_device *dev);
+int drm_connector_register_all(struct drm_device *dev);
+int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
+                                   struct drm_property *property,
+                                   uint64_t value);
+int drm_connector_create_standard_properties(struct drm_device *dev);
+
+/* IOCTL */
+int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
+                                         void *data, struct drm_file *file_priv);
+int drm_mode_getconnector(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv);
+
+/* drm_framebuffer.c */
+struct drm_framebuffer *
+drm_internal_framebuffer_create(struct drm_device *dev,
+                               const struct drm_mode_fb_cmd2 *r,
+                               struct drm_file *file_priv);
+void drm_framebuffer_free(struct kref *kref);
+int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y,
+                                    uint32_t src_w, uint32_t src_h,
+                                    const struct drm_framebuffer *fb);
+
+/* IOCTL */
+int drm_mode_addfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv);
+int drm_mode_addfb2(struct drm_device *dev,
+                   void *data, struct drm_file *file_priv);
+int drm_mode_rmfb(struct drm_device *dev,
+                 void *data, struct drm_file *file_priv);
+int drm_mode_getfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv);
+int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv);
 
 /* drm_atomic.c */
 int drm_atomic_get_property(struct drm_mode_object *obj,
@@ -129,6 +169,23 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
 int drm_modeset_register_all(struct drm_device *dev);
 void drm_modeset_unregister_all(struct drm_device *dev);
 
-/* drm_blend.c */
-int drm_atomic_helper_normalize_zpos(struct drm_device *dev,
-                                    struct drm_atomic_state *state);
+
+/* drm_plane.c */
+int drm_plane_register_all(struct drm_device *dev);
+void drm_plane_unregister_all(struct drm_device *dev);
+int drm_plane_check_pixel_format(const struct drm_plane *plane,
+                                u32 format);
+
+/* IOCTL */
+int drm_mode_getplane_res(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv);
+int drm_mode_getplane(struct drm_device *dev,
+                     void *data, struct drm_file *file_priv);
+int drm_mode_setplane(struct drm_device *dev,
+                     void *data, struct drm_file *file_priv);
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv);
+int drm_mode_cursor2_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv);
+int drm_mode_page_flip_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv);
index ea48180..3f83e2c 100644 (file)
@@ -50,9 +50,8 @@ int drm_legacy_dma_setup(struct drm_device *dev)
        int i;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) ||
-           drm_core_check_feature(dev, DRIVER_MODESET)) {
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return 0;
-       }
 
        dev->buf_use = 0;
        atomic_set(&dev->buf_alloc, 0);
@@ -81,9 +80,8 @@ void drm_legacy_dma_takedown(struct drm_device *dev)
        int i, j;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) ||
-           drm_core_check_feature(dev, DRIVER_MODESET)) {
+           !drm_core_check_feature(dev, DRIVER_LEGACY))
                return;
-       }
 
        if (!dma)
                return;
index 734f86a..ec1ed94 100644 (file)
@@ -36,6 +36,8 @@
 #include <drm/drm_crtc.h>
 #include <drm/drmP.h>
 
+#include "drm_crtc_helper_internal.h"
+
 struct drm_dp_aux_dev {
        unsigned index;
        struct drm_dp_aux *aux;
@@ -283,12 +285,7 @@ static int auxdev_wait_atomic_t(atomic_t *p)
        schedule();
        return 0;
 }
-/**
- * drm_dp_aux_unregister_devnode() - unregister a devnode for this aux channel
- * @aux: DisplayPort AUX channel
- *
- * Returns 0 on success or a negative error code on failure.
- */
+
 void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
 {
        struct drm_dp_aux_dev *aux_dev;
@@ -314,14 +311,7 @@ void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
        DRM_DEBUG("drm_dp_aux_dev: aux [%s] unregistering\n", aux->name);
        kref_put(&aux_dev->refcount, release_drm_dp_aux_dev);
 }
-EXPORT_SYMBOL(drm_dp_aux_unregister_devnode);
 
-/**
- * drm_dp_aux_register_devnode() - register a devnode for this aux channel
- * @aux: DisplayPort AUX channel
- *
- * Returns 0 on success or a negative error code on failure.
- */
 int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
 {
        struct drm_dp_aux_dev *aux_dev;
@@ -347,7 +337,6 @@ error:
        drm_dp_aux_unregister_devnode(aux);
        return res;
 }
-EXPORT_SYMBOL(drm_dp_aux_register_devnode);
 
 int drm_dp_aux_dev_init(void)
 {
@@ -369,11 +358,9 @@ out:
        class_destroy(drm_dp_aux_dev_class);
        return res;
 }
-EXPORT_SYMBOL(drm_dp_aux_dev_init);
 
 void drm_dp_aux_dev_exit(void)
 {
        unregister_chrdev(drm_dev_major, "aux");
        class_destroy(drm_dp_aux_dev_class);
 }
-EXPORT_SYMBOL(drm_dp_aux_dev_exit);
index 2bd0644..3e6fe82 100644 (file)
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/i2c.h>
+#include <linux/seq_file.h>
 #include <drm/drm_dp_helper.h>
-#include <drm/drm_dp_aux_dev.h>
 #include <drm/drmP.h>
 
+#include "drm_crtc_helper_internal.h"
+
 /**
  * DOC: dp helpers
  *
@@ -223,7 +225,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
                        err = ret;
        }
 
-       DRM_DEBUG_KMS("too many retries, giving up\n");
+       DRM_DEBUG_KMS("Too many retries, giving up. First error: %d\n", err);
        ret = err;
 
 unlock:
@@ -438,6 +440,179 @@ int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link)
 }
 EXPORT_SYMBOL(drm_dp_link_configure);
 
+/**
+ * drm_dp_downstream_max_clock() - extract branch device max
+ *                                 pixel rate for legacy VGA
+ *                                 converter or max TMDS clock
+ *                                 rate for others
+ * @dpcd: DisplayPort configuration data
+ * @port_cap: port capabilities
+ *
+ * Returns max clock in kHz on success or 0 if max clock not defined
+ */
+int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                               const u8 port_cap[4])
+{
+       int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
+       bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+               DP_DETAILED_CAP_INFO_AVAILABLE;
+
+       if (!detailed_cap_info)
+               return 0;
+
+       switch (type) {
+       case DP_DS_PORT_TYPE_VGA:
+               return port_cap[1] * 8 * 1000;
+       case DP_DS_PORT_TYPE_DVI:
+       case DP_DS_PORT_TYPE_HDMI:
+       case DP_DS_PORT_TYPE_DP_DUALMODE:
+               return port_cap[1] * 2500;
+       default:
+               return 0;
+       }
+}
+EXPORT_SYMBOL(drm_dp_downstream_max_clock);
+
+/**
+ * drm_dp_downstream_max_bpc() - extract branch device max
+ *                               bits per component
+ * @dpcd: DisplayPort configuration data
+ * @port_cap: port capabilities
+ *
+ * Returns max bpc on success or 0 if max bpc not defined
+ */
+int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                             const u8 port_cap[4])
+{
+       int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
+       bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+               DP_DETAILED_CAP_INFO_AVAILABLE;
+       int bpc;
+
+       if (!detailed_cap_info)
+               return 0;
+
+       switch (type) {
+       case DP_DS_PORT_TYPE_VGA:
+       case DP_DS_PORT_TYPE_DVI:
+       case DP_DS_PORT_TYPE_HDMI:
+       case DP_DS_PORT_TYPE_DP_DUALMODE:
+               bpc = port_cap[2] & DP_DS_MAX_BPC_MASK;
+
+               switch (bpc) {
+               case DP_DS_8BPC:
+                       return 8;
+               case DP_DS_10BPC:
+                       return 10;
+               case DP_DS_12BPC:
+                       return 12;
+               case DP_DS_16BPC:
+                       return 16;
+               }
+       default:
+               return 0;
+       }
+}
+EXPORT_SYMBOL(drm_dp_downstream_max_bpc);
+
+/**
+ * drm_dp_downstream_id() - identify branch device
+ * @aux: DisplayPort AUX channel
+ * @id: DisplayPort branch device id
+ *
+ * Returns branch device id on success or NULL on failure
+ */
+int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6])
+{
+       return drm_dp_dpcd_read(aux, DP_BRANCH_ID, id, 6);
+}
+EXPORT_SYMBOL(drm_dp_downstream_id);
+
+/**
+ * drm_dp_downstream_debug() - debug DP branch devices
+ * @m: pointer for debugfs file
+ * @dpcd: DisplayPort configuration data
+ * @port_cap: port capabilities
+ * @aux: DisplayPort AUX channel
+ *
+ */
+void drm_dp_downstream_debug(struct seq_file *m,
+                            const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                            const u8 port_cap[4], struct drm_dp_aux *aux)
+{
+       bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+                                DP_DETAILED_CAP_INFO_AVAILABLE;
+       int clk;
+       int bpc;
+       char id[6];
+       int len;
+       uint8_t rev[2];
+       int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
+       bool branch_device = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+                            DP_DWN_STRM_PORT_PRESENT;
+
+       seq_printf(m, "\tDP branch device present: %s\n",
+                  branch_device ? "yes" : "no");
+
+       if (!branch_device)
+               return;
+
+       switch (type) {
+       case DP_DS_PORT_TYPE_DP:
+               seq_puts(m, "\t\tType: DisplayPort\n");
+               break;
+       case DP_DS_PORT_TYPE_VGA:
+               seq_puts(m, "\t\tType: VGA\n");
+               break;
+       case DP_DS_PORT_TYPE_DVI:
+               seq_puts(m, "\t\tType: DVI\n");
+               break;
+       case DP_DS_PORT_TYPE_HDMI:
+               seq_puts(m, "\t\tType: HDMI\n");
+               break;
+       case DP_DS_PORT_TYPE_NON_EDID:
+               seq_puts(m, "\t\tType: others without EDID support\n");
+               break;
+       case DP_DS_PORT_TYPE_DP_DUALMODE:
+               seq_puts(m, "\t\tType: DP++\n");
+               break;
+       case DP_DS_PORT_TYPE_WIRELESS:
+               seq_puts(m, "\t\tType: Wireless\n");
+               break;
+       default:
+               seq_puts(m, "\t\tType: N/A\n");
+       }
+
+       drm_dp_downstream_id(aux, id);
+       seq_printf(m, "\t\tID: %s\n", id);
+
+       len = drm_dp_dpcd_read(aux, DP_BRANCH_HW_REV, &rev[0], 1);
+       if (len > 0)
+               seq_printf(m, "\t\tHW: %d.%d\n",
+                          (rev[0] & 0xf0) >> 4, rev[0] & 0xf);
+
+       len = drm_dp_dpcd_read(aux, DP_BRANCH_SW_REV, &rev, 2);
+       if (len > 0)
+               seq_printf(m, "\t\tSW: %d.%d\n", rev[0], rev[1]);
+
+       if (detailed_cap_info) {
+               clk = drm_dp_downstream_max_clock(dpcd, port_cap);
+
+               if (clk > 0) {
+                       if (type == DP_DS_PORT_TYPE_VGA)
+                               seq_printf(m, "\t\tMax dot clock: %d kHz\n", clk);
+                       else
+                               seq_printf(m, "\t\tMax TMDS clock: %d kHz\n", clk);
+               }
+
+               bpc = drm_dp_downstream_max_bpc(dpcd, port_cap);
+
+               if (bpc > 0)
+                       seq_printf(m, "\t\tMax bpc: %d\n", bpc);
+       }
+}
+EXPORT_SYMBOL(drm_dp_downstream_debug);
+
 /*
  * I2C-over-AUX implementation
  */
@@ -574,7 +749,17 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                        if (ret == -EBUSY)
                                continue;
 
-                       DRM_DEBUG_KMS("transaction failed: %d\n", ret);
+                       /*
+                        * While timeouts can be errors, they're usually normal
+                        * behavior (for instance, when a driver tries to
+                        * communicate with a non-existant DisplayPort device).
+                        * Avoid spamming the kernel log with timeout errors.
+                        */
+                       if (ret == -ETIMEDOUT)
+                               DRM_DEBUG_KMS_RATELIMITED("transaction timed out\n");
+                       else
+                               DRM_DEBUG_KMS("transaction failed: %d\n", ret);
+
                        return ret;
                }
 
index be27ed3..6efdba4 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/mount.h>
 #include <linux/slab.h>
 #include <drm/drmP.h>
-#include <drm/drm_core.h>
 #include "drm_crtc_internal.h"
 #include "drm_legacy.h"
 #include "drm_internal.h"
@@ -46,8 +45,8 @@
 unsigned int drm_debug = 0;
 EXPORT_SYMBOL(drm_debug);
 
-MODULE_AUTHOR(CORE_AUTHOR);
-MODULE_DESCRIPTION(CORE_DESC);
+MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl");
+MODULE_DESCRIPTION("DRM shared core routines");
 MODULE_LICENSE("GPL and additional rights");
 MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n"
 "\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n"
@@ -63,37 +62,52 @@ static struct idr drm_minors_idr;
 
 static struct dentry *drm_debugfs_root;
 
-void drm_err(const char *format, ...)
+#define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV"
+
+void drm_dev_printk(const struct device *dev, const char *level,
+                   unsigned int category, const char *function_name,
+                   const char *prefix, const char *format, ...)
 {
        struct va_format vaf;
        va_list args;
 
-       va_start(args, format);
+       if (category != DRM_UT_NONE && !(drm_debug & category))
+               return;
 
+       va_start(args, format);
        vaf.fmt = format;
        vaf.va = &args;
 
-       printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV",
-              __builtin_return_address(0), &vaf);
+       if (dev)
+               dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix,
+                          &vaf);
+       else
+               printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf);
 
        va_end(args);
 }
-EXPORT_SYMBOL(drm_err);
+EXPORT_SYMBOL(drm_dev_printk);
 
-void drm_ut_debug_printk(const char *function_name, const char *format, ...)
+void drm_printk(const char *level, unsigned int category,
+               const char *format, ...)
 {
        struct va_format vaf;
        va_list args;
 
+       if (category != DRM_UT_NONE && !(drm_debug & category))
+               return;
+
        va_start(args, format);
        vaf.fmt = format;
        vaf.va = &args;
 
-       printk(KERN_DEBUG "[" DRM_NAME ":%s] %pV", function_name, &vaf);
+       printk("%s" "[" DRM_NAME ":%ps]%s %pV",
+              level, __builtin_return_address(0),
+              strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf);
 
        va_end(args);
 }
-EXPORT_SYMBOL(drm_ut_debug_printk);
+EXPORT_SYMBOL(drm_printk);
 
 /*
  * DRM Minors
@@ -112,7 +126,7 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
                                             unsigned int type)
 {
        switch (type) {
-       case DRM_MINOR_LEGACY:
+       case DRM_MINOR_PRIMARY:
                return &dev->primary;
        case DRM_MINOR_RENDER:
                return &dev->render;
@@ -325,6 +339,9 @@ void drm_minor_release(struct drm_minor *minor)
 
 static int drm_dev_set_unique(struct drm_device *dev, const char *name)
 {
+       if (!name)
+               return -EINVAL;
+
        kfree(dev->unique);
        dev->unique = kstrdup(name, GFP_KERNEL);
 
@@ -512,7 +529,7 @@ int drm_dev_init(struct drm_device *dev,
                        goto err_minors;
        }
 
-       ret = drm_minor_alloc(dev, DRM_MINOR_LEGACY);
+       ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
        if (ret)
                goto err_minors;
 
@@ -545,7 +562,7 @@ err_ctxbitmap:
        drm_legacy_ctxbitmap_cleanup(dev);
        drm_ht_remove(&dev->map_hash);
 err_minors:
-       drm_minor_free(dev, DRM_MINOR_LEGACY);
+       drm_minor_free(dev, DRM_MINOR_PRIMARY);
        drm_minor_free(dev, DRM_MINOR_RENDER);
        drm_minor_free(dev, DRM_MINOR_CONTROL);
        drm_fs_inode_free(dev->anon_inode);
@@ -575,7 +592,7 @@ EXPORT_SYMBOL(drm_dev_init);
  * own struct should look at using drm_dev_init() instead.
  *
  * RETURNS:
- * Pointer to new DRM device, or NULL if out of memory.
+ * Pointer to new DRM device, or ERR_PTR on failure.
  */
 struct drm_device *drm_dev_alloc(struct drm_driver *driver,
                                 struct device *parent)
@@ -585,12 +602,12 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        ret = drm_dev_init(dev, driver, parent);
        if (ret) {
                kfree(dev);
-               return NULL;
+               return ERR_PTR(ret);
        }
 
        return dev;
@@ -608,7 +625,7 @@ static void drm_dev_release(struct kref *ref)
        drm_ht_remove(&dev->map_hash);
        drm_fs_inode_free(dev->anon_inode);
 
-       drm_minor_free(dev, DRM_MINOR_LEGACY);
+       drm_minor_free(dev, DRM_MINOR_PRIMARY);
        drm_minor_free(dev, DRM_MINOR_RENDER);
        drm_minor_free(dev, DRM_MINOR_CONTROL);
 
@@ -684,7 +701,7 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
        if (ret)
                goto err_minors;
 
-       ret = drm_minor_register(dev, DRM_MINOR_LEGACY);
+       ret = drm_minor_register(dev, DRM_MINOR_PRIMARY);
        if (ret)
                goto err_minors;
 
@@ -701,7 +718,7 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
        goto out_unlock;
 
 err_minors:
-       drm_minor_unregister(dev, DRM_MINOR_LEGACY);
+       drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
        drm_minor_unregister(dev, DRM_MINOR_RENDER);
        drm_minor_unregister(dev, DRM_MINOR_CONTROL);
 out_unlock:
@@ -741,7 +758,7 @@ void drm_dev_unregister(struct drm_device *dev)
        list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
                drm_legacy_rmmap(dev, r_list->map);
 
-       drm_minor_unregister(dev, DRM_MINOR_LEGACY);
+       drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
        drm_minor_unregister(dev, DRM_MINOR_RENDER);
        drm_minor_unregister(dev, DRM_MINOR_CONTROL);
 }
@@ -807,53 +824,48 @@ static const struct file_operations drm_stub_fops = {
        .llseek = noop_llseek,
 };
 
+static void drm_core_exit(void)
+{
+       unregister_chrdev(DRM_MAJOR, "drm");
+       debugfs_remove(drm_debugfs_root);
+       drm_sysfs_destroy();
+       idr_destroy(&drm_minors_idr);
+       drm_connector_ida_destroy();
+       drm_global_release();
+}
+
 static int __init drm_core_init(void)
 {
-       int ret = -ENOMEM;
+       int ret;
 
        drm_global_init();
        drm_connector_ida_init();
        idr_init(&drm_minors_idr);
 
-       if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))
-               goto err_p1;
-
        ret = drm_sysfs_init();
        if (ret < 0) {
-               printk(KERN_ERR "DRM: Error creating drm class.\n");
-               goto err_p2;
+               DRM_ERROR("Cannot create DRM class: %d\n", ret);
+               goto error;
        }
 
        drm_debugfs_root = debugfs_create_dir("dri", NULL);
        if (!drm_debugfs_root) {
-               DRM_ERROR("Cannot create /sys/kernel/debug/dri\n");
-               ret = -1;
-               goto err_p3;
+               ret = -ENOMEM;
+               DRM_ERROR("Cannot create debugfs-root: %d\n", ret);
+               goto error;
        }
 
-       DRM_INFO("Initialized %s %d.%d.%d %s\n",
-                CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
+       ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops);
+       if (ret < 0)
+               goto error;
+
+       DRM_INFO("Initialized\n");
        return 0;
-err_p3:
-       drm_sysfs_destroy();
-err_p2:
-       unregister_chrdev(DRM_MAJOR, "drm");
 
-       idr_destroy(&drm_minors_idr);
-err_p1:
+error:
+       drm_core_exit();
        return ret;
 }
 
-static void __exit drm_core_exit(void)
-{
-       debugfs_remove(drm_debugfs_root);
-       drm_sysfs_destroy();
-
-       unregister_chrdev(DRM_MAJOR, "drm");
-
-       drm_connector_ida_destroy();
-       idr_destroy(&drm_minors_idr);
-}
-
 module_init(drm_core_init);
 module_exit(drm_core_exit);
index 637a0aa..ec77bd3 100644 (file)
@@ -991,7 +991,7 @@ static const struct drm_display_mode edid_cea_modes[] = {
         .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 64 - 1920x1080@100Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
-                  2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
+                  2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
         .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 };
@@ -3253,16 +3253,12 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
 }
 
 static void
-parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
+drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
 {
        u8 len = cea_db_payload_len(db);
 
-       if (len >= 6) {
+       if (len >= 6)
                connector->eld[5] |= (db[6] >> 7) << 1;  /* Supports_AI */
-               connector->dvi_dual = db[6] & 1;
-       }
-       if (len >= 7)
-               connector->max_tmds_clock = db[7] * 5;
        if (len >= 8) {
                connector->latency_present[0] = db[8] >> 7;
                connector->latency_present[1] = (db[8] >> 6) & 1;
@@ -3276,19 +3272,15 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
        if (len >= 12)
                connector->audio_latency[1] = db[12];
 
-       DRM_DEBUG_KMS("HDMI: DVI dual %d, "
-                   "max TMDS clock %d, "
-                   "latency present %d %d, "
-                   "video latency %d %d, "
-                   "audio latency %d %d\n",
-                   connector->dvi_dual,
-                   connector->max_tmds_clock,
-             (int) connector->latency_present[0],
-             (int) connector->latency_present[1],
-                   connector->video_latency[0],
-                   connector->video_latency[1],
-                   connector->audio_latency[0],
-                   connector->audio_latency[1]);
+       DRM_DEBUG_KMS("HDMI: latency present %d %d, "
+                     "video latency %d %d, "
+                     "audio latency %d %d\n",
+                     connector->latency_present[0],
+                     connector->latency_present[1],
+                     connector->video_latency[0],
+                     connector->video_latency[1],
+                     connector->audio_latency[0],
+                     connector->audio_latency[1]);
 }
 
 static void
@@ -3358,6 +3350,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
 
        memset(eld, 0, sizeof(connector->eld));
 
+       connector->latency_present[0] = false;
+       connector->latency_present[1] = false;
+       connector->video_latency[0] = 0;
+       connector->audio_latency[0] = 0;
+       connector->video_latency[1] = 0;
+       connector->audio_latency[1] = 0;
+
        cea = drm_find_cea_extension(edid);
        if (!cea) {
                DRM_DEBUG_KMS("ELD: no CEA Extension found\n");
@@ -3407,7 +3406,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
                        case VENDOR_BLOCK:
                                /* HDMI Vendor-Specific Data Block */
                                if (cea_db_is_hdmi_vsdb(db))
-                                       parse_hdmi_vsdb(connector, db);
+                                       drm_parse_hdmi_vsdb_audio(connector, db);
                                break;
                        default:
                                break;
@@ -3721,122 +3720,127 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
 }
 EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
 
-/**
- * drm_assign_hdmi_deep_color_info - detect whether monitor supports
- * hdmi deep color modes and update drm_display_info if so.
- * @edid: monitor EDID information
- * @info: Updated with maximum supported deep color bpc and color format
- *        if deep color supported.
- * @connector: DRM connector, used only for debug output
- *
- * Parse the CEA extension according to CEA-861-B.
- * Return true if HDMI deep color supported, false if not or unknown.
- */
-static bool drm_assign_hdmi_deep_color_info(struct edid *edid,
-                                            struct drm_display_info *info,
-                                            struct drm_connector *connector)
+static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
+                                          const u8 *hdmi)
 {
-       u8 *edid_ext, *hdmi;
-       int i;
-       int start_offset, end_offset;
+       struct drm_display_info *info = &connector->display_info;
        unsigned int dc_bpc = 0;
 
-       edid_ext = drm_find_cea_extension(edid);
-       if (!edid_ext)
-               return false;
+       /* HDMI supports at least 8 bpc */
+       info->bpc = 8;
 
-       if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
-               return false;
+       if (cea_db_payload_len(hdmi) < 6)
+               return;
+
+       if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
+               dc_bpc = 10;
+               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30;
+               DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
+                         connector->name);
+       }
+
+       if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
+               dc_bpc = 12;
+               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36;
+               DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
+                         connector->name);
+       }
+
+       if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
+               dc_bpc = 16;
+               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48;
+               DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
+                         connector->name);
+       }
+
+       if (dc_bpc == 0) {
+               DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
+                         connector->name);
+               return;
+       }
+
+       DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
+                 connector->name, dc_bpc);
+       info->bpc = dc_bpc;
 
        /*
-        * Because HDMI identifier is in Vendor Specific Block,
-        * search it from all data blocks of CEA extension.
+        * Deep color support mandates RGB444 support for all video
+        * modes and forbids YCRCB422 support for all video modes per
+        * HDMI 1.3 spec.
         */
-       for_each_cea_db(edid_ext, i, start_offset, end_offset) {
-               if (cea_db_is_hdmi_vsdb(&edid_ext[i])) {
-                       /* HDMI supports at least 8 bpc */
-                       info->bpc = 8;
-
-                       hdmi = &edid_ext[i];
-                       if (cea_db_payload_len(hdmi) < 6)
-                               return false;
-
-                       if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
-                               dc_bpc = 10;
-                               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30;
-                               DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
-                                                 connector->name);
-                       }
+       info->color_formats = DRM_COLOR_FORMAT_RGB444;
 
-                       if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
-                               dc_bpc = 12;
-                               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36;
-                               DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
-                                                 connector->name);
-                       }
+       /* YCRCB444 is optional according to spec. */
+       if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
+               info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
+               DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
+                         connector->name);
+       }
 
-                       if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
-                               dc_bpc = 16;
-                               info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48;
-                               DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
-                                                 connector->name);
-                       }
+       /*
+        * Spec says that if any deep color mode is supported at all,
+        * then deep color 36 bit must be supported.
+        */
+       if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
+               DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
+                         connector->name);
+       }
+}
 
-                       if (dc_bpc > 0) {
-                               DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
-                                                 connector->name, dc_bpc);
-                               info->bpc = dc_bpc;
-
-                               /*
-                                * Deep color support mandates RGB444 support for all video
-                                * modes and forbids YCRCB422 support for all video modes per
-                                * HDMI 1.3 spec.
-                                */
-                               info->color_formats = DRM_COLOR_FORMAT_RGB444;
-
-                               /* YCRCB444 is optional according to spec. */
-                               if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
-                                       info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
-                                       DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
-                                                         connector->name);
-                               }
+static void
+drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
+{
+       struct drm_display_info *info = &connector->display_info;
+       u8 len = cea_db_payload_len(db);
 
-                               /*
-                                * Spec says that if any deep color mode is supported at all,
-                                * then deep color 36 bit must be supported.
-                                */
-                               if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
-                                       DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
-                                                         connector->name);
-                               }
+       if (len >= 6)
+               info->dvi_dual = db[6] & 1;
+       if (len >= 7)
+               info->max_tmds_clock = db[7] * 5000;
 
-                               return true;
-                       }
-                       else {
-                               DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
-                                                 connector->name);
-                       }
-               }
-       }
+       DRM_DEBUG_KMS("HDMI: DVI dual %d, "
+                     "max TMDS clock %d kHz\n",
+                     info->dvi_dual,
+                     info->max_tmds_clock);
 
-       return false;
+       drm_parse_hdmi_deep_color_info(connector, db);
 }
 
-/**
- * drm_add_display_info - pull display info out if present
- * @edid: EDID data
- * @info: display info (attached to connector)
- * @connector: connector whose edid is used to build display info
- *
- * Grab any available display info and stuff it into the drm_display_info
- * structure that's part of the connector.  Useful for tracking bpp and
- * color spaces.
- */
-static void drm_add_display_info(struct edid *edid,
-                                 struct drm_display_info *info,
-                                 struct drm_connector *connector)
+static void drm_parse_cea_ext(struct drm_connector *connector,
+                             struct edid *edid)
 {
-       u8 *edid_ext;
+       struct drm_display_info *info = &connector->display_info;
+       const u8 *edid_ext;
+       int i, start, end;
+
+       edid_ext = drm_find_cea_extension(edid);
+       if (!edid_ext)
+               return;
+
+       info->cea_rev = edid_ext[1];
+
+       /* The existence of a CEA block should imply RGB support */
+       info->color_formats = DRM_COLOR_FORMAT_RGB444;
+       if (edid_ext[3] & EDID_CEA_YCRCB444)
+               info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
+       if (edid_ext[3] & EDID_CEA_YCRCB422)
+               info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+
+       if (cea_db_offsets(edid_ext, &start, &end))
+               return;
+
+       for_each_cea_db(edid_ext, i, start, end) {
+               const u8 *db = &edid_ext[i];
+
+               if (cea_db_is_hdmi_vsdb(db))
+                       drm_parse_hdmi_vsdb_video(connector, db);
+       }
+}
+
+static void drm_add_display_info(struct drm_connector *connector,
+                                struct edid *edid)
+{
+       struct drm_display_info *info = &connector->display_info;
 
        info->width_mm = edid->width_cm * 10;
        info->height_mm = edid->height_cm * 10;
@@ -3844,6 +3848,9 @@ static void drm_add_display_info(struct edid *edid,
        /* driver figures it out in this case */
        info->bpc = 0;
        info->color_formats = 0;
+       info->cea_rev = 0;
+       info->max_tmds_clock = 0;
+       info->dvi_dual = false;
 
        if (edid->revision < 3)
                return;
@@ -3851,21 +3858,7 @@ static void drm_add_display_info(struct edid *edid,
        if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
                return;
 
-       /* Get data from CEA blocks if present */
-       edid_ext = drm_find_cea_extension(edid);
-       if (edid_ext) {
-               info->cea_rev = edid_ext[1];
-
-               /* The existence of a CEA block should imply RGB support */
-               info->color_formats = DRM_COLOR_FORMAT_RGB444;
-               if (edid_ext[3] & EDID_CEA_YCRCB444)
-                       info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
-               if (edid_ext[3] & EDID_CEA_YCRCB422)
-                       info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
-       }
-
-       /* HDMI deep color modes supported? Assign to info, if so */
-       drm_assign_hdmi_deep_color_info(edid, info, connector);
+       drm_parse_cea_ext(connector, edid);
 
        /*
         * Digital sink with "DFP 1.x compliant TMDS" according to EDID 1.3?
@@ -4052,7 +4045,9 @@ static int add_displayid_detailed_modes(struct drm_connector *connector,
  * @connector: connector we're probing
  * @edid: EDID data
  *
- * Add the specified modes to the connector's mode list.
+ * Add the specified modes to the connector's mode list. Also fills out the
+ * &drm_display_info structure in @connector with any information which can be
+ * derived from the edid.
  *
  * Return: The number of modes added or 0 if we couldn't find any.
  */
@@ -4099,7 +4094,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
 
-       drm_add_display_info(edid, &connector->display_info, connector);
+       drm_add_display_info(connector, edid);
 
        if (quirks & EDID_QUIRK_FORCE_6BPC)
                connector->display_info.bpc = 6;
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
new file mode 100644 (file)
index 0000000..5c06771
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include <drm/drmP.h>
+#include <drm/drm_encoder.h>
+
+#include "drm_crtc_internal.h"
+
+/**
+ * DOC: overview
+ *
+ * Encoders represent the connecting element between the CRTC (as the overall
+ * pixel pipeline, represented by struct &drm_crtc) and the connectors (as the
+ * generic sink entity, represented by struct &drm_connector). An encoder takes
+ * pixel data from a CRTC and converts it to a format suitable for any attached
+ * connector. Encoders are objects exposed to userspace, originally to allow
+ * userspace to infer cloning and connector/CRTC restrictions. Unfortunately
+ * almost all drivers get this wrong, making the uabi pretty much useless. On
+ * top of that the exposed restrictions are too simple for today's hardware, and
+ * the recommended way to infer restrictions is by using the
+ * DRM_MODE_ATOMIC_TEST_ONLY flag for the atomic IOCTL.
+ *
+ * Otherwise encoders aren't used in the uapi at all (any modeset request from
+ * userspace directly connects a connector with a CRTC), drivers are therefore
+ * free to use them however they wish. Modeset helper libraries make strong use
+ * of encoders to facilitate code sharing. But for more complex settings it is
+ * usually better to move shared code into a separate &drm_bridge. Compared to
+ * encoders, bridges also have the benefit of being purely an internal
+ * abstraction since they are not exposed to userspace at all.
+ *
+ * Encoders are initialized with drm_encoder_init() and cleaned up using
+ * drm_encoder_cleanup().
+ */
+static const struct drm_prop_enum_list drm_encoder_enum_list[] = {
+       { DRM_MODE_ENCODER_NONE, "None" },
+       { DRM_MODE_ENCODER_DAC, "DAC" },
+       { DRM_MODE_ENCODER_TMDS, "TMDS" },
+       { DRM_MODE_ENCODER_LVDS, "LVDS" },
+       { DRM_MODE_ENCODER_TVDAC, "TV" },
+       { DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
+       { DRM_MODE_ENCODER_DSI, "DSI" },
+       { DRM_MODE_ENCODER_DPMST, "DP MST" },
+       { DRM_MODE_ENCODER_DPI, "DPI" },
+};
+
+int drm_encoder_register_all(struct drm_device *dev)
+{
+       struct drm_encoder *encoder;
+       int ret = 0;
+
+       drm_for_each_encoder(encoder, dev) {
+               if (encoder->funcs->late_register)
+                       ret = encoder->funcs->late_register(encoder);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void drm_encoder_unregister_all(struct drm_device *dev)
+{
+       struct drm_encoder *encoder;
+
+       drm_for_each_encoder(encoder, dev) {
+               if (encoder->funcs->early_unregister)
+                       encoder->funcs->early_unregister(encoder);
+       }
+}
+
+/**
+ * drm_encoder_init - Init a preallocated encoder
+ * @dev: drm device
+ * @encoder: the encoder to init
+ * @funcs: callbacks for this encoder
+ * @encoder_type: user visible type of the encoder
+ * @name: printf style format string for the encoder name, or NULL for default name
+ *
+ * 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.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_encoder_init(struct drm_device *dev,
+                    struct drm_encoder *encoder,
+                    const struct drm_encoder_funcs *funcs,
+                    int encoder_type, const char *name, ...)
+{
+       int ret;
+
+       drm_modeset_lock_all(dev);
+
+       ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
+       if (ret)
+               goto out_unlock;
+
+       encoder->dev = dev;
+       encoder->encoder_type = encoder_type;
+       encoder->funcs = funcs;
+       if (name) {
+               va_list ap;
+
+               va_start(ap, name);
+               encoder->name = kvasprintf(GFP_KERNEL, name, ap);
+               va_end(ap);
+       } else {
+               encoder->name = kasprintf(GFP_KERNEL, "%s-%d",
+                                         drm_encoder_enum_list[encoder_type].name,
+                                         encoder->base.id);
+       }
+       if (!encoder->name) {
+               ret = -ENOMEM;
+               goto out_put;
+       }
+
+       list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
+       encoder->index = dev->mode_config.num_encoder++;
+
+out_put:
+       if (ret)
+               drm_mode_object_unregister(dev, &encoder->base);
+
+out_unlock:
+       drm_modeset_unlock_all(dev);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_encoder_init);
+
+/**
+ * drm_encoder_cleanup - cleans up an initialised encoder
+ * @encoder: encoder to cleanup
+ *
+ * Cleans up the encoder but doesn't free the object.
+ */
+void drm_encoder_cleanup(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+
+       /* Note that the encoder_list is considered to be static; should we
+        * remove the drm_encoder at runtime we would have to decrement all
+        * the indices on the drm_encoder after us in the encoder_list.
+        */
+
+       drm_modeset_lock_all(dev);
+       drm_mode_object_unregister(dev, &encoder->base);
+       kfree(encoder->name);
+       list_del(&encoder->head);
+       dev->mode_config.num_encoder--;
+       drm_modeset_unlock_all(dev);
+
+       memset(encoder, 0, sizeof(*encoder));
+}
+EXPORT_SYMBOL(drm_encoder_cleanup);
+
+static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
+{
+       struct drm_connector *connector;
+       struct drm_device *dev = encoder->dev;
+       bool uses_atomic = false;
+
+       /* For atomic drivers only state objects are synchronously updated and
+        * protected by modeset locks, so check those first. */
+       drm_for_each_connector(connector, dev) {
+               if (!connector->state)
+                       continue;
+
+               uses_atomic = true;
+
+               if (connector->state->best_encoder != encoder)
+                       continue;
+
+               return connector->state->crtc;
+       }
+
+       /* Don't return stale data (e.g. pending async disable). */
+       if (uses_atomic)
+               return NULL;
+
+       return encoder->crtc;
+}
+
+int drm_mode_getencoder(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       struct drm_mode_get_encoder *enc_resp = data;
+       struct drm_encoder *encoder;
+       struct drm_crtc *crtc;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       encoder = drm_encoder_find(dev, enc_resp->encoder_id);
+       if (!encoder)
+               return -ENOENT;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+       crtc = drm_encoder_get_crtc(encoder);
+       if (crtc)
+               enc_resp->crtc_id = crtc->base.id;
+       else
+               enc_resp->crtc_id = 0;
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
+       enc_resp->encoder_type = encoder->encoder_type;
+       enc_resp->encoder_id = encoder->base.id;
+       enc_resp->possible_crtcs = encoder->possible_crtcs;
+       enc_resp->possible_clones = encoder->possible_clones;
+
+       return 0;
+}
index 0a06f91..03414bd 100644 (file)
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/console.h>
 #include <linux/kernel.h>
 #include <linux/sysrq.h>
 #include <linux/slab.h>
-#include <linux/fb.h>
 #include <linux/module.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
@@ -41,6 +41,8 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 
+#include "drm_crtc_helper_internal.h"
+
 static bool drm_fbdev_emulation = true;
 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
 MODULE_PARM_DESC(fbdev_emulation,
@@ -335,7 +337,7 @@ retry:
                        goto fail;
                }
 
-               plane_state->rotation = BIT(DRM_ROTATE_0);
+               plane_state->rotation = DRM_ROTATE_0;
 
                plane->old_fb = plane->fb;
                plane_mask |= 1 << drm_plane_index(plane);
@@ -395,7 +397,7 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
                if (dev->mode_config.rotation_property) {
                        drm_mode_plane_set_obj_prop(plane,
                                                    dev->mode_config.rotation_property,
-                                                   BIT(DRM_ROTATE_0));
+                                                   DRM_ROTATE_0);
                }
        }
 
@@ -618,6 +620,16 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
        kfree(helper->crtc_info);
 }
 
+static void drm_fb_helper_resume_worker(struct work_struct *work)
+{
+       struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
+                                                   resume_work);
+
+       console_lock();
+       fb_set_suspend(helper->fbdev, 0);
+       console_unlock();
+}
+
 static void drm_fb_helper_dirty_work(struct work_struct *work)
 {
        struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
@@ -649,6 +661,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
 {
        INIT_LIST_HEAD(&helper->kernel_fb_list);
        spin_lock_init(&helper->dirty_lock);
+       INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
        INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
        helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
        helper->funcs = funcs;
@@ -1024,17 +1037,65 @@ EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
 /**
  * drm_fb_helper_set_suspend - wrapper around fb_set_suspend
  * @fb_helper: driver-allocated fbdev helper
- * @state: desired state, zero to resume, non-zero to suspend
+ * @suspend: whether to suspend or resume
  *
- * A wrapper around fb_set_suspend implemented by fbdev core
+ * A wrapper around fb_set_suspend implemented by fbdev core.
+ * Use drm_fb_helper_set_suspend_unlocked() if you don't need to take
+ * the lock yourself
  */
-void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state)
+void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend)
 {
        if (fb_helper && fb_helper->fbdev)
-               fb_set_suspend(fb_helper->fbdev, state);
+               fb_set_suspend(fb_helper->fbdev, suspend);
 }
 EXPORT_SYMBOL(drm_fb_helper_set_suspend);
 
+/**
+ * drm_fb_helper_set_suspend_unlocked - wrapper around fb_set_suspend that also
+ *                                      takes the console lock
+ * @fb_helper: driver-allocated fbdev helper
+ * @suspend: whether to suspend or resume
+ *
+ * A wrapper around fb_set_suspend() that takes the console lock. If the lock
+ * isn't available on resume, a worker is tasked with waiting for the lock
+ * to become available. The console lock can be pretty contented on resume
+ * 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.
+ *
+ * Use drm_fb_helper_set_suspend() if you need to take the lock yourself.
+ */
+void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
+                                       bool suspend)
+{
+       if (!fb_helper || !fb_helper->fbdev)
+               return;
+
+       /* make sure there's no pending/ongoing resume */
+       flush_work(&fb_helper->resume_work);
+
+       if (suspend) {
+               if (fb_helper->fbdev->state != FBINFO_STATE_RUNNING)
+                       return;
+
+               console_lock();
+
+       } else {
+               if (fb_helper->fbdev->state == FBINFO_STATE_RUNNING)
+                       return;
+
+               if (!console_trylock()) {
+                       schedule_work(&fb_helper->resume_work);
+                       return;
+               }
+       }
+
+       fb_set_suspend(fb_helper->fbdev, suspend);
+       console_unlock();
+}
+EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked);
+
 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
                     u16 blue, u16 regno, struct fb_info *info)
 {
@@ -2194,7 +2255,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
  * @fb_helper: the drm_fb_helper
  *
  * Scan the connectors attached to the fb_helper and try to put together a
- * setup after *notification of a change in output configuration.
+ * setup after notification of a change in output configuration.
  *
  * Called at runtime, takes the mode config locks to be able to check/change the
  * modeset configuration. Must be run from process context (which usually means
index 323c238..e84faec 100644 (file)
@@ -92,7 +92,7 @@ static int drm_setup(struct drm_device * dev)
        int ret;
 
        if (dev->driver->firstopen &&
-           !drm_core_check_feature(dev, DRIVER_MODESET)) {
+           drm_core_check_feature(dev, DRIVER_LEGACY)) {
                ret = dev->driver->firstopen(dev);
                if (ret != 0)
                        return ret;
@@ -199,7 +199,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
 
        filp->private_data = priv;
        priv->filp = filp;
-       priv->uid = current_euid();
        priv->pid = get_pid(task_pid(current));
        priv->minor = minor;
 
@@ -346,7 +345,7 @@ void drm_lastclose(struct drm_device * dev)
                dev->driver->lastclose(dev);
        DRM_DEBUG("driver lastclose completed\n");
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+       if (drm_core_check_feature(dev, DRIVER_LEGACY))
                drm_legacy_dev_reinit(dev);
 }
 
@@ -389,7 +388,7 @@ int drm_release(struct inode *inode, struct file *filp)
                  (long)old_encode_dev(file_priv->minor->kdev->devt),
                  dev->open_count);
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+       if (drm_core_check_feature(dev, DRIVER_LEGACY))
                drm_legacy_lock_release(dev, filp);
 
        if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
index 0645c85..29c56b4 100644 (file)
@@ -35,20 +35,61 @@ static char printable_char(int c)
        return isascii(c) && isprint(c) ? c : '?';
 }
 
+/**
+ * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
+ * @bpp: bits per pixels
+ * @depth: bit depth per pixel
+ *
+ * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
+ * Useful in fbdev emulation code, since that deals in those values.
+ */
+uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
+{
+       uint32_t fmt;
+
+       switch (bpp) {
+       case 8:
+               fmt = DRM_FORMAT_C8;
+               break;
+       case 16:
+               if (depth == 15)
+                       fmt = DRM_FORMAT_XRGB1555;
+               else
+                       fmt = DRM_FORMAT_RGB565;
+               break;
+       case 24:
+               fmt = DRM_FORMAT_RGB888;
+               break;
+       case 32:
+               if (depth == 24)
+                       fmt = DRM_FORMAT_XRGB8888;
+               else if (depth == 30)
+                       fmt = DRM_FORMAT_XRGB2101010;
+               else
+                       fmt = DRM_FORMAT_ARGB8888;
+               break;
+       default:
+               DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
+               fmt = DRM_FORMAT_XRGB8888;
+               break;
+       }
+
+       return fmt;
+}
+EXPORT_SYMBOL(drm_mode_legacy_fb_format);
+
 /**
  * drm_get_format_name - return a string for drm fourcc format
  * @format: format to compute name of
  *
- * Note that the buffer used by this function is globally shared and owned by
- * the function itself.
- *
- * FIXME: This isn't really multithreading safe.
+ * Note that the buffer returned by this function is owned by the caller
+ * and will need to be freed using kfree().
  */
-const char *drm_get_format_name(uint32_t format)
+char *drm_get_format_name(uint32_t format)
 {
-       static char buf[32];
+       char *buf = kmalloc(32, GFP_KERNEL);
 
-       snprintf(buf, sizeof(buf),
+       snprintf(buf, 32,
                 "%c%c%c%c %s-endian (0x%08x)",
                 printable_char(format & 0xff),
                 printable_char((format >> 8) & 0xff),
@@ -73,6 +114,8 @@ EXPORT_SYMBOL(drm_get_format_name);
 void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
                          int *bpp)
 {
+       char *format_name;
+
        switch (format) {
        case DRM_FORMAT_C8:
        case DRM_FORMAT_RGB332:
@@ -127,8 +170,9 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
                *bpp = 32;
                break;
        default:
-               DRM_DEBUG_KMS("unsupported pixel format %s\n",
-                             drm_get_format_name(format));
+               format_name = drm_get_format_name(format);
+               DRM_DEBUG_KMS("unsupported pixel format %s\n", format_name);
+               kfree(format_name);
                *depth = 0;
                *bpp = 0;
                break;
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
new file mode 100644 (file)
index 0000000..398efd6
--- /dev/null
@@ -0,0 +1,857 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include <drm/drmP.h>
+#include <drm/drm_auth.h>
+#include <drm/drm_framebuffer.h>
+
+#include "drm_crtc_internal.h"
+
+/**
+ * DOC: overview
+ *
+ * Frame buffers are abstract memory objects that provide a source of pixels to
+ * scanout to a CRTC. Applications explicitly request the creation of frame
+ * buffers through the DRM_IOCTL_MODE_ADDFB(2) ioctls and receive an opaque
+ * handle that can be passed to the KMS CRTC control, plane configuration and
+ * page flip functions.
+ *
+ * Frame buffers rely on the underlying memory manager for allocating backing
+ * storage. When creating a frame buffer applications pass a memory handle
+ * (or a list of memory handles for multi-planar formats) through the
+ * struct &drm_mode_fb_cmd2 argument. For drivers using GEM as their userspace
+ * buffer management interface this would be a GEM handle.  Drivers are however
+ * free to use their own backing storage object handles, e.g. vmwgfx directly
+ * exposes special TTM handles to userspace and so expects TTM handles in the
+ * create ioctl and not GEM handles.
+ *
+ * Framebuffers are tracked with struct &drm_framebuffer. They are published
+ * using drm_framebuffer_init() - after calling that function userspace can use
+ * and access the framebuffer object. The helper function
+ * drm_helper_mode_fill_fb_struct() can be used to pre-fill the required
+ * metadata fields.
+ *
+ * The lifetime of a drm framebuffer is controlled with a reference count,
+ * drivers can grab additional references with drm_framebuffer_reference() and
+ * drop them again with drm_framebuffer_unreference(). For driver-private
+ * framebuffers for which the last reference is never dropped (e.g. for the
+ * 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.
+ */
+
+int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y,
+                                    uint32_t src_w, uint32_t src_h,
+                                    const struct drm_framebuffer *fb)
+{
+       unsigned int fb_width, fb_height;
+
+       fb_width = fb->width << 16;
+       fb_height = fb->height << 16;
+
+       /* Make sure source coordinates are inside the fb. */
+       if (src_w > fb_width ||
+           src_x > fb_width - src_w ||
+           src_h > fb_height ||
+           src_y > fb_height - src_h) {
+               DRM_DEBUG_KMS("Invalid source coordinates "
+                             "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+                             src_w >> 16, ((src_w & 0xffff) * 15625) >> 10,
+                             src_h >> 16, ((src_h & 0xffff) * 15625) >> 10,
+                             src_x >> 16, ((src_x & 0xffff) * 15625) >> 10,
+                             src_y >> 16, ((src_y & 0xffff) * 15625) >> 10);
+               return -ENOSPC;
+       }
+
+       return 0;
+}
+
+/**
+ * drm_mode_addfb - add an FB to the graphics configuration
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Add a new FB to the specified CRTC, given a user request. This is the
+ * original addfb ioctl which only supported RGB formats.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_addfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd *or = data;
+       struct drm_mode_fb_cmd2 r = {};
+       int ret;
+
+       /* convert to new format and call new ioctl */
+       r.fb_id = or->fb_id;
+       r.width = or->width;
+       r.height = or->height;
+       r.pitches[0] = or->pitch;
+       r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
+       r.handles[0] = or->handle;
+
+       ret = drm_mode_addfb2(dev, &r, file_priv);
+       if (ret)
+               return ret;
+
+       or->fb_id = r.fb_id;
+
+       return 0;
+}
+
+static int format_check(const struct drm_mode_fb_cmd2 *r)
+{
+       uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
+       char *format_name;
+
+       switch (format) {
+       case DRM_FORMAT_C8:
+       case DRM_FORMAT_RGB332:
+       case DRM_FORMAT_BGR233:
+       case DRM_FORMAT_XRGB4444:
+       case DRM_FORMAT_XBGR4444:
+       case DRM_FORMAT_RGBX4444:
+       case DRM_FORMAT_BGRX4444:
+       case DRM_FORMAT_ARGB4444:
+       case DRM_FORMAT_ABGR4444:
+       case DRM_FORMAT_RGBA4444:
+       case DRM_FORMAT_BGRA4444:
+       case DRM_FORMAT_XRGB1555:
+       case DRM_FORMAT_XBGR1555:
+       case DRM_FORMAT_RGBX5551:
+       case DRM_FORMAT_BGRX5551:
+       case DRM_FORMAT_ARGB1555:
+       case DRM_FORMAT_ABGR1555:
+       case DRM_FORMAT_RGBA5551:
+       case DRM_FORMAT_BGRA5551:
+       case DRM_FORMAT_RGB565:
+       case DRM_FORMAT_BGR565:
+       case DRM_FORMAT_RGB888:
+       case DRM_FORMAT_BGR888:
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_RGBX8888:
+       case DRM_FORMAT_BGRX8888:
+       case DRM_FORMAT_ARGB8888:
+       case DRM_FORMAT_ABGR8888:
+       case DRM_FORMAT_RGBA8888:
+       case DRM_FORMAT_BGRA8888:
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_RGBX1010102:
+       case DRM_FORMAT_BGRX1010102:
+       case DRM_FORMAT_ARGB2101010:
+       case DRM_FORMAT_ABGR2101010:
+       case DRM_FORMAT_RGBA1010102:
+       case DRM_FORMAT_BGRA1010102:
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_YVYU:
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_VYUY:
+       case DRM_FORMAT_AYUV:
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV24:
+       case DRM_FORMAT_NV42:
+       case DRM_FORMAT_YUV410:
+       case DRM_FORMAT_YVU410:
+       case DRM_FORMAT_YUV411:
+       case DRM_FORMAT_YVU411:
+       case DRM_FORMAT_YUV420:
+       case DRM_FORMAT_YVU420:
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YVU422:
+       case DRM_FORMAT_YUV444:
+       case DRM_FORMAT_YVU444:
+               return 0;
+       default:
+               format_name = drm_get_format_name(r->pixel_format);
+               DRM_DEBUG_KMS("invalid pixel format %s\n", format_name);
+               kfree(format_name);
+               return -EINVAL;
+       }
+}
+
+static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
+{
+       int ret, hsub, vsub, num_planes, i;
+
+       ret = format_check(r);
+       if (ret) {
+               char *format_name = drm_get_format_name(r->pixel_format);
+               DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name);
+               kfree(format_name);
+               return ret;
+       }
+
+       hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
+       vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
+       num_planes = drm_format_num_planes(r->pixel_format);
+
+       if (r->width == 0 || r->width % hsub) {
+               DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
+               return -EINVAL;
+       }
+
+       if (r->height == 0 || r->height % vsub) {
+               DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < num_planes; i++) {
+               unsigned int width = r->width / (i != 0 ? hsub : 1);
+               unsigned int height = r->height / (i != 0 ? vsub : 1);
+               unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
+
+               if (!r->handles[i]) {
+                       DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
+                       return -EINVAL;
+               }
+
+               if ((uint64_t) width * cpp > UINT_MAX)
+                       return -ERANGE;
+
+               if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
+                       return -ERANGE;
+
+               if (r->pitches[i] < width * cpp) {
+                       DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
+                       return -EINVAL;
+               }
+
+               if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
+                       DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n",
+                                     r->modifier[i], i);
+                       return -EINVAL;
+               }
+
+               /* modifier specific checks: */
+               switch (r->modifier[i]) {
+               case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
+                       /* NOTE: the pitch restriction may be lifted later if it turns
+                        * out that no hw has this restriction:
+                        */
+                       if (r->pixel_format != DRM_FORMAT_NV12 ||
+                                       width % 128 || height % 32 ||
+                                       r->pitches[i] % 128) {
+                               DRM_DEBUG_KMS("bad modifier data for plane %d\n", i);
+                               return -EINVAL;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       for (i = num_planes; i < 4; i++) {
+               if (r->modifier[i]) {
+                       DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i);
+                       return -EINVAL;
+               }
+
+               /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */
+               if (!(r->flags & DRM_MODE_FB_MODIFIERS))
+                       continue;
+
+               if (r->handles[i]) {
+                       DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i);
+                       return -EINVAL;
+               }
+
+               if (r->pitches[i]) {
+                       DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i);
+                       return -EINVAL;
+               }
+
+               if (r->offsets[i]) {
+                       DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+struct drm_framebuffer *
+drm_internal_framebuffer_create(struct drm_device *dev,
+                               const struct drm_mode_fb_cmd2 *r,
+                               struct drm_file *file_priv)
+{
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_framebuffer *fb;
+       int ret;
+
+       if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
+               DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if ((config->min_width > r->width) || (r->width > config->max_width)) {
+               DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
+                         r->width, config->min_width, config->max_width);
+               return ERR_PTR(-EINVAL);
+       }
+       if ((config->min_height > r->height) || (r->height > config->max_height)) {
+               DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
+                         r->height, config->min_height, config->max_height);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (r->flags & DRM_MODE_FB_MODIFIERS &&
+           !dev->mode_config.allow_fb_modifiers) {
+               DRM_DEBUG_KMS("driver does not support fb modifiers\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       ret = framebuffer_check(r);
+       if (ret)
+               return ERR_PTR(ret);
+
+       fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
+       if (IS_ERR(fb)) {
+               DRM_DEBUG_KMS("could not create framebuffer\n");
+               return fb;
+       }
+
+       return fb;
+}
+
+/**
+ * drm_mode_addfb2 - add an FB to the graphics configuration
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Add a new FB to the specified CRTC, given a user request with format. This is
+ * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
+ * and uses fourcc codes as pixel format specifiers.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_addfb2(struct drm_device *dev,
+                   void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd2 *r = data;
+       struct drm_framebuffer *fb;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       fb = drm_internal_framebuffer_create(dev, r, file_priv);
+       if (IS_ERR(fb))
+               return PTR_ERR(fb);
+
+       DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
+       r->fb_id = fb->base.id;
+
+       /* Transfer ownership to the filp for reaping on close */
+       mutex_lock(&file_priv->fbs_lock);
+       list_add(&fb->filp_head, &file_priv->fbs);
+       mutex_unlock(&file_priv->fbs_lock);
+
+       return 0;
+}
+
+struct drm_mode_rmfb_work {
+       struct work_struct work;
+       struct list_head fbs;
+};
+
+static void drm_mode_rmfb_work_fn(struct work_struct *w)
+{
+       struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work);
+
+       while (!list_empty(&arg->fbs)) {
+               struct drm_framebuffer *fb =
+                       list_first_entry(&arg->fbs, typeof(*fb), filp_head);
+
+               list_del_init(&fb->filp_head);
+               drm_framebuffer_remove(fb);
+       }
+}
+
+/**
+ * drm_mode_rmfb - remove an FB from the configuration
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Remove the FB specified by the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_rmfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_framebuffer *fb = NULL;
+       struct drm_framebuffer *fbl = NULL;
+       uint32_t *id = data;
+       int found = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       fb = drm_framebuffer_lookup(dev, *id);
+       if (!fb)
+               return -ENOENT;
+
+       mutex_lock(&file_priv->fbs_lock);
+       list_for_each_entry(fbl, &file_priv->fbs, filp_head)
+               if (fb == fbl)
+                       found = 1;
+       if (!found) {
+               mutex_unlock(&file_priv->fbs_lock);
+               goto fail_unref;
+       }
+
+       list_del_init(&fb->filp_head);
+       mutex_unlock(&file_priv->fbs_lock);
+
+       /* drop the reference we picked up in framebuffer lookup */
+       drm_framebuffer_unreference(fb);
+
+       /*
+        * we now own the reference that was stored in the fbs list
+        *
+        * drm_framebuffer_remove may fail with -EINTR on pending signals,
+        * so run this in a separate stack as there's no way to correctly
+        * handle this after the fb is already removed from the lookup table.
+        */
+       if (drm_framebuffer_read_refcount(fb) > 1) {
+               struct drm_mode_rmfb_work arg;
+
+               INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn);
+               INIT_LIST_HEAD(&arg.fbs);
+               list_add_tail(&fb->filp_head, &arg.fbs);
+
+               schedule_work(&arg.work);
+               flush_work(&arg.work);
+               destroy_work_on_stack(&arg.work);
+       } else
+               drm_framebuffer_unreference(fb);
+
+       return 0;
+
+fail_unref:
+       drm_framebuffer_unreference(fb);
+       return -ENOENT;
+}
+
+/**
+ * drm_mode_getfb - get FB info
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Lookup the FB given its ID and return info about it.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_getfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd *r = data;
+       struct drm_framebuffer *fb;
+       int ret;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       fb = drm_framebuffer_lookup(dev, r->fb_id);
+       if (!fb)
+               return -ENOENT;
+
+       r->height = fb->height;
+       r->width = fb->width;
+       r->depth = fb->depth;
+       r->bpp = fb->bits_per_pixel;
+       r->pitch = fb->pitches[0];
+       if (fb->funcs->create_handle) {
+               if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) ||
+                   drm_is_control_client(file_priv)) {
+                       ret = fb->funcs->create_handle(fb, file_priv,
+                                                      &r->handle);
+               } else {
+                       /* GET_FB() is an unprivileged ioctl so we must not
+                        * return a buffer-handle to non-master processes! For
+                        * backwards-compatibility reasons, we cannot make
+                        * GET_FB() privileged, so just return an invalid handle
+                        * for non-masters. */
+                       r->handle = 0;
+                       ret = 0;
+               }
+       } else {
+               ret = -ENODEV;
+       }
+
+       drm_framebuffer_unreference(fb);
+
+       return ret;
+}
+
+/**
+ * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Lookup the FB and flush out the damaged area supplied by userspace as a clip
+ * rectangle list. Generic userspace which does frontbuffer rendering must call
+ * this ioctl to flush out the changes on manual-update display outputs, e.g.
+ * 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.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv)
+{
+       struct drm_clip_rect __user *clips_ptr;
+       struct drm_clip_rect *clips = NULL;
+       struct drm_mode_fb_dirty_cmd *r = data;
+       struct drm_framebuffer *fb;
+       unsigned flags;
+       int num_clips;
+       int ret;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       fb = drm_framebuffer_lookup(dev, r->fb_id);
+       if (!fb)
+               return -ENOENT;
+
+       num_clips = r->num_clips;
+       clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
+
+       if (!num_clips != !clips_ptr) {
+               ret = -EINVAL;
+               goto out_err1;
+       }
+
+       flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
+
+       /* If userspace annotates copy, clips must come in pairs */
+       if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
+               ret = -EINVAL;
+               goto out_err1;
+       }
+
+       if (num_clips && clips_ptr) {
+               if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
+                       ret = -EINVAL;
+                       goto out_err1;
+               }
+               clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
+               if (!clips) {
+                       ret = -ENOMEM;
+                       goto out_err1;
+               }
+
+               ret = copy_from_user(clips, clips_ptr,
+                                    num_clips * sizeof(*clips));
+               if (ret) {
+                       ret = -EFAULT;
+                       goto out_err2;
+               }
+       }
+
+       if (fb->funcs->dirty) {
+               ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
+                                      clips, num_clips);
+       } else {
+               ret = -ENOSYS;
+       }
+
+out_err2:
+       kfree(clips);
+out_err1:
+       drm_framebuffer_unreference(fb);
+
+       return ret;
+}
+
+/**
+ * drm_fb_release - remove and free the FBs on this file
+ * @priv: drm file for the ioctl
+ *
+ * Destroy all the FBs associated with @filp.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+void drm_fb_release(struct drm_file *priv)
+{
+       struct drm_framebuffer *fb, *tfb;
+       struct drm_mode_rmfb_work arg;
+
+       INIT_LIST_HEAD(&arg.fbs);
+
+       /*
+        * When the file gets released that means no one else can access the fb
+        * list any more, so no need to grab fpriv->fbs_lock. And we need to
+        * avoid upsetting lockdep since the universal cursor code adds a
+        * framebuffer while holding mutex locks.
+        *
+        * Note that a real deadlock between fpriv->fbs_lock and the modeset
+        * locks is impossible here since no one else but this function can get
+        * at it any more.
+        */
+       list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
+               if (drm_framebuffer_read_refcount(fb) > 1) {
+                       list_move_tail(&fb->filp_head, &arg.fbs);
+               } else {
+                       list_del_init(&fb->filp_head);
+
+                       /* This drops the fpriv->fbs reference. */
+                       drm_framebuffer_unreference(fb);
+               }
+       }
+
+       if (!list_empty(&arg.fbs)) {
+               INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn);
+
+               schedule_work(&arg.work);
+               flush_work(&arg.work);
+               destroy_work_on_stack(&arg.work);
+       }
+}
+
+void drm_framebuffer_free(struct kref *kref)
+{
+       struct drm_framebuffer *fb =
+                       container_of(kref, struct drm_framebuffer, base.refcount);
+       struct drm_device *dev = fb->dev;
+
+       /*
+        * The lookup idr holds a weak reference, which has not necessarily been
+        * removed at this point. Check for that.
+        */
+       drm_mode_object_unregister(dev, &fb->base);
+
+       fb->funcs->destroy(fb);
+}
+
+/**
+ * drm_framebuffer_init - initialize a framebuffer
+ * @dev: DRM device
+ * @fb: framebuffer to be initialized
+ * @funcs: ... with these functions
+ *
+ * Allocates an ID for the framebuffer's parent mode object, sets its mode
+ * functions & device file and adds it to the master fd list.
+ *
+ * IMPORTANT:
+ * This functions publishes the fb and makes it available for concurrent access
+ * by other users. Which means by this point the fb _must_ be fully set up -
+ * since all the fb attributes are invariant over its lifetime, no further
+ * locking but only correct reference counting is required.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
+                        const struct drm_framebuffer_funcs *funcs)
+{
+       int ret;
+
+       INIT_LIST_HEAD(&fb->filp_head);
+       fb->dev = dev;
+       fb->funcs = funcs;
+
+       ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB,
+                                     false, drm_framebuffer_free);
+       if (ret)
+               goto out;
+
+       mutex_lock(&dev->mode_config.fb_lock);
+       dev->mode_config.num_fb++;
+       list_add(&fb->head, &dev->mode_config.fb_list);
+       mutex_unlock(&dev->mode_config.fb_lock);
+
+       drm_mode_object_register(dev, &fb->base);
+out:
+       return ret;
+}
+EXPORT_SYMBOL(drm_framebuffer_init);
+
+/**
+ * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
+ * @dev: drm device
+ * @id: id of the fb object
+ *
+ * If successful, this grabs an additional reference to the framebuffer -
+ * callers need to make sure to eventually unreference the returned framebuffer
+ * again, using @drm_framebuffer_unreference.
+ */
+struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
+                                              uint32_t id)
+{
+       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb = NULL;
+
+       obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_FB);
+       if (obj)
+               fb = obj_to_fb(obj);
+       return fb;
+}
+EXPORT_SYMBOL(drm_framebuffer_lookup);
+
+/**
+ * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
+ * @fb: fb to unregister
+ *
+ * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
+ * those used for fbdev. Note that the caller must hold a reference of it's own,
+ * i.e. the object may not be destroyed through this call (since it'll lead to a
+ * locking inversion).
+ */
+void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
+{
+       struct drm_device *dev;
+
+       if (!fb)
+               return;
+
+       dev = fb->dev;
+
+       /* Mark fb as reaped and drop idr ref. */
+       drm_mode_object_unregister(dev, &fb->base);
+}
+EXPORT_SYMBOL(drm_framebuffer_unregister_private);
+
+/**
+ * drm_framebuffer_cleanup - remove a framebuffer object
+ * @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.
+ *
+ * Note that this function does not remove the fb from active usuage - 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.
+ *
+ * Also, the framebuffer will not be removed from the lookup idr - for
+ * user-created framebuffers this will happen in in the rmfb ioctl. For
+ * driver-private objects (e.g. for fbdev) drivers need to explicitly call
+ * drm_framebuffer_unregister_private.
+ */
+void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
+{
+       struct drm_device *dev = fb->dev;
+
+       mutex_lock(&dev->mode_config.fb_lock);
+       list_del(&fb->head);
+       dev->mode_config.num_fb--;
+       mutex_unlock(&dev->mode_config.fb_lock);
+}
+EXPORT_SYMBOL(drm_framebuffer_cleanup);
+
+/**
+ * drm_framebuffer_remove - remove and unreference a framebuffer object
+ * @fb: framebuffer to remove
+ *
+ * Scans all the CRTCs and planes in @dev's mode_config.  If they're
+ * using @fb, removes it, setting it to NULL. Then drops the reference to the
+ * passed-in framebuffer. Might take the modeset locks.
+ *
+ * Note that this function optimizes the cleanup away if the caller holds the
+ * last reference to the framebuffer. It is also guaranteed to not take the
+ * modeset locks in this case.
+ */
+void drm_framebuffer_remove(struct drm_framebuffer *fb)
+{
+       struct drm_device *dev;
+       struct drm_crtc *crtc;
+       struct drm_plane *plane;
+
+       if (!fb)
+               return;
+
+       dev = fb->dev;
+
+       WARN_ON(!list_empty(&fb->filp_head));
+
+       /*
+        * drm ABI mandates that we remove any deleted framebuffers from active
+        * useage. But since most sane clients only remove framebuffers they no
+        * longer need, try to optimize this away.
+        *
+        * Since we're holding a reference ourselves, observing a refcount of 1
+        * means that we're the last holder and can skip it. Also, the refcount
+        * can never increase from 1 again, so we don't need any barriers or
+        * locks.
+        *
+        * Note that userspace could try to race with use and instate a new
+        * usage _after_ we've cleared all current ones. End result will be an
+        * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot
+        * in this manner.
+        */
+       if (drm_framebuffer_read_refcount(fb) > 1) {
+               drm_modeset_lock_all(dev);
+               /* remove from any CRTC */
+               drm_for_each_crtc(crtc, dev) {
+                       if (crtc->primary->fb == fb) {
+                               /* should turn off the crtc */
+                               if (drm_crtc_force_disable(crtc))
+                                       DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
+                       }
+               }
+
+               drm_for_each_plane(plane, dev) {
+                       if (plane->fb == fb)
+                               drm_plane_force_disable(plane);
+               }
+               drm_modeset_unlock_all(dev);
+       }
+
+       drm_framebuffer_unreference(fb);
+}
+EXPORT_SYMBOL(drm_framebuffer_remove);
index 9134ae1..465bacd 100644 (file)
@@ -257,7 +257,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
 
        if (drm_core_check_feature(dev, DRIVER_PRIME))
                drm_gem_remove_prime_handles(obj, file_priv);
-       drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
+       drm_vma_node_revoke(&obj->vma_node, file_priv);
 
        if (dev->driver->gem_close_object)
                dev->driver->gem_close_object(obj, file_priv);
@@ -372,7 +372,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
 
        handle = ret;
 
-       ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp);
+       ret = drm_vma_node_allow(&obj->vma_node, file_priv);
        if (ret)
                goto err_remove;
 
@@ -386,7 +386,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
        return 0;
 
 err_revoke:
-       drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
+       drm_vma_node_revoke(&obj->vma_node, file_priv);
 err_remove:
        spin_lock(&file_priv->table_lock);
        idr_remove(&file_priv->object_idr, handle);
@@ -991,7 +991,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        if (!obj)
                return -EINVAL;
 
-       if (!drm_vma_node_is_allowed(node, filp)) {
+       if (!drm_vma_node_is_allowed(node, priv)) {
                drm_gem_object_unreference_unlocked(obj);
                return -EACCES;
        }
index 3d2e91c..b404287 100644 (file)
@@ -65,30 +65,34 @@ void drm_global_release(void)
 
 int drm_global_item_ref(struct drm_global_reference *ref)
 {
-       int ret;
+       int ret = 0;
        struct drm_global_item *item = &glob[ref->global_type];
 
        mutex_lock(&item->mutex);
        if (item->refcount == 0) {
-               item->object = kzalloc(ref->size, GFP_KERNEL);
-               if (unlikely(item->object == NULL)) {
+               ref->object = kzalloc(ref->size, GFP_KERNEL);
+               if (unlikely(ref->object == NULL)) {
                        ret = -ENOMEM;
-                       goto out_err;
+                       goto error_unlock;
                }
-
-               ref->object = item->object;
                ret = ref->init(ref);
                if (unlikely(ret != 0))
-                       goto out_err;
+                       goto error_free;
 
+               item->object = ref->object;
+       } else {
+               ref->object = item->object;
        }
+
        ++item->refcount;
-       ref->object = item->object;
        mutex_unlock(&item->mutex);
        return 0;
-out_err:
+
+error_free:
+       kfree(ref->object);
+       ref->object = NULL;
+error_unlock:
        mutex_unlock(&item->mutex);
-       item->object = NULL;
        return ret;
 }
 EXPORT_SYMBOL(drm_global_item_ref);
index 7b30b30..dae18e5 100644 (file)
@@ -142,7 +142,7 @@ int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *it
                              unsigned long add)
 {
        int ret;
-       unsigned long mask = (1 << bits) - 1;
+       unsigned long mask = (1UL << bits) - 1;
        unsigned long first, unshifted_key;
 
        unshifted_key = hash_long(seed, bits);
index 9ae353f..1df2d33 100644 (file)
@@ -80,6 +80,7 @@ int drm_clients_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 drm_file *priv;
+       kuid_t uid;
 
        seq_printf(m,
                   "%20s %5s %3s master a %5s %10s\n",
@@ -98,13 +99,14 @@ int drm_clients_info(struct seq_file *m, void *data)
 
                rcu_read_lock(); /* locks pid_task()->comm */
                task = pid_task(priv->pid, PIDTYPE_PID);
+               uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID;
                seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u\n",
                           task ? task->comm : "<unknown>",
                           pid_vnr(priv->pid),
                           priv->minor->index,
                           drm_is_current_master(priv) ? 'y' : 'n',
                           priv->authenticated ? 'y' : 'n',
-                          from_kuid_munged(seq_user_ns(m), priv->uid),
+                          from_kuid_munged(seq_user_ns(m), uid),
                           priv->magic);
                rcu_read_unlock();
        }
index b86dc9b..e66af28 100644 (file)
@@ -21,6 +21,9 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#define DRM_IF_MAJOR 1
+#define DRM_IF_MINOR 4
+
 /* drm_irq.c */
 extern unsigned int drm_timestamp_monotonic;
 
index a628975..867ab8c 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/export.h>
 
 #include <drm/drmP.h>
-#include <drm/drm_core.h>
 
 #define DRM_IOCTL_VERSION32            DRM_IOWR(0x00, drm_version32_t)
 #define DRM_IOCTL_GET_UNIQUE32         DRM_IOWR(0x01, drm_unique32_t)
@@ -346,6 +345,7 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd,
        struct drm_stats __user *stats;
        int i, err;
 
+       memset(&s32, 0, sizeof(drm_stats32_t));
        stats = compat_alloc_user_space(sizeof(*stats));
        if (!stats)
                return -EFAULT;
index 33af4a5..0ad2c47 100644 (file)
@@ -29,7 +29,6 @@
  */
 
 #include <drm/drmP.h>
-#include <drm/drm_core.h>
 #include <drm/drm_auth.h>
 #include "drm_legacy.h"
 #include "drm_internal.h"
@@ -189,9 +188,8 @@ static int drm_getclient(struct drm_device *dev, void *data,
         */
        if (client->idx == 0) {
                client->auth = file_priv->authenticated;
-               client->pid = pid_vnr(file_priv->pid);
-               client->uid = from_kuid_munged(current_user_ns(),
-                                              file_priv->uid);
+               client->pid = task_pid_vnr(current);
+               client->uid = overflowuid;
                client->magic = 0;
                client->iocs = 0;
 
@@ -228,6 +226,7 @@ static int drm_getstats(struct drm_device *dev, void *data,
 static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_get_cap *req = data;
+       struct drm_crtc *crtc;
 
        req->value = 0;
        switch (req->capability) {
@@ -254,6 +253,13 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
        case DRM_CAP_ASYNC_PAGE_FLIP:
                req->value = dev->mode_config.async_page_flip;
                break;
+       case DRM_CAP_PAGE_FLIP_TARGET:
+               req->value = 1;
+               drm_for_each_crtc(crtc, dev) {
+                       if (!crtc->funcs->page_flip_target)
+                               req->value = 0;
+               }
+               break;
        case DRM_CAP_CURSOR_WIDTH:
                if (dev->mode_config.cursor_width)
                        req->value = dev->mode_config.cursor_width;
@@ -714,9 +720,9 @@ long drm_ioctl(struct file *filp,
        if (ksize > in_size)
                memset(kdata + in_size, 0, ksize - in_size);
 
-       /* Enforce sane locking for kms driver ioctls. Core ioctls are
+       /* Enforce sane locking for modern driver ioctls. Core ioctls are
         * too messy still. */
-       if ((drm_core_check_feature(dev, DRIVER_MODESET) && is_driver_ioctl) ||
+       if ((!drm_core_check_feature(dev, DRIVER_LEGACY) && is_driver_ioctl) ||
            (ioctl->flags & DRM_UNLOCKED))
                retcode = func(dev, kdata, file_priv);
        else {
index 77f357b..b969a64 100644 (file)
@@ -482,7 +482,7 @@ int drm_irq_install(struct drm_device *dev, int irq)
                return ret;
        }
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+       if (drm_core_check_feature(dev, DRIVER_LEGACY))
                vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
 
        /* After installing handler */
@@ -491,7 +491,7 @@ int drm_irq_install(struct drm_device *dev, int irq)
 
        if (ret < 0) {
                dev->irq_enabled = false;
-               if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               if (drm_core_check_feature(dev, DRIVER_LEGACY))
                        vga_client_register(dev->pdev, NULL, NULL, NULL);
                free_irq(irq, dev);
        } else {
@@ -557,7 +557,7 @@ int drm_irq_uninstall(struct drm_device *dev)
 
        DRM_DEBUG("irq=%d\n", dev->irq);
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+       if (drm_core_check_feature(dev, DRIVER_LEGACY))
                vga_client_register(dev->pdev, NULL, NULL, NULL);
 
        if (dev->driver->irq_uninstall)
@@ -592,7 +592,7 @@ int drm_control(struct drm_device *dev, void *data,
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return 0;
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return 0;
        /* UMS was only ever supported on pci devices. */
        if (WARN_ON(!dev->pdev))
@@ -713,10 +713,10 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
  * Negative value on error, failure or if not supported in current
  * video mode:
  *
- * -EINVAL   - Invalid CRTC.
- * -EAGAIN   - Temporary unavailable, e.g., called before initial modeset.
- * -ENOTSUPP - Function not supported in current display mode.
- * -EIO      - Failed, e.g., due to failed scanout position query.
+ * -EINVAL    Invalid CRTC.
+ * -EAGAIN    Temporary unavailable, e.g., called before initial modeset.
+ * -ENOTSUPP  Function not supported in current display mode.
+ * -EIO       Failed, e.g., due to failed scanout position query.
  *
  * Returns or'ed positive status flags on success:
  *
@@ -1008,6 +1008,31 @@ 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:
+ *
+ * 1. Driver commits new hardware state into vblank-synchronized registers.
+ * 2. A vblank happens, committing the hardware state. Also the corresponding
+ *    vblank interrupt is fired off and fully processed by the interrupt
+ *    handler.
+ * 3. The atomic commit operation proceeds to call drm_crtc_arm_vblank_event().
+ * 4. The event is only send out for the next vblank, which is wrong.
+ *
+ * An equivalent race can happen when the driver calls
+ * drm_crtc_arm_vblank_event() before writing out the new hardware state.
+ *
+ * The only way to make this work safely is to prevent the vblank from firing
+ * (and the hardware from committing anything else) until the entire atomic
+ * commit sequence has run to completion. If the hardware does not have such a
+ * feature (e.g. using a "go" bit), then it is unsafe to use this functions.
+ * Instead drivers need to manually send out the event from their interrupt
+ * handler by calling drm_crtc_send_vblank_event() and make sure that there's no
+ * possible race with the hardware committing the atomic update.
+ *
  * Caller must hold event lock. Caller must also hold a vblank reference for
  * the event @e, which will be dropped when the next vblank arrives.
  */
@@ -1030,8 +1055,11 @@ EXPORT_SYMBOL(drm_crtc_arm_vblank_event);
  * @crtc: the source CRTC of the vblank event
  * @e: the event to send
  *
- * Updates sequence # and timestamp on event, and sends it to userspace.
- * Caller must hold event lock.
+ * Updates sequence # and timestamp on event for the most recently processed
+ * vblank, and sends it to userspace.  Caller must hold event lock.
+ *
+ * See drm_crtc_arm_vblank_event() for a helper which can be used in certain
+ * situation, especially to send out events for atomic commit operations.
  */
 void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
                                struct drm_pending_vblank_event *e)
@@ -1295,7 +1323,7 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe)
                if (e->pipe != pipe)
                        continue;
                DRM_DEBUG("Sending premature vblank event on disable: "
-                         "wanted %d, current %d\n",
+                         "wanted %u, current %u\n",
                          e->event.sequence, seq);
                list_del(&e->base.link);
                drm_vblank_put(dev, pipe);
@@ -1519,7 +1547,7 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                return 0;
 
        /* KMS drivers handle this internally */
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return 0;
 
        pipe = modeset->crtc;
@@ -1585,7 +1613,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
 
        seq = drm_vblank_count_and_time(dev, pipe, &now);
 
-       DRM_DEBUG("event on vblank count %d, current %d, crtc %u\n",
+       DRM_DEBUG("event on vblank count %u, current %u, crtc %u\n",
                  vblwait->request.sequence, seq, pipe);
 
        trace_drm_vblank_event_queued(current->pid, pipe,
@@ -1693,7 +1721,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
                return drm_queue_vblank_event(dev, pipe, vblwait, file_priv);
        }
 
-       DRM_DEBUG("waiting on vblank count %d, crtc %u\n",
+       DRM_DEBUG("waiting on vblank count %u, crtc %u\n",
                  vblwait->request.sequence, pipe);
        DRM_WAIT_ON(ret, vblank->queue, 3 * HZ,
                    (((drm_vblank_count(dev, pipe) -
@@ -1708,7 +1736,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
                vblwait->reply.tval_sec = now.tv_sec;
                vblwait->reply.tval_usec = now.tv_usec;
 
-               DRM_DEBUG("returning %d to client\n",
+               DRM_DEBUG("returning %u to client\n",
                          vblwait->reply.sequence);
        } else {
                DRM_DEBUG("vblank wait interrupted by signal\n");
@@ -1735,7 +1763,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe)
                if ((seq - e->event.sequence) > (1<<23))
                        continue;
 
-               DRM_DEBUG("vblank event on %d, current %d\n",
+               DRM_DEBUG("vblank event on %u, current %u\n",
                          e->event.sequence, seq);
 
                list_del(&e->base.link);
@@ -1826,6 +1854,7 @@ EXPORT_SYMBOL(drm_crtc_handle_vblank);
  */
 u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
 {
+       WARN_ON_ONCE(dev->max_vblank_count != 0);
        return 0;
 }
 EXPORT_SYMBOL(drm_vblank_no_hw_counter);
index 3187c4b..45db36c 100644 (file)
@@ -27,7 +27,8 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
-#include <drm/drm_dp_aux_dev.h>
+
+#include "drm_crtc_helper_internal.h"
 
 MODULE_AUTHOR("David Airlie, Jesse Barnes");
 MODULE_DESCRIPTION("DRM KMS helper");
index 48ac0eb..c901f3c 100644 (file)
@@ -163,7 +163,7 @@ int drm_legacy_lock(struct drm_device *dev, void *data,
        struct drm_master *master = file_priv->master;
        int ret = 0;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        ++file_priv->lock_count;
@@ -252,7 +252,7 @@ int drm_legacy_unlock(struct drm_device *dev, void *data, struct drm_file *file_
        struct drm_lock *lock = data;
        struct drm_master *master = file_priv->master;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (lock->context == DRM_KERNEL_CONTEXT) {
index af0d471..1160a57 100644 (file)
@@ -998,6 +998,27 @@ int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
 }
 EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_on);
 
+/**
+ * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image
+ *    data used by the interface
+ * @dsi: DSI peripheral device
+ * @format: pixel format
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,
+                                sizeof(format));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_pixel_format);
+
 /**
  * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for
  *    the Tearing Effect output signal of the display module
@@ -1021,25 +1042,53 @@ int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline)
 EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline);
 
 /**
- * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image
- *    data used by the interface
+ * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the
+ *    display
  * @dsi: DSI peripheral device
- * @format: pixel format
+ * @brightness: brightness value
  *
  * Return: 0 on success or a negative error code on failure.
  */
-int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format)
+int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,
+                                       u16 brightness)
 {
+       u8 payload[2] = { brightness & 0xff, brightness >> 8 };
        ssize_t err;
 
-       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,
-                                sizeof(format));
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
+                                payload, sizeof(payload));
        if (err < 0)
                return err;
 
        return 0;
 }
-EXPORT_SYMBOL(mipi_dsi_dcs_set_pixel_format);
+EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness);
+
+/**
+ * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value
+ *    of the display
+ * @dsi: DSI peripheral device
+ * @brightness: brightness value
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
+                                       u16 *brightness)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
+                               brightness, sizeof(*brightness));
+       if (err <= 0) {
+               if (err == 0)
+                       err = -ENODATA;
+
+               return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness);
 
 static int mipi_dsi_drv_probe(struct device *dev)
 {
index cb39f45..11d44a1 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <linux/export.h>
+#include <linux/interval_tree_generic.h>
 
 /**
  * DOC: Overview
@@ -103,6 +104,72 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
                                                u64 end,
                                                enum drm_mm_search_flags flags);
 
+#define START(node) ((node)->start)
+#define LAST(node)  ((node)->start + (node)->size - 1)
+
+INTERVAL_TREE_DEFINE(struct drm_mm_node, rb,
+                    u64, __subtree_last,
+                    START, LAST, static inline, drm_mm_interval_tree)
+
+struct drm_mm_node *
+drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last)
+{
+       return drm_mm_interval_tree_iter_first(&mm->interval_tree,
+                                              start, last);
+}
+EXPORT_SYMBOL(drm_mm_interval_first);
+
+struct drm_mm_node *
+drm_mm_interval_next(struct drm_mm_node *node, u64 start, u64 last)
+{
+       return drm_mm_interval_tree_iter_next(node, start, last);
+}
+EXPORT_SYMBOL(drm_mm_interval_next);
+
+static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node,
+                                         struct drm_mm_node *node)
+{
+       struct drm_mm *mm = hole_node->mm;
+       struct rb_node **link, *rb;
+       struct drm_mm_node *parent;
+
+       node->__subtree_last = LAST(node);
+
+       if (hole_node->allocated) {
+               rb = &hole_node->rb;
+               while (rb) {
+                       parent = rb_entry(rb, struct drm_mm_node, rb);
+                       if (parent->__subtree_last >= node->__subtree_last)
+                               break;
+
+                       parent->__subtree_last = node->__subtree_last;
+                       rb = rb_parent(rb);
+               }
+
+               rb = &hole_node->rb;
+               link = &hole_node->rb.rb_right;
+       } else {
+               rb = NULL;
+               link = &mm->interval_tree.rb_node;
+       }
+
+       while (*link) {
+               rb = *link;
+               parent = rb_entry(rb, struct drm_mm_node, rb);
+               if (parent->__subtree_last < node->__subtree_last)
+                       parent->__subtree_last = node->__subtree_last;
+               if (node->start < parent->start)
+                       link = &parent->rb.rb_left;
+               else
+                       link = &parent->rb.rb_right;
+       }
+
+       rb_link_node(&node->rb, rb, link);
+       rb_insert_augmented(&node->rb,
+                           &mm->interval_tree,
+                           &drm_mm_interval_tree_augment);
+}
+
 static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
                                 struct drm_mm_node *node,
                                 u64 size, unsigned alignment,
@@ -150,9 +217,10 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
        node->color = color;
        node->allocated = 1;
 
-       INIT_LIST_HEAD(&node->hole_stack);
        list_add(&node->node_list, &hole_node->node_list);
 
+       drm_mm_interval_tree_add_node(hole_node, node);
+
        BUG_ON(node->start + node->size > adj_end);
 
        node->hole_follows = 0;
@@ -178,41 +246,54 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
  */
 int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
 {
+       u64 end = node->start + node->size;
        struct drm_mm_node *hole;
-       u64 end;
-       u64 hole_start;
-       u64 hole_end;
+       u64 hole_start, hole_end;
 
-       BUG_ON(node == NULL);
+       if (WARN_ON(node->size == 0))
+               return -EINVAL;
 
        end = node->start + node->size;
 
        /* Find the relevant hole to add our node to */
-       drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
-               if (hole_start > node->start || hole_end < end)
-                       continue;
+       hole = drm_mm_interval_tree_iter_first(&mm->interval_tree,
+                                              node->start, ~(u64)0);
+       if (hole) {
+               if (hole->start < end)
+                       return -ENOSPC;
+       } else {
+               hole = list_entry(&mm->head_node.node_list,
+                                 typeof(*hole), node_list);
+       }
 
-               node->mm = mm;
-               node->allocated = 1;
+       hole = list_last_entry(&hole->node_list, typeof(*hole), node_list);
+       if (!hole->hole_follows)
+               return -ENOSPC;
 
-               INIT_LIST_HEAD(&node->hole_stack);
-               list_add(&node->node_list, &hole->node_list);
+       hole_start = __drm_mm_hole_node_start(hole);
+       hole_end = __drm_mm_hole_node_end(hole);
+       if (hole_start > node->start || hole_end < end)
+               return -ENOSPC;
 
-               if (node->start == hole_start) {
-                       hole->hole_follows = 0;
-                       list_del_init(&hole->hole_stack);
-               }
+       node->mm = mm;
+       node->allocated = 1;
 
-               node->hole_follows = 0;
-               if (end != hole_end) {
-                       list_add(&node->hole_stack, &mm->hole_stack);
-                       node->hole_follows = 1;
-               }
+       list_add(&node->node_list, &hole->node_list);
 
-               return 0;
+       drm_mm_interval_tree_add_node(hole, node);
+
+       if (node->start == hole_start) {
+               hole->hole_follows = 0;
+               list_del(&hole->hole_stack);
        }
 
-       return -ENOSPC;
+       node->hole_follows = 0;
+       if (end != hole_end) {
+               list_add(&node->hole_stack, &mm->hole_stack);
+               node->hole_follows = 1;
+       }
+
+       return 0;
 }
 EXPORT_SYMBOL(drm_mm_reserve_node);
 
@@ -239,6 +320,9 @@ int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
 {
        struct drm_mm_node *hole_node;
 
+       if (WARN_ON(size == 0))
+               return -EINVAL;
+
        hole_node = drm_mm_search_free_generic(mm, size, alignment,
                                               color, sflags);
        if (!hole_node)
@@ -299,9 +383,10 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
        node->color = color;
        node->allocated = 1;
 
-       INIT_LIST_HEAD(&node->hole_stack);
        list_add(&node->node_list, &hole_node->node_list);
 
+       drm_mm_interval_tree_add_node(hole_node, node);
+
        BUG_ON(node->start < start);
        BUG_ON(node->start < adj_start);
        BUG_ON(node->start + node->size > adj_end);
@@ -340,6 +425,9 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *n
 {
        struct drm_mm_node *hole_node;
 
+       if (WARN_ON(size == 0))
+               return -EINVAL;
+
        hole_node = drm_mm_search_free_in_range_generic(mm,
                                                        size, alignment, color,
                                                        start, end, sflags);
@@ -390,6 +478,7 @@ void drm_mm_remove_node(struct drm_mm_node *node)
        } else
                list_move(&prev_node->hole_stack, &mm->hole_stack);
 
+       drm_mm_interval_tree_remove(node, &mm->interval_tree);
        list_del(&node->node_list);
        node->allocated = 0;
 }
@@ -516,11 +605,13 @@ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
 {
        list_replace(&old->node_list, &new->node_list);
        list_replace(&old->hole_stack, &new->hole_stack);
+       rb_replace_node(&old->rb, &new->rb, &old->mm->interval_tree);
        new->hole_follows = old->hole_follows;
        new->mm = old->mm;
        new->start = old->start;
        new->size = old->size;
        new->color = old->color;
+       new->__subtree_last = old->__subtree_last;
 
        old->allocated = 0;
        new->allocated = 1;
@@ -748,7 +839,6 @@ void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
 
        /* Clever trick to avoid a special case in the free hole tracking. */
        INIT_LIST_HEAD(&mm->head_node.node_list);
-       INIT_LIST_HEAD(&mm->head_node.hole_stack);
        mm->head_node.hole_follows = 1;
        mm->head_node.scanned_block = 0;
        mm->head_node.scanned_prev_free = 0;
@@ -758,6 +848,8 @@ void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
        mm->head_node.size = start - mm->head_node.start;
        list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack);
 
+       mm->interval_tree = RB_ROOT;
+
        mm->color_adjust = NULL;
 }
 EXPORT_SYMBOL(drm_mm_init);
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
new file mode 100644 (file)
index 0000000..9f17085
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include <drm/drmP.h>
+#include <drm/drm_mode_object.h>
+
+#include "drm_crtc_internal.h"
+
+/*
+ * Internal function to assign a slot in the object idr and optionally
+ * register the object into the idr.
+ */
+int drm_mode_object_get_reg(struct drm_device *dev,
+                           struct drm_mode_object *obj,
+                           uint32_t obj_type,
+                           bool register_obj,
+                           void (*obj_free_cb)(struct kref *kref))
+{
+       int ret;
+
+       mutex_lock(&dev->mode_config.idr_mutex);
+       ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
+       if (ret >= 0) {
+               /*
+                * Set up the object linking under the protection of the idr
+                * lock so that other users can't see inconsistent state.
+                */
+               obj->id = ret;
+               obj->type = obj_type;
+               if (obj_free_cb) {
+                       obj->free_cb = obj_free_cb;
+                       kref_init(&obj->refcount);
+               }
+       }
+       mutex_unlock(&dev->mode_config.idr_mutex);
+
+       return ret < 0 ? ret : 0;
+}
+
+/**
+ * drm_mode_object_get - allocate a new modeset identifier
+ * @dev: DRM device
+ * @obj: object pointer, used to generate unique ID
+ * @obj_type: object type
+ *
+ * Create a unique identifier based on @ptr in @dev's identifier space.  Used
+ * for tracking modes, CRTCs and connectors. Note that despite the _get postfix
+ * modeset identifiers are _not_ reference counted. Hence don't use this for
+ * reference counted modeset objects like framebuffers.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_mode_object_get(struct drm_device *dev,
+                       struct drm_mode_object *obj, uint32_t obj_type)
+{
+       return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL);
+}
+
+void drm_mode_object_register(struct drm_device *dev,
+                             struct drm_mode_object *obj)
+{
+       mutex_lock(&dev->mode_config.idr_mutex);
+       idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
+       mutex_unlock(&dev->mode_config.idr_mutex);
+}
+
+/**
+ * drm_mode_object_unregister - free a modeset identifer
+ * @dev: DRM device
+ * @object: object to free
+ *
+ * Free @id from @dev's unique identifier pool.
+ * This function can be called multiple times, and guards against
+ * multiple removals.
+ * These modeset identifiers are _not_ reference counted. Hence don't use this
+ * for reference counted modeset objects like framebuffers.
+ */
+void drm_mode_object_unregister(struct drm_device *dev,
+                               struct drm_mode_object *object)
+{
+       mutex_lock(&dev->mode_config.idr_mutex);
+       if (object->id) {
+               idr_remove(&dev->mode_config.crtc_idr, object->id);
+               object->id = 0;
+       }
+       mutex_unlock(&dev->mode_config.idr_mutex);
+}
+
+struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
+                                              uint32_t id, uint32_t type)
+{
+       struct drm_mode_object *obj = NULL;
+
+       mutex_lock(&dev->mode_config.idr_mutex);
+       obj = idr_find(&dev->mode_config.crtc_idr, id);
+       if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
+               obj = NULL;
+       if (obj && obj->id != id)
+               obj = NULL;
+
+       if (obj && obj->free_cb) {
+               if (!kref_get_unless_zero(&obj->refcount))
+                       obj = NULL;
+       }
+       mutex_unlock(&dev->mode_config.idr_mutex);
+
+       return obj;
+}
+
+/**
+ * drm_mode_object_find - look up a drm object with static lifetime
+ * @dev: drm device
+ * @id: id of the mode object
+ * @type: type of the mode object
+ *
+ * This function is used to look up a modeset object. It will acquire a
+ * reference for reference counted objects. This reference must be dropped again
+ * by callind drm_mode_object_unreference().
+ */
+struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
+               uint32_t id, uint32_t type)
+{
+       struct drm_mode_object *obj = NULL;
+
+       obj = __drm_mode_object_find(dev, id, type);
+       return obj;
+}
+EXPORT_SYMBOL(drm_mode_object_find);
+
+/**
+ * drm_mode_object_unreference - decr the object refcnt
+ * @obj: mode_object
+ *
+ * This function decrements the object's refcount if it is a refcounted modeset
+ * object. It is a no-op on any other object. This is used to drop references
+ * acquired with drm_mode_object_reference().
+ */
+void drm_mode_object_unreference(struct drm_mode_object *obj)
+{
+       if (obj->free_cb) {
+               DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
+               kref_put(&obj->refcount, obj->free_cb);
+       }
+}
+EXPORT_SYMBOL(drm_mode_object_unreference);
+
+/**
+ * drm_mode_object_reference - incr the object refcnt
+ * @obj: mode_object
+ *
+ * This function increments the object's refcount if it is a refcounted modeset
+ * object. It is a no-op on any other object. References should be dropped again
+ * by calling drm_mode_object_unreference().
+ */
+void drm_mode_object_reference(struct drm_mode_object *obj)
+{
+       if (obj->free_cb) {
+               DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
+               kref_get(&obj->refcount);
+       }
+}
+EXPORT_SYMBOL(drm_mode_object_reference);
+
+/**
+ * drm_object_attach_property - attach a property to a modeset object
+ * @obj: drm modeset object
+ * @property: property to attach
+ * @init_val: initial value of the property
+ *
+ * This attaches the given property to the modeset object with the given initial
+ * value. Currently this function cannot fail since the properties are stored in
+ * a statically sized array.
+ */
+void drm_object_attach_property(struct drm_mode_object *obj,
+                               struct drm_property *property,
+                               uint64_t init_val)
+{
+       int count = obj->properties->count;
+
+       if (count == DRM_OBJECT_MAX_PROPERTY) {
+               WARN(1, "Failed to attach object property (type: 0x%x). Please "
+                       "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
+                       "you see this message on the same object type.\n",
+                       obj->type);
+               return;
+       }
+
+       obj->properties->properties[count] = property;
+       obj->properties->values[count] = init_val;
+       obj->properties->count++;
+}
+EXPORT_SYMBOL(drm_object_attach_property);
+
+/**
+ * drm_object_property_set_value - set the value of a property
+ * @obj: drm mode object to set property value for
+ * @property: property to set
+ * @val: value the property should be set to
+ *
+ * This function sets a given property on a given object. This function only
+ * changes the software state of the property, it does not call into the
+ * driver's ->set_property callback.
+ *
+ * Note that atomic drivers should not have any need to call this, the core will
+ * ensure consistency of values reported back to userspace through the
+ * appropriate ->atomic_get_property callback. Only legacy drivers should call
+ * this function to update the tracked value (after clamping and other
+ * restrictions have been applied).
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_object_property_set_value(struct drm_mode_object *obj,
+                                 struct drm_property *property, uint64_t val)
+{
+       int i;
+
+       for (i = 0; i < obj->properties->count; i++) {
+               if (obj->properties->properties[i] == property) {
+                       obj->properties->values[i] = val;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(drm_object_property_set_value);
+
+/**
+ * drm_object_property_get_value - retrieve the value of a property
+ * @obj: drm mode object to get property value from
+ * @property: property to retrieve
+ * @val: storage for the property value
+ *
+ * This function retrieves the softare state of the given property for the given
+ * property. Since there is no driver callback to retrieve the current property
+ * value this might be out of sync with the hardware, depending upon the driver
+ * and property.
+ *
+ * Atomic drivers should never call this function directly, the core will read
+ * out property values through the various ->atomic_get_property callbacks.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_object_property_get_value(struct drm_mode_object *obj,
+                                 struct drm_property *property, uint64_t *val)
+{
+       int i;
+
+       /* read-only properties bypass atomic mechanism and still store
+        * their value in obj->properties->values[].. mostly to avoid
+        * having to deal w/ EDID and similar props in atomic paths:
+        */
+       if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) &&
+                       !(property->flags & DRM_MODE_PROP_IMMUTABLE))
+               return drm_atomic_get_property(obj, property, val);
+
+       for (i = 0; i < obj->properties->count; i++) {
+               if (obj->properties->properties[i] == property) {
+                       *val = obj->properties->values[i];
+                       return 0;
+               }
+
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(drm_object_property_get_value);
+
+/* helper for getconnector and getproperties ioctls */
+int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
+                                  uint32_t __user *prop_ptr,
+                                  uint64_t __user *prop_values,
+                                  uint32_t *arg_count_props)
+{
+       int i, ret, count;
+
+       for (i = 0, count = 0; i < obj->properties->count; i++) {
+               struct drm_property *prop = obj->properties->properties[i];
+               uint64_t val;
+
+               if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
+                       continue;
+
+               if (*arg_count_props > count) {
+                       ret = drm_object_property_get_value(obj, prop, &val);
+                       if (ret)
+                               return ret;
+
+                       if (put_user(prop->base.id, prop_ptr + count))
+                               return -EFAULT;
+
+                       if (put_user(val, prop_values + count))
+                               return -EFAULT;
+               }
+
+               count++;
+       }
+       *arg_count_props = count;
+
+       return 0;
+}
+
+/**
+ * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * This function retrieves the current value for an object's property. Compared
+ * to the connector specific ioctl this one is extended to also work on crtc and
+ * plane objects.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
+                                     struct drm_file *file_priv)
+{
+       struct drm_mode_obj_get_properties *arg = data;
+       struct drm_mode_object *obj;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       drm_modeset_lock_all(dev);
+
+       obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
+       if (!obj) {
+               ret = -ENOENT;
+               goto out;
+       }
+       if (!obj->properties) {
+               ret = -EINVAL;
+               goto out_unref;
+       }
+
+       ret = drm_mode_object_get_properties(obj, file_priv->atomic,
+                       (uint32_t __user *)(unsigned long)(arg->props_ptr),
+                       (uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
+                       &arg->count_props);
+
+out_unref:
+       drm_mode_object_unreference(obj);
+out:
+       drm_modeset_unlock_all(dev);
+       return ret;
+}
+
+struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj,
+                                              uint32_t prop_id)
+{
+       int i;
+
+       for (i = 0; i < obj->properties->count; i++)
+               if (obj->properties->properties[i]->base.id == prop_id)
+                       return obj->properties->properties[i];
+
+       return NULL;
+}
+
+int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv)
+{
+       struct drm_mode_obj_set_property *arg = data;
+       struct drm_mode_object *arg_obj;
+       struct drm_property *property;
+       int ret = -EINVAL;
+       struct drm_mode_object *ref;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       drm_modeset_lock_all(dev);
+
+       arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
+       if (!arg_obj) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       if (!arg_obj->properties)
+               goto out_unref;
+
+       property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id);
+       if (!property)
+               goto out_unref;
+
+       if (!drm_property_change_valid_get(property, arg->value, &ref))
+               goto out_unref;
+
+       switch (arg_obj->type) {
+       case DRM_MODE_OBJECT_CONNECTOR:
+               ret = drm_mode_connector_set_obj_prop(arg_obj, property,
+                                                     arg->value);
+               break;
+       case DRM_MODE_OBJECT_CRTC:
+               ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
+               break;
+       case DRM_MODE_OBJECT_PLANE:
+               ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj),
+                                                 property, arg->value);
+               break;
+       }
+
+       drm_property_change_valid_put(property, ref);
+
+out_unref:
+       drm_mode_object_unreference(arg_obj);
+out:
+       drm_modeset_unlock_all(dev);
+       return ret;
+}
index fc5040a..53f07ac 100644 (file)
@@ -657,11 +657,36 @@ void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
 }
 EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
 
+/**
+ * drm_bus_flags_from_videomode - extract information about pixelclk and
+ * DE polarity from videomode and store it in a separate variable
+ * @vm: videomode structure to use
+ * @bus_flags: information about pixelclk and DE polarity will be stored here
+ *
+ * Sets DRM_BUS_FLAG_DE_(LOW|HIGH) and DRM_BUS_FLAG_PIXDATA_(POS|NEG)EDGE
+ * in @bus_flags according to DISPLAY_FLAGS found in @vm
+ */
+void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
+{
+       *bus_flags = 0;
+       if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+               *bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE;
+       if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+               *bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
+
+       if (vm->flags & DISPLAY_FLAGS_DE_LOW)
+               *bus_flags |= DRM_BUS_FLAG_DE_LOW;
+       if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
+               *bus_flags |= DRM_BUS_FLAG_DE_HIGH;
+}
+EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode);
+
 #ifdef CONFIG_OF
 /**
  * of_get_drm_display_mode - get a drm_display_mode from devicetree
  * @np: device_node with the timing specification
  * @dmode: will be set to the return value
+ * @bus_flags: information about pixelclk and DE polarity
  * @index: index into the list of display timings in devicetree
  *
  * This function is expensive and should only be used, if only one mode is to be
@@ -672,7 +697,8 @@ EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
  * 0 on success, a negative errno code when no of videomode node was found.
  */
 int of_get_drm_display_mode(struct device_node *np,
-                           struct drm_display_mode *dmode, int index)
+                           struct drm_display_mode *dmode, u32 *bus_flags,
+                           int index)
 {
        struct videomode vm;
        int ret;
@@ -682,6 +708,8 @@ int of_get_drm_display_mode(struct device_node *np,
                return ret;
 
        drm_display_mode_from_videomode(&vm, dmode);
+       if (bus_flags)
+               drm_bus_flags_from_videomode(&vm, bus_flags);
 
        pr_debug("%s: got %dx%d display mode from %s\n",
                of_node_full_name(np), vm.hactive, vm.vactive, np->name);
diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c
new file mode 100644 (file)
index 0000000..1d45738
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_plane_helper.h>
+
+/**
+ * DOC: aux kms helpers
+ *
+ * This helper library contains various one-off functions which don't really fit
+ * anywhere else in the DRM modeset helper library.
+ */
+
+/**
+ * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
+ *                                             connector list
+ * @dev: drm device to operate on
+ *
+ * Some userspace presumes that the first connected connector is the main
+ * display, where it's supposed to display e.g. the login screen. For
+ * laptops, this should be the main panel. Use this function to sort all
+ * (eDP/LVDS) panels to the front of the connector list, instead of
+ * painstakingly trying to initialize them in the right order.
+ */
+void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
+{
+       struct drm_connector *connector, *tmp;
+       struct list_head panel_list;
+
+       INIT_LIST_HEAD(&panel_list);
+
+       list_for_each_entry_safe(connector, tmp,
+                                &dev->mode_config.connector_list, head) {
+               if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
+                   connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+                       list_move_tail(&connector->head, &panel_list);
+       }
+
+       list_splice(&panel_list, &dev->mode_config.connector_list);
+}
+EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
+
+/**
+ * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata
+ * @fb: drm_framebuffer object to fill out
+ * @mode_cmd: metadata from the userspace fb creation request
+ *
+ * This helper can be used in a drivers fb_create callback to pre-fill the fb's
+ * metadata fields.
+ */
+void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
+                                   const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       int i;
+
+       fb->width = mode_cmd->width;
+       fb->height = mode_cmd->height;
+       for (i = 0; i < 4; i++) {
+               fb->pitches[i] = mode_cmd->pitches[i];
+               fb->offsets[i] = mode_cmd->offsets[i];
+               fb->modifier[i] = mode_cmd->modifier[i];
+       }
+       drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
+                                   &fb->bits_per_pixel);
+       fb->pixel_format = mode_cmd->pixel_format;
+       fb->flags = mode_cmd->flags;
+}
+EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
+
+/*
+ * This is the minimal list of formats that seem to be safe for modeset use
+ * with all current DRM drivers.  Most hardware can actually support more
+ * formats than this and drivers may specify a more accurate list when
+ * creating the primary plane.  However drivers that still call
+ * drm_plane_init() will use this minimal format list as the default.
+ */
+static const uint32_t safe_modeset_formats[] = {
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_ARGB8888,
+};
+
+static struct drm_plane *create_primary_plane(struct drm_device *dev)
+{
+       struct drm_plane *primary;
+       int ret;
+
+       primary = kzalloc(sizeof(*primary), GFP_KERNEL);
+       if (primary == NULL) {
+               DRM_DEBUG_KMS("Failed to allocate primary plane\n");
+               return NULL;
+       }
+
+       /*
+        * Remove the format_default field from drm_plane when dropping
+        * this helper.
+        */
+       primary->format_default = true;
+
+       /* possible_crtc's will be filled in later by crtc_init */
+       ret = drm_universal_plane_init(dev, primary, 0,
+                                      &drm_primary_helper_funcs,
+                                      safe_modeset_formats,
+                                      ARRAY_SIZE(safe_modeset_formats),
+                                      DRM_PLANE_TYPE_PRIMARY, NULL);
+       if (ret) {
+               kfree(primary);
+               primary = NULL;
+       }
+
+       return primary;
+}
+
+/**
+ * drm_crtc_init - Legacy CRTC initialization function
+ * @dev: DRM device
+ * @crtc: CRTC object to init
+ * @funcs: callbacks for the new CRTC
+ *
+ * Initialize a CRTC object with a default helper-provided primary plane and no
+ * cursor plane.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+                 const struct drm_crtc_funcs *funcs)
+{
+       struct drm_plane *primary;
+
+       primary = create_primary_plane(dev);
+       return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs,
+                                        NULL);
+}
+EXPORT_SYMBOL(drm_crtc_init);
index b2f8f10..3ceea9c 100644 (file)
@@ -175,7 +175,7 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
 {
        struct drm_irq_busid *p = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        /* UMS was only ever support on PCI devices. */
@@ -236,8 +236,8 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
        DRM_DEBUG("\n");
 
        dev = drm_dev_alloc(driver, &pdev->dev);
-       if (!dev)
-               return -ENOMEM;
+       if (IS_ERR(dev))
+               return PTR_ERR(dev);
 
        ret = pci_enable_device(pdev);
        if (ret)
@@ -263,7 +263,7 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
 
        /* No locking needed since shadow-attach is single-threaded since it may
         * only be called from the per-driver module init hook. */
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+       if (drm_core_check_feature(dev, DRIVER_LEGACY))
                list_add_tail(&dev->legacy_dev_list, &driver->legacy_dev_list);
 
        return 0;
@@ -299,7 +299,7 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
 
        DRM_DEBUG("\n");
 
-       if (driver->driver_features & DRIVER_MODESET)
+       if (!(driver->driver_features & DRIVER_LEGACY))
                return pci_register_driver(pdriver);
 
        /* If not using KMS, fall back to stealth mode manual scanning. */
@@ -421,7 +421,7 @@ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
        struct drm_device *dev, *tmp;
        DRM_DEBUG("\n");
 
-       if (driver->driver_features & DRIVER_MODESET) {
+       if (!(driver->driver_features & DRIVER_LEGACY)) {
                pci_unregister_driver(pdriver);
        } else {
                list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
new file mode 100644 (file)
index 0000000..249c0ae
--- /dev/null
@@ -0,0 +1,906 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_plane.h>
+
+#include "drm_crtc_internal.h"
+
+/**
+ * DOC: overview
+ *
+ * A plane represents an image source that can be blended with or overlayed on
+ * top of a CRTC during the scanout process. Planes take their input data from a
+ * &drm_framebuffer object. The plane itself specifies the cropping and scaling
+ * of that image, and where it is placed on the visible are of a display
+ * pipeline, represented by &drm_crtc. A plane can also have additional
+ * properties that specify how the pixels are positioned and blended, like
+ * rotation or Z-position. All these properties are stored in &drm_plane_state.
+ *
+ * To create a plane, a KMS drivers allocates and zeroes an instances of
+ * struct &drm_plane (possibly as part of a larger structure) and registers it
+ * with a call to drm_universal_plane_init().
+ *
+ * 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
+ * plane types. Special planes are associated with their CRTC by calling
+ * drm_crtc_init_with_planes().
+ *
+ * The type of a plane is exposed in the immutable "type" enumeration property,
+ * which has one of the following values: "Overlay", "Primary", "Cursor".
+ */
+
+static unsigned int drm_num_planes(struct drm_device *dev)
+{
+       unsigned int num = 0;
+       struct drm_plane *tmp;
+
+       drm_for_each_plane(tmp, dev) {
+               num++;
+       }
+
+       return num;
+}
+
+/**
+ * drm_universal_plane_init - Initialize a new universal plane object
+ * @dev: DRM device
+ * @plane: plane object to init
+ * @possible_crtcs: bitmask of possible CRTCs
+ * @funcs: callbacks for the new plane
+ * @formats: array of supported formats (DRM_FORMAT\_\*)
+ * @format_count: number of elements in @formats
+ * @type: type of plane (overlay, primary, cursor)
+ * @name: printf style format string for the plane name, or NULL for default name
+ *
+ * Initializes a plane object of type @type.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
+                            unsigned long possible_crtcs,
+                            const struct drm_plane_funcs *funcs,
+                            const uint32_t *formats, unsigned int format_count,
+                            enum drm_plane_type type,
+                            const char *name, ...)
+{
+       struct drm_mode_config *config = &dev->mode_config;
+       int ret;
+
+       ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
+       if (ret)
+               return ret;
+
+       drm_modeset_lock_init(&plane->mutex);
+
+       plane->base.properties = &plane->properties;
+       plane->dev = dev;
+       plane->funcs = funcs;
+       plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
+                                           GFP_KERNEL);
+       if (!plane->format_types) {
+               DRM_DEBUG_KMS("out of memory when allocating plane\n");
+               drm_mode_object_unregister(dev, &plane->base);
+               return -ENOMEM;
+       }
+
+       if (name) {
+               va_list ap;
+
+               va_start(ap, name);
+               plane->name = kvasprintf(GFP_KERNEL, name, ap);
+               va_end(ap);
+       } else {
+               plane->name = kasprintf(GFP_KERNEL, "plane-%d",
+                                       drm_num_planes(dev));
+       }
+       if (!plane->name) {
+               kfree(plane->format_types);
+               drm_mode_object_unregister(dev, &plane->base);
+               return -ENOMEM;
+       }
+
+       memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
+       plane->format_count = format_count;
+       plane->possible_crtcs = possible_crtcs;
+       plane->type = type;
+
+       list_add_tail(&plane->head, &config->plane_list);
+       plane->index = config->num_total_plane++;
+       if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+               config->num_overlay_plane++;
+
+       drm_object_attach_property(&plane->base,
+                                  config->plane_type_property,
+                                  plane->type);
+
+       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+               drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
+               drm_object_attach_property(&plane->base, config->prop_src_x, 0);
+               drm_object_attach_property(&plane->base, config->prop_src_y, 0);
+               drm_object_attach_property(&plane->base, config->prop_src_w, 0);
+               drm_object_attach_property(&plane->base, config->prop_src_h, 0);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_universal_plane_init);
+
+int drm_plane_register_all(struct drm_device *dev)
+{
+       struct drm_plane *plane;
+       int ret = 0;
+
+       drm_for_each_plane(plane, dev) {
+               if (plane->funcs->late_register)
+                       ret = plane->funcs->late_register(plane);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void drm_plane_unregister_all(struct drm_device *dev)
+{
+       struct drm_plane *plane;
+
+       drm_for_each_plane(plane, dev) {
+               if (plane->funcs->early_unregister)
+                       plane->funcs->early_unregister(plane);
+       }
+}
+
+/**
+ * drm_plane_init - Initialize a legacy plane
+ * @dev: DRM device
+ * @plane: plane object to init
+ * @possible_crtcs: bitmask of possible CRTCs
+ * @funcs: callbacks for the new plane
+ * @formats: array of supported formats (DRM_FORMAT\_\*)
+ * @format_count: number of elements in @formats
+ * @is_primary: plane type (primary vs overlay)
+ *
+ * Legacy API to initialize a DRM plane.
+ *
+ * New drivers should call drm_universal_plane_init() instead.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
+                  unsigned long possible_crtcs,
+                  const struct drm_plane_funcs *funcs,
+                  const uint32_t *formats, unsigned int format_count,
+                  bool is_primary)
+{
+       enum drm_plane_type type;
+
+       type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+       return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
+                                       formats, format_count, type, NULL);
+}
+EXPORT_SYMBOL(drm_plane_init);
+
+/**
+ * drm_plane_cleanup - Clean up the core plane usage
+ * @plane: plane to cleanup
+ *
+ * This function cleans up @plane and removes it from the DRM mode setting
+ * core. Note that the function does *not* free the plane structure itself,
+ * this is the responsibility of the caller.
+ */
+void drm_plane_cleanup(struct drm_plane *plane)
+{
+       struct drm_device *dev = plane->dev;
+
+       drm_modeset_lock_all(dev);
+       kfree(plane->format_types);
+       drm_mode_object_unregister(dev, &plane->base);
+
+       BUG_ON(list_empty(&plane->head));
+
+       /* Note that the plane_list is considered to be static; should we
+        * remove the drm_plane at runtime we would have to decrement all
+        * the indices on the drm_plane after us in the plane_list.
+        */
+
+       list_del(&plane->head);
+       dev->mode_config.num_total_plane--;
+       if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+               dev->mode_config.num_overlay_plane--;
+       drm_modeset_unlock_all(dev);
+
+       WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
+       if (plane->state && plane->funcs->atomic_destroy_state)
+               plane->funcs->atomic_destroy_state(plane, plane->state);
+
+       kfree(plane->name);
+
+       memset(plane, 0, sizeof(*plane));
+}
+EXPORT_SYMBOL(drm_plane_cleanup);
+
+/**
+ * drm_plane_from_index - find the registered plane at an index
+ * @dev: DRM device
+ * @idx: index of registered plane to find for
+ *
+ * Given a plane index, return the registered plane from DRM device's
+ * list of planes with matching index.
+ */
+struct drm_plane *
+drm_plane_from_index(struct drm_device *dev, int idx)
+{
+       struct drm_plane *plane;
+
+       drm_for_each_plane(plane, dev)
+               if (idx == plane->index)
+                       return plane;
+
+       return NULL;
+}
+EXPORT_SYMBOL(drm_plane_from_index);
+
+/**
+ * drm_plane_force_disable - Forcibly disable a plane
+ * @plane: plane to disable
+ *
+ * Forces the plane to be disabled.
+ *
+ * Used when the plane's current framebuffer is destroyed,
+ * and when restoring fbdev mode.
+ */
+void drm_plane_force_disable(struct drm_plane *plane)
+{
+       int ret;
+
+       if (!plane->fb)
+               return;
+
+       plane->old_fb = plane->fb;
+       ret = plane->funcs->disable_plane(plane);
+       if (ret) {
+               DRM_ERROR("failed to disable plane with busy fb\n");
+               plane->old_fb = NULL;
+               return;
+       }
+       /* disconnect the plane from the fb and crtc: */
+       drm_framebuffer_unreference(plane->old_fb);
+       plane->old_fb = NULL;
+       plane->fb = NULL;
+       plane->crtc = NULL;
+}
+EXPORT_SYMBOL(drm_plane_force_disable);
+
+/**
+ * drm_mode_plane_set_obj_prop - set the value of a property
+ * @plane: drm plane object to set property value for
+ * @property: property to set
+ * @value: value the property should be set to
+ *
+ * This functions sets a given property on a given plane object. This function
+ * calls the driver's ->set_property callback and changes the software state of
+ * the property if the callback succeeds.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+                               struct drm_property *property,
+                               uint64_t value)
+{
+       int ret = -EINVAL;
+       struct drm_mode_object *obj = &plane->base;
+
+       if (plane->funcs->set_property)
+               ret = plane->funcs->set_property(plane, property, value);
+       if (!ret)
+               drm_object_property_set_value(obj, property, value);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
+
+int drm_mode_getplane_res(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+       struct drm_mode_get_plane_res *plane_resp = data;
+       struct drm_mode_config *config;
+       struct drm_plane *plane;
+       uint32_t __user *plane_ptr;
+       int copied = 0;
+       unsigned num_planes;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       config = &dev->mode_config;
+
+       if (file_priv->universal_planes)
+               num_planes = config->num_total_plane;
+       else
+               num_planes = config->num_overlay_plane;
+
+       /*
+        * This ioctl is called twice, once to determine how much space is
+        * needed, and the 2nd time to fill it.
+        */
+       if (num_planes &&
+           (plane_resp->count_planes >= num_planes)) {
+               plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
+
+               /* Plane lists are invariant, no locking needed. */
+               drm_for_each_plane(plane, dev) {
+                       /*
+                        * Unless userspace set the 'universal planes'
+                        * capability bit, only advertise overlays.
+                        */
+                       if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
+                           !file_priv->universal_planes)
+                               continue;
+
+                       if (put_user(plane->base.id, plane_ptr + copied))
+                               return -EFAULT;
+                       copied++;
+               }
+       }
+       plane_resp->count_planes = num_planes;
+
+       return 0;
+}
+
+int drm_mode_getplane(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv)
+{
+       struct drm_mode_get_plane *plane_resp = data;
+       struct drm_plane *plane;
+       uint32_t __user *format_ptr;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       plane = drm_plane_find(dev, plane_resp->plane_id);
+       if (!plane)
+               return -ENOENT;
+
+       drm_modeset_lock(&plane->mutex, NULL);
+       if (plane->crtc)
+               plane_resp->crtc_id = plane->crtc->base.id;
+       else
+               plane_resp->crtc_id = 0;
+
+       if (plane->fb)
+               plane_resp->fb_id = plane->fb->base.id;
+       else
+               plane_resp->fb_id = 0;
+       drm_modeset_unlock(&plane->mutex);
+
+       plane_resp->plane_id = plane->base.id;
+       plane_resp->possible_crtcs = plane->possible_crtcs;
+       plane_resp->gamma_size = 0;
+
+       /*
+        * This ioctl is called twice, once to determine how much space is
+        * needed, and the 2nd time to fill it.
+        */
+       if (plane->format_count &&
+           (plane_resp->count_format_types >= plane->format_count)) {
+               format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
+               if (copy_to_user(format_ptr,
+                                plane->format_types,
+                                sizeof(uint32_t) * plane->format_count)) {
+                       return -EFAULT;
+               }
+       }
+       plane_resp->count_format_types = plane->format_count;
+
+       return 0;
+}
+
+int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
+{
+       unsigned int i;
+
+       for (i = 0; i < plane->format_count; i++) {
+               if (format == plane->format_types[i])
+                       return 0;
+       }
+
+       return -EINVAL;
+}
+
+/*
+ * setplane_internal - setplane handler for internal callers
+ *
+ * Note that we assume an extra reference has already been taken on fb.  If the
+ * update fails, this reference will be dropped before return; if it succeeds,
+ * the previous framebuffer (if any) will be unreferenced instead.
+ *
+ * src_{x,y,w,h} are provided in 16.16 fixed point format
+ */
+static int __setplane_internal(struct drm_plane *plane,
+                              struct drm_crtc *crtc,
+                              struct drm_framebuffer *fb,
+                              int32_t crtc_x, int32_t crtc_y,
+                              uint32_t crtc_w, uint32_t crtc_h,
+                              /* src_{x,y,w,h} values are 16.16 fixed point */
+                              uint32_t src_x, uint32_t src_y,
+                              uint32_t src_w, uint32_t src_h)
+{
+       int ret = 0;
+
+       /* No fb means shut it down */
+       if (!fb) {
+               plane->old_fb = plane->fb;
+               ret = plane->funcs->disable_plane(plane);
+               if (!ret) {
+                       plane->crtc = NULL;
+                       plane->fb = NULL;
+               } else {
+                       plane->old_fb = NULL;
+               }
+               goto out;
+       }
+
+       /* Check whether this plane is usable on this CRTC */
+       if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
+               DRM_DEBUG_KMS("Invalid crtc for plane\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* Check whether this plane supports the fb pixel format. */
+       ret = drm_plane_check_pixel_format(plane, fb->pixel_format);
+       if (ret) {
+               char *format_name = drm_get_format_name(fb->pixel_format);
+               DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name);
+               kfree(format_name);
+               goto out;
+       }
+
+       /* Give drivers some help against integer overflows */
+       if (crtc_w > INT_MAX ||
+           crtc_x > INT_MAX - (int32_t) crtc_w ||
+           crtc_h > INT_MAX ||
+           crtc_y > INT_MAX - (int32_t) crtc_h) {
+               DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+                             crtc_w, crtc_h, crtc_x, crtc_y);
+               ret = -ERANGE;
+               goto out;
+       }
+
+       ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb);
+       if (ret)
+               goto out;
+
+       plane->old_fb = plane->fb;
+       ret = plane->funcs->update_plane(plane, crtc, fb,
+                                        crtc_x, crtc_y, crtc_w, crtc_h,
+                                        src_x, src_y, src_w, src_h);
+       if (!ret) {
+               plane->crtc = crtc;
+               plane->fb = fb;
+               fb = NULL;
+       } else {
+               plane->old_fb = NULL;
+       }
+
+out:
+       if (fb)
+               drm_framebuffer_unreference(fb);
+       if (plane->old_fb)
+               drm_framebuffer_unreference(plane->old_fb);
+       plane->old_fb = NULL;
+
+       return ret;
+}
+
+static int setplane_internal(struct drm_plane *plane,
+                            struct drm_crtc *crtc,
+                            struct drm_framebuffer *fb,
+                            int32_t crtc_x, int32_t crtc_y,
+                            uint32_t crtc_w, uint32_t crtc_h,
+                            /* src_{x,y,w,h} values are 16.16 fixed point */
+                            uint32_t src_x, uint32_t src_y,
+                            uint32_t src_w, uint32_t src_h)
+{
+       int ret;
+
+       drm_modeset_lock_all(plane->dev);
+       ret = __setplane_internal(plane, crtc, fb,
+                                 crtc_x, crtc_y, crtc_w, crtc_h,
+                                 src_x, src_y, src_w, src_h);
+       drm_modeset_unlock_all(plane->dev);
+
+       return ret;
+}
+
+int drm_mode_setplane(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv)
+{
+       struct drm_mode_set_plane *plane_req = data;
+       struct drm_plane *plane;
+       struct drm_crtc *crtc = NULL;
+       struct drm_framebuffer *fb = NULL;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       /*
+        * First, find the plane, crtc, and fb objects.  If not available,
+        * we don't bother to call the driver.
+        */
+       plane = drm_plane_find(dev, plane_req->plane_id);
+       if (!plane) {
+               DRM_DEBUG_KMS("Unknown plane ID %d\n",
+                             plane_req->plane_id);
+               return -ENOENT;
+       }
+
+       if (plane_req->fb_id) {
+               fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
+               if (!fb) {
+                       DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
+                                     plane_req->fb_id);
+                       return -ENOENT;
+               }
+
+               crtc = drm_crtc_find(dev, plane_req->crtc_id);
+               if (!crtc) {
+                       DRM_DEBUG_KMS("Unknown crtc ID %d\n",
+                                     plane_req->crtc_id);
+                       return -ENOENT;
+               }
+       }
+
+       /*
+        * setplane_internal will take care of deref'ing either the old or new
+        * framebuffer depending on success.
+        */
+       return setplane_internal(plane, crtc, fb,
+                                plane_req->crtc_x, plane_req->crtc_y,
+                                plane_req->crtc_w, plane_req->crtc_h,
+                                plane_req->src_x, plane_req->src_y,
+                                plane_req->src_w, plane_req->src_h);
+}
+
+static int drm_mode_cursor_universal(struct drm_crtc *crtc,
+                                    struct drm_mode_cursor2 *req,
+                                    struct drm_file *file_priv)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_framebuffer *fb = NULL;
+       struct drm_mode_fb_cmd2 fbreq = {
+               .width = req->width,
+               .height = req->height,
+               .pixel_format = DRM_FORMAT_ARGB8888,
+               .pitches = { req->width * 4 },
+               .handles = { req->handle },
+       };
+       int32_t crtc_x, crtc_y;
+       uint32_t crtc_w = 0, crtc_h = 0;
+       uint32_t src_w = 0, src_h = 0;
+       int ret = 0;
+
+       BUG_ON(!crtc->cursor);
+       WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL);
+
+       /*
+        * Obtain fb we'll be using (either new or existing) and take an extra
+        * reference to it if fb != null.  setplane will take care of dropping
+        * the reference if the plane update fails.
+        */
+       if (req->flags & DRM_MODE_CURSOR_BO) {
+               if (req->handle) {
+                       fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv);
+                       if (IS_ERR(fb)) {
+                               DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
+                               return PTR_ERR(fb);
+                       }
+                       fb->hot_x = req->hot_x;
+                       fb->hot_y = req->hot_y;
+               } else {
+                       fb = NULL;
+               }
+       } else {
+               fb = crtc->cursor->fb;
+               if (fb)
+                       drm_framebuffer_reference(fb);
+       }
+
+       if (req->flags & DRM_MODE_CURSOR_MOVE) {
+               crtc_x = req->x;
+               crtc_y = req->y;
+       } else {
+               crtc_x = crtc->cursor_x;
+               crtc_y = crtc->cursor_y;
+       }
+
+       if (fb) {
+               crtc_w = fb->width;
+               crtc_h = fb->height;
+               src_w = fb->width << 16;
+               src_h = fb->height << 16;
+       }
+
+       /*
+        * setplane_internal will take care of deref'ing either the old or new
+        * framebuffer depending on success.
+        */
+       ret = __setplane_internal(crtc->cursor, crtc, fb,
+                               crtc_x, crtc_y, crtc_w, crtc_h,
+                               0, 0, src_w, src_h);
+
+       /* Update successful; save new cursor position, if necessary */
+       if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
+               crtc->cursor_x = req->x;
+               crtc->cursor_y = req->y;
+       }
+
+       return ret;
+}
+
+static int drm_mode_cursor_common(struct drm_device *dev,
+                                 struct drm_mode_cursor2 *req,
+                                 struct drm_file *file_priv)
+{
+       struct drm_crtc *crtc;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
+               return -EINVAL;
+
+       crtc = drm_crtc_find(dev, req->crtc_id);
+       if (!crtc) {
+               DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
+               return -ENOENT;
+       }
+
+       /*
+        * If this crtc has a universal cursor plane, call that plane's update
+        * handler rather than using legacy cursor handlers.
+        */
+       drm_modeset_lock_crtc(crtc, crtc->cursor);
+       if (crtc->cursor) {
+               ret = drm_mode_cursor_universal(crtc, req, file_priv);
+               goto out;
+       }
+
+       if (req->flags & DRM_MODE_CURSOR_BO) {
+               if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
+                       ret = -ENXIO;
+                       goto out;
+               }
+               /* Turns off the cursor if handle is 0 */
+               if (crtc->funcs->cursor_set2)
+                       ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
+                                                     req->width, req->height, req->hot_x, req->hot_y);
+               else
+                       ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
+                                                     req->width, req->height);
+       }
+
+       if (req->flags & DRM_MODE_CURSOR_MOVE) {
+               if (crtc->funcs->cursor_move) {
+                       ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
+               } else {
+                       ret = -EFAULT;
+                       goto out;
+               }
+       }
+out:
+       drm_modeset_unlock_crtc(crtc);
+
+       return ret;
+
+}
+
+
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_cursor *req = data;
+       struct drm_mode_cursor2 new_req;
+
+       memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
+       new_req.hot_x = new_req.hot_y = 0;
+
+       return drm_mode_cursor_common(dev, &new_req, file_priv);
+}
+
+/*
+ * Set the cursor configuration based on user request. This implements the 2nd
+ * version of the cursor ioctl, which allows userspace to additionally specify
+ * the hotspot of the pointer.
+ */
+int drm_mode_cursor2_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_cursor2 *req = data;
+
+       return drm_mode_cursor_common(dev, req, file_priv);
+}
+
+int drm_mode_page_flip_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc_page_flip_target *page_flip = data;
+       struct drm_crtc *crtc;
+       struct drm_framebuffer *fb = NULL;
+       struct drm_pending_vblank_event *e = NULL;
+       u32 target_vblank = page_flip->sequence;
+       int ret = -EINVAL;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
+               return -EINVAL;
+
+       if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
+               return -EINVAL;
+
+       /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags
+        * can be specified
+        */
+       if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
+               return -EINVAL;
+
+       if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
+               return -EINVAL;
+
+       crtc = drm_crtc_find(dev, page_flip->crtc_id);
+       if (!crtc)
+               return -ENOENT;
+
+       if (crtc->funcs->page_flip_target) {
+               u32 current_vblank;
+               int r;
+
+               r = drm_crtc_vblank_get(crtc);
+               if (r)
+                       return r;
+
+               current_vblank = drm_crtc_vblank_count(crtc);
+
+               switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
+               case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
+                       if ((int)(target_vblank - current_vblank) > 1) {
+                               DRM_DEBUG("Invalid absolute flip target %u, "
+                                         "must be <= %u\n", target_vblank,
+                                         current_vblank + 1);
+                               drm_crtc_vblank_put(crtc);
+                               return -EINVAL;
+                       }
+                       break;
+               case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
+                       if (target_vblank != 0 && target_vblank != 1) {
+                               DRM_DEBUG("Invalid relative flip target %u, "
+                                         "must be 0 or 1\n", target_vblank);
+                               drm_crtc_vblank_put(crtc);
+                               return -EINVAL;
+                       }
+                       target_vblank += current_vblank;
+                       break;
+               default:
+                       target_vblank = current_vblank +
+                               !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
+                       break;
+               }
+       } else if (crtc->funcs->page_flip == NULL ||
+                  (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
+               return -EINVAL;
+       }
+
+       drm_modeset_lock_crtc(crtc, crtc->primary);
+       if (crtc->primary->fb == NULL) {
+               /* The framebuffer is currently unbound, presumably
+                * due to a hotplug event, that userspace has not
+                * yet discovered.
+                */
+               ret = -EBUSY;
+               goto out;
+       }
+
+       fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
+       if (!fb) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       if (crtc->state) {
+               const struct drm_plane_state *state = crtc->primary->state;
+
+               ret = drm_framebuffer_check_src_coords(state->src_x,
+                                                      state->src_y,
+                                                      state->src_w,
+                                                      state->src_h,
+                                                      fb);
+       } else {
+               ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
+       }
+       if (ret)
+               goto out;
+
+       if (crtc->primary->fb->pixel_format != fb->pixel_format) {
+               DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+               e = kzalloc(sizeof *e, GFP_KERNEL);
+               if (!e) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
+               e->event.base.length = sizeof(e->event);
+               e->event.user_data = page_flip->user_data;
+               ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
+               if (ret) {
+                       kfree(e);
+                       goto out;
+               }
+       }
+
+       crtc->primary->old_fb = crtc->primary->fb;
+       if (crtc->funcs->page_flip_target)
+               ret = crtc->funcs->page_flip_target(crtc, fb, e,
+                                                   page_flip->flags,
+                                                   target_vblank);
+       else
+               ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
+       if (ret) {
+               if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
+                       drm_event_cancel_free(dev, &e->base);
+               /* Keep the old fb, don't unref it. */
+               crtc->primary->old_fb = NULL;
+       } else {
+               crtc->primary->fb = fb;
+               /* Unref only the old framebuffer. */
+               fb = NULL;
+       }
+
+out:
+       if (ret && crtc->funcs->page_flip_target)
+               drm_crtc_vblank_put(crtc);
+       if (fb)
+               drm_framebuffer_unreference(fb);
+       if (crtc->primary->old_fb)
+               drm_framebuffer_unreference(crtc->primary->old_fb);
+       crtc->primary->old_fb = NULL;
+       drm_modeset_unlock_crtc(crtc);
+
+       return ret;
+}
index 16c4a7b..7899fc1 100644 (file)
  * the details.
  */
 
-/*
- * This is the minimal list of formats that seem to be safe for modeset use
- * with all current DRM drivers.  Most hardware can actually support more
- * formats than this and drivers may specify a more accurate list when
- * creating the primary plane.  However drivers that still call
- * drm_plane_init() will use this minimal format list as the default.
- */
-static const uint32_t safe_modeset_formats[] = {
-       DRM_FORMAT_XRGB8888,
-       DRM_FORMAT_ARGB8888,
-};
-
 /*
  * Returns the connectors currently associated with a CRTC.  This function
  * should be called twice:  once with a NULL connector list to retrieve
@@ -108,14 +96,9 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
 }
 
 /**
- * drm_plane_helper_check_update() - Check plane update for validity
- * @plane: plane object to update
- * @crtc: owning CRTC of owning plane
- * @fb: framebuffer to flip onto plane
- * @src: source coordinates in 16.16 fixed point
- * @dest: integer destination coordinates
+ * drm_plane_helper_check_state() - Check plane state for validity
+ * @state: plane state to check
  * @clip: integer clipping coordinates
- * @rotation: plane rotation
  * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
  * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
  * @can_position: is it legal to position the plane such that it
@@ -123,10 +106,9 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
  *                only be false for primary planes.
  * @can_update_disabled: can the plane be updated while the crtc
  *                       is disabled?
- * @visible: output parameter indicating whether plane is still visible after
- *           clipping
  *
- * Checks that a desired plane update is valid.  Drivers that provide
+ * Checks that a desired plane update is valid, and updates various
+ * bits of derived state (clipped coordinates etc.). Drivers that provide
  * their own plane handling rather than helper-provided implementations may
  * still wish to call this function to avoid duplication of error checking
  * code.
@@ -134,29 +116,38 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
  * RETURNS:
  * Zero if update appears valid, error code on failure
  */
-int drm_plane_helper_check_update(struct drm_plane *plane,
-                                 struct drm_crtc *crtc,
-                                 struct drm_framebuffer *fb,
-                                 struct drm_rect *src,
-                                 struct drm_rect *dest,
-                                 const struct drm_rect *clip,
-                                 unsigned int rotation,
-                                 int min_scale,
-                                 int max_scale,
-                                 bool can_position,
-                                 bool can_update_disabled,
-                                 bool *visible)
+int drm_plane_helper_check_state(struct drm_plane_state *state,
+                                const struct drm_rect *clip,
+                                int min_scale,
+                                int max_scale,
+                                bool can_position,
+                                bool can_update_disabled)
 {
+       struct drm_crtc *crtc = state->crtc;
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_rect *src = &state->src;
+       struct drm_rect *dst = &state->dst;
+       unsigned int rotation = state->rotation;
        int hscale, vscale;
 
+       src->x1 = state->src_x;
+       src->y1 = state->src_y;
+       src->x2 = state->src_x + state->src_w;
+       src->y2 = state->src_y + state->src_h;
+
+       dst->x1 = state->crtc_x;
+       dst->y1 = state->crtc_y;
+       dst->x2 = state->crtc_x + state->crtc_w;
+       dst->y2 = state->crtc_y + state->crtc_h;
+
        if (!fb) {
-               *visible = false;
+               state->visible = false;
                return 0;
        }
 
        /* crtc should only be NULL when disabling (i.e., !fb) */
        if (WARN_ON(!crtc)) {
-               *visible = false;
+               state->visible = false;
                return 0;
        }
 
@@ -168,20 +159,20 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
        drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
 
        /* Check scaling */
-       hscale = drm_rect_calc_hscale(src, dest, min_scale, max_scale);
-       vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale);
+       hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
+       vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
        if (hscale < 0 || vscale < 0) {
                DRM_DEBUG_KMS("Invalid scaling of plane\n");
-               drm_rect_debug_print("src: ", src, true);
-               drm_rect_debug_print("dst: ", dest, false);
+               drm_rect_debug_print("src: ", &state->src, true);
+               drm_rect_debug_print("dst: ", &state->dst, false);
                return -ERANGE;
        }
 
-       *visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale);
+       state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
 
        drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
 
-       if (!*visible)
+       if (!state->visible)
                /*
                 * Plane isn't visible; some drivers can handle this
                 * so we just return success here.  Drivers that can't
@@ -191,15 +182,87 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
                 */
                return 0;
 
-       if (!can_position && !drm_rect_equals(dest, clip)) {
+       if (!can_position && !drm_rect_equals(dst, clip)) {
                DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
-               drm_rect_debug_print("dst: ", dest, false);
+               drm_rect_debug_print("dst: ", dst, false);
                drm_rect_debug_print("clip: ", clip, false);
                return -EINVAL;
        }
 
        return 0;
 }
+EXPORT_SYMBOL(drm_plane_helper_check_state);
+
+/**
+ * drm_plane_helper_check_update() - Check plane update for validity
+ * @plane: plane object to update
+ * @crtc: owning CRTC of owning plane
+ * @fb: framebuffer to flip onto plane
+ * @src: source coordinates in 16.16 fixed point
+ * @dst: integer destination coordinates
+ * @clip: integer clipping coordinates
+ * @rotation: plane rotation
+ * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
+ * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
+ * @can_position: is it legal to position the plane such that it
+ *                doesn't cover the entire crtc?  This will generally
+ *                only be false for primary planes.
+ * @can_update_disabled: can the plane be updated while the crtc
+ *                       is disabled?
+ * @visible: output parameter indicating whether plane is still visible after
+ *           clipping
+ *
+ * Checks that a desired plane update is valid.  Drivers that provide
+ * their own plane handling rather than helper-provided implementations may
+ * still wish to call this function to avoid duplication of error checking
+ * code.
+ *
+ * RETURNS:
+ * Zero if update appears valid, error code on failure
+ */
+int drm_plane_helper_check_update(struct drm_plane *plane,
+                                 struct drm_crtc *crtc,
+                                 struct drm_framebuffer *fb,
+                                 struct drm_rect *src,
+                                 struct drm_rect *dst,
+                                 const struct drm_rect *clip,
+                                 unsigned int rotation,
+                                 int min_scale,
+                                 int max_scale,
+                                 bool can_position,
+                                 bool can_update_disabled,
+                                 bool *visible)
+{
+       struct drm_plane_state state = {
+               .plane = plane,
+               .crtc = crtc,
+               .fb = fb,
+               .src_x = src->x1,
+               .src_y = src->y1,
+               .src_w = drm_rect_width(src),
+               .src_h = drm_rect_height(src),
+               .crtc_x = dst->x1,
+               .crtc_y = dst->y1,
+               .crtc_w = drm_rect_width(dst),
+               .crtc_h = drm_rect_height(dst),
+               .rotation = rotation,
+               .visible = *visible,
+       };
+       int ret;
+
+       ret = drm_plane_helper_check_state(&state, clip,
+                                          min_scale, max_scale,
+                                          can_position,
+                                          can_update_disabled);
+       if (ret)
+               return ret;
+
+       *src = state.src;
+       *dst = state.dst;
+       *visible = state.visible;
+
+       return 0;
+}
 EXPORT_SYMBOL(drm_plane_helper_check_update);
 
 /**
@@ -274,7 +337,7 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
 
        ret = drm_plane_helper_check_update(plane, crtc, fb,
                                            &src, &dest, &clip,
-                                           BIT(DRM_ROTATE_0),
+                                           DRM_ROTATE_0,
                                            DRM_PLANE_HELPER_NO_SCALING,
                                            DRM_PLANE_HELPER_NO_SCALING,
                                            false, false, &visible);
@@ -363,60 +426,6 @@ const struct drm_plane_funcs drm_primary_helper_funcs = {
 };
 EXPORT_SYMBOL(drm_primary_helper_funcs);
 
-static struct drm_plane *create_primary_plane(struct drm_device *dev)
-{
-       struct drm_plane *primary;
-       int ret;
-
-       primary = kzalloc(sizeof(*primary), GFP_KERNEL);
-       if (primary == NULL) {
-               DRM_DEBUG_KMS("Failed to allocate primary plane\n");
-               return NULL;
-       }
-
-       /*
-        * Remove the format_default field from drm_plane when dropping
-        * this helper.
-        */
-       primary->format_default = true;
-
-       /* possible_crtc's will be filled in later by crtc_init */
-       ret = drm_universal_plane_init(dev, primary, 0,
-                                      &drm_primary_helper_funcs,
-                                      safe_modeset_formats,
-                                      ARRAY_SIZE(safe_modeset_formats),
-                                      DRM_PLANE_TYPE_PRIMARY, NULL);
-       if (ret) {
-               kfree(primary);
-               primary = NULL;
-       }
-
-       return primary;
-}
-
-/**
- * drm_crtc_init - Legacy CRTC initialization function
- * @dev: DRM device
- * @crtc: CRTC object to init
- * @funcs: callbacks for the new CRTC
- *
- * Initialize a CRTC object with a default helper-provided primary plane and no
- * cursor plane.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
-                 const struct drm_crtc_funcs *funcs)
-{
-       struct drm_plane *primary;
-
-       primary = create_primary_plane(dev);
-       return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs,
-                                        NULL);
-}
-EXPORT_SYMBOL(drm_crtc_init);
-
 int drm_plane_helper_commit(struct drm_plane *plane,
                            struct drm_plane_state *plane_state,
                            struct drm_framebuffer *old_fb)
index 2c819ef..0262698 100644 (file)
@@ -48,8 +48,8 @@ static int drm_get_platform_dev(struct platform_device *platdev,
        DRM_DEBUG("\n");
 
        dev = drm_dev_alloc(driver, &platdev->dev);
-       if (!dev)
-               return -ENOMEM;
+       if (IS_ERR(dev))
+               return PTR_ERR(dev);
 
        dev->platformdev = platdev;
 
index 780589b..b22a94d 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <linux/export.h>
 #include <linux/dma-buf.h>
+#include <linux/rbtree.h>
 #include <drm/drmP.h>
 #include <drm/drm_gem.h>
 
  */
 
 struct drm_prime_member {
-       struct list_head entry;
        struct dma_buf *dma_buf;
        uint32_t handle;
+
+       struct rb_node dmabuf_rb;
+       struct rb_node handle_rb;
 };
 
 struct drm_prime_attachment {
@@ -75,6 +78,7 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
                                    struct dma_buf *dma_buf, uint32_t handle)
 {
        struct drm_prime_member *member;
+       struct rb_node **p, *rb;
 
        member = kmalloc(sizeof(*member), GFP_KERNEL);
        if (!member)
@@ -83,18 +87,56 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
        get_dma_buf(dma_buf);
        member->dma_buf = dma_buf;
        member->handle = handle;
-       list_add(&member->entry, &prime_fpriv->head);
+
+       rb = NULL;
+       p = &prime_fpriv->dmabufs.rb_node;
+       while (*p) {
+               struct drm_prime_member *pos;
+
+               rb = *p;
+               pos = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
+               if (dma_buf > pos->dma_buf)
+                       p = &rb->rb_right;
+               else
+                       p = &rb->rb_left;
+       }
+       rb_link_node(&member->dmabuf_rb, rb, p);
+       rb_insert_color(&member->dmabuf_rb, &prime_fpriv->dmabufs);
+
+       rb = NULL;
+       p = &prime_fpriv->handles.rb_node;
+       while (*p) {
+               struct drm_prime_member *pos;
+
+               rb = *p;
+               pos = rb_entry(rb, struct drm_prime_member, handle_rb);
+               if (handle > pos->handle)
+                       p = &rb->rb_right;
+               else
+                       p = &rb->rb_left;
+       }
+       rb_link_node(&member->handle_rb, rb, p);
+       rb_insert_color(&member->handle_rb, &prime_fpriv->handles);
+
        return 0;
 }
 
 static struct dma_buf *drm_prime_lookup_buf_by_handle(struct drm_prime_file_private *prime_fpriv,
                                                      uint32_t handle)
 {
-       struct drm_prime_member *member;
+       struct rb_node *rb;
+
+       rb = prime_fpriv->handles.rb_node;
+       while (rb) {
+               struct drm_prime_member *member;
 
-       list_for_each_entry(member, &prime_fpriv->head, entry) {
+               member = rb_entry(rb, struct drm_prime_member, handle_rb);
                if (member->handle == handle)
                        return member->dma_buf;
+               else if (member->handle < handle)
+                       rb = rb->rb_right;
+               else
+                       rb = rb->rb_left;
        }
 
        return NULL;
@@ -104,14 +146,23 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri
                                       struct dma_buf *dma_buf,
                                       uint32_t *handle)
 {
-       struct drm_prime_member *member;
+       struct rb_node *rb;
+
+       rb = prime_fpriv->dmabufs.rb_node;
+       while (rb) {
+               struct drm_prime_member *member;
 
-       list_for_each_entry(member, &prime_fpriv->head, entry) {
+               member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
                if (member->dma_buf == dma_buf) {
                        *handle = member->handle;
                        return 0;
+               } else if (member->dma_buf < dma_buf) {
+                       rb = rb->rb_right;
+               } else {
+                       rb = rb->rb_left;
                }
        }
+
        return -ENOENT;
 }
 
@@ -166,13 +217,24 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf,
 void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
                                        struct dma_buf *dma_buf)
 {
-       struct drm_prime_member *member, *safe;
+       struct rb_node *rb;
 
-       list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
+       rb = prime_fpriv->dmabufs.rb_node;
+       while (rb) {
+               struct drm_prime_member *member;
+
+               member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
                if (member->dma_buf == dma_buf) {
+                       rb_erase(&member->handle_rb, &prime_fpriv->handles);
+                       rb_erase(&member->dmabuf_rb, &prime_fpriv->dmabufs);
+
                        dma_buf_put(dma_buf);
-                       list_del(&member->entry);
                        kfree(member);
+                       return;
+               } else if (member->dma_buf < dma_buf) {
+                       rb = rb->rb_right;
+               } else {
+                       rb = rb->rb_left;
                }
        }
 }
@@ -221,19 +283,48 @@ static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
        /* nothing to be done here */
 }
 
+/**
+ * drm_gem_dmabuf_export - dma_buf export implementation for GEM
+ * @dev: parent device for the exported dmabuf
+ * @exp_info: the export information used by dma_buf_export()
+ *
+ * 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 which is released by drm_gem_dmabuf_release().
+ *
+ * Returns the new dmabuf.
+ */
+struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
+                                     struct dma_buf_export_info *exp_info)
+{
+       struct dma_buf *dma_buf;
+
+       dma_buf = dma_buf_export(exp_info);
+       if (!IS_ERR(dma_buf))
+               drm_dev_ref(dev);
+
+       return dma_buf;
+}
+EXPORT_SYMBOL(drm_gem_dmabuf_export);
+
 /**
  * drm_gem_dmabuf_release - dma_buf release implementation for GEM
  * @dma_buf: buffer to be released
  *
  * Generic release function for dma_bufs exported as PRIME buffers. GEM drivers
  * must use this in their dma_buf ops structure as the release callback.
+ * drm_gem_dmabuf_release() should be used in conjunction with
+ * drm_gem_dmabuf_export().
  */
 void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
 {
        struct drm_gem_object *obj = dma_buf->priv;
+       struct drm_device *dev = obj->dev;
 
        /* drop the reference on the export fd holds */
        drm_gem_object_unreference_unlocked(obj);
+
+       drm_dev_unref(dev);
 }
 EXPORT_SYMBOL(drm_gem_dmabuf_release);
 
@@ -335,19 +426,22 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
  * using the PRIME helpers.
  */
 struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
-                                    struct drm_gem_object *obj, int flags)
+                                    struct drm_gem_object *obj,
+                                    int flags)
 {
-       DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-
-       exp_info.ops = &drm_gem_prime_dmabuf_ops;
-       exp_info.size = obj->size;
-       exp_info.flags = flags;
-       exp_info.priv = obj;
+       struct dma_buf_export_info exp_info = {
+               .exp_name = KBUILD_MODNAME, /* white lie for debug */
+               .owner = dev->driver->fops->owner,
+               .ops = &drm_gem_prime_dmabuf_ops,
+               .size = obj->size,
+               .flags = flags,
+               .priv = obj,
+       };
 
        if (dev->driver->gem_prime_res_obj)
                exp_info.resv = dev->driver->gem_prime_res_obj(obj);
 
-       return dma_buf_export(&exp_info);
+       return drm_gem_dmabuf_export(dev, &exp_info);
 }
 EXPORT_SYMBOL(drm_gem_prime_export);
 
@@ -759,12 +853,13 @@ EXPORT_SYMBOL(drm_prime_gem_destroy);
 
 void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
 {
-       INIT_LIST_HEAD(&prime_fpriv->head);
        mutex_init(&prime_fpriv->lock);
+       prime_fpriv->dmabufs = RB_ROOT;
+       prime_fpriv->handles = RB_ROOT;
 }
 
 void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
 {
        /* by now drm_gem_release should've made sure the list is empty */
-       WARN_ON(!list_empty(&prime_fpriv->head));
+       WARN_ON(!RB_EMPTY_ROOT(&prime_fpriv->dmabufs));
 }
index a0df377..f6b64d7 100644 (file)
@@ -129,6 +129,7 @@ void drm_kms_helper_poll_enable_locked(struct drm_device *dev)
 {
        bool poll = false;
        struct drm_connector *connector;
+       unsigned long delay = DRM_OUTPUT_POLL_PERIOD;
 
        WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
@@ -141,8 +142,13 @@ void drm_kms_helper_poll_enable_locked(struct drm_device *dev)
                        poll = true;
        }
 
+       if (dev->mode_config.delayed_event) {
+               poll = true;
+               delay = 0;
+       }
+
        if (poll)
-               schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD);
+               schedule_delayed_work(&dev->mode_config.output_poll_work, delay);
 }
 EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked);
 
diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c
new file mode 100644 (file)
index 0000000..a4d81cf
--- /dev/null
@@ -0,0 +1,912 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include <drm/drmP.h>
+#include <drm/drm_property.h>
+
+#include "drm_crtc_internal.h"
+
+/**
+ * DOC: overview
+ *
+ * Properties as represented by &drm_property are used to extend the modeset
+ * interface exposed to userspace. For the atomic modeset IOCTL properties are
+ * even the only way to transport metadata about the desired new modeset
+ * configuration from userspace to the kernel. Properties have a well-defined
+ * value range, which is enforced by the drm core. See the documentation of the
+ * flags member of struct &drm_property for an overview of the different
+ * property types and ranges.
+ *
+ * Properties don't store the current value directly, but need to be
+ * instatiated by attaching them to a &drm_mode_object with
+ * 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
+ *
+ * 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
+ * IOCTL and in the get/set property IOCTL.
+ */
+
+static bool drm_property_type_valid(struct drm_property *property)
+{
+       if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+               return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+       return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+}
+
+/**
+ * drm_property_create - create a new property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @num_values: number of pre-defined values
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy(), which is done automatically when calling
+ * drm_mode_config_cleanup().
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create(struct drm_device *dev, int flags,
+                                        const char *name, int num_values)
+{
+       struct drm_property *property = NULL;
+       int ret;
+
+       property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
+       if (!property)
+               return NULL;
+
+       property->dev = dev;
+
+       if (num_values) {
+               property->values = kcalloc(num_values, sizeof(uint64_t),
+                                          GFP_KERNEL);
+               if (!property->values)
+                       goto fail;
+       }
+
+       ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
+       if (ret)
+               goto fail;
+
+       property->flags = flags;
+       property->num_values = num_values;
+       INIT_LIST_HEAD(&property->enum_list);
+
+       if (name) {
+               strncpy(property->name, name, DRM_PROP_NAME_LEN);
+               property->name[DRM_PROP_NAME_LEN-1] = '\0';
+       }
+
+       list_add_tail(&property->head, &dev->mode_config.property_list);
+
+       WARN_ON(!drm_property_type_valid(property));
+
+       return property;
+fail:
+       kfree(property->values);
+       kfree(property);
+       return NULL;
+}
+EXPORT_SYMBOL(drm_property_create);
+
+/**
+ * drm_property_create_enum - create a new enumeration property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @props: enumeration lists with property values
+ * @num_values: number of pre-defined values
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy(), which is done automatically when calling
+ * drm_mode_config_cleanup().
+ *
+ * Userspace is only allowed to set one of the predefined values for enumeration
+ * properties.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
+                                        const char *name,
+                                        const struct drm_prop_enum_list *props,
+                                        int num_values)
+{
+       struct drm_property *property;
+       int i, ret;
+
+       flags |= DRM_MODE_PROP_ENUM;
+
+       property = drm_property_create(dev, flags, name, num_values);
+       if (!property)
+               return NULL;
+
+       for (i = 0; i < num_values; i++) {
+               ret = drm_property_add_enum(property, i,
+                                     props[i].type,
+                                     props[i].name);
+               if (ret) {
+                       drm_property_destroy(dev, property);
+                       return NULL;
+               }
+       }
+
+       return property;
+}
+EXPORT_SYMBOL(drm_property_create_enum);
+
+/**
+ * drm_property_create_bitmask - create a new bitmask property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @props: enumeration lists with property bitflags
+ * @num_props: size of the @props array
+ * @supported_bits: bitmask of all supported enumeration values
+ *
+ * This creates a new bitmask drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy(), which is done automatically when calling
+ * drm_mode_config_cleanup().
+ *
+ * Compared to plain enumeration properties userspace is allowed to set any
+ * or'ed together combination of the predefined property bitflag values
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
+                                        int flags, const char *name,
+                                        const struct drm_prop_enum_list *props,
+                                        int num_props,
+                                        uint64_t supported_bits)
+{
+       struct drm_property *property;
+       int i, ret, index = 0;
+       int num_values = hweight64(supported_bits);
+
+       flags |= DRM_MODE_PROP_BITMASK;
+
+       property = drm_property_create(dev, flags, name, num_values);
+       if (!property)
+               return NULL;
+       for (i = 0; i < num_props; i++) {
+               if (!(supported_bits & (1ULL << props[i].type)))
+                       continue;
+
+               if (WARN_ON(index >= num_values)) {
+                       drm_property_destroy(dev, property);
+                       return NULL;
+               }
+
+               ret = drm_property_add_enum(property, index++,
+                                     props[i].type,
+                                     props[i].name);
+               if (ret) {
+                       drm_property_destroy(dev, property);
+                       return NULL;
+               }
+       }
+
+       return property;
+}
+EXPORT_SYMBOL(drm_property_create_bitmask);
+
+static struct drm_property *property_create_range(struct drm_device *dev,
+                                        int flags, const char *name,
+                                        uint64_t min, uint64_t max)
+{
+       struct drm_property *property;
+
+       property = drm_property_create(dev, flags, name, 2);
+       if (!property)
+               return NULL;
+
+       property->values[0] = min;
+       property->values[1] = max;
+
+       return property;
+}
+
+/**
+ * drm_property_create_range - create a new unsigned ranged property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @min: minimum value of the property
+ * @max: maximum value of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy(), which is done automatically when calling
+ * drm_mode_config_cleanup().
+ *
+ * Userspace is allowed to set any unsigned integer value in the (min, max)
+ * range inclusive.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
+                                        const char *name,
+                                        uint64_t min, uint64_t max)
+{
+       return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
+                       name, min, max);
+}
+EXPORT_SYMBOL(drm_property_create_range);
+
+/**
+ * drm_property_create_signed_range - create a new signed ranged property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @min: minimum value of the property
+ * @max: maximum value of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy(), which is done automatically when calling
+ * drm_mode_config_cleanup().
+ *
+ * Userspace is allowed to set any signed integer value in the (min, max)
+ * range inclusive.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
+                                        int flags, const char *name,
+                                        int64_t min, int64_t max)
+{
+       return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
+                       name, I642U64(min), I642U64(max));
+}
+EXPORT_SYMBOL(drm_property_create_signed_range);
+
+/**
+ * drm_property_create_object - create a new object property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @type: object type from DRM_MODE_OBJECT_* defines
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy(), which is done automatically when calling
+ * drm_mode_config_cleanup().
+ *
+ * Userspace is only allowed to set this to any property value of the given
+ * @type. Only useful for atomic properties, which is enforced.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_object(struct drm_device *dev,
+                                               int flags, const char *name,
+                                               uint32_t type)
+{
+       struct drm_property *property;
+
+       flags |= DRM_MODE_PROP_OBJECT;
+
+       if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
+               return NULL;
+
+       property = drm_property_create(dev, flags, name, 1);
+       if (!property)
+               return NULL;
+
+       property->values[0] = type;
+
+       return property;
+}
+EXPORT_SYMBOL(drm_property_create_object);
+
+/**
+ * drm_property_create_bool - create a new boolean property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy(), which is done automatically when calling
+ * drm_mode_config_cleanup().
+ *
+ * This is implemented as a ranged property with only {0, 1} as valid values.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
+                                             const char *name)
+{
+       return drm_property_create_range(dev, flags, name, 0, 1);
+}
+EXPORT_SYMBOL(drm_property_create_bool);
+
+/**
+ * drm_property_add_enum - add a possible value to an enumeration property
+ * @property: enumeration property to change
+ * @index: index of the new enumeration
+ * @value: value of the new enumeration
+ * @name: symbolic name of the new enumeration
+ *
+ * This functions adds enumerations to a property.
+ *
+ * It's use is deprecated, drivers should use one of the more specific helpers
+ * to directly create the property with all enumerations already attached.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_property_add_enum(struct drm_property *property, int index,
+                         uint64_t value, const char *name)
+{
+       struct drm_property_enum *prop_enum;
+
+       if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+                       drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
+               return -EINVAL;
+
+       /*
+        * Bitmask enum properties have the additional constraint of values
+        * from 0 to 63
+        */
+       if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
+                       (value > 63))
+               return -EINVAL;
+
+       if (!list_empty(&property->enum_list)) {
+               list_for_each_entry(prop_enum, &property->enum_list, head) {
+                       if (prop_enum->value == value) {
+                               strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
+                               prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
+                               return 0;
+                       }
+               }
+       }
+
+       prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
+       if (!prop_enum)
+               return -ENOMEM;
+
+       strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
+       prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
+       prop_enum->value = value;
+
+       property->values[index] = value;
+       list_add_tail(&prop_enum->head, &property->enum_list);
+       return 0;
+}
+EXPORT_SYMBOL(drm_property_add_enum);
+
+/**
+ * drm_property_destroy - destroy a drm property
+ * @dev: drm device
+ * @property: property to destry
+ *
+ * This function frees a property including any attached resources like
+ * enumeration values.
+ */
+void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
+{
+       struct drm_property_enum *prop_enum, *pt;
+
+       list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
+               list_del(&prop_enum->head);
+               kfree(prop_enum);
+       }
+
+       if (property->num_values)
+               kfree(property->values);
+       drm_mode_object_unregister(dev, &property->base);
+       list_del(&property->head);
+       kfree(property);
+}
+EXPORT_SYMBOL(drm_property_destroy);
+
+int drm_mode_getproperty_ioctl(struct drm_device *dev,
+                              void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_get_property *out_resp = data;
+       struct drm_property *property;
+       int enum_count = 0;
+       int value_count = 0;
+       int ret = 0, i;
+       int copied;
+       struct drm_property_enum *prop_enum;
+       struct drm_mode_property_enum __user *enum_ptr;
+       uint64_t __user *values_ptr;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       drm_modeset_lock_all(dev);
+       property = drm_property_find(dev, out_resp->prop_id);
+       if (!property) {
+               ret = -ENOENT;
+               goto done;
+       }
+
+       if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+                       drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
+               list_for_each_entry(prop_enum, &property->enum_list, head)
+                       enum_count++;
+       }
+
+       value_count = property->num_values;
+
+       strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
+       out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
+       out_resp->flags = property->flags;
+
+       if ((out_resp->count_values >= value_count) && value_count) {
+               values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr;
+               for (i = 0; i < value_count; i++) {
+                       if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
+                               ret = -EFAULT;
+                               goto done;
+                       }
+               }
+       }
+       out_resp->count_values = value_count;
+
+       if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+                       drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
+               if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
+                       copied = 0;
+                       enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
+                       list_for_each_entry(prop_enum, &property->enum_list, head) {
+
+                               if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+
+                               if (copy_to_user(&enum_ptr[copied].name,
+                                                &prop_enum->name, DRM_PROP_NAME_LEN)) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+                               copied++;
+                       }
+               }
+               out_resp->count_enum_blobs = enum_count;
+       }
+
+       /*
+        * NOTE: The idea seems to have been to use this to read all the blob
+        * property values. But nothing ever added them to the corresponding
+        * list, userspace always used the special-purpose get_blob ioctl to
+        * read the value for a blob property. It also doesn't make a lot of
+        * sense to return values here when everything else is just metadata for
+        * the property itself.
+        */
+       if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
+               out_resp->count_enum_blobs = 0;
+done:
+       drm_modeset_unlock_all(dev);
+       return ret;
+}
+
+static void drm_property_free_blob(struct kref *kref)
+{
+       struct drm_property_blob *blob =
+               container_of(kref, struct drm_property_blob, base.refcount);
+
+       mutex_lock(&blob->dev->mode_config.blob_lock);
+       list_del(&blob->head_global);
+       mutex_unlock(&blob->dev->mode_config.blob_lock);
+
+       drm_mode_object_unregister(blob->dev, &blob->base);
+
+       kfree(blob);
+}
+
+/**
+ * drm_property_create_blob - Create new blob property
+ * @dev: DRM device to create property for
+ * @length: Length to allocate for blob data
+ * @data: If specified, copies data into blob
+ *
+ * Creates a new blob property for a specified DRM device, optionally
+ * copying data. Note that blob properties are meant to be invariant, hence the
+ * data must be filled out before the blob is used as the value of any property.
+ *
+ * Returns:
+ * New blob property with a single reference on success, or an ERR_PTR
+ * value on failure.
+ */
+struct drm_property_blob *
+drm_property_create_blob(struct drm_device *dev, size_t length,
+                        const void *data)
+{
+       struct drm_property_blob *blob;
+       int ret;
+
+       if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob))
+               return ERR_PTR(-EINVAL);
+
+       blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
+       if (!blob)
+               return ERR_PTR(-ENOMEM);
+
+       /* This must be explicitly initialised, so we can safely call list_del
+        * on it in the removal handler, even if it isn't in a file list. */
+       INIT_LIST_HEAD(&blob->head_file);
+       blob->length = length;
+       blob->dev = dev;
+
+       if (data)
+               memcpy(blob->data, data, length);
+
+       ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
+                                     true, drm_property_free_blob);
+       if (ret) {
+               kfree(blob);
+               return ERR_PTR(-EINVAL);
+       }
+
+       mutex_lock(&dev->mode_config.blob_lock);
+       list_add_tail(&blob->head_global,
+                     &dev->mode_config.property_blob_list);
+       mutex_unlock(&dev->mode_config.blob_lock);
+
+       return blob;
+}
+EXPORT_SYMBOL(drm_property_create_blob);
+
+/**
+ * drm_property_unreference_blob - Unreference a blob property
+ * @blob: Pointer to blob property
+ *
+ * Drop a reference on a blob property. May free the object.
+ */
+void drm_property_unreference_blob(struct drm_property_blob *blob)
+{
+       if (!blob)
+               return;
+
+       drm_mode_object_unreference(&blob->base);
+}
+EXPORT_SYMBOL(drm_property_unreference_blob);
+
+void drm_property_destroy_user_blobs(struct drm_device *dev,
+                                    struct drm_file *file_priv)
+{
+       struct drm_property_blob *blob, *bt;
+
+       /*
+        * When the file gets released that means no one else can access the
+        * blob list any more, so no need to grab dev->blob_lock.
+        */
+       list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
+               list_del_init(&blob->head_file);
+               drm_property_unreference_blob(blob);
+       }
+}
+
+/**
+ * drm_property_reference_blob - Take a reference on an existing property
+ * @blob: Pointer to blob property
+ *
+ * Take a new reference on an existing blob property. Returns @blob, which
+ * allows this to be used as a shorthand in assignments.
+ */
+struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob)
+{
+       drm_mode_object_reference(&blob->base);
+       return blob;
+}
+EXPORT_SYMBOL(drm_property_reference_blob);
+
+/**
+ * drm_property_lookup_blob - look up a blob property and take a reference
+ * @dev: drm device
+ * @id: id of the blob property
+ *
+ * If successful, this takes an additional reference to the blob property.
+ * callers need to make sure to eventually unreference the returned property
+ * again, using @drm_property_unreference_blob.
+ *
+ * Return:
+ * NULL on failure, pointer to the blob on success.
+ */
+struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
+                                                  uint32_t id)
+{
+       struct drm_mode_object *obj;
+       struct drm_property_blob *blob = NULL;
+
+       obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB);
+       if (obj)
+               blob = obj_to_blob(obj);
+       return blob;
+}
+EXPORT_SYMBOL(drm_property_lookup_blob);
+
+/**
+ * drm_property_replace_global_blob - replace existing blob property
+ * @dev: drm device
+ * @replace: location of blob property pointer to be replaced
+ * @length: length of data for new blob, or 0 for no data
+ * @data: content for new blob, or NULL for no data
+ * @obj_holds_id: optional object for property holding blob ID
+ * @prop_holds_id: optional property holding blob ID
+ * @return 0 on success or error on failure
+ *
+ * This function will replace a global property in the blob list, optionally
+ * updating a property which holds the ID of that property.
+ *
+ * If length is 0 or data is NULL, no new blob will be created, and the holding
+ * property, if specified, will be set to 0.
+ *
+ * Access to the replace pointer is assumed to be protected by the caller, e.g.
+ * by holding the relevant modesetting object lock for its parent.
+ *
+ * For example, a drm_connector has a 'PATH' property, which contains the ID
+ * of a blob property with the value of the MST path information. Calling this
+ * function with replace pointing to the connector's path_blob_ptr, length and
+ * data set for the new path information, obj_holds_id set to the connector's
+ * base object, and prop_holds_id set to the path property name, will perform
+ * a completely atomic update. The access to path_blob_ptr is protected by the
+ * caller holding a lock on the connector.
+ */
+int drm_property_replace_global_blob(struct drm_device *dev,
+                                    struct drm_property_blob **replace,
+                                    size_t length,
+                                    const void *data,
+                                    struct drm_mode_object *obj_holds_id,
+                                    struct drm_property *prop_holds_id)
+{
+       struct drm_property_blob *new_blob = NULL;
+       struct drm_property_blob *old_blob = NULL;
+       int ret;
+
+       WARN_ON(replace == NULL);
+
+       old_blob = *replace;
+
+       if (length && data) {
+               new_blob = drm_property_create_blob(dev, length, data);
+               if (IS_ERR(new_blob))
+                       return PTR_ERR(new_blob);
+       }
+
+       if (obj_holds_id) {
+               ret = drm_object_property_set_value(obj_holds_id,
+                                                   prop_holds_id,
+                                                   new_blob ?
+                                                       new_blob->base.id : 0);
+               if (ret != 0)
+                       goto err_created;
+       }
+
+       drm_property_unreference_blob(old_blob);
+       *replace = new_blob;
+
+       return 0;
+
+err_created:
+       drm_property_unreference_blob(new_blob);
+       return ret;
+}
+EXPORT_SYMBOL(drm_property_replace_global_blob);
+
+int drm_mode_getblob_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_get_blob *out_resp = data;
+       struct drm_property_blob *blob;
+       int ret = 0;
+       void __user *blob_ptr;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       blob = drm_property_lookup_blob(dev, out_resp->blob_id);
+       if (!blob)
+               return -ENOENT;
+
+       if (out_resp->length == blob->length) {
+               blob_ptr = (void __user *)(unsigned long)out_resp->data;
+               if (copy_to_user(blob_ptr, blob->data, blob->length)) {
+                       ret = -EFAULT;
+                       goto unref;
+               }
+       }
+       out_resp->length = blob->length;
+unref:
+       drm_property_unreference_blob(blob);
+
+       return ret;
+}
+
+int drm_mode_createblob_ioctl(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_create_blob *out_resp = data;
+       struct drm_property_blob *blob;
+       void __user *blob_ptr;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       blob = drm_property_create_blob(dev, out_resp->length, NULL);
+       if (IS_ERR(blob))
+               return PTR_ERR(blob);
+
+       blob_ptr = (void __user *)(unsigned long)out_resp->data;
+       if (copy_from_user(blob->data, blob_ptr, out_resp->length)) {
+               ret = -EFAULT;
+               goto out_blob;
+       }
+
+       /* Dropping the lock between create_blob and our access here is safe
+        * as only the same file_priv can remove the blob; at this point, it is
+        * not associated with any file_priv. */
+       mutex_lock(&dev->mode_config.blob_lock);
+       out_resp->blob_id = blob->base.id;
+       list_add_tail(&blob->head_file, &file_priv->blobs);
+       mutex_unlock(&dev->mode_config.blob_lock);
+
+       return 0;
+
+out_blob:
+       drm_property_unreference_blob(blob);
+       return ret;
+}
+
+int drm_mode_destroyblob_ioctl(struct drm_device *dev,
+                              void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_destroy_blob *out_resp = data;
+       struct drm_property_blob *blob = NULL, *bt;
+       bool found = false;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       blob = drm_property_lookup_blob(dev, out_resp->blob_id);
+       if (!blob)
+               return -ENOENT;
+
+       mutex_lock(&dev->mode_config.blob_lock);
+       /* Ensure the property was actually created by this user. */
+       list_for_each_entry(bt, &file_priv->blobs, head_file) {
+               if (bt == blob) {
+                       found = true;
+                       break;
+               }
+       }
+
+       if (!found) {
+               ret = -EPERM;
+               goto err;
+       }
+
+       /* We must drop head_file here, because we may not be the last
+        * reference on the blob. */
+       list_del_init(&blob->head_file);
+       mutex_unlock(&dev->mode_config.blob_lock);
+
+       /* One reference from lookup, and one from the filp. */
+       drm_property_unreference_blob(blob);
+       drm_property_unreference_blob(blob);
+
+       return 0;
+
+err:
+       mutex_unlock(&dev->mode_config.blob_lock);
+       drm_property_unreference_blob(blob);
+
+       return ret;
+}
+
+/* Some properties could refer to dynamic refcnt'd objects, or things that
+ * need special locking to handle lifetime issues (ie. to ensure the prop
+ * value doesn't become invalid part way through the property update due to
+ * race).  The value returned by reference via 'obj' should be passed back
+ * to drm_property_change_valid_put() after the property is set (and the
+ * object to which the property is attached has a chance to take it's own
+ * reference).
+ */
+bool drm_property_change_valid_get(struct drm_property *property,
+                                  uint64_t value, struct drm_mode_object **ref)
+{
+       int i;
+
+       if (property->flags & DRM_MODE_PROP_IMMUTABLE)
+               return false;
+
+       *ref = NULL;
+
+       if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
+               if (value < property->values[0] || value > property->values[1])
+                       return false;
+               return true;
+       } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
+               int64_t svalue = U642I64(value);
+
+               if (svalue < U642I64(property->values[0]) ||
+                               svalue > U642I64(property->values[1]))
+                       return false;
+               return true;
+       } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
+               uint64_t valid_mask = 0;
+
+               for (i = 0; i < property->num_values; i++)
+                       valid_mask |= (1ULL << property->values[i]);
+               return !(value & ~valid_mask);
+       } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
+               struct drm_property_blob *blob;
+
+               if (value == 0)
+                       return true;
+
+               blob = drm_property_lookup_blob(property->dev, value);
+               if (blob) {
+                       *ref = &blob->base;
+                       return true;
+               } else {
+                       return false;
+               }
+       } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
+               /* a zero value for an object property translates to null: */
+               if (value == 0)
+                       return true;
+
+               *ref = __drm_mode_object_find(property->dev, value,
+                                             property->values[0]);
+               return *ref != NULL;
+       }
+
+       for (i = 0; i < property->num_values; i++)
+               if (property->values[i] == value)
+                       return true;
+       return false;
+}
+
+void drm_property_change_valid_put(struct drm_property *property,
+               struct drm_mode_object *ref)
+{
+       if (!ref)
+               return;
+
+       if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
+               drm_mode_object_unreference(ref);
+       } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
+               drm_property_unreference_blob(obj_to_blob(ref));
+}
index a8e2c86..73e53a8 100644 (file)
@@ -100,7 +100,7 @@ static int drm_calc_scale(int src, int dst)
 {
        int scale = 0;
 
-       if (src < 0 || dst < 0)
+       if (WARN_ON(src < 0 || dst < 0))
                return -EINVAL;
 
        if (dst == 0)
@@ -317,38 +317,38 @@ void drm_rect_rotate(struct drm_rect *r,
 {
        struct drm_rect tmp;
 
-       if (rotation & (BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y))) {
+       if (rotation & (DRM_REFLECT_X | DRM_REFLECT_Y)) {
                tmp = *r;
 
-               if (rotation & BIT(DRM_REFLECT_X)) {
+               if (rotation & DRM_REFLECT_X) {
                        r->x1 = width - tmp.x2;
                        r->x2 = width - tmp.x1;
                }
 
-               if (rotation & BIT(DRM_REFLECT_Y)) {
+               if (rotation & DRM_REFLECT_Y) {
                        r->y1 = height - tmp.y2;
                        r->y2 = height - tmp.y1;
                }
        }
 
        switch (rotation & DRM_ROTATE_MASK) {
-       case BIT(DRM_ROTATE_0):
+       case DRM_ROTATE_0:
                break;
-       case BIT(DRM_ROTATE_90):
+       case DRM_ROTATE_90:
                tmp = *r;
                r->x1 = tmp.y1;
                r->x2 = tmp.y2;
                r->y1 = width - tmp.x2;
                r->y2 = width - tmp.x1;
                break;
-       case BIT(DRM_ROTATE_180):
+       case DRM_ROTATE_180:
                tmp = *r;
                r->x1 = width - tmp.x2;
                r->x2 = width - tmp.x1;
                r->y1 = height - tmp.y2;
                r->y2 = height - tmp.y1;
                break;
-       case BIT(DRM_ROTATE_270):
+       case DRM_ROTATE_270:
                tmp = *r;
                r->x1 = height - tmp.y2;
                r->x2 = height - tmp.y1;
@@ -392,23 +392,23 @@ void drm_rect_rotate_inv(struct drm_rect *r,
        struct drm_rect tmp;
 
        switch (rotation & DRM_ROTATE_MASK) {
-       case BIT(DRM_ROTATE_0):
+       case DRM_ROTATE_0:
                break;
-       case BIT(DRM_ROTATE_90):
+       case DRM_ROTATE_90:
                tmp = *r;
                r->x1 = width - tmp.y2;
                r->x2 = width - tmp.y1;
                r->y1 = tmp.x1;
                r->y2 = tmp.x2;
                break;
-       case BIT(DRM_ROTATE_180):
+       case DRM_ROTATE_180:
                tmp = *r;
                r->x1 = width - tmp.x2;
                r->x2 = width - tmp.x1;
                r->y1 = height - tmp.y2;
                r->y2 = height - tmp.y1;
                break;
-       case BIT(DRM_ROTATE_270):
+       case DRM_ROTATE_270:
                tmp = *r;
                r->x1 = tmp.y1;
                r->x2 = tmp.y2;
@@ -419,15 +419,15 @@ void drm_rect_rotate_inv(struct drm_rect *r,
                break;
        }
 
-       if (rotation & (BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y))) {
+       if (rotation & (DRM_REFLECT_X | DRM_REFLECT_Y)) {
                tmp = *r;
 
-               if (rotation & BIT(DRM_REFLECT_X)) {
+               if (rotation & DRM_REFLECT_X) {
                        r->x1 = width - tmp.x2;
                        r->x2 = width - tmp.x1;
                }
 
-               if (rotation & BIT(DRM_REFLECT_Y)) {
+               if (rotation & DRM_REFLECT_Y) {
                        r->y1 = height - tmp.y2;
                        r->y2 = height - tmp.y1;
                }
index bf70431..275bca4 100644 (file)
@@ -68,7 +68,7 @@ static void drm_sg_cleanup(struct drm_sg_mem * entry)
 void drm_legacy_sg_cleanup(struct drm_device *dev)
 {
        if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg &&
-           !drm_core_check_feature(dev, DRIVER_MODESET)) {
+           drm_core_check_feature(dev, DRIVER_LEGACY)) {
                drm_sg_cleanup(dev->sg);
                dev->sg = NULL;
        }
@@ -88,7 +88,7 @@ int drm_legacy_sg_alloc(struct drm_device *dev, void *data,
 
        DRM_DEBUG("\n");
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (!drm_core_check_feature(dev, DRIVER_SG))
@@ -201,7 +201,7 @@ int drm_legacy_sg_free(struct drm_device *dev, void *data,
        struct drm_scatter_gather *request = data;
        struct drm_sg_mem *entry;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (!drm_core_check_feature(dev, DRIVER_LEGACY))
                return -EINVAL;
 
        if (!drm_core_check_feature(dev, DRIVER_SG))
index 0db36d2..7bae08c 100644 (file)
@@ -34,6 +34,12 @@ static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = {
        .destroy = drm_encoder_cleanup,
 };
 
+static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
+                                    struct drm_crtc_state *state)
+{
+       return drm_atomic_add_affected_planes(state->state, crtc);
+}
+
 static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_simple_display_pipe *pipe;
@@ -57,6 +63,7 @@ static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc)
 }
 
 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
+       .atomic_check = drm_simple_kms_crtc_check,
        .disable = drm_simple_kms_crtc_disable,
        .enable = drm_simple_kms_crtc_enable,
 };
@@ -73,22 +80,9 @@ static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
 static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
                                        struct drm_plane_state *plane_state)
 {
-       struct drm_rect src = {
-               .x1 = plane_state->src_x,
-               .y1 = plane_state->src_y,
-               .x2 = plane_state->src_x + plane_state->src_w,
-               .y2 = plane_state->src_y + plane_state->src_h,
-       };
-       struct drm_rect dest = {
-               .x1 = plane_state->crtc_x,
-               .y1 = plane_state->crtc_y,
-               .x2 = plane_state->crtc_x + plane_state->crtc_w,
-               .y2 = plane_state->crtc_y + plane_state->crtc_h,
-       };
        struct drm_rect clip = { 0 };
        struct drm_simple_display_pipe *pipe;
        struct drm_crtc_state *crtc_state;
-       bool visible;
        int ret;
 
        pipe = container_of(plane, struct drm_simple_display_pipe, plane);
@@ -102,17 +96,15 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
 
        clip.x2 = crtc_state->adjusted_mode.hdisplay;
        clip.y2 = crtc_state->adjusted_mode.vdisplay;
-       ret = drm_plane_helper_check_update(plane, &pipe->crtc,
-                                           plane_state->fb,
-                                           &src, &dest, &clip,
-                                           plane_state->rotation,
-                                           DRM_PLANE_HELPER_NO_SCALING,
-                                           DRM_PLANE_HELPER_NO_SCALING,
-                                           false, true, &visible);
+
+       ret = drm_plane_helper_check_state(plane_state, &clip,
+                                          DRM_PLANE_HELPER_NO_SCALING,
+                                          DRM_PLANE_HELPER_NO_SCALING,
+                                          false, true);
        if (ret)
                return ret;
 
-       if (!visible)
+       if (!plane_state->visible)
                return -EINVAL;
 
        if (!pipe->funcs || !pipe->funcs->check)
@@ -133,7 +125,33 @@ static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
        pipe->funcs->update(pipe, pstate);
 }
 
+static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
+                                          struct drm_plane_state *state)
+{
+       struct drm_simple_display_pipe *pipe;
+
+       pipe = container_of(plane, struct drm_simple_display_pipe, plane);
+       if (!pipe->funcs || !pipe->funcs->prepare_fb)
+               return 0;
+
+       return pipe->funcs->prepare_fb(pipe, state);
+}
+
+static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
+                                           struct drm_plane_state *state)
+{
+       struct drm_simple_display_pipe *pipe;
+
+       pipe = container_of(plane, struct drm_simple_display_pipe, plane);
+       if (!pipe->funcs || !pipe->funcs->cleanup_fb)
+               return;
+
+       pipe->funcs->cleanup_fb(pipe, state);
+}
+
 static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
+       .prepare_fb = drm_simple_kms_plane_prepare_fb,
+       .cleanup_fb = drm_simple_kms_plane_cleanup_fb,
        .atomic_check = drm_simple_kms_plane_atomic_check,
        .atomic_update = drm_simple_kms_plane_atomic_update,
 };
@@ -147,17 +165,62 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
        .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
 };
 
+/**
+ * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
+ * @pipe: simple display pipe object
+ * @bridge: bridge to attach
+ *
+ * Makes it possible to still use the drm_simple_display_pipe helpers when
+ * a DRM bridge has to be used.
+ *
+ * Note that you probably want to initialize the pipe by passing a NULL
+ * connector to drm_simple_display_pipe_init().
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
+                                         struct drm_bridge *bridge)
+{
+       bridge->encoder = &pipe->encoder;
+       pipe->encoder.bridge = bridge;
+       return drm_bridge_attach(pipe->encoder.dev, bridge);
+}
+EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
+
+/**
+ * drm_simple_display_pipe_detach_bridge - Detach the bridge from the display pipe
+ * @pipe: simple display pipe object
+ *
+ * Detaches the drm bridge previously attached with
+ * drm_simple_display_pipe_attach_bridge()
+ */
+void drm_simple_display_pipe_detach_bridge(struct drm_simple_display_pipe *pipe)
+{
+       if (WARN_ON(!pipe->encoder.bridge))
+               return;
+
+       drm_bridge_detach(pipe->encoder.bridge);
+       pipe->encoder.bridge = NULL;
+}
+EXPORT_SYMBOL(drm_simple_display_pipe_detach_bridge);
+
 /**
  * drm_simple_display_pipe_init - Initialize a simple display pipeline
  * @dev: DRM device
  * @pipe: simple display pipe object to initialize
  * @funcs: callbacks for the display pipe (optional)
- * @formats: array of supported formats (%DRM_FORMAT_*)
+ * @formats: array of supported formats (DRM_FORMAT\_\*)
  * @format_count: number of elements in @formats
- * @connector: connector to attach and register
+ * @connector: connector to attach and register (optional)
  *
  * Sets up a display pipeline which consist of a really simple
- * plane-crtc-encoder pipe coupled with the provided connector.
+ * plane-crtc-encoder pipe.
+ *
+ * If a connector is supplied, the pipe will be coupled with the provided
+ * connector. You may supply a NULL connector when using drm bridges, that
+ * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
+ *
  * Teardown of a simple display pipe is all handled automatically by the drm
  * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
  * release the memory for the structure themselves.
@@ -196,7 +259,7 @@ int drm_simple_display_pipe_init(struct drm_device *dev,
        encoder->possible_crtcs = 1 << drm_crtc_index(crtc);
        ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs,
                               DRM_MODE_ENCODER_NONE, NULL);
-       if (ret)
+       if (ret || !connector)
                return ret;
 
        return drm_mode_connector_attach_encoder(connector, encoder);
index 32dd821..9a37196 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/export.h>
 
 #include <drm/drm_sysfs.h>
-#include <drm/drm_core.h>
 #include <drm/drmP.h>
 #include "drm_internal.h"
 
@@ -37,12 +36,7 @@ static char *drm_devnode(struct device *dev, umode_t *mode)
        return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
 }
 
-static CLASS_ATTR_STRING(version, S_IRUGO,
-               CORE_NAME " "
-               __stringify(CORE_MAJOR) "."
-               __stringify(CORE_MINOR) "."
-               __stringify(CORE_PATCHLEVEL) " "
-               CORE_DATE);
+static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810");
 
 /**
  * drm_sysfs_init - initialize sysfs helpers
index f306c88..20cc33d 100644 (file)
@@ -25,7 +25,6 @@
 #include <drm/drmP.h>
 #include <drm/drm_mm.h>
 #include <drm/drm_vma_manager.h>
-#include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/rbtree.h>
@@ -86,7 +85,6 @@ void drm_vma_offset_manager_init(struct drm_vma_offset_manager *mgr,
                                 unsigned long page_offset, unsigned long size)
 {
        rwlock_init(&mgr->vm_lock);
-       mgr->vm_addr_space_rb = RB_ROOT;
        drm_mm_init(&mgr->vm_addr_space_mm, page_offset, size);
 }
 EXPORT_SYMBOL(drm_vma_offset_manager_init);
@@ -145,16 +143,16 @@ struct drm_vma_offset_node *drm_vma_offset_lookup_locked(struct drm_vma_offset_m
                                                         unsigned long start,
                                                         unsigned long pages)
 {
-       struct drm_vma_offset_node *node, *best;
+       struct drm_mm_node *node, *best;
        struct rb_node *iter;
        unsigned long offset;
 
-       iter = mgr->vm_addr_space_rb.rb_node;
+       iter = mgr->vm_addr_space_mm.interval_tree.rb_node;
        best = NULL;
 
        while (likely(iter)) {
-               node = rb_entry(iter, struct drm_vma_offset_node, vm_rb);
-               offset = node->vm_node.start;
+               node = rb_entry(iter, struct drm_mm_node, rb);
+               offset = node->start;
                if (start >= offset) {
                        iter = iter->rb_right;
                        best = node;
@@ -167,38 +165,17 @@ struct drm_vma_offset_node *drm_vma_offset_lookup_locked(struct drm_vma_offset_m
 
        /* verify that the node spans the requested area */
        if (best) {
-               offset = best->vm_node.start + best->vm_node.size;
+               offset = best->start + best->size;
                if (offset < start + pages)
                        best = NULL;
        }
 
-       return best;
-}
-EXPORT_SYMBOL(drm_vma_offset_lookup_locked);
-
-/* internal helper to link @node into the rb-tree */
-static void _drm_vma_offset_add_rb(struct drm_vma_offset_manager *mgr,
-                                  struct drm_vma_offset_node *node)
-{
-       struct rb_node **iter = &mgr->vm_addr_space_rb.rb_node;
-       struct rb_node *parent = NULL;
-       struct drm_vma_offset_node *iter_node;
-
-       while (likely(*iter)) {
-               parent = *iter;
-               iter_node = rb_entry(*iter, struct drm_vma_offset_node, vm_rb);
+       if (!best)
+               return NULL;
 
-               if (node->vm_node.start < iter_node->vm_node.start)
-                       iter = &(*iter)->rb_left;
-               else if (node->vm_node.start > iter_node->vm_node.start)
-                       iter = &(*iter)->rb_right;
-               else
-                       BUG();
-       }
-
-       rb_link_node(&node->vm_rb, parent, iter);
-       rb_insert_color(&node->vm_rb, &mgr->vm_addr_space_rb);
+       return container_of(best, struct drm_vma_offset_node, vm_node);
 }
+EXPORT_SYMBOL(drm_vma_offset_lookup_locked);
 
 /**
  * drm_vma_offset_add() - Add offset node to manager
@@ -240,8 +217,6 @@ int drm_vma_offset_add(struct drm_vma_offset_manager *mgr,
        if (ret)
                goto out_unlock;
 
-       _drm_vma_offset_add_rb(mgr, node);
-
 out_unlock:
        write_unlock(&mgr->vm_lock);
        return ret;
@@ -265,7 +240,6 @@ void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr,
        write_lock(&mgr->vm_lock);
 
        if (drm_mm_node_allocated(&node->vm_node)) {
-               rb_erase(&node->vm_rb, &mgr->vm_addr_space_rb);
                drm_mm_remove_node(&node->vm_node);
                memset(&node->vm_node, 0, sizeof(node->vm_node));
        }
@@ -277,9 +251,9 @@ EXPORT_SYMBOL(drm_vma_offset_remove);
 /**
  * drm_vma_node_allow - Add open-file to list of allowed users
  * @node: Node to modify
- * @filp: Open file to add
+ * @tag: Tag of file to remove
  *
- * Add @filp to the list of allowed open-files for this node. If @filp is
+ * Add @tag to the list of allowed open-files for this node. If @tag is
  * already on this list, the ref-count is incremented.
  *
  * The list of allowed-users is preserved across drm_vma_offset_add() and
@@ -294,7 +268,7 @@ EXPORT_SYMBOL(drm_vma_offset_remove);
  * RETURNS:
  * 0 on success, negative error code on internal failure (out-of-mem)
  */
-int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp)
+int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag)
 {
        struct rb_node **iter;
        struct rb_node *parent = NULL;
@@ -315,10 +289,10 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp)
                parent = *iter;
                entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb);
 
-               if (filp == entry->vm_filp) {
+               if (tag == entry->vm_tag) {
                        entry->vm_count++;
                        goto unlock;
-               } else if (filp > entry->vm_filp) {
+               } else if (tag > entry->vm_tag) {
                        iter = &(*iter)->rb_right;
                } else {
                        iter = &(*iter)->rb_left;
@@ -330,7 +304,7 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp)
                goto unlock;
        }
 
-       new->vm_filp = filp;
+       new->vm_tag = tag;
        new->vm_count = 1;
        rb_link_node(&new->vm_rb, parent, iter);
        rb_insert_color(&new->vm_rb, &node->vm_files);
@@ -346,17 +320,18 @@ EXPORT_SYMBOL(drm_vma_node_allow);
 /**
  * drm_vma_node_revoke - Remove open-file from list of allowed users
  * @node: Node to modify
- * @filp: Open file to remove
+ * @tag: Tag of file to remove
  *
- * Decrement the ref-count of @filp in the list of allowed open-files on @node.
- * If the ref-count drops to zero, remove @filp from the list. You must call
- * this once for every drm_vma_node_allow() on @filp.
+ * Decrement the ref-count of @tag in the list of allowed open-files on @node.
+ * If the ref-count drops to zero, remove @tag from the list. You must call
+ * this once for every drm_vma_node_allow() on @tag.
  *
  * This is locked against concurrent access internally.
  *
- * If @filp is not on the list, nothing is done.
+ * If @tag is not on the list, nothing is done.
  */
-void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp)
+void drm_vma_node_revoke(struct drm_vma_offset_node *node,
+                        struct drm_file *tag)
 {
        struct drm_vma_offset_file *entry;
        struct rb_node *iter;
@@ -366,13 +341,13 @@ void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp)
        iter = node->vm_files.rb_node;
        while (likely(iter)) {
                entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb);
-               if (filp == entry->vm_filp) {
+               if (tag == entry->vm_tag) {
                        if (!--entry->vm_count) {
                                rb_erase(&entry->vm_rb, &node->vm_files);
                                kfree(entry);
                        }
                        break;
-               } else if (filp > entry->vm_filp) {
+               } else if (tag > entry->vm_tag) {
                        iter = iter->rb_right;
                } else {
                        iter = iter->rb_left;
@@ -386,9 +361,9 @@ EXPORT_SYMBOL(drm_vma_node_revoke);
 /**
  * drm_vma_node_is_allowed - Check whether an open-file is granted access
  * @node: Node to check
- * @filp: Open-file to check for
+ * @tag: Tag of file to remove
  *
- * Search the list in @node whether @filp is currently on the list of allowed
+ * Search the list in @node whether @tag is currently on the list of allowed
  * open-files (see drm_vma_node_allow()).
  *
  * This is locked against concurrent access internally.
@@ -397,7 +372,7 @@ EXPORT_SYMBOL(drm_vma_node_revoke);
  * true iff @filp is on the list
  */
 bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node,
-                            struct file *filp)
+                            struct drm_file *tag)
 {
        struct drm_vma_offset_file *entry;
        struct rb_node *iter;
@@ -407,9 +382,9 @@ bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node,
        iter = node->vm_files.rb_node;
        while (likely(iter)) {
                entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb);
-               if (filp == entry->vm_filp)
+               if (tag == entry->vm_tag)
                        break;
-               else if (filp > entry->vm_filp)
+               else if (tag > entry->vm_tag)
                        iter = iter->rb_right;
                else
                        iter = iter->rb_left;
index d8d5564..cb86c7e 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "common.xml.h"
 #include "state.xml.h"
+#include "state_hi.xml.h"
 #include "state_3d.xml.h"
 #include "cmdstream.xml.h"
 
@@ -117,11 +118,6 @@ static void etnaviv_cmd_select_pipe(struct etnaviv_gpu *gpu,
                       VIVS_GL_PIPE_SELECT_PIPE(pipe));
 }
 
-static u32 gpu_va(struct etnaviv_gpu *gpu, struct etnaviv_cmdbuf *buf)
-{
-       return buf->paddr - gpu->memory_base;
-}
-
 static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
        struct etnaviv_cmdbuf *buf, u32 off, u32 len)
 {
@@ -129,7 +125,7 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
        u32 *ptr = buf->vaddr + off;
 
        dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n",
-                       ptr, gpu_va(gpu, buf) + off, size - len * 4 - off);
+                       ptr, etnaviv_iommu_get_cmdbuf_va(gpu, buf) + off, size - len * 4 - off);
 
        print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
                        ptr, len * 4, 0);
@@ -162,7 +158,7 @@ static u32 etnaviv_buffer_reserve(struct etnaviv_gpu *gpu,
        if (buffer->user_size + cmd_dwords * sizeof(u64) > buffer->size)
                buffer->user_size = 0;
 
-       return gpu_va(gpu, buffer) + buffer->user_size;
+       return etnaviv_iommu_get_cmdbuf_va(gpu, buffer) + buffer->user_size;
 }
 
 u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
@@ -173,7 +169,41 @@ u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
        buffer->user_size = 0;
 
        CMD_WAIT(buffer);
-       CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + buffer->user_size - 4);
+       CMD_LINK(buffer, 2, etnaviv_iommu_get_cmdbuf_va(gpu, buffer) +
+                buffer->user_size - 4);
+
+       return buffer->user_size / 8;
+}
+
+u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr)
+{
+       struct etnaviv_cmdbuf *buffer = gpu->buffer;
+
+       buffer->user_size = 0;
+
+       if (gpu->identity.features & chipFeatures_PIPE_3D) {
+               CMD_LOAD_STATE(buffer, VIVS_GL_PIPE_SELECT,
+                              VIVS_GL_PIPE_SELECT_PIPE(ETNA_PIPE_3D));
+               CMD_LOAD_STATE(buffer, VIVS_MMUv2_CONFIGURATION,
+                       mtlb_addr | VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K);
+               CMD_LOAD_STATE(buffer, VIVS_MMUv2_SAFE_ADDRESS, safe_addr);
+               CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+               CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+       }
+
+       if (gpu->identity.features & chipFeatures_PIPE_2D) {
+               CMD_LOAD_STATE(buffer, VIVS_GL_PIPE_SELECT,
+                              VIVS_GL_PIPE_SELECT_PIPE(ETNA_PIPE_2D));
+               CMD_LOAD_STATE(buffer, VIVS_MMUv2_CONFIGURATION,
+                       mtlb_addr | VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K);
+               CMD_LOAD_STATE(buffer, VIVS_MMUv2_SAFE_ADDRESS, safe_addr);
+               CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+               CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+       }
+
+       CMD_END(buffer);
+
+       buffer->user_size = ALIGN(buffer->user_size, 8);
 
        return buffer->user_size / 8;
 }
@@ -231,7 +261,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
        if (drm_debug & DRM_UT_DRIVER)
                etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
 
-       link_target = gpu_va(gpu, cmdbuf);
+       link_target = etnaviv_iommu_get_cmdbuf_va(gpu, cmdbuf);
        link_dwords = cmdbuf->size / 8;
 
        /*
@@ -246,8 +276,12 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
                extra_dwords = 1;
 
                /* flush command */
-               if (gpu->mmu->need_flush)
-                       extra_dwords += 1;
+               if (gpu->mmu->need_flush) {
+                       if (gpu->mmu->version == ETNAVIV_IOMMU_V1)
+                               extra_dwords += 1;
+                       else
+                               extra_dwords += 3;
+               }
 
                /* pipe switch commands */
                if (gpu->switch_context)
@@ -257,12 +291,23 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 
                if (gpu->mmu->need_flush) {
                        /* Add the MMU flush */
-                       CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_MMU,
-                                      VIVS_GL_FLUSH_MMU_FLUSH_FEMMU |
-                                      VIVS_GL_FLUSH_MMU_FLUSH_UNK1 |
-                                      VIVS_GL_FLUSH_MMU_FLUSH_UNK2 |
-                                      VIVS_GL_FLUSH_MMU_FLUSH_PEMMU |
-                                      VIVS_GL_FLUSH_MMU_FLUSH_UNK4);
+                       if (gpu->mmu->version == ETNAVIV_IOMMU_V1) {
+                               CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_MMU,
+                                              VIVS_GL_FLUSH_MMU_FLUSH_FEMMU |
+                                              VIVS_GL_FLUSH_MMU_FLUSH_UNK1 |
+                                              VIVS_GL_FLUSH_MMU_FLUSH_UNK2 |
+                                              VIVS_GL_FLUSH_MMU_FLUSH_PEMMU |
+                                              VIVS_GL_FLUSH_MMU_FLUSH_UNK4);
+                       } else {
+                               CMD_LOAD_STATE(buffer, VIVS_MMUv2_CONFIGURATION,
+                                       VIVS_MMUv2_CONFIGURATION_MODE_MASK |
+                                       VIVS_MMUv2_CONFIGURATION_ADDRESS_MASK |
+                                       VIVS_MMUv2_CONFIGURATION_FLUSH_FLUSH);
+                               CMD_SEM(buffer, SYNC_RECIPIENT_FE,
+                                       SYNC_RECIPIENT_PE);
+                               CMD_STALL(buffer, SYNC_RECIPIENT_FE,
+                                       SYNC_RECIPIENT_PE);
+                       }
 
                        gpu->mmu->need_flush = false;
                }
@@ -301,7 +346,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 
        if (drm_debug & DRM_UT_DRIVER)
                pr_info("stream link to 0x%08x @ 0x%08x %p\n",
-                       return_target, gpu_va(gpu, cmdbuf), cmdbuf->vaddr);
+                       return_target, etnaviv_iommu_get_cmdbuf_va(gpu, cmdbuf), cmdbuf->vaddr);
 
        if (drm_debug & DRM_UT_DRIVER) {
                print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
index ffd1b32..aa68766 100644 (file)
@@ -488,8 +488,7 @@ static const struct file_operations fops = {
 };
 
 static struct drm_driver etnaviv_drm_driver = {
-       .driver_features    = DRIVER_HAVE_IRQ |
-                               DRIVER_GEM |
+       .driver_features    = DRIVER_GEM |
                                DRIVER_PRIME |
                                DRIVER_RENDER,
        .open               = etnaviv_open,
@@ -530,10 +529,8 @@ static int etnaviv_bind(struct device *dev)
        int ret;
 
        drm = drm_dev_alloc(&etnaviv_drm_driver, dev);
-       if (!drm)
-               return -ENOMEM;
-
-       drm->platformdev = to_platform_device(dev);
+       if (IS_ERR(drm))
+               return PTR_ERR(drm);
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
index 115c5bc..65e0576 100644 (file)
@@ -96,6 +96,7 @@ struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
 int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
        uintptr_t ptr, u32 size, u32 flags, u32 *handle);
 u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu);
+u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr);
 void etnaviv_buffer_end(struct etnaviv_gpu *gpu);
 void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
        struct etnaviv_cmdbuf *cmdbuf);
index 4a29eea..2bef501 100644 (file)
@@ -175,11 +175,13 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
        etnaviv_core_dump_registers(&iter, gpu);
        etnaviv_core_dump_mmu(&iter, gpu, mmu_size);
        etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr,
-                             gpu->buffer->size, gpu->buffer->paddr);
+                             gpu->buffer->size,
+                             etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer));
 
        list_for_each_entry(cmd, &gpu->active_cmd_list, node)
                etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,
-                                     cmd->size, cmd->paddr);
+                                     cmd->size,
+                                     etnaviv_iommu_get_cmdbuf_va(gpu, cmd));
 
        /* Reserve space for the bomap */
        if (n_bomap_pages) {
index b382cf5..b1254f8 100644 (file)
@@ -22,8 +22,6 @@
 #include "etnaviv_gpu.h"
 #include "etnaviv_gem.h"
 #include "etnaviv_mmu.h"
-#include "etnaviv_iommu.h"
-#include "etnaviv_iommu_v2.h"
 #include "common.xml.h"
 #include "state.xml.h"
 #include "state_hi.xml.h"
@@ -329,6 +327,18 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
                                gpu->identity.revision = 0x1051;
                        }
                }
+
+               /*
+                * NXP likes to call the GPU on the i.MX6QP GC2000+, but in
+                * reality it's just a re-branded GC3000. We can identify this
+                * core by the upper half of the revision register being all 1.
+                * Fix model/rev here, so all other places can refer to this
+                * core by its real identity.
+                */
+               if (etnaviv_is_model_rev(gpu, GC2000, 0xffff5450)) {
+                       gpu->identity.model = chipModel_GC3000;
+                       gpu->identity.revision &= 0xffff;
+               }
        }
 
        dev_info(gpu->dev, "model: GC%x, revision: %x\n",
@@ -528,6 +538,14 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu)
        gpu_write(gpu, VIVS_PM_MODULE_CONTROLS, pmc);
 }
 
+void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch)
+{
+       gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS, address);
+       gpu_write(gpu, VIVS_FE_COMMAND_CONTROL,
+                 VIVS_FE_COMMAND_CONTROL_ENABLE |
+                 VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
+}
+
 static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
 {
        u16 prefetch;
@@ -568,33 +586,20 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
                gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config);
        }
 
-       /* set base addresses */
-       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base);
-       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base);
-       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base);
-       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base);
-       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base);
-
-       /* setup the MMU page table pointers */
-       etnaviv_iommu_domain_restore(gpu, gpu->mmu->domain);
+       /* setup the MMU */
+       etnaviv_iommu_restore(gpu);
 
        /* Start command processor */
        prefetch = etnaviv_buffer_init(gpu);
 
        gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U);
-       gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS,
-                 gpu->buffer->paddr - gpu->memory_base);
-       gpu_write(gpu, VIVS_FE_COMMAND_CONTROL,
-                 VIVS_FE_COMMAND_CONTROL_ENABLE |
-                 VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
+       etnaviv_gpu_start_fe(gpu, etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer),
+                            prefetch);
 }
 
 int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
 {
        int ret, i;
-       struct iommu_domain *iommu;
-       enum etnaviv_iommu_version version;
-       bool mmuv2;
 
        ret = pm_runtime_get_sync(gpu->dev);
        if (ret < 0) {
@@ -642,32 +647,10 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
                goto fail;
        }
 
-       /* Setup IOMMU.. eventually we will (I think) do this once per context
-        * and have separate page tables per context.  For now, to keep things
-        * simple and to get something working, just use a single address space:
-        */
-       mmuv2 = gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION;
-       dev_dbg(gpu->dev, "mmuv2: %d\n", mmuv2);
-
-       if (!mmuv2) {
-               iommu = etnaviv_iommu_domain_alloc(gpu);
-               version = ETNAVIV_IOMMU_V1;
-       } else {
-               iommu = etnaviv_iommu_v2_domain_alloc(gpu);
-               version = ETNAVIV_IOMMU_V2;
-       }
-
-       if (!iommu) {
-               dev_err(gpu->dev, "Failed to allocate GPU IOMMU domain\n");
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       gpu->mmu = etnaviv_iommu_new(gpu, iommu, version);
-       if (!gpu->mmu) {
+       gpu->mmu = etnaviv_iommu_new(gpu);
+       if (IS_ERR(gpu->mmu)) {
                dev_err(gpu->dev, "Failed to instantiate GPU IOMMU\n");
-               iommu_domain_free(iommu);
-               ret = -ENOMEM;
+               ret = PTR_ERR(gpu->mmu);
                goto fail;
        }
 
@@ -678,7 +661,9 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
                dev_err(gpu->dev, "could not create command buffer\n");
                goto destroy_iommu;
        }
-       if (gpu->buffer->paddr - gpu->memory_base > 0x80000000) {
+
+       if (gpu->mmu->version == ETNAVIV_IOMMU_V1 &&
+           gpu->buffer->paddr - gpu->memory_base > 0x80000000) {
                ret = -EINVAL;
                dev_err(gpu->dev,
                        "command buffer outside valid memory window\n");
@@ -867,45 +852,6 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
 }
 #endif
 
-/*
- * Power Management:
- */
-static int enable_clk(struct etnaviv_gpu *gpu)
-{
-       if (gpu->clk_core)
-               clk_prepare_enable(gpu->clk_core);
-       if (gpu->clk_shader)
-               clk_prepare_enable(gpu->clk_shader);
-
-       return 0;
-}
-
-static int disable_clk(struct etnaviv_gpu *gpu)
-{
-       if (gpu->clk_core)
-               clk_disable_unprepare(gpu->clk_core);
-       if (gpu->clk_shader)
-               clk_disable_unprepare(gpu->clk_shader);
-
-       return 0;
-}
-
-static int enable_axi(struct etnaviv_gpu *gpu)
-{
-       if (gpu->clk_bus)
-               clk_prepare_enable(gpu->clk_bus);
-
-       return 0;
-}
-
-static int disable_axi(struct etnaviv_gpu *gpu)
-{
-       if (gpu->clk_bus)
-               clk_disable_unprepare(gpu->clk_bus);
-
-       return 0;
-}
-
 /*
  * Hangcheck detection for locked gpu:
  */
@@ -945,7 +891,7 @@ static void recover_worker(struct work_struct *work)
        gpu->completed_fence = gpu->active_fence;
 
        etnaviv_gpu_hw_init(gpu);
-       gpu->switch_context = true;
+       gpu->lastctx = NULL;
        gpu->exec_state = -1;
 
        mutex_unlock(&gpu->lock);
@@ -1178,6 +1124,9 @@ struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size,
        if (!cmdbuf)
                return NULL;
 
+       if (gpu->mmu->version == ETNAVIV_IOMMU_V2)
+               size = ALIGN(size, SZ_4K);
+
        cmdbuf->vaddr = dma_alloc_wc(gpu->dev, size, &cmdbuf->paddr,
                                     GFP_KERNEL);
        if (!cmdbuf->vaddr) {
@@ -1193,6 +1142,7 @@ struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size,
 
 void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
 {
+       etnaviv_iommu_put_cmdbuf_va(cmdbuf->gpu, cmdbuf);
        dma_free_wc(cmdbuf->gpu->dev, cmdbuf->size, cmdbuf->vaddr,
                    cmdbuf->paddr);
        kfree(cmdbuf);
@@ -1425,6 +1375,21 @@ static irqreturn_t irq_handler(int irq, void *data)
                        intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR;
                }
 
+               if (intr & VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION) {
+                       int i;
+
+                       dev_err_ratelimited(gpu->dev,
+                               "MMU fault status 0x%08x\n",
+                               gpu_read(gpu, VIVS_MMUv2_STATUS));
+                       for (i = 0; i < 4; i++) {
+                               dev_err_ratelimited(gpu->dev,
+                                       "MMU %d fault addr 0x%08x\n",
+                                       i, gpu_read(gpu,
+                                       VIVS_MMUv2_EXCEPTION_ADDR(i)));
+                       }
+                       intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION;
+               }
+
                while ((event = ffs(intr)) != 0) {
                        struct fence *fence;
 
@@ -1466,39 +1431,72 @@ static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu)
 {
        int ret;
 
-       ret = enable_clk(gpu);
-       if (ret)
-               return ret;
+       if (gpu->clk_bus) {
+               ret = clk_prepare_enable(gpu->clk_bus);
+               if (ret)
+                       return ret;
+       }
 
-       ret = enable_axi(gpu);
-       if (ret) {
-               disable_clk(gpu);
-               return ret;
+       if (gpu->clk_core) {
+               ret = clk_prepare_enable(gpu->clk_core);
+               if (ret)
+                       goto disable_clk_bus;
+       }
+
+       if (gpu->clk_shader) {
+               ret = clk_prepare_enable(gpu->clk_shader);
+               if (ret)
+                       goto disable_clk_core;
        }
 
        return 0;
+
+disable_clk_core:
+       if (gpu->clk_core)
+               clk_disable_unprepare(gpu->clk_core);
+disable_clk_bus:
+       if (gpu->clk_bus)
+               clk_disable_unprepare(gpu->clk_bus);
+
+       return ret;
 }
 
 static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu)
 {
-       int ret;
+       if (gpu->clk_shader)
+               clk_disable_unprepare(gpu->clk_shader);
+       if (gpu->clk_core)
+               clk_disable_unprepare(gpu->clk_core);
+       if (gpu->clk_bus)
+               clk_disable_unprepare(gpu->clk_bus);
 
-       ret = disable_axi(gpu);
-       if (ret)
-               return ret;
+       return 0;
+}
 
-       ret = disable_clk(gpu);
-       if (ret)
-               return ret;
+int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
 
-       return 0;
+       do {
+               u32 idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+
+               if ((idle & gpu->idle_mask) == gpu->idle_mask)
+                       return 0;
+
+               if (time_is_before_jiffies(timeout)) {
+                       dev_warn(gpu->dev,
+                                "timed out waiting for idle: idle=0x%x\n",
+                                idle);
+                       return -ETIMEDOUT;
+               }
+
+               udelay(5);
+       } while (1);
 }
 
 static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
 {
        if (gpu->buffer) {
-               unsigned long timeout;
-
                /* Replace the last WAIT with END */
                etnaviv_buffer_end(gpu);
 
@@ -1507,22 +1505,7 @@ static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
                 * happen quickly (as the WAIT is only 200 cycles).  If
                 * we fail, just warn and continue.
                 */
-               timeout = jiffies + msecs_to_jiffies(100);
-               do {
-                       u32 idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
-
-                       if ((idle & gpu->idle_mask) == gpu->idle_mask)
-                               break;
-
-                       if (time_is_before_jiffies(timeout)) {
-                               dev_warn(gpu->dev,
-                                        "timed out waiting for idle: idle=0x%x\n",
-                                        idle);
-                               break;
-                       }
-
-                       udelay(5);
-               } while (1);
+               etnaviv_gpu_wait_idle(gpu, 100);
        }
 
        return etnaviv_gpu_clk_disable(gpu);
@@ -1634,7 +1617,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct etnaviv_gpu *gpu;
-       int err = 0;
+       int err;
 
        gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL);
        if (!gpu)
@@ -1651,16 +1634,15 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
        /* Get Interrupt: */
        gpu->irq = platform_get_irq(pdev, 0);
        if (gpu->irq < 0) {
-               err = gpu->irq;
-               dev_err(dev, "failed to get irq: %d\n", err);
-               goto fail;
+               dev_err(dev, "failed to get irq: %d\n", gpu->irq);
+               return gpu->irq;
        }
 
        err = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, 0,
                               dev_name(gpu->dev), gpu);
        if (err) {
                dev_err(dev, "failed to request IRQ%u: %d\n", gpu->irq, err);
-               goto fail;
+               return err;
        }
 
        /* Get Clocks: */
@@ -1694,13 +1676,10 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
        err = component_add(&pdev->dev, &gpu_ops);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to register component: %d\n", err);
-               goto fail;
+               return err;
        }
 
        return 0;
-
-fail:
-       return err;
 }
 
 static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
index a69cdd5..73c278d 100644 (file)
@@ -160,6 +160,8 @@ struct etnaviv_cmdbuf {
        dma_addr_t paddr;
        u32 size;
        u32 user_size;
+       /* vram node used if the cmdbuf is mapped through the MMUv2 */
+       struct drm_mm_node vram_node;
        /* fence after which this buffer is to be disposed */
        struct fence *fence;
        /* target exec state */
@@ -214,6 +216,8 @@ struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
 void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);
 int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
 void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
+int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms);
+void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch);
 
 extern struct platform_driver etnaviv_gpu_driver;
 
index 16353ee..81f1583 100644 (file)
@@ -196,12 +196,19 @@ static struct etnaviv_iommu_ops etnaviv_iommu_ops = {
        .dump = etnaviv_iommuv1_dump,
 };
 
-void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu,
-       struct iommu_domain *domain)
+void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu)
 {
-       struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
+       struct etnaviv_iommu_domain *etnaviv_domain =
+                       to_etnaviv_domain(gpu->mmu->domain);
        u32 pgtable;
 
+       /* set base addresses */
+       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base);
+       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base);
+       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base);
+       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base);
+       gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base);
+
        /* set page table address in MC */
        pgtable = (u32)etnaviv_domain->pgtable.paddr;
 
@@ -212,7 +219,7 @@ void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu,
        gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable);
 }
 
-struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu)
+struct iommu_domain *etnaviv_iommuv1_domain_alloc(struct etnaviv_gpu *gpu)
 {
        struct etnaviv_iommu_domain *etnaviv_domain;
        int ret;
index cf45503..8b51e7c 100644 (file)
 #ifndef __ETNAVIV_IOMMU_H__
 #define __ETNAVIV_IOMMU_H__
 
-#include <linux/iommu.h>
 struct etnaviv_gpu;
 
-struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu);
-void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu,
-       struct iommu_domain *domain);
-struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu);
+struct iommu_domain *etnaviv_iommuv1_domain_alloc(struct etnaviv_gpu *gpu);
+void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu);
+
+struct iommu_domain *etnaviv_iommuv2_domain_alloc(struct etnaviv_gpu *gpu);
+void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu);
 
 #endif /* __ETNAVIV_IOMMU_H__ */
index fbb4aed..7e9c4d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner@gmail.com>
+ * Copyright (C) 2016 Etnaviv Project
   *
  * 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
 #include <linux/bitops.h>
 
 #include "etnaviv_gpu.h"
+#include "etnaviv_mmu.h"
 #include "etnaviv_iommu.h"
+#include "state.xml.h"
 #include "state_hi.xml.h"
 
+#define MMUv2_PTE_PRESENT              BIT(0)
+#define MMUv2_PTE_EXCEPTION            BIT(1)
+#define MMUv2_PTE_WRITEABLE            BIT(2)
 
-struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu)
+#define MMUv2_MTLB_MASK                        0xffc00000
+#define MMUv2_MTLB_SHIFT               22
+#define MMUv2_STLB_MASK                        0x003ff000
+#define MMUv2_STLB_SHIFT               12
+
+#define MMUv2_MAX_STLB_ENTRIES         1024
+
+struct etnaviv_iommuv2_domain {
+       struct iommu_domain domain;
+       struct device *dev;
+       void *bad_page_cpu;
+       dma_addr_t bad_page_dma;
+       /* M(aster) TLB aka first level pagetable */
+       u32 *mtlb_cpu;
+       dma_addr_t mtlb_dma;
+       /* S(lave) TLB aka second level pagetable */
+       u32 *stlb_cpu[1024];
+       dma_addr_t stlb_dma[1024];
+};
+
+static struct etnaviv_iommuv2_domain *to_etnaviv_domain(struct iommu_domain *domain)
+{
+       return container_of(domain, struct etnaviv_iommuv2_domain, domain);
+}
+
+static int etnaviv_iommuv2_map(struct iommu_domain *domain, unsigned long iova,
+          phys_addr_t paddr, size_t size, int prot)
+{
+       struct etnaviv_iommuv2_domain *etnaviv_domain =
+                       to_etnaviv_domain(domain);
+       int mtlb_entry, stlb_entry;
+       u32 entry = (u32)paddr | MMUv2_PTE_PRESENT;
+
+       if (size != SZ_4K)
+               return -EINVAL;
+
+       if (prot & IOMMU_WRITE)
+               entry |= MMUv2_PTE_WRITEABLE;
+
+       mtlb_entry = (iova & MMUv2_MTLB_MASK) >> MMUv2_MTLB_SHIFT;
+       stlb_entry = (iova & MMUv2_STLB_MASK) >> MMUv2_STLB_SHIFT;
+
+       etnaviv_domain->stlb_cpu[mtlb_entry][stlb_entry] = entry;
+
+       return 0;
+}
+
+static size_t etnaviv_iommuv2_unmap(struct iommu_domain *domain,
+       unsigned long iova, size_t size)
+{
+       struct etnaviv_iommuv2_domain *etnaviv_domain =
+                       to_etnaviv_domain(domain);
+       int mtlb_entry, stlb_entry;
+
+       if (size != SZ_4K)
+               return -EINVAL;
+
+       mtlb_entry = (iova & MMUv2_MTLB_MASK) >> MMUv2_MTLB_SHIFT;
+       stlb_entry = (iova & MMUv2_STLB_MASK) >> MMUv2_STLB_SHIFT;
+
+       etnaviv_domain->stlb_cpu[mtlb_entry][stlb_entry] = MMUv2_PTE_EXCEPTION;
+
+       return SZ_4K;
+}
+
+static phys_addr_t etnaviv_iommuv2_iova_to_phys(struct iommu_domain *domain,
+       dma_addr_t iova)
+{
+       struct etnaviv_iommuv2_domain *etnaviv_domain =
+                       to_etnaviv_domain(domain);
+       int mtlb_entry, stlb_entry;
+
+       mtlb_entry = (iova & MMUv2_MTLB_MASK) >> MMUv2_MTLB_SHIFT;
+       stlb_entry = (iova & MMUv2_STLB_MASK) >> MMUv2_STLB_SHIFT;
+
+       return etnaviv_domain->stlb_cpu[mtlb_entry][stlb_entry] & ~(SZ_4K - 1);
+}
+
+static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain)
+{
+       u32 *p;
+       int ret, i, j;
+
+       /* allocate scratch page */
+       etnaviv_domain->bad_page_cpu = dma_alloc_coherent(etnaviv_domain->dev,
+                                                 SZ_4K,
+                                                 &etnaviv_domain->bad_page_dma,
+                                                 GFP_KERNEL);
+       if (!etnaviv_domain->bad_page_cpu) {
+               ret = -ENOMEM;
+               goto fail_mem;
+       }
+       p = etnaviv_domain->bad_page_cpu;
+       for (i = 0; i < SZ_4K / 4; i++)
+               *p++ = 0xdead55aa;
+
+       etnaviv_domain->mtlb_cpu = dma_alloc_coherent(etnaviv_domain->dev,
+                                                 SZ_4K,
+                                                 &etnaviv_domain->mtlb_dma,
+                                                 GFP_KERNEL);
+       if (!etnaviv_domain->mtlb_cpu) {
+               ret = -ENOMEM;
+               goto fail_mem;
+       }
+
+       /* pre-populate STLB pages (may want to switch to on-demand later) */
+       for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++) {
+               etnaviv_domain->stlb_cpu[i] =
+                               dma_alloc_coherent(etnaviv_domain->dev,
+                                                  SZ_4K,
+                                                  &etnaviv_domain->stlb_dma[i],
+                                                  GFP_KERNEL);
+               if (!etnaviv_domain->stlb_cpu[i]) {
+                       ret = -ENOMEM;
+                       goto fail_mem;
+               }
+               p = etnaviv_domain->stlb_cpu[i];
+               for (j = 0; j < SZ_4K / 4; j++)
+                       *p++ = MMUv2_PTE_EXCEPTION;
+
+               etnaviv_domain->mtlb_cpu[i] = etnaviv_domain->stlb_dma[i] |
+                                             MMUv2_PTE_PRESENT;
+       }
+
+       return 0;
+
+fail_mem:
+       if (etnaviv_domain->bad_page_cpu)
+               dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+                                 etnaviv_domain->bad_page_cpu,
+                                 etnaviv_domain->bad_page_dma);
+
+       if (etnaviv_domain->mtlb_cpu)
+               dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+                                 etnaviv_domain->mtlb_cpu,
+                                 etnaviv_domain->mtlb_dma);
+
+       for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++) {
+               if (etnaviv_domain->stlb_cpu[i])
+                       dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+                                         etnaviv_domain->stlb_cpu[i],
+                                         etnaviv_domain->stlb_dma[i]);
+       }
+
+       return ret;
+}
+
+static void etnaviv_iommuv2_domain_free(struct iommu_domain *domain)
+{
+       struct etnaviv_iommuv2_domain *etnaviv_domain =
+                       to_etnaviv_domain(domain);
+       int i;
+
+       dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+                         etnaviv_domain->bad_page_cpu,
+                         etnaviv_domain->bad_page_dma);
+
+       dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+                         etnaviv_domain->mtlb_cpu,
+                         etnaviv_domain->mtlb_dma);
+
+       for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++) {
+               if (etnaviv_domain->stlb_cpu[i])
+                       dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+                                         etnaviv_domain->stlb_cpu[i],
+                                         etnaviv_domain->stlb_dma[i]);
+       }
+
+       vfree(etnaviv_domain);
+}
+
+static size_t etnaviv_iommuv2_dump_size(struct iommu_domain *domain)
+{
+       struct etnaviv_iommuv2_domain *etnaviv_domain =
+                       to_etnaviv_domain(domain);
+       size_t dump_size = SZ_4K;
+       int i;
+
+       for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++)
+               if (etnaviv_domain->mtlb_cpu[i] & MMUv2_PTE_PRESENT)
+                       dump_size += SZ_4K;
+
+       return dump_size;
+}
+
+static void etnaviv_iommuv2_dump(struct iommu_domain *domain, void *buf)
 {
-       /* TODO */
+       struct etnaviv_iommuv2_domain *etnaviv_domain =
+                       to_etnaviv_domain(domain);
+       int i;
+
+       memcpy(buf, etnaviv_domain->mtlb_cpu, SZ_4K);
+       buf += SZ_4K;
+       for (i = 0; i < MMUv2_MAX_STLB_ENTRIES; i++, buf += SZ_4K)
+               if (etnaviv_domain->mtlb_cpu[i] & MMUv2_PTE_PRESENT)
+                       memcpy(buf, etnaviv_domain->stlb_cpu[i], SZ_4K);
+}
+
+static struct etnaviv_iommu_ops etnaviv_iommu_ops = {
+       .ops = {
+               .domain_free = etnaviv_iommuv2_domain_free,
+               .map = etnaviv_iommuv2_map,
+               .unmap = etnaviv_iommuv2_unmap,
+               .iova_to_phys = etnaviv_iommuv2_iova_to_phys,
+               .pgsize_bitmap = SZ_4K,
+       },
+       .dump_size = etnaviv_iommuv2_dump_size,
+       .dump = etnaviv_iommuv2_dump,
+};
+
+void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu)
+{
+       struct etnaviv_iommuv2_domain *etnaviv_domain =
+                       to_etnaviv_domain(gpu->mmu->domain);
+       u16 prefetch;
+
+       /* If the MMU is already enabled the state is still there. */
+       if (gpu_read(gpu, VIVS_MMUv2_CONTROL) & VIVS_MMUv2_CONTROL_ENABLE)
+               return;
+
+       prefetch = etnaviv_buffer_config_mmuv2(gpu,
+                               (u32)etnaviv_domain->mtlb_dma,
+                               (u32)etnaviv_domain->bad_page_dma);
+       etnaviv_gpu_start_fe(gpu, gpu->buffer->paddr, prefetch);
+       etnaviv_gpu_wait_idle(gpu, 100);
+
+       gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE);
+}
+struct iommu_domain *etnaviv_iommuv2_domain_alloc(struct etnaviv_gpu *gpu)
+{
+       struct etnaviv_iommuv2_domain *etnaviv_domain;
+       int ret;
+
+       etnaviv_domain = vzalloc(sizeof(*etnaviv_domain));
+       if (!etnaviv_domain)
+               return NULL;
+
+       etnaviv_domain->dev = gpu->dev;
+
+       etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING;
+       etnaviv_domain->domain.ops = &etnaviv_iommu_ops.ops;
+       etnaviv_domain->domain.pgsize_bitmap = SZ_4K;
+       etnaviv_domain->domain.geometry.aperture_start = 0;
+       etnaviv_domain->domain.geometry.aperture_end = ~0UL & ~(SZ_4K - 1);
+
+       ret = etnaviv_iommuv2_init(etnaviv_domain);
+       if (ret)
+               goto out_free;
+
+       return &etnaviv_domain->domain;
+
+out_free:
+       vfree(etnaviv_domain);
        return NULL;
 }
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.h b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.h
deleted file mode 100644 (file)
index 603ea41..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner@gmail.com>
-  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __ETNAVIV_IOMMU_V2_H__
-#define __ETNAVIV_IOMMU_V2_H__
-
-#include <linux/iommu.h>
-struct etnaviv_gpu;
-
-struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu);
-
-#endif /* __ETNAVIV_IOMMU_V2_H__ */
index 29a723f..d3796ed 100644 (file)
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "common.xml.h"
 #include "etnaviv_drv.h"
 #include "etnaviv_gem.h"
 #include "etnaviv_gpu.h"
+#include "etnaviv_iommu.h"
 #include "etnaviv_mmu.h"
 
 static int etnaviv_fault_handler(struct iommu_domain *iommu, struct device *dev,
@@ -101,40 +103,21 @@ static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu *mmu,
        drm_mm_remove_node(&mapping->vram_node);
 }
 
-int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
-       struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
-       struct etnaviv_vram_mapping *mapping)
+static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu,
+                                  struct drm_mm_node *node, size_t size)
 {
        struct etnaviv_vram_mapping *free = NULL;
-       struct sg_table *sgt = etnaviv_obj->sgt;
-       struct drm_mm_node *node;
        int ret;
 
-       lockdep_assert_held(&etnaviv_obj->lock);
-
-       mutex_lock(&mmu->lock);
-
-       /* v1 MMU can optimize single entry (contiguous) scatterlists */
-       if (sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) {
-               u32 iova;
-
-               iova = sg_dma_address(sgt->sgl) - memory_base;
-               if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) {
-                       mapping->iova = iova;
-                       list_add_tail(&mapping->mmu_node, &mmu->mappings);
-                       mutex_unlock(&mmu->lock);
-                       return 0;
-               }
-       }
+       lockdep_assert_held(&mmu->lock);
 
-       node = &mapping->vram_node;
        while (1) {
                struct etnaviv_vram_mapping *m, *n;
                struct list_head list;
                bool found;
 
                ret = drm_mm_insert_node_in_range(&mmu->mm, node,
-                       etnaviv_obj->base.size, 0, mmu->last_iova, ~0UL,
+                       size, 0, mmu->last_iova, ~0UL,
                        DRM_MM_SEARCH_DEFAULT);
 
                if (ret != -ENOSPC)
@@ -151,7 +134,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
                }
 
                /* Try to retire some entries */
-               drm_mm_init_scan(&mmu->mm, etnaviv_obj->base.size, 0, 0);
+               drm_mm_init_scan(&mmu->mm, size, 0, 0);
 
                found = 0;
                INIT_LIST_HEAD(&list);
@@ -212,6 +195,38 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
                mmu->need_flush = true;
        }
 
+       return ret;
+}
+
+int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
+       struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
+       struct etnaviv_vram_mapping *mapping)
+{
+       struct sg_table *sgt = etnaviv_obj->sgt;
+       struct drm_mm_node *node;
+       int ret;
+
+       lockdep_assert_held(&etnaviv_obj->lock);
+
+       mutex_lock(&mmu->lock);
+
+       /* v1 MMU can optimize single entry (contiguous) scatterlists */
+       if (mmu->version == ETNAVIV_IOMMU_V1 &&
+           sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) {
+               u32 iova;
+
+               iova = sg_dma_address(sgt->sgl) - memory_base;
+               if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) {
+                       mapping->iova = iova;
+                       list_add_tail(&mapping->mmu_node, &mmu->mappings);
+                       mutex_unlock(&mmu->lock);
+                       return 0;
+               }
+       }
+
+       node = &mapping->vram_node;
+
+       ret = etnaviv_iommu_find_iova(mmu, node, etnaviv_obj->base.size);
        if (ret < 0) {
                mutex_unlock(&mmu->lock);
                return ret;
@@ -256,30 +271,102 @@ void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu)
        kfree(mmu);
 }
 
-struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu,
-       struct iommu_domain *domain, enum etnaviv_iommu_version version)
+struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu)
 {
+       enum etnaviv_iommu_version version;
        struct etnaviv_iommu *mmu;
 
        mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
        if (!mmu)
                return ERR_PTR(-ENOMEM);
 
-       mmu->domain = domain;
+       if (!(gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION)) {
+               mmu->domain = etnaviv_iommuv1_domain_alloc(gpu);
+               version = ETNAVIV_IOMMU_V1;
+       } else {
+               mmu->domain = etnaviv_iommuv2_domain_alloc(gpu);
+               version = ETNAVIV_IOMMU_V2;
+       }
+
+       if (!mmu->domain) {
+               dev_err(gpu->dev, "Failed to allocate GPU IOMMU domain\n");
+               kfree(mmu);
+               return ERR_PTR(-ENOMEM);
+       }
+
        mmu->gpu = gpu;
        mmu->version = version;
        mutex_init(&mmu->lock);
        INIT_LIST_HEAD(&mmu->mappings);
 
-       drm_mm_init(&mmu->mm, domain->geometry.aperture_start,
-                   domain->geometry.aperture_end -
-                     domain->geometry.aperture_start + 1);
+       drm_mm_init(&mmu->mm, mmu->domain->geometry.aperture_start,
+                   mmu->domain->geometry.aperture_end -
+                   mmu->domain->geometry.aperture_start + 1);
 
-       iommu_set_fault_handler(domain, etnaviv_fault_handler, gpu->dev);
+       iommu_set_fault_handler(mmu->domain, etnaviv_fault_handler, gpu->dev);
 
        return mmu;
 }
 
+void etnaviv_iommu_restore(struct etnaviv_gpu *gpu)
+{
+       if (gpu->mmu->version == ETNAVIV_IOMMU_V1)
+               etnaviv_iommuv1_restore(gpu);
+       else
+               etnaviv_iommuv2_restore(gpu);
+}
+
+u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu,
+                               struct etnaviv_cmdbuf *buf)
+{
+       struct etnaviv_iommu *mmu = gpu->mmu;
+
+       if (mmu->version == ETNAVIV_IOMMU_V1) {
+               return buf->paddr - gpu->memory_base;
+       } else {
+               int ret;
+
+               if (buf->vram_node.allocated)
+                       return (u32)buf->vram_node.start;
+
+               mutex_lock(&mmu->lock);
+               ret = etnaviv_iommu_find_iova(mmu, &buf->vram_node, buf->size);
+               if (ret < 0) {
+                       mutex_unlock(&mmu->lock);
+                       return 0;
+               }
+               ret = iommu_map(mmu->domain, buf->vram_node.start, buf->paddr,
+                               buf->size, IOMMU_READ);
+               if (ret < 0) {
+                       drm_mm_remove_node(&buf->vram_node);
+                       mutex_unlock(&mmu->lock);
+                       return 0;
+               }
+               /*
+                * At least on GC3000 the FE MMU doesn't properly flush old TLB
+                * entries. Make sure to space the command buffers out in a way
+                * that the FE MMU prefetch won't load invalid entries.
+                */
+               mmu->last_iova = buf->vram_node.start + buf->size + SZ_64K;
+               gpu->mmu->need_flush = true;
+               mutex_unlock(&mmu->lock);
+
+               return (u32)buf->vram_node.start;
+       }
+}
+
+void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu,
+                                struct etnaviv_cmdbuf *buf)
+{
+       struct etnaviv_iommu *mmu = gpu->mmu;
+
+       if (mmu->version == ETNAVIV_IOMMU_V2 && buf->vram_node.allocated) {
+               mutex_lock(&mmu->lock);
+               iommu_unmap(mmu->domain, buf->vram_node.start, buf->size);
+               drm_mm_remove_node(&buf->vram_node);
+               mutex_unlock(&mmu->lock);
+       }
+}
 size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu)
 {
        struct etnaviv_iommu_ops *ops;
index fff215a..e787e49 100644 (file)
@@ -62,10 +62,15 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
        struct etnaviv_vram_mapping *mapping);
 void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
 
+u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu,
+                               struct etnaviv_cmdbuf *buf);
+void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu,
+                                struct etnaviv_cmdbuf *buf);
+
 size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu);
 void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf);
 
-struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu,
-       struct iommu_domain *domain, enum etnaviv_iommu_version version);
+struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu);
+void etnaviv_iommu_restore(struct etnaviv_gpu *gpu);
 
 #endif /* __ETNAVIV_MMU_H__ */
index 807a3d9..43c73e2 100644 (file)
@@ -8,10 +8,10 @@ http://0x04.net/cgit/index.cgi/rules-ng-ng
 git clone git://0x04.net/rules-ng-ng
 
 The rules-ng-ng source files this header was generated from are:
-- state_hi.xml (  24309 bytes, from 2015-12-12 09:02:53)
-- common.xml   (  18437 bytes, from 2015-12-12 09:02:53)
+- state_hi.xml (  25620 bytes, from 2016-08-19 22:07:37)
+- common.xml   (  20583 bytes, from 2016-06-07 05:22:38)
 
-Copyright (C) 2015
+Copyright (C) 2016
 */
 
 
@@ -78,9 +78,10 @@ Copyright (C) 2015
 #define VIVS_HI_AXI_STATUS_DET_RD_ERR                          0x00000200
 
 #define VIVS_HI_INTR_ACKNOWLEDGE                               0x00000010
-#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK                        0x7fffffff
+#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK                        0x3fffffff
 #define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT               0
 #define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC(x)                   (((x) << VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT) & VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK)
+#define VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION                 0x40000000
 #define VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR                 0x80000000
 
 #define VIVS_HI_INTR_ENBL                                      0x00000014
index ac21b40..6ca1f31 100644 (file)
@@ -551,7 +551,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
 {
        struct decon_context *ctx = dev_id;
        u32 val;
-       int win;
 
        if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags))
                goto out;
@@ -560,16 +559,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
        val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND;
 
        if (val) {
-               for (win = ctx->first_win; win < WINDOWS_NR ; win++) {
-                       struct exynos_drm_plane *plane = &ctx->planes[win];
-
-                       if (!plane->pending_fb)
-                               continue;
-
-                       exynos_drm_crtc_finish_update(ctx->crtc, plane);
-               }
-
-               /* clear */
                writel(val, ctx->addr + DECON_VIDINTCON1);
                drm_crtc_handle_vblank(&ctx->crtc->base);
        }
index 7f9901b..f4d5a21 100644 (file)
@@ -603,7 +603,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
 {
        struct decon_context *ctx = (struct decon_context *)dev_id;
        u32 val, clear_bit;
-       int win;
 
        val = readl(ctx->regs + VIDINTCON1);
 
@@ -617,14 +616,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
 
        if (!ctx->i80_if) {
                drm_crtc_handle_vblank(&ctx->crtc->base);
-               for (win = 0 ; win < WINDOWS_NR ; win++) {
-                       struct exynos_drm_plane *plane = &ctx->planes[win];
-
-                       if (!plane->pending_fb)
-                               continue;
-
-                       exynos_drm_crtc_finish_update(ctx->crtc, plane);
-               }
 
                /* set wait vsync event to zero and wake up queue. */
                if (atomic_read(&ctx->wait_vsync_event)) {
index 4f08505..528229f 100644 (file)
@@ -43,7 +43,7 @@ struct exynos_dp_device {
        struct analogix_dp_plat_data plat_data;
 };
 
-int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data,
+static int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data,
                                bool enable)
 {
        struct exynos_dp_device *dp = to_dp(plat_data);
index 785ffa6..2530bf5 100644 (file)
@@ -69,8 +69,6 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
-       exynos_crtc->event = crtc->state->event;
-
        if (exynos_crtc->ops->atomic_begin)
                exynos_crtc->ops->atomic_begin(exynos_crtc);
 }
@@ -79,9 +77,24 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
                                     struct drm_crtc_state *old_crtc_state)
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct drm_pending_vblank_event *event;
+       unsigned long flags;
 
        if (exynos_crtc->ops->atomic_flush)
                exynos_crtc->ops->atomic_flush(exynos_crtc);
+
+       event = crtc->state->event;
+       if (event) {
+               crtc->state->event = NULL;
+
+               spin_lock_irqsave(&crtc->dev->event_lock, flags);
+               if (drm_crtc_vblank_get(crtc) == 0)
+                       drm_crtc_arm_vblank_event(crtc, event);
+               else
+                       drm_crtc_send_vblank_event(crtc, event);
+               spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+       }
+
 }
 
 static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
@@ -134,8 +147,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
        exynos_crtc->ops = ops;
        exynos_crtc->ctx = ctx;
 
-       init_waitqueue_head(&exynos_crtc->wait_update);
-
        crtc = &exynos_crtc->base;
 
        private->crtc[pipe] = crtc;
@@ -175,32 +186,6 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe)
                exynos_crtc->ops->disable_vblank(exynos_crtc);
 }
 
-void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc)
-{
-       wait_event_timeout(exynos_crtc->wait_update,
-                          (atomic_read(&exynos_crtc->pending_update) == 0),
-                          msecs_to_jiffies(50));
-}
-
-void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
-                               struct exynos_drm_plane *exynos_plane)
-{
-       struct drm_crtc *crtc = &exynos_crtc->base;
-       unsigned long flags;
-
-       exynos_plane->pending_fb = NULL;
-
-       if (atomic_dec_and_test(&exynos_crtc->pending_update))
-               wake_up(&exynos_crtc->wait_update);
-
-       spin_lock_irqsave(&crtc->dev->event_lock, flags);
-       if (exynos_crtc->event)
-               drm_crtc_send_vblank_event(crtc, exynos_crtc->event);
-
-       exynos_crtc->event = NULL;
-       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
-}
-
 int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
                                       enum exynos_drm_output_type out_type)
 {
@@ -228,20 +213,19 @@ void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
 void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
                                        struct drm_file *file)
 {
-       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
        struct drm_pending_vblank_event *e;
        unsigned long flags;
 
        spin_lock_irqsave(&crtc->dev->event_lock, flags);
 
-       e = exynos_crtc->event;
-       if (e && e->base.file_priv == file) {
-               exynos_crtc->event = NULL;
-               atomic_dec(&exynos_crtc->pending_update);
-       }
+       e = crtc->state->event;
+       if (e && e->base.file_priv == file)
+               crtc->state->event = NULL;
+       else
+               e = NULL;
 
        spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 
-       if (e && e->base.file_priv == file)
+       if (e)
                drm_event_cancel_free(crtc->dev, &e->base);
 }
index 877d2ef..def78c8 100644 (file)
@@ -45,37 +45,11 @@ struct exynos_atomic_commit {
        u32                     crtcs;
 };
 
-static void exynos_atomic_wait_for_commit(struct drm_atomic_state *state)
-{
-       struct drm_crtc_state *crtc_state;
-       struct drm_crtc *crtc;
-       int i, ret;
-
-       for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-
-               if (!crtc->state->enable)
-                       continue;
-
-               ret = drm_crtc_vblank_get(crtc);
-               if (ret)
-                       continue;
-
-               exynos_drm_crtc_wait_pending_update(exynos_crtc);
-               drm_crtc_vblank_put(crtc);
-       }
-}
-
 static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
 {
        struct drm_device *dev = commit->dev;
        struct exynos_drm_private *priv = dev->dev_private;
        struct drm_atomic_state *state = commit->state;
-       struct drm_plane *plane;
-       struct drm_crtc *crtc;
-       struct drm_plane_state *plane_state;
-       struct drm_crtc_state *crtc_state;
-       int i;
 
        drm_atomic_helper_commit_modeset_disables(dev, state);
 
@@ -89,25 +63,9 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
         * have the relevant clocks enabled to perform the update.
         */
 
-       for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-
-               atomic_set(&exynos_crtc->pending_update, 0);
-       }
-
-       for_each_plane_in_state(state, plane, plane_state, i) {
-               struct exynos_drm_crtc *exynos_crtc =
-                                               to_exynos_crtc(plane->crtc);
-
-               if (!plane->crtc)
-                       continue;
-
-               atomic_inc(&exynos_crtc->pending_update);
-       }
-
-       drm_atomic_helper_commit_planes(dev, state, false);
+       drm_atomic_helper_commit_planes(dev, state, 0);
 
-       exynos_atomic_wait_for_commit(state);
+       drm_atomic_helper_wait_for_vblanks(dev, state);
 
        drm_atomic_helper_cleanup_planes(dev, state);
 
index 7f1a49d..d215149 100644 (file)
@@ -86,7 +86,6 @@ struct exynos_drm_plane {
        struct drm_plane base;
        const struct exynos_drm_plane_config *config;
        unsigned int index;
-       struct drm_framebuffer *pending_fb;
 };
 
 #define EXYNOS_DRM_PLANE_CAP_DOUBLE    (1 << 0)
@@ -172,9 +171,6 @@ struct exynos_drm_crtc {
        struct drm_crtc                 base;
        enum exynos_drm_output_type     type;
        unsigned int                    pipe;
-       struct drm_pending_vblank_event *event;
-       wait_queue_head_t               wait_update;
-       atomic_t                        pending_update;
        const struct exynos_drm_crtc_ops        *ops;
        void                            *ctx;
        struct exynos_drm_clk           *pipe_clk;
index d472164..e2e4051 100644 (file)
@@ -198,6 +198,7 @@ struct fimd_context {
        atomic_t                        wait_vsync_event;
        atomic_t                        win_updated;
        atomic_t                        triggering;
+       u32                             clkdiv;
 
        const struct fimd_driver_data *driver_data;
        struct drm_encoder *encoder;
@@ -389,15 +390,18 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc)
        pm_runtime_put(ctx->dev);
 }
 
-static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
-               const struct drm_display_mode *mode)
+
+static int fimd_atomic_check(struct exynos_drm_crtc *crtc,
+               struct drm_crtc_state *state)
 {
-       unsigned long ideal_clk;
+       struct drm_display_mode *mode = &state->adjusted_mode;
+       struct fimd_context *ctx = crtc->ctx;
+       unsigned long ideal_clk, lcd_rate;
        u32 clkdiv;
 
        if (mode->clock == 0) {
-               DRM_ERROR("Mode has zero clock value.\n");
-               return 0xff;
+               DRM_INFO("Mode has zero clock value.\n");
+               return -EINVAL;
        }
 
        ideal_clk = mode->clock * 1000;
@@ -410,10 +414,23 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
                ideal_clk *= 2;
        }
 
+       lcd_rate = clk_get_rate(ctx->lcd_clk);
+       if (2 * lcd_rate < ideal_clk) {
+               DRM_INFO("sclk_fimd clock too low(%lu) for requested pixel clock(%lu)\n",
+                        lcd_rate, ideal_clk);
+               return -EINVAL;
+       }
+
        /* Find the clock divider value that gets us closest to ideal_clk */
-       clkdiv = DIV_ROUND_CLOSEST(clk_get_rate(ctx->lcd_clk), ideal_clk);
+       clkdiv = DIV_ROUND_CLOSEST(lcd_rate, ideal_clk);
+       if (clkdiv >= 0x200) {
+               DRM_INFO("requested pixel clock(%lu) too low\n", ideal_clk);
+               return -EINVAL;
+       }
+
+       ctx->clkdiv = (clkdiv < 0x100) ? clkdiv : 0xff;
 
-       return (clkdiv < 0x100) ? clkdiv : 0xff;
+       return 0;
 }
 
 static void fimd_setup_trigger(struct fimd_context *ctx)
@@ -442,7 +459,7 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
        struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
        const struct fimd_driver_data *driver_data = ctx->driver_data;
        void *timing_base = ctx->regs + driver_data->timing_base;
-       u32 val, clkdiv;
+       u32 val;
 
        if (ctx->suspended)
                return;
@@ -543,9 +560,8 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
        if (ctx->driver_data->has_clksel)
                val |= VIDCON0_CLKSEL_LCD;
 
-       clkdiv = fimd_calc_clkdiv(ctx, mode);
-       if (clkdiv > 1)
-               val |= VIDCON0_CLKVAL_F(clkdiv - 1) | VIDCON0_CLKDIR;
+       if (ctx->clkdiv > 1)
+               val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
 
        writel(val, ctx->regs + VIDCON0);
 }
@@ -939,14 +955,14 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
        .update_plane = fimd_update_plane,
        .disable_plane = fimd_disable_plane,
        .atomic_flush = fimd_atomic_flush,
+       .atomic_check = fimd_atomic_check,
        .te_handler = fimd_te_handler,
 };
 
 static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
 {
        struct fimd_context *ctx = (struct fimd_context *)dev_id;
-       u32 val, clear_bit, start, start_s;
-       int win;
+       u32 val, clear_bit;
 
        val = readl(ctx->regs + VIDINTCON1);
 
@@ -961,18 +977,6 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
        if (!ctx->i80_if)
                drm_crtc_handle_vblank(&ctx->crtc->base);
 
-       for (win = 0 ; win < WINDOWS_NR ; win++) {
-               struct exynos_drm_plane *plane = &ctx->planes[win];
-
-               if (!plane->pending_fb)
-                       continue;
-
-               start = readl(ctx->regs + VIDWx_BUF_START(win, 0));
-               start_s = readl(ctx->regs + VIDWx_BUF_START_S(win, 0));
-               if (start == start_s)
-                       exynos_drm_crtc_finish_update(ctx->crtc, plane);
-       }
-
        if (ctx->i80_if) {
                /* Exits triggering mode */
                atomic_set(&ctx->triggering, 0);
index 6eca8bb..aa92dec 100644 (file)
@@ -138,6 +138,18 @@ enum g2d_reg_type {
        MAX_REG_TYPE_NR
 };
 
+enum g2d_flag_bits {
+       /*
+        * If set, suspends the runqueue worker after the currently
+        * processed node is finished.
+        */
+       G2D_BIT_SUSPEND_RUNQUEUE,
+       /*
+        * If set, indicates that the engine is currently busy.
+        */
+       G2D_BIT_ENGINE_BUSY,
+};
+
 /* cmdlist data structure */
 struct g2d_cmdlist {
        u32             head;
@@ -226,7 +238,7 @@ struct g2d_data {
        struct workqueue_struct         *g2d_workq;
        struct work_struct              runqueue_work;
        struct exynos_drm_subdrv        subdrv;
-       bool                            suspended;
+       unsigned long                   flags;
 
        /* cmdlist */
        struct g2d_cmdlist_node         *cmdlist_node;
@@ -246,6 +258,12 @@ struct g2d_data {
        unsigned long                   max_pool;
 };
 
+static inline void g2d_hw_reset(struct g2d_data *g2d)
+{
+       writel(G2D_R | G2D_SFRCLEAR, g2d->regs + G2D_SOFT_RESET);
+       clear_bit(G2D_BIT_ENGINE_BUSY, &g2d->flags);
+}
+
 static int g2d_init_cmdlist(struct g2d_data *g2d)
 {
        struct device *dev = g2d->dev;
@@ -803,12 +821,8 @@ static void g2d_dma_start(struct g2d_data *g2d,
        struct g2d_cmdlist_node *node =
                                list_first_entry(&runqueue_node->run_cmdlist,
                                                struct g2d_cmdlist_node, list);
-       int ret;
-
-       ret = pm_runtime_get_sync(g2d->dev);
-       if (ret < 0)
-               return;
 
+       set_bit(G2D_BIT_ENGINE_BUSY, &g2d->flags);
        writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR);
        writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND);
 }
@@ -831,9 +845,6 @@ static void g2d_free_runqueue_node(struct g2d_data *g2d,
 {
        struct g2d_cmdlist_node *node;
 
-       if (!runqueue_node)
-               return;
-
        mutex_lock(&g2d->cmdlist_mutex);
        /*
         * commands in run_cmdlist have been completed so unmap all gem
@@ -847,29 +858,65 @@ static void g2d_free_runqueue_node(struct g2d_data *g2d,
        kmem_cache_free(g2d->runqueue_slab, runqueue_node);
 }
 
-static void g2d_exec_runqueue(struct g2d_data *g2d)
+/**
+ * g2d_remove_runqueue_nodes - remove items from the list of runqueue nodes
+ * @g2d: G2D state object
+ * @file: if not zero, only remove items with this DRM file
+ *
+ * Has to be called under runqueue lock.
+ */
+static void g2d_remove_runqueue_nodes(struct g2d_data *g2d, struct drm_file* file)
 {
-       g2d->runqueue_node = g2d_get_runqueue_node(g2d);
-       if (g2d->runqueue_node)
-               g2d_dma_start(g2d, g2d->runqueue_node);
+       struct g2d_runqueue_node *node, *n;
+
+       if (list_empty(&g2d->runqueue))
+               return;
+
+       list_for_each_entry_safe(node, n, &g2d->runqueue, list) {
+               if (file && node->filp != file)
+                       continue;
+
+               list_del_init(&node->list);
+               g2d_free_runqueue_node(g2d, node);
+       }
 }
 
 static void g2d_runqueue_worker(struct work_struct *work)
 {
        struct g2d_data *g2d = container_of(work, struct g2d_data,
                                            runqueue_work);
+       struct g2d_runqueue_node *runqueue_node;
+
+       /*
+        * The engine is busy and the completion of the current node is going
+        * to poke the runqueue worker, so nothing to do here.
+        */
+       if (test_bit(G2D_BIT_ENGINE_BUSY, &g2d->flags))
+               return;
 
        mutex_lock(&g2d->runqueue_mutex);
-       pm_runtime_put_sync(g2d->dev);
 
-       complete(&g2d->runqueue_node->complete);
-       if (g2d->runqueue_node->async)
-               g2d_free_runqueue_node(g2d, g2d->runqueue_node);
+       runqueue_node = g2d->runqueue_node;
+       g2d->runqueue_node = NULL;
+
+       if (runqueue_node) {
+               pm_runtime_mark_last_busy(g2d->dev);
+               pm_runtime_put_autosuspend(g2d->dev);
+
+               complete(&runqueue_node->complete);
+               if (runqueue_node->async)
+                       g2d_free_runqueue_node(g2d, runqueue_node);
+       }
+
+       if (!test_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags)) {
+               g2d->runqueue_node = g2d_get_runqueue_node(g2d);
+
+               if (g2d->runqueue_node) {
+                       pm_runtime_get_sync(g2d->dev);
+                       g2d_dma_start(g2d, g2d->runqueue_node);
+               }
+       }
 
-       if (g2d->suspended)
-               g2d->runqueue_node = NULL;
-       else
-               g2d_exec_runqueue(g2d);
        mutex_unlock(&g2d->runqueue_mutex);
 }
 
@@ -918,12 +965,72 @@ static irqreturn_t g2d_irq_handler(int irq, void *dev_id)
                }
        }
 
-       if (pending & G2D_INTP_ACMD_FIN)
+       if (pending & G2D_INTP_ACMD_FIN) {
+               clear_bit(G2D_BIT_ENGINE_BUSY, &g2d->flags);
                queue_work(g2d->g2d_workq, &g2d->runqueue_work);
+       }
 
        return IRQ_HANDLED;
 }
 
+/**
+ * g2d_wait_finish - wait for the G2D engine to finish the current runqueue node
+ * @g2d: G2D state object
+ * @file: if not zero, only wait if the current runqueue node belongs
+ *        to the DRM file
+ *
+ * Should the engine not become idle after a 100ms timeout, a hardware
+ * reset is issued.
+ */
+static void g2d_wait_finish(struct g2d_data *g2d, struct drm_file *file)
+{
+       struct device *dev = g2d->dev;
+
+       struct g2d_runqueue_node *runqueue_node = NULL;
+       unsigned int tries = 10;
+
+       mutex_lock(&g2d->runqueue_mutex);
+
+       /* If no node is currently processed, we have nothing to do. */
+       if (!g2d->runqueue_node)
+               goto out;
+
+       runqueue_node = g2d->runqueue_node;
+
+       /* Check if the currently processed item belongs to us. */
+       if (file && runqueue_node->filp != file)
+               goto out;
+
+       mutex_unlock(&g2d->runqueue_mutex);
+
+       /* Wait for the G2D engine to finish. */
+       while (tries-- && (g2d->runqueue_node == runqueue_node))
+               mdelay(10);
+
+       mutex_lock(&g2d->runqueue_mutex);
+
+       if (g2d->runqueue_node != runqueue_node)
+               goto out;
+
+       dev_err(dev, "wait timed out, resetting engine...\n");
+       g2d_hw_reset(g2d);
+
+       /*
+        * After the hardware reset of the engine we are going to loose
+        * the IRQ which triggers the PM runtime put().
+        * So do this manually here.
+        */
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
+       complete(&runqueue_node->complete);
+       if (runqueue_node->async)
+               g2d_free_runqueue_node(g2d, runqueue_node);
+
+out:
+       mutex_unlock(&g2d->runqueue_mutex);
+}
+
 static int g2d_check_reg_offset(struct device *dev,
                                struct g2d_cmdlist_node *node,
                                int nr, bool for_addr)
@@ -1259,10 +1366,11 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
        runqueue_node->pid = current->pid;
        runqueue_node->filp = file;
        list_add_tail(&runqueue_node->list, &g2d->runqueue);
-       if (!g2d->runqueue_node)
-               g2d_exec_runqueue(g2d);
        mutex_unlock(&g2d->runqueue_mutex);
 
+       /* Let the runqueue know that there is work to do. */
+       queue_work(g2d->g2d_workq, &g2d->runqueue_work);
+
        if (runqueue_node->async)
                goto out;
 
@@ -1339,15 +1447,26 @@ static void g2d_close(struct drm_device *drm_dev, struct device *dev,
        if (!g2d)
                return;
 
+       /* Remove the runqueue nodes that belong to us. */
+       mutex_lock(&g2d->runqueue_mutex);
+       g2d_remove_runqueue_nodes(g2d, file);
+       mutex_unlock(&g2d->runqueue_mutex);
+
+       /*
+        * Wait for the runqueue worker to finish its current node.
+        * After this the engine should no longer be accessing any
+        * memory belonging to us.
+        */
+       g2d_wait_finish(g2d, file);
+
+       /*
+        * Even after the engine is idle, there might still be stale cmdlists
+        * (i.e. cmdlisst which we submitted but never executed) around, with
+        * their corresponding GEM/userptr buffers.
+        * Properly unmap these buffers here.
+        */
        mutex_lock(&g2d->cmdlist_mutex);
        list_for_each_entry_safe(node, n, &g2d_priv->inuse_cmdlist, list) {
-               /*
-                * unmap all gem objects not completed.
-                *
-                * P.S. if current process was terminated forcely then
-                * there may be some commands in inuse_cmdlist so unmap
-                * them.
-                */
                g2d_unmap_cmdlist_gem(g2d, node, file);
                list_move_tail(&node->list, &g2d->free_cmdlist);
        }
@@ -1399,7 +1518,11 @@ static int g2d_probe(struct platform_device *pdev)
                goto err_destroy_workqueue;
        }
 
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_set_autosuspend_delay(dev, 2000);
        pm_runtime_enable(dev);
+       clear_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
+       clear_bit(G2D_BIT_ENGINE_BUSY, &g2d->flags);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
@@ -1440,7 +1563,7 @@ static int g2d_probe(struct platform_device *pdev)
                goto err_put_clk;
        }
 
-       dev_info(dev, "The exynos g2d(ver %d.%d) successfully probed\n",
+       dev_info(dev, "The Exynos G2D (ver %d.%d) successfully probed.\n",
                        G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER);
 
        return 0;
@@ -1458,14 +1581,17 @@ static int g2d_remove(struct platform_device *pdev)
 {
        struct g2d_data *g2d = platform_get_drvdata(pdev);
 
+       /* Suspend operation and wait for engine idle. */
+       set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
+       g2d_wait_finish(g2d, NULL);
+
        cancel_work_sync(&g2d->runqueue_work);
        exynos_drm_subdrv_unregister(&g2d->subdrv);
 
-       while (g2d->runqueue_node) {
-               g2d_free_runqueue_node(g2d, g2d->runqueue_node);
-               g2d->runqueue_node = g2d_get_runqueue_node(g2d);
-       }
+       /* There should be no locking needed here. */
+       g2d_remove_runqueue_nodes(g2d, NULL);
 
+       pm_runtime_dont_use_autosuspend(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
        g2d_fini_cmdlist(g2d);
@@ -1475,20 +1601,37 @@ static int g2d_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int g2d_runtime_suspend(struct device *dev)
+#ifdef CONFIG_PM_SLEEP
+static int g2d_suspend(struct device *dev)
 {
        struct g2d_data *g2d = dev_get_drvdata(dev);
 
-       mutex_lock(&g2d->runqueue_mutex);
-       g2d->suspended = true;
-       mutex_unlock(&g2d->runqueue_mutex);
+       /*
+        * Suspend the runqueue worker operation and wait until the G2D
+        * engine is idle.
+        */
+       set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
+       g2d_wait_finish(g2d, NULL);
+       flush_work(&g2d->runqueue_work);
 
-       while (g2d->runqueue_node)
-               /* FIXME: good range? */
-               usleep_range(500, 1000);
+       return 0;
+}
 
-       flush_work(&g2d->runqueue_work);
+static int g2d_resume(struct device *dev)
+{
+       struct g2d_data *g2d = dev_get_drvdata(dev);
+
+       clear_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
+       queue_work(g2d->g2d_workq, &g2d->runqueue_work);
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int g2d_runtime_suspend(struct device *dev)
+{
+       struct g2d_data *g2d = dev_get_drvdata(dev);
 
        clk_disable_unprepare(g2d->gate_clk);
 
@@ -1504,16 +1647,12 @@ static int g2d_runtime_resume(struct device *dev)
        if (ret < 0)
                dev_warn(dev, "failed to enable clock.\n");
 
-       g2d->suspended = false;
-       g2d_exec_runqueue(g2d);
-
        return ret;
 }
 #endif
 
 static const struct dev_pm_ops g2d_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                               pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(g2d_suspend, g2d_resume)
        SET_RUNTIME_PM_OPS(g2d_runtime_suspend, g2d_runtime_resume, NULL)
 };
 
index 7f32419..c2f17f3 100644 (file)
@@ -238,7 +238,6 @@ static void exynos_plane_atomic_update(struct drm_plane *plane,
                return;
 
        plane->crtc = state->crtc;
-       exynos_plane->pending_fb = state->fb;
 
        if (exynos_crtc->ops->update_plane)
                exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane);
index e8f6c92..57fe514 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/component.h>
+#include <linux/timer.h>
 
 #include <drm/exynos_drm.h>
 
@@ -28,6 +29,9 @@
 #include "exynos_drm_plane.h"
 #include "exynos_drm_vidi.h"
 
+/* VIDI uses fixed refresh rate of 50Hz */
+#define VIDI_REFRESH_TIME (1000 / 50)
+
 /* vidi has totally three virtual windows. */
 #define WINDOWS_NR             3
 
@@ -43,12 +47,9 @@ struct vidi_context {
        struct exynos_drm_plane         planes[WINDOWS_NR];
        struct edid                     *raw_edid;
        unsigned int                    clkdiv;
-       unsigned long                   irq_flags;
        unsigned int                    connected;
-       bool                            vblank_on;
        bool                            suspended;
-       bool                            direct_vblank;
-       struct work_struct              work;
+       struct timer_list               timer;
        struct mutex                    lock;
        int                             pipe;
 };
@@ -102,30 +103,14 @@ static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
        if (ctx->suspended)
                return -EPERM;
 
-       if (!test_and_set_bit(0, &ctx->irq_flags))
-               ctx->vblank_on = true;
-
-       ctx->direct_vblank = true;
-
-       /*
-        * in case of page flip request, vidi_finish_pageflip function
-        * will not be called because direct_vblank is true and then
-        * that function will be called by crtc_ops->update_plane callback
-        */
-       schedule_work(&ctx->work);
+       mod_timer(&ctx->timer,
+               jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
 
        return 0;
 }
 
 static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
 {
-       struct vidi_context *ctx = crtc->ctx;
-
-       if (ctx->suspended)
-               return;
-
-       if (test_and_clear_bit(0, &ctx->irq_flags))
-               ctx->vblank_on = false;
 }
 
 static void vidi_update_plane(struct exynos_drm_crtc *crtc,
@@ -140,9 +125,6 @@ static void vidi_update_plane(struct exynos_drm_crtc *crtc,
 
        addr = exynos_drm_fb_dma_addr(state->fb, 0);
        DRM_DEBUG_KMS("dma_addr = %pad\n", &addr);
-
-       if (ctx->vblank_on)
-               schedule_work(&ctx->work);
 }
 
 static void vidi_enable(struct exynos_drm_crtc *crtc)
@@ -153,17 +135,17 @@ static void vidi_enable(struct exynos_drm_crtc *crtc)
 
        ctx->suspended = false;
 
-       /* if vblank was enabled status, enable it again. */
-       if (test_and_clear_bit(0, &ctx->irq_flags))
-               vidi_enable_vblank(ctx->crtc);
-
        mutex_unlock(&ctx->lock);
+
+       drm_crtc_vblank_on(&crtc->base);
 }
 
 static void vidi_disable(struct exynos_drm_crtc *crtc)
 {
        struct vidi_context *ctx = crtc->ctx;
 
+       drm_crtc_vblank_off(&crtc->base);
+
        mutex_lock(&ctx->lock);
 
        ctx->suspended = true;
@@ -190,37 +172,16 @@ static const struct exynos_drm_crtc_ops vidi_crtc_ops = {
        .update_plane = vidi_update_plane,
 };
 
-static void vidi_fake_vblank_handler(struct work_struct *work)
+static void vidi_fake_vblank_timer(unsigned long arg)
 {
-       struct vidi_context *ctx = container_of(work, struct vidi_context,
-                                       work);
-       int win;
+       struct vidi_context *ctx = (void *)arg;
 
        if (ctx->pipe < 0)
                return;
 
-       /* refresh rate is about 50Hz. */
-       usleep_range(16000, 20000);
-
-       mutex_lock(&ctx->lock);
-
-       if (ctx->direct_vblank) {
-               drm_crtc_handle_vblank(&ctx->crtc->base);
-               ctx->direct_vblank = false;
-               mutex_unlock(&ctx->lock);
-               return;
-       }
-
-       mutex_unlock(&ctx->lock);
-
-       for (win = 0 ; win < WINDOWS_NR ; win++) {
-               struct exynos_drm_plane *plane = &ctx->planes[win];
-
-               if (!plane->pending_fb)
-                       continue;
-
-               exynos_drm_crtc_finish_update(ctx->crtc, plane);
-       }
+       if (drm_crtc_handle_vblank(&ctx->crtc->base))
+               mod_timer(&ctx->timer,
+                       jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
 }
 
 static ssize_t vidi_show_connection(struct device *dev,
@@ -489,6 +450,9 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
 
 static void vidi_unbind(struct device *dev, struct device *master, void *data)
 {
+       struct vidi_context *ctx = dev_get_drvdata(dev);
+
+       del_timer_sync(&ctx->timer);
 }
 
 static const struct component_ops vidi_component_ops = {
@@ -507,7 +471,7 @@ static int vidi_probe(struct platform_device *pdev)
 
        ctx->pdev = pdev;
 
-       INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
+       setup_timer(&ctx->timer, vidi_fake_vblank_timer, (unsigned long)ctx);
 
        mutex_init(&ctx->lock);
 
index 2275efe..e8fb6ef 100644 (file)
@@ -1669,10 +1669,9 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
        if (ret)
                return ret;
 
-       for (i = 0; i < ARRAY_SIZE(supply); ++i) {
+       for (i = 0; i < ARRAY_SIZE(supply); ++i)
                hdata->regul_bulk[i].supply = supply[i];
-               hdata->regul_bulk[i].consumer = NULL;
-       }
+
        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
        if (ret) {
                if (ret != -EPROBE_DEFER)
@@ -1760,28 +1759,74 @@ static const struct component_ops hdmi_component_ops = {
        .unbind = hdmi_unbind,
 };
 
-static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
+static int hdmi_get_ddc_adapter(struct hdmi_context *hdata)
 {
        const char *compatible_str = "samsung,exynos4210-hdmiddc";
        struct device_node *np;
+       struct i2c_adapter *adpt;
 
        np = of_find_compatible_node(NULL, NULL, compatible_str);
        if (np)
-               return of_get_next_parent(np);
+               np = of_get_next_parent(np);
+       else
+               np = of_parse_phandle(hdata->dev->of_node, "ddc", 0);
+
+       if (!np) {
+               DRM_ERROR("Failed to find ddc node in device tree\n");
+               return -ENODEV;
+       }
 
-       return NULL;
+       adpt = of_find_i2c_adapter_by_node(np);
+       of_node_put(np);
+
+       if (!adpt) {
+               DRM_INFO("Failed to get ddc i2c adapter by node\n");
+               return -EPROBE_DEFER;
+       }
+
+       hdata->ddc_adpt = adpt;
+
+       return 0;
 }
 
-static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
+static int hdmi_get_phy_io(struct hdmi_context *hdata)
 {
        const char *compatible_str = "samsung,exynos4212-hdmiphy";
+       struct device_node *np;
+       int ret = 0;
+
+       np = of_find_compatible_node(NULL, NULL, compatible_str);
+       if (!np) {
+               np = of_parse_phandle(hdata->dev->of_node, "phy", 0);
+               if (!np) {
+                       DRM_ERROR("Failed to find hdmiphy node in device tree\n");
+                       return -ENODEV;
+               }
+       }
+
+       if (hdata->drv_data->is_apb_phy) {
+               hdata->regs_hdmiphy = of_iomap(np, 0);
+               if (!hdata->regs_hdmiphy) {
+                       DRM_ERROR("failed to ioremap hdmi phy\n");
+                       ret = -ENOMEM;
+                       goto out;
+               }
+       } else {
+               hdata->hdmiphy_port = of_find_i2c_device_by_node(np);
+               if (!hdata->hdmiphy_port) {
+                       DRM_INFO("Failed to get hdmi phy i2c client\n");
+                       ret = -EPROBE_DEFER;
+                       goto out;
+               }
+       }
 
-       return of_find_compatible_node(NULL, NULL, compatible_str);
+out:
+       of_node_put(np);
+       return ret;
 }
 
 static int hdmi_probe(struct platform_device *pdev)
 {
-       struct device_node *ddc_node, *phy_node;
        struct device *dev = &pdev->dev;
        struct hdmi_context *hdata;
        struct resource *res;
@@ -1811,52 +1856,13 @@ static int hdmi_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ddc_node = hdmi_legacy_ddc_dt_binding(dev);
-       if (ddc_node)
-               goto out_get_ddc_adpt;
-
-       ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
-       if (!ddc_node) {
-               DRM_ERROR("Failed to find ddc node in device tree\n");
-               return -ENODEV;
-       }
-       of_node_put(dev->of_node);
-
-out_get_ddc_adpt:
-       hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
-       if (!hdata->ddc_adpt) {
-               DRM_ERROR("Failed to get ddc i2c adapter by node\n");
-               return -EPROBE_DEFER;
-       }
-
-       phy_node = hdmi_legacy_phy_dt_binding(dev);
-       if (phy_node)
-               goto out_get_phy_port;
+       ret = hdmi_get_ddc_adapter(hdata);
+       if (ret)
+               return ret;
 
-       phy_node = of_parse_phandle(dev->of_node, "phy", 0);
-       if (!phy_node) {
-               DRM_ERROR("Failed to find hdmiphy node in device tree\n");
-               ret = -ENODEV;
+       ret = hdmi_get_phy_io(hdata);
+       if (ret)
                goto err_ddc;
-       }
-       of_node_put(dev->of_node);
-
-out_get_phy_port:
-       if (hdata->drv_data->is_apb_phy) {
-               hdata->regs_hdmiphy = of_iomap(phy_node, 0);
-               if (!hdata->regs_hdmiphy) {
-                       DRM_ERROR("failed to ioremap hdmi phy\n");
-                       ret = -ENOMEM;
-                       goto err_ddc;
-               }
-       } else {
-               hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
-               if (!hdata->hdmiphy_port) {
-                       DRM_ERROR("Failed to get hdmi phy i2c client\n");
-                       ret = -EPROBE_DEFER;
-                       goto err_ddc;
-               }
-       }
 
        INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
 
index e1d47f9..edb20a3 100644 (file)
@@ -73,6 +73,9 @@ enum mixer_version_id {
 enum mixer_flag_bits {
        MXR_BIT_POWERED,
        MXR_BIT_VSYNC,
+       MXR_BIT_INTERLACE,
+       MXR_BIT_VP_ENABLED,
+       MXR_BIT_HAS_SCLK,
 };
 
 static const uint32_t mixer_formats[] = {
@@ -98,9 +101,6 @@ struct mixer_context {
        struct exynos_drm_plane planes[MIXER_WIN_NR];
        int                     pipe;
        unsigned long           flags;
-       bool                    interlace;
-       bool                    vp_enabled;
-       bool                    has_sclk;
 
        struct mixer_resources  mixer_res;
        enum mixer_version_id   mxr_ver;
@@ -346,7 +346,7 @@ static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
        mixer_reg_writemask(res, MXR_STATUS, enable ?
                        MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
 
-       if (ctx->vp_enabled)
+       if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
                vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
                        VP_SHADOW_UPDATE_ENABLE : 0);
 }
@@ -357,8 +357,8 @@ static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
        u32 val;
 
        /* choosing between interlace and progressive mode */
-       val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
-                               MXR_CFG_SCAN_PROGRESSIVE);
+       val = test_bit(MXR_BIT_INTERLACE, &ctx->flags) ?
+               MXR_CFG_SCAN_INTERLACE : MXR_CFG_SCAN_PROGRESSIVE;
 
        if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
                /* choosing between proper HD and SD mode */
@@ -436,9 +436,10 @@ static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
                mixer_reg_writemask(res, MXR_LAYER_CFG,
                                    MXR_LAYER_CFG_GRP1_VAL(priority),
                                    MXR_LAYER_CFG_GRP1_MASK);
+
                break;
        case VP_DEFAULT_WIN:
-               if (ctx->vp_enabled) {
+               if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
                        vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
                        mixer_reg_writemask(res, MXR_CFG, val,
                                MXR_CFG_VP_ENABLE);
@@ -501,7 +502,7 @@ static void vp_video_buffer(struct mixer_context *ctx,
        chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
 
        if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
-               ctx->interlace = true;
+               __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
                if (tiled_mode) {
                        luma_addr[1] = luma_addr[0] + 0x40;
                        chroma_addr[1] = chroma_addr[0] + 0x40;
@@ -510,7 +511,7 @@ static void vp_video_buffer(struct mixer_context *ctx,
                        chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
                }
        } else {
-               ctx->interlace = false;
+               __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
                luma_addr[1] = 0;
                chroma_addr[1] = 0;
        }
@@ -518,7 +519,7 @@ static void vp_video_buffer(struct mixer_context *ctx,
        spin_lock_irqsave(&res->reg_slock, flags);
 
        /* interlace or progressive scan mode */
-       val = (ctx->interlace ? ~0 : 0);
+       val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
        vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
 
        /* setup format */
@@ -541,7 +542,7 @@ static void vp_video_buffer(struct mixer_context *ctx,
 
        vp_reg_write(res, VP_DST_WIDTH, state->crtc.w);
        vp_reg_write(res, VP_DST_H_POSITION, state->crtc.x);
-       if (ctx->interlace) {
+       if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
                vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h / 2);
                vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y / 2);
        } else {
@@ -636,9 +637,9 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
        src_y_offset = 0;
 
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-               ctx->interlace = true;
+               __set_bit(MXR_BIT_INTERLACE, &ctx->flags);
        else
-               ctx->interlace = false;
+               __clear_bit(MXR_BIT_INTERLACE, &ctx->flags);
 
        spin_lock_irqsave(&res->reg_slock, flags);
 
@@ -697,10 +698,10 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
 static void vp_win_reset(struct mixer_context *ctx)
 {
        struct mixer_resources *res = &ctx->mixer_res;
-       int tries = 100;
+       unsigned int tries = 100;
 
        vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
-       for (tries = 100; tries; --tries) {
+       while (tries--) {
                /* waiting until VP_SRESET_PROCESSING is 0 */
                if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
                        break;
@@ -733,7 +734,7 @@ static void mixer_win_reset(struct mixer_context *ctx)
        mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
        mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
 
-       if (ctx->vp_enabled) {
+       if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
                /* configuration of Video Processor Registers */
                vp_win_reset(ctx);
                vp_default_filter(res);
@@ -742,7 +743,7 @@ static void mixer_win_reset(struct mixer_context *ctx)
        /* disable all layers */
        mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
        mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
-       if (ctx->vp_enabled)
+       if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
                mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
 
        spin_unlock_irqrestore(&res->reg_slock, flags);
@@ -753,7 +754,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
        struct mixer_context *ctx = arg;
        struct mixer_resources *res = &ctx->mixer_res;
        u32 val, base, shadow;
-       int win;
 
        spin_lock(&res->reg_slock);
 
@@ -767,7 +767,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
                val &= ~MXR_INT_STATUS_VSYNC;
 
                /* interlace scan need to check shadow register */
-               if (ctx->interlace) {
+               if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
                        base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
                        shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
                        if (base != shadow)
@@ -780,14 +780,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
                }
 
                drm_crtc_handle_vblank(&ctx->crtc->base);
-               for (win = 0 ; win < MIXER_WIN_NR ; win++) {
-                       struct exynos_drm_plane *plane = &ctx->planes[win];
-
-                       if (!plane->pending_fb)
-                               continue;
-
-                       exynos_drm_crtc_finish_update(ctx->crtc, plane);
-               }
        }
 
 out:
@@ -867,7 +859,7 @@ static int vp_resources_init(struct mixer_context *mixer_ctx)
                return -ENODEV;
        }
 
-       if (mixer_ctx->has_sclk) {
+       if (test_bit(MXR_BIT_HAS_SCLK, &mixer_ctx->flags)) {
                mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
                if (IS_ERR(mixer_res->sclk_mixer)) {
                        dev_err(dev, "failed to get clock 'sclk_mixer'\n");
@@ -917,7 +909,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
                return ret;
        }
 
-       if (mixer_ctx->vp_enabled) {
+       if (test_bit(MXR_BIT_VP_ENABLED, &mixer_ctx->flags)) {
                /* acquire vp resources: regs, irqs, clocks */
                ret = vp_resources_init(mixer_ctx);
                if (ret) {
@@ -1160,7 +1152,8 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
                return ret;
 
        for (i = 0; i < MIXER_WIN_NR; i++) {
-               if (i == VP_DEFAULT_WIN && !ctx->vp_enabled)
+               if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED,
+                                                    &ctx->flags))
                        continue;
 
                ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
@@ -1215,10 +1208,13 @@ static int mixer_probe(struct platform_device *pdev)
 
        ctx->pdev = pdev;
        ctx->dev = dev;
-       ctx->vp_enabled = drv->is_vp_enabled;
-       ctx->has_sclk = drv->has_sclk;
        ctx->mxr_ver = drv->version;
 
+       if (drv->is_vp_enabled)
+               __set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
+       if (drv->has_sclk)
+               __set_bit(MXR_BIT_HAS_SCLK, &ctx->flags);
+
        platform_set_drvdata(pdev, ctx);
 
        ret = component_add(&pdev->dev, &mixer_component_ops);
@@ -1244,9 +1240,9 @@ static int __maybe_unused exynos_mixer_suspend(struct device *dev)
 
        clk_disable_unprepare(res->hdmi);
        clk_disable_unprepare(res->mixer);
-       if (ctx->vp_enabled) {
+       if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
                clk_disable_unprepare(res->vp);
-               if (ctx->has_sclk)
+               if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags))
                        clk_disable_unprepare(res->sclk_mixer);
        }
 
@@ -1269,14 +1265,14 @@ static int __maybe_unused exynos_mixer_resume(struct device *dev)
                DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
                return ret;
        }
-       if (ctx->vp_enabled) {
+       if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) {
                ret = clk_prepare_enable(res->vp);
                if (ret < 0) {
                        DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
                                  ret);
                        return ret;
                }
-               if (ctx->has_sclk) {
+               if (test_bit(MXR_BIT_HAS_SCLK, &ctx->flags)) {
                        ret = clk_prepare_enable(res->sclk_mixer);
                        if (ret < 0) {
                                DRM_ERROR("Failed to prepare_enable the " \
index 7882387..0884c45 100644 (file)
@@ -270,7 +270,7 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
        ret = clk_prepare_enable(fsl_dev->pix_clk);
        if (ret < 0) {
                dev_err(dev, "failed to enable pix clk\n");
-               return ret;
+               goto disable_dcu_clk;
        }
 
        fsl_dcu_drm_init_planes(fsl_dev->drm);
@@ -284,6 +284,10 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
        enable_irq(fsl_dev->irq);
 
        return 0;
+
+disable_dcu_clk:
+       clk_disable_unprepare(fsl_dev->clk);
+       return ret;
 }
 #endif
 
@@ -330,6 +334,7 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
        const char *pix_clk_in_name;
        const struct of_device_id *id;
        int ret;
+       u8 div_ratio_shift = 0;
 
        fsl_dev = devm_kzalloc(dev, sizeof(*fsl_dev), GFP_KERNEL);
        if (!fsl_dev)
@@ -382,11 +387,14 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
                pix_clk_in = fsl_dev->clk;
        }
 
+       if (of_property_read_bool(dev->of_node, "big-endian"))
+               div_ratio_shift = 24;
+
        pix_clk_in_name = __clk_get_name(pix_clk_in);
        snprintf(pix_clk_name, sizeof(pix_clk_name), "%s_pix", pix_clk_in_name);
        fsl_dev->pix_clk = clk_register_divider(dev, pix_clk_name,
                        pix_clk_in_name, 0, base + DCU_DIV_RATIO,
-                       0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL);
+                       div_ratio_shift, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL);
        if (IS_ERR(fsl_dev->pix_clk)) {
                dev_err(dev, "failed to register pix clk\n");
                ret = PTR_ERR(fsl_dev->pix_clk);
@@ -402,8 +410,8 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
        fsl_dev->tcon = fsl_tcon_init(dev);
 
        drm = drm_dev_alloc(driver, dev);
-       if (!drm) {
-               ret = -ENOMEM;
+       if (IS_ERR(drm)) {
+               ret = PTR_ERR(drm);
                goto disable_pix_clk;
        }
 
index e50467a..a7e5486 100644 (file)
@@ -169,25 +169,10 @@ static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
        return;
 }
 
-static void
-fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
-                            const struct drm_plane_state *new_state)
-{
-}
-
-static int
-fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,
-                            const struct drm_plane_state *new_state)
-{
-       return 0;
-}
-
 static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {
        .atomic_check = fsl_dcu_drm_plane_atomic_check,
        .atomic_disable = fsl_dcu_drm_plane_atomic_disable,
        .atomic_update = fsl_dcu_drm_plane_atomic_update,
-       .cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
-       .prepare_fb = fsl_dcu_drm_plane_prepare_fb,
 };
 
 static void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
index bca09ea..3194e54 100644 (file)
@@ -57,10 +57,7 @@ static int fsl_tcon_init_regmap(struct device *dev,
 
        tcon->regs = devm_regmap_init_mmio(dev, regs,
                                           &fsl_tcon_regmap_config);
-       if (IS_ERR(tcon->regs))
-               return PTR_ERR(tcon->regs);
-
-       return 0;
+       return PTR_ERR_OR_ZERO(tcon->regs);
 }
 
 struct fsl_tcon *fsl_tcon_init(struct device *dev)
index db9f7d0..0d2bb16 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/tty.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/console.h>
 
index 38dc890..ea733ab 100644 (file)
@@ -415,14 +415,6 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector)
        if (ret)
                return ret;
 
-       /* Didn't get an EDID, so
-        * Set wide sync ranges so we get all modes
-        * handed to valid_mode for checking
-        */
-       connector->display_info.min_vfreq = 0;
-       connector->display_info.max_vfreq = 200;
-       connector->display_info.min_hfreq = 0;
-       connector->display_info.max_hfreq = 200;
        if (mode_dev->panel_fixed_mode != NULL) {
                struct drm_display_mode *mode =
                    drm_mode_duplicate(dev, mode_dev->panel_fixed_mode);
index 0fcdce0..3a44e70 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/tty.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/console.h>
 
index 907cb51..acb3848 100644 (file)
@@ -335,11 +335,6 @@ static int mdfld_dsi_connector_get_modes(struct drm_connector *connector)
        struct drm_display_mode *dup_mode = NULL;
        struct drm_device *dev = connector->dev;
 
-       connector->display_info.min_vfreq = 0;
-       connector->display_info.max_vfreq = 200;
-       connector->display_info.min_hfreq = 0;
-       connector->display_info.max_hfreq = 200;
-
        if (fixed_mode) {
                dev_dbg(dev->dev, "fixed_mode %dx%d\n",
                                fixed_mode->hdisplay, fixed_mode->vdisplay);
index ab696ca..eab6d88 100644 (file)
@@ -163,10 +163,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
        if (bclp > 255)
                return ASLE_BACKLIGHT_FAILED;
 
-       if (config_enabled(CONFIG_BACKLIGHT_CLASS_DEVICE)) {
-               int max = bd->props.max_brightness;
-               gma_backlight_set(dev, bclp * max / 255);
-       }
+       gma_backlight_set(dev, bclp * bd->props.max_brightness / 255);
 
        asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID;
 
index e55733c..fd7c912 100644 (file)
@@ -530,15 +530,6 @@ static int psb_intel_lvds_get_modes(struct drm_connector *connector)
        if (ret)
                return ret;
 
-       /* Didn't get an EDID, so
-        * Set wide sync ranges so we get all modes
-        * handed to valid_mode for checking
-        */
-       connector->display_info.min_vfreq = 0;
-       connector->display_info.max_vfreq = 200;
-       connector->display_info.min_hfreq = 0;
-       connector->display_info.max_hfreq = 200;
-
        if (mode_dev->panel_fixed_mode != NULL) {
                struct drm_display_mode *mode =
                    drm_mode_duplicate(dev, mode_dev->panel_fixed_mode);
index 4fca0d6..e536072 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <linux/i2c.h>
-#include <linux/fb.h>
 #include <drm/drmP.h>
 #include "psb_intel_drv.h"
 
index c3707d4..7e7a4d4 100644 (file)
@@ -608,15 +608,17 @@ static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb,
                         u32 ch, u32 y, u32 in_h, u32 fmt)
 {
        struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
+       char *format_name;
        u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
        u32 stride = fb->pitches[0];
        u32 addr = (u32)obj->paddr + y * stride;
 
        DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n",
                         ch + 1, y, in_h, stride, (u32)obj->paddr);
+       format_name = drm_get_format_name(fb->pixel_format);
        DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
-                        addr, fb->width, fb->height, fmt,
-                        drm_get_format_name(fb->pixel_format));
+                        addr, fb->width, fb->height, fmt, format_name);
+       kfree(format_name);
 
        /* get reg offset */
        reg_ctrl = RD_CH_CTRL(ch);
@@ -815,19 +817,6 @@ static void ade_disable_channel(struct ade_plane *aplane)
        ade_compositor_routing_disable(base, ch);
 }
 
-static int ade_plane_prepare_fb(struct drm_plane *plane,
-                               const struct drm_plane_state *new_state)
-{
-       /* do nothing */
-       return 0;
-}
-
-static void ade_plane_cleanup_fb(struct drm_plane *plane,
-                                const struct drm_plane_state *old_state)
-{
-       /* do nothing */
-}
-
 static int ade_plane_atomic_check(struct drm_plane *plane,
                                  struct drm_plane_state *state)
 {
@@ -895,8 +884,6 @@ static void ade_plane_atomic_disable(struct drm_plane *plane,
 }
 
 static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
-       .prepare_fb = ade_plane_prepare_fb,
-       .cleanup_fb = ade_plane_cleanup_fb,
        .atomic_check = ade_plane_atomic_check,
        .atomic_update = ade_plane_atomic_update,
        .atomic_disable = ade_plane_atomic_disable,
index 1edd9bc..90377a6 100644 (file)
@@ -169,7 +169,7 @@ static int kirin_gem_cma_dumb_create(struct drm_file *file,
 
 static struct drm_driver kirin_drm_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
-                                 DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
+                                 DRIVER_ATOMIC,
        .fops                   = &kirin_drm_fops,
 
        .gem_free_object_unlocked = drm_gem_cma_free_object,
@@ -207,8 +207,8 @@ static int kirin_drm_bind(struct device *dev)
        int ret;
 
        drm_dev = drm_dev_alloc(driver, dev);
-       if (!drm_dev)
-               return -ENOMEM;
+       if (IS_ERR(drm_dev))
+               return PTR_ERR(drm_dev);
 
        drm_dev->platformdev = to_platform_device(dev);
 
index 4d341db..a6c92be 100644 (file)
@@ -22,6 +22,7 @@ config DRM_I2C_SIL164
 config DRM_I2C_NXP_TDA998X
        tristate "NXP Semiconductors TDA998X HDMI encoder"
        default m if DRM_TILCDC
+       select SND_SOC_HDMI_CODEC if SND_SOC
        help
          Support for NXP Semiconductors TDA998X HDMI encoders.
 
index f4315bc..9798d40 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/irq.h>
 #include <sound/asoundef.h>
+#include <sound/hdmi-codec.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic_helper.h>
 
 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 
+struct tda998x_audio_port {
+       u8 format;              /* AFMT_xxx */
+       u8 config;              /* AP value */
+};
+
 struct tda998x_priv {
        struct i2c_client *cec;
        struct i2c_client *hdmi;
@@ -41,7 +47,10 @@ struct tda998x_priv {
        u8 vip_cntrl_0;
        u8 vip_cntrl_1;
        u8 vip_cntrl_2;
-       struct tda998x_encoder_params params;
+       struct tda998x_audio_params audio_params;
+
+       struct platform_device *audio_pdev;
+       struct mutex audio_mutex;
 
        wait_queue_head_t wq_edid;
        volatile int wq_edid_wait;
@@ -53,6 +62,8 @@ struct tda998x_priv {
 
        struct drm_encoder encoder;
        struct drm_connector connector;
+
+       struct tda998x_audio_port audio_port[2];
 };
 
 #define conn_to_tda998x_priv(x) \
@@ -666,26 +677,16 @@ tda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr,
        reg_set(priv, REG_DIP_IF_FLAGS, bit);
 }
 
-static void
-tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p)
+static int tda998x_write_aif(struct tda998x_priv *priv,
+                            struct hdmi_audio_infoframe *cea)
 {
        union hdmi_infoframe frame;
 
-       hdmi_audio_infoframe_init(&frame.audio);
-
-       frame.audio.channels = p->audio_frame[1] & 0x07;
-       frame.audio.channel_allocation = p->audio_frame[4];
-       frame.audio.level_shift_value = (p->audio_frame[5] & 0x78) >> 3;
-       frame.audio.downmix_inhibit = (p->audio_frame[5] & 0x80) >> 7;
-
-       /*
-        * L-PCM and IEC61937 compressed audio shall always set sample
-        * frequency to "refer to stream".  For others, see the HDMI
-        * specification.
-        */
-       frame.audio.sample_frequency = (p->audio_frame[2] & 0x1c) >> 2;
+       frame.audio = *cea;
 
        tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame);
+
+       return 0;
 }
 
 static void
@@ -710,20 +711,21 @@ static void tda998x_audio_mute(struct tda998x_priv *priv, bool on)
        }
 }
 
-static void
+static int
 tda998x_configure_audio(struct tda998x_priv *priv,
-               struct drm_display_mode *mode, struct tda998x_encoder_params *p)
+                       struct tda998x_audio_params *params,
+                       unsigned mode_clock)
 {
        u8 buf[6], clksel_aip, clksel_fs, cts_n, adiv;
        u32 n;
 
        /* Enable audio ports */
-       reg_write(priv, REG_ENA_AP, p->audio_cfg);
-       reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg);
+       reg_write(priv, REG_ENA_AP, params->config);
 
        /* Set audio input source */
-       switch (p->audio_format) {
+       switch (params->format) {
        case AFMT_SPDIF:
+               reg_write(priv, REG_ENA_ACLK, 0);
                reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF);
                clksel_aip = AIP_CLKSEL_AIP_SPDIF;
                clksel_fs = AIP_CLKSEL_FS_FS64SPDIF;
@@ -731,15 +733,29 @@ tda998x_configure_audio(struct tda998x_priv *priv,
                break;
 
        case AFMT_I2S:
+               reg_write(priv, REG_ENA_ACLK, 1);
                reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S);
                clksel_aip = AIP_CLKSEL_AIP_I2S;
                clksel_fs = AIP_CLKSEL_FS_ACLK;
-               cts_n = CTS_N_M(3) | CTS_N_K(3);
+               switch (params->sample_width) {
+               case 16:
+                       cts_n = CTS_N_M(3) | CTS_N_K(1);
+                       break;
+               case 18:
+               case 20:
+               case 24:
+                       cts_n = CTS_N_M(3) | CTS_N_K(2);
+                       break;
+               default:
+               case 32:
+                       cts_n = CTS_N_M(3) | CTS_N_K(3);
+                       break;
+               }
                break;
 
        default:
-               BUG();
-               return;
+               dev_err(&priv->hdmi->dev, "Unsupported I2S format\n");
+               return -EINVAL;
        }
 
        reg_write(priv, REG_AIP_CLKSEL, clksel_aip);
@@ -755,11 +771,11 @@ tda998x_configure_audio(struct tda998x_priv *priv,
         * assume 100MHz requires larger divider.
         */
        adiv = AUDIO_DIV_SERCLK_8;
-       if (mode->clock > 100000)
+       if (mode_clock > 100000)
                adiv++;                 /* AUDIO_DIV_SERCLK_16 */
 
        /* S/PDIF asks for a larger divider */
-       if (p->audio_format == AFMT_SPDIF)
+       if (params->format == AFMT_SPDIF)
                adiv++;                 /* AUDIO_DIV_SERCLK_16 or _32 */
 
        reg_write(priv, REG_AUDIO_DIV, adiv);
@@ -768,7 +784,7 @@ tda998x_configure_audio(struct tda998x_priv *priv,
         * This is the approximate value of N, which happens to be
         * the recommended values for non-coherent clocks.
         */
-       n = 128 * p->audio_sample_rate / 1000;
+       n = 128 * params->sample_rate / 1000;
 
        /* Write the CTS and N values */
        buf[0] = 0x44;
@@ -786,20 +802,21 @@ tda998x_configure_audio(struct tda998x_priv *priv,
        reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
        reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
 
-       /* Write the channel status */
-       buf[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
-       buf[1] = 0x00;
-       buf[2] = IEC958_AES3_CON_FS_NOTID;
-       buf[3] = IEC958_AES4_CON_ORIGFS_NOTID |
-                       IEC958_AES4_CON_MAX_WORDLEN_24;
+       /* Write the channel status
+        * The REG_CH_STAT_B-registers skip IEC958 AES2 byte, because
+        * there is a separate register for each I2S wire.
+        */
+       buf[0] = params->status[0];
+       buf[1] = params->status[1];
+       buf[2] = params->status[3];
+       buf[3] = params->status[4];
        reg_write_range(priv, REG_CH_STAT_B(0), buf, 4);
 
        tda998x_audio_mute(priv, true);
        msleep(20);
        tda998x_audio_mute(priv, false);
 
-       /* Write the audio information packet */
-       tda998x_write_aif(priv, p);
+       return tda998x_write_aif(priv, &params->cea);
 }
 
 /* DRM encoder functions */
@@ -820,7 +837,7 @@ static void tda998x_encoder_set_config(struct tda998x_priv *priv,
                            VIP_CNTRL_2_SWAP_F(p->swap_f) |
                            (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0);
 
-       priv->params = *p;
+       priv->audio_params = p->audio_params;
 }
 
 static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
@@ -1057,9 +1074,13 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
 
                tda998x_write_avi(priv, adjusted_mode);
 
-               if (priv->params.audio_cfg)
-                       tda998x_configure_audio(priv, adjusted_mode,
-                                               &priv->params);
+               if (priv->audio_params.format != AFMT_UNUSED) {
+                       mutex_lock(&priv->audio_mutex);
+                       tda998x_configure_audio(priv,
+                                               &priv->audio_params,
+                                               adjusted_mode->clock);
+                       mutex_unlock(&priv->audio_mutex);
+               }
        }
 }
 
@@ -1159,6 +1180,8 @@ static int tda998x_connector_get_modes(struct drm_connector *connector)
        drm_mode_connector_update_edid_property(connector, edid);
        n = drm_add_edid_modes(connector, edid);
        priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid);
+       drm_edid_to_eld(connector, edid);
+
        kfree(edid);
 
        return n;
@@ -1180,6 +1203,9 @@ static void tda998x_destroy(struct tda998x_priv *priv)
        cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
        reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
 
+       if (priv->audio_pdev)
+               platform_device_unregister(priv->audio_pdev);
+
        if (priv->hdmi->irq)
                free_irq(priv->hdmi->irq, priv);
 
@@ -1189,8 +1215,189 @@ static void tda998x_destroy(struct tda998x_priv *priv)
        i2c_unregister_device(priv->cec);
 }
 
+static int tda998x_audio_hw_params(struct device *dev, void *data,
+                                  struct hdmi_codec_daifmt *daifmt,
+                                  struct hdmi_codec_params *params)
+{
+       struct tda998x_priv *priv = dev_get_drvdata(dev);
+       int i, ret;
+       struct tda998x_audio_params audio = {
+               .sample_width = params->sample_width,
+               .sample_rate = params->sample_rate,
+               .cea = params->cea,
+       };
+
+       if (!priv->encoder.crtc)
+               return -ENODEV;
+
+       memcpy(audio.status, params->iec.status,
+              min(sizeof(audio.status), sizeof(params->iec.status)));
+
+       switch (daifmt->fmt) {
+       case HDMI_I2S:
+               if (daifmt->bit_clk_inv || daifmt->frame_clk_inv ||
+                   daifmt->bit_clk_master || daifmt->frame_clk_master) {
+                       dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
+                               daifmt->bit_clk_inv, daifmt->frame_clk_inv,
+                               daifmt->bit_clk_master,
+                               daifmt->frame_clk_master);
+                       return -EINVAL;
+               }
+               for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++)
+                       if (priv->audio_port[i].format == AFMT_I2S)
+                               audio.config = priv->audio_port[i].config;
+               audio.format = AFMT_I2S;
+               break;
+       case HDMI_SPDIF:
+               for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++)
+                       if (priv->audio_port[i].format == AFMT_SPDIF)
+                               audio.config = priv->audio_port[i].config;
+               audio.format = AFMT_SPDIF;
+               break;
+       default:
+               dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt);
+               return -EINVAL;
+       }
+
+       if (audio.config == 0) {
+               dev_err(dev, "%s: No audio configutation found\n", __func__);
+               return -EINVAL;
+       }
+
+       mutex_lock(&priv->audio_mutex);
+       ret = tda998x_configure_audio(priv,
+                                     &audio,
+                                     priv->encoder.crtc->hwmode.clock);
+
+       if (ret == 0)
+               priv->audio_params = audio;
+       mutex_unlock(&priv->audio_mutex);
+
+       return ret;
+}
+
+static void tda998x_audio_shutdown(struct device *dev, void *data)
+{
+       struct tda998x_priv *priv = dev_get_drvdata(dev);
+
+       mutex_lock(&priv->audio_mutex);
+
+       reg_write(priv, REG_ENA_AP, 0);
+
+       priv->audio_params.format = AFMT_UNUSED;
+
+       mutex_unlock(&priv->audio_mutex);
+}
+
+int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)
+{
+       struct tda998x_priv *priv = dev_get_drvdata(dev);
+
+       mutex_lock(&priv->audio_mutex);
+
+       tda998x_audio_mute(priv, enable);
+
+       mutex_unlock(&priv->audio_mutex);
+       return 0;
+}
+
+static int tda998x_audio_get_eld(struct device *dev, void *data,
+                                uint8_t *buf, size_t len)
+{
+       struct tda998x_priv *priv = dev_get_drvdata(dev);
+       struct drm_mode_config *config = &priv->encoder.dev->mode_config;
+       struct drm_connector *connector;
+       int ret = -ENODEV;
+
+       mutex_lock(&config->mutex);
+       list_for_each_entry(connector, &config->connector_list, head) {
+               if (&priv->encoder == connector->encoder) {
+                       memcpy(buf, connector->eld,
+                              min(sizeof(connector->eld), len));
+                       ret = 0;
+               }
+       }
+       mutex_unlock(&config->mutex);
+
+       return ret;
+}
+
+static const struct hdmi_codec_ops audio_codec_ops = {
+       .hw_params = tda998x_audio_hw_params,
+       .audio_shutdown = tda998x_audio_shutdown,
+       .digital_mute = tda998x_audio_digital_mute,
+       .get_eld = tda998x_audio_get_eld,
+};
+
+static int tda998x_audio_codec_init(struct tda998x_priv *priv,
+                                   struct device *dev)
+{
+       struct hdmi_codec_pdata codec_data = {
+               .ops = &audio_codec_ops,
+               .max_i2s_channels = 2,
+       };
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) {
+               if (priv->audio_port[i].format == AFMT_I2S &&
+                   priv->audio_port[i].config != 0)
+                       codec_data.i2s = 1;
+               if (priv->audio_port[i].format == AFMT_SPDIF &&
+                   priv->audio_port[i].config != 0)
+                       codec_data.spdif = 1;
+       }
+
+       priv->audio_pdev = platform_device_register_data(
+               dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
+               &codec_data, sizeof(codec_data));
+
+       return PTR_ERR_OR_ZERO(priv->audio_pdev);
+}
+
 /* I2C driver functions */
 
+static int tda998x_get_audio_ports(struct tda998x_priv *priv,
+                                  struct device_node *np)
+{
+       const u32 *port_data;
+       u32 size;
+       int i;
+
+       port_data = of_get_property(np, "audio-ports", &size);
+       if (!port_data)
+               return 0;
+
+       size /= sizeof(u32);
+       if (size > 2 * ARRAY_SIZE(priv->audio_port) || size % 2 != 0) {
+               dev_err(&priv->hdmi->dev,
+                       "Bad number of elements in audio-ports dt-property\n");
+               return -EINVAL;
+       }
+
+       size /= 2;
+
+       for (i = 0; i < size; i++) {
+               u8 afmt = be32_to_cpup(&port_data[2*i]);
+               u8 ena_ap = be32_to_cpup(&port_data[2*i+1]);
+
+               if (afmt != AFMT_SPDIF && afmt != AFMT_I2S) {
+                       dev_err(&priv->hdmi->dev,
+                               "Bad audio format %u\n", afmt);
+                       return -EINVAL;
+               }
+
+               priv->audio_port[i].format = afmt;
+               priv->audio_port[i].config = ena_ap;
+       }
+
+       if (priv->audio_port[0].format == priv->audio_port[1].format) {
+               dev_err(&priv->hdmi->dev,
+                       "There can only be on I2S port and one SPDIF port\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
 {
        struct device_node *np = client->dev.of_node;
@@ -1304,7 +1511,7 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
        if (!np)
                return 0;               /* non-DT */
 
-       /* get the optional video properties */
+       /* get the device tree parameters */
        ret = of_property_read_u32(np, "video-ports", &video);
        if (ret == 0) {
                priv->vip_cntrl_0 = video >> 16;
@@ -1312,8 +1519,16 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
                priv->vip_cntrl_2 = video;
        }
 
-       return 0;
+       mutex_init(&priv->audio_mutex); /* Protect access from audio thread */
 
+       ret = tda998x_get_audio_ports(priv, np);
+       if (ret)
+               goto fail;
+
+       if (priv->audio_port[0].format != AFMT_UNUSED)
+               tda998x_audio_codec_init(priv, &client->dev);
+
+       return 0;
 fail:
        /* if encoder_init fails, the encoder slave is never registered,
         * so cleanup here:
index 44f4a13..0be55dc 100644 (file)
@@ -56,9 +56,7 @@ static const struct file_operations i810_driver_fops = {
 };
 
 static struct drm_driver driver = {
-       .driver_features =
-           DRIVER_USE_AGP |
-           DRIVER_HAVE_DMA,
+       .driver_features = DRIVER_USE_AGP | DRIVER_HAVE_DMA | DRIVER_LEGACY,
        .dev_priv_size = sizeof(drm_i810_buf_priv_t),
        .load = i810_driver_load,
        .lastclose = i810_driver_lastclose,
index 684fc1c..a998c2b 100644 (file)
@@ -3,15 +3,20 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 subdir-ccflags-$(CONFIG_DRM_I915_WERROR) := -Werror
+subdir-ccflags-y += \
+       $(call as-instr,movntdqa (%eax)$(comma)%xmm0,-DCONFIG_AS_MOVNTDQA)
 
 # Please keep these build lists sorted!
 
 # core driver code
 i915-y := i915_drv.o \
          i915_irq.o \
+         i915_memcpy.o \
+         i915_mm.o \
          i915_params.o \
          i915_pci.o \
           i915_suspend.o \
+         i915_sw_fence.o \
          i915_sysfs.o \
          intel_csr.o \
          intel_device_info.o \
@@ -25,7 +30,6 @@ i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
 i915-y += i915_cmd_parser.o \
          i915_gem_batch_pool.o \
          i915_gem_context.o \
-         i915_gem_debug.o \
          i915_gem_dmabuf.o \
          i915_gem_evict.o \
          i915_gem_execbuffer.o \
@@ -33,6 +37,7 @@ i915-y += i915_cmd_parser.o \
          i915_gem_gtt.o \
          i915_gem.o \
          i915_gem_render_state.o \
+         i915_gem_request.o \
          i915_gem_shrinker.o \
          i915_gem_stolen.o \
          i915_gem_tiling.o \
@@ -40,6 +45,7 @@ i915-y += i915_cmd_parser.o \
          i915_gpu_error.o \
          i915_trace_points.o \
          intel_breadcrumbs.o \
+         intel_engine_cs.o \
          intel_lrc.o \
          intel_mocs.o \
          intel_ringbuffer.o \
@@ -109,6 +115,6 @@ i915-y += intel_gvt.o
 include $(src)/gvt/Makefile
 endif
 
-obj-$(CONFIG_DRM_I915)  += i915.o
+obj-$(CONFIG_DRM_I915) += i915.o
 
 CFLAGS_i915_trace_points.o := -I$(src)
index b0fd6a7..70980f8 100644 (file)
  * The parser always rejects such commands.
  *
  * The majority of the problematic commands fall in the MI_* range, with only a
- * few specific commands on each ring (e.g. PIPE_CONTROL and MI_FLUSH_DW).
+ * few specific commands on each engine (e.g. PIPE_CONTROL and MI_FLUSH_DW).
  *
  * Implementation:
- * Each ring maintains tables of commands and registers which the parser uses in
- * scanning batch buffers submitted to that ring.
+ * Each engine maintains tables of commands and registers which the parser
+ * uses in scanning batch buffers submitted to that engine.
  *
  * Since the set of commands that the parser must check for is significantly
  * smaller than the number of commands supported, the parser tables contain only
  * those commands required by the parser. This generally works because command
  * opcode ranges have standard command length encodings. So for commands that
  * the parser does not need to check, it can easily skip them. This is
- * implemented via a per-ring length decoding vfunc.
+ * implemented via a per-engine length decoding vfunc.
  *
  * Unfortunately, there are a number of commands that do not follow the standard
  * length encoding for their opcode range, primarily amongst the MI_* commands.
  * To handle this, the parser provides a way to define explicit "skip" entries
- * in the per-ring command tables.
+ * in the per-engine command tables.
  *
  * Other command table entries map fairly directly to high level categories
  * mentioned above: rejected, master-only, register whitelist. The parser
  * general bitmasking mechanism.
  */
 
-#define STD_MI_OPCODE_MASK  0xFF800000
-#define STD_3D_OPCODE_MASK  0xFFFF0000
-#define STD_2D_OPCODE_MASK  0xFFC00000
-#define STD_MFX_OPCODE_MASK 0xFFFF0000
+#define STD_MI_OPCODE_SHIFT  (32 - 9)
+#define STD_3D_OPCODE_SHIFT  (32 - 16)
+#define STD_2D_OPCODE_SHIFT  (32 - 10)
+#define STD_MFX_OPCODE_SHIFT (32 - 16)
+#define MIN_OPCODE_SHIFT 16
 
 #define CMD(op, opm, f, lm, fl, ...)                           \
        {                                                       \
                .flags = (fl) | ((f) ? CMD_DESC_FIXED : 0),     \
-               .cmd = { (op), (opm) },                         \
+               .cmd = { (op), ~0u << (opm) },                  \
                .length = { (lm) },                             \
                __VA_ARGS__                                     \
        }
 
 /* Convenience macros to compress the tables */
-#define SMI STD_MI_OPCODE_MASK
-#define S3D STD_3D_OPCODE_MASK
-#define S2D STD_2D_OPCODE_MASK
-#define SMFX STD_MFX_OPCODE_MASK
+#define SMI STD_MI_OPCODE_SHIFT
+#define S3D STD_3D_OPCODE_SHIFT
+#define S2D STD_2D_OPCODE_SHIFT
+#define SMFX STD_MFX_OPCODE_SHIFT
 #define F true
 #define S CMD_DESC_SKIP
 #define R CMD_DESC_REJECT
@@ -350,6 +351,9 @@ static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = {
        CMD(  MI_LOAD_SCAN_LINES_EXCL,          SMI,   !F,  0x3F,   R  ),
 };
 
+static const struct drm_i915_cmd_descriptor noop_desc =
+       CMD(MI_NOOP, SMI, F, 1, S);
+
 #undef CMD
 #undef SMI
 #undef S3D
@@ -458,6 +462,7 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = {
        REG32(GEN7_GPGPU_DISPATCHDIMX),
        REG32(GEN7_GPGPU_DISPATCHDIMY),
        REG32(GEN7_GPGPU_DISPATCHDIMZ),
+       REG64_IDX(RING_TIMESTAMP, BSD_RING_BASE),
        REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 0),
        REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 1),
        REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 2),
@@ -473,6 +478,7 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = {
        REG32(GEN7_L3SQCREG1),
        REG32(GEN7_L3CNTLREG2),
        REG32(GEN7_L3CNTLREG3),
+       REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE),
 };
 
 static const struct drm_i915_reg_descriptor hsw_render_regs[] = {
@@ -502,7 +508,10 @@ static const struct drm_i915_reg_descriptor hsw_render_regs[] = {
 };
 
 static const struct drm_i915_reg_descriptor gen7_blt_regs[] = {
+       REG64_IDX(RING_TIMESTAMP, RENDER_RING_BASE),
+       REG64_IDX(RING_TIMESTAMP, BSD_RING_BASE),
        REG32(BCS_SWCTRL),
+       REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE),
 };
 
 static const struct drm_i915_reg_descriptor ivb_master_regs[] = {
@@ -603,7 +612,7 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
        return 0;
 }
 
-static bool validate_cmds_sorted(struct intel_engine_cs *engine,
+static bool validate_cmds_sorted(const struct intel_engine_cs *engine,
                                 const struct drm_i915_cmd_table *cmd_tables,
                                 int cmd_table_count)
 {
@@ -624,8 +633,10 @@ static bool validate_cmds_sorted(struct intel_engine_cs *engine,
                        u32 curr = desc->cmd.value & desc->cmd.mask;
 
                        if (curr < previous) {
-                               DRM_ERROR("CMD: table not sorted ring=%d table=%d entry=%d cmd=0x%08X prev=0x%08X\n",
-                                         engine->id, i, j, curr, previous);
+                               DRM_ERROR("CMD: %s [%d] command table not sorted: "
+                                         "table=%d entry=%d cmd=0x%08X prev=0x%08X\n",
+                                         engine->name, engine->id,
+                                         i, j, curr, previous);
                                ret = false;
                        }
 
@@ -636,7 +647,7 @@ static bool validate_cmds_sorted(struct intel_engine_cs *engine,
        return ret;
 }
 
-static bool check_sorted(int ring_id,
+static bool check_sorted(const struct intel_engine_cs *engine,
                         const struct drm_i915_reg_descriptor *reg_table,
                         int reg_count)
 {
@@ -648,8 +659,10 @@ static bool check_sorted(int ring_id,
                u32 curr = i915_mmio_reg_offset(reg_table[i].addr);
 
                if (curr < previous) {
-                       DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n",
-                                 ring_id, i, curr, previous);
+                       DRM_ERROR("CMD: %s [%d] register table not sorted: "
+                                 "entry=%d reg=0x%08X prev=0x%08X\n",
+                                 engine->name, engine->id,
+                                 i, curr, previous);
                        ret = false;
                }
 
@@ -666,7 +679,7 @@ static bool validate_regs_sorted(struct intel_engine_cs *engine)
 
        for (i = 0; i < engine->reg_table_count; i++) {
                table = &engine->reg_tables[i];
-               if (!check_sorted(engine->id, table->regs, table->num_regs))
+               if (!check_sorted(engine, table->regs, table->num_regs))
                        return false;
        }
 
@@ -687,12 +700,26 @@ struct cmd_node {
  * non-opcode bits being set. But if we don't include those bits, some 3D
  * commands may hash to the same bucket due to not including opcode bits that
  * make the command unique. For now, we will risk hashing to the same bucket.
- *
- * If we attempt to generate a perfect hash, we should be able to look at bits
- * 31:29 of a command from a batch buffer and use the full mask for that
- * client. The existing INSTR_CLIENT_MASK/SHIFT defines can be used for this.
  */
-#define CMD_HASH_MASK STD_MI_OPCODE_MASK
+static inline u32 cmd_header_key(u32 x)
+{
+       u32 shift;
+
+       switch (x >> INSTR_CLIENT_SHIFT) {
+       default:
+       case INSTR_MI_CLIENT:
+               shift = STD_MI_OPCODE_SHIFT;
+               break;
+       case INSTR_RC_CLIENT:
+               shift = STD_3D_OPCODE_SHIFT;
+               break;
+       case INSTR_BC_CLIENT:
+               shift = STD_2D_OPCODE_SHIFT;
+               break;
+       }
+
+       return x >> shift;
+}
 
 static int init_hash_table(struct intel_engine_cs *engine,
                           const struct drm_i915_cmd_table *cmd_tables,
@@ -716,7 +743,7 @@ static int init_hash_table(struct intel_engine_cs *engine,
 
                        desc_node->desc = desc;
                        hash_add(engine->cmd_hash, &desc_node->node,
-                                desc->cmd.value & CMD_HASH_MASK);
+                                cmd_header_key(desc->cmd.value));
                }
        }
 
@@ -736,23 +763,21 @@ static void fini_hash_table(struct intel_engine_cs *engine)
 }
 
 /**
- * i915_cmd_parser_init_ring() - set cmd parser related fields for a ringbuffer
+ * intel_engine_init_cmd_parser() - set cmd parser related fields for an engine
  * @engine: the engine to initialize
  *
  * Optionally initializes fields related to batch buffer command parsing in the
  * struct intel_engine_cs based on whether the platform requires software
  * command parsing.
- *
- * Return: non-zero if initialization fails
  */
-int i915_cmd_parser_init_ring(struct intel_engine_cs *engine)
+void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
 {
        const struct drm_i915_cmd_table *cmd_tables;
        int cmd_table_count;
        int ret;
 
        if (!IS_GEN7(engine->i915))
-               return 0;
+               return;
 
        switch (engine->id) {
        case RCS:
@@ -806,36 +831,38 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *engine)
                engine->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
                break;
        default:
-               DRM_ERROR("CMD: cmd_parser_init with unknown ring: %d\n",
-                         engine->id);
-               BUG();
+               MISSING_CASE(engine->id);
+               return;
        }
 
-       BUG_ON(!validate_cmds_sorted(engine, cmd_tables, cmd_table_count));
-       BUG_ON(!validate_regs_sorted(engine));
-
-       WARN_ON(!hash_empty(engine->cmd_hash));
+       if (!validate_cmds_sorted(engine, cmd_tables, cmd_table_count)) {
+               DRM_ERROR("%s: command descriptions are not sorted\n",
+                         engine->name);
+               return;
+       }
+       if (!validate_regs_sorted(engine)) {
+               DRM_ERROR("%s: registers are not sorted\n", engine->name);
+               return;
+       }
 
        ret = init_hash_table(engine, cmd_tables, cmd_table_count);
        if (ret) {
-               DRM_ERROR("CMD: cmd_parser_init failed!\n");
+               DRM_ERROR("%s: initialised failed!\n", engine->name);
                fini_hash_table(engine);
-               return ret;
+               return;
        }
 
        engine->needs_cmd_parser = true;
-
-       return 0;
 }
 
 /**
- * i915_cmd_parser_fini_ring() - clean up cmd parser related fields
+ * intel_engine_cleanup_cmd_parser() - clean up cmd parser related fields
  * @engine: the engine to clean up
  *
  * Releases any resources related to command parsing that may have been
- * initialized for the specified ring.
+ * initialized for the specified engine.
  */
-void i915_cmd_parser_fini_ring(struct intel_engine_cs *engine)
+void intel_engine_cleanup_cmd_parser(struct intel_engine_cs *engine)
 {
        if (!engine->needs_cmd_parser)
                return;
@@ -850,12 +877,9 @@ find_cmd_in_table(struct intel_engine_cs *engine,
        struct cmd_node *desc_node;
 
        hash_for_each_possible(engine->cmd_hash, desc_node, node,
-                              cmd_header & CMD_HASH_MASK) {
+                              cmd_header_key(cmd_header)) {
                const struct drm_i915_cmd_descriptor *desc = desc_node->desc;
-               u32 masked_cmd = desc->cmd.mask & cmd_header;
-               u32 masked_value = desc->cmd.value & desc->cmd.mask;
-
-               if (masked_cmd == masked_value)
+               if (((cmd_header ^ desc->cmd.value) & desc->cmd.mask) == 0)
                        return desc;
        }
 
@@ -866,18 +890,21 @@ find_cmd_in_table(struct intel_engine_cs *engine,
  * Returns a pointer to a descriptor for the command specified by cmd_header.
  *
  * The caller must supply space for a default descriptor via the default_desc
- * parameter. If no descriptor for the specified command exists in the ring's
+ * parameter. If no descriptor for the specified command exists in the engine's
  * command parser tables, this function fills in default_desc based on the
- * ring's default length encoding and returns default_desc.
+ * engine's default length encoding and returns default_desc.
  */
 static const struct drm_i915_cmd_descriptor*
 find_cmd(struct intel_engine_cs *engine,
         u32 cmd_header,
+        const struct drm_i915_cmd_descriptor *desc,
         struct drm_i915_cmd_descriptor *default_desc)
 {
-       const struct drm_i915_cmd_descriptor *desc;
        u32 mask;
 
+       if (((cmd_header ^ desc->cmd.value) & desc->cmd.mask) == 0)
+               return desc;
+
        desc = find_cmd_in_table(engine, cmd_header);
        if (desc)
                return desc;
@@ -886,152 +913,140 @@ find_cmd(struct intel_engine_cs *engine,
        if (!mask)
                return NULL;
 
-       BUG_ON(!default_desc);
-       default_desc->flags = CMD_DESC_SKIP;
+       default_desc->cmd.value = cmd_header;
+       default_desc->cmd.mask = ~0u << MIN_OPCODE_SHIFT;
        default_desc->length.mask = mask;
-
+       default_desc->flags = CMD_DESC_SKIP;
        return default_desc;
 }
 
 static const struct drm_i915_reg_descriptor *
-find_reg(const struct drm_i915_reg_descriptor *table,
-        int count, u32 addr)
+__find_reg(const struct drm_i915_reg_descriptor *table, int count, u32 addr)
 {
-       int i;
-
-       for (i = 0; i < count; i++) {
-               if (i915_mmio_reg_offset(table[i].addr) == addr)
-                       return &table[i];
+       int start = 0, end = count;
+       while (start < end) {
+               int mid = start + (end - start) / 2;
+               int ret = addr - i915_mmio_reg_offset(table[mid].addr);
+               if (ret < 0)
+                       end = mid;
+               else if (ret > 0)
+                       start = mid + 1;
+               else
+                       return &table[mid];
        }
-
        return NULL;
 }
 
 static const struct drm_i915_reg_descriptor *
-find_reg_in_tables(const struct drm_i915_reg_table *tables,
-                  int count, bool is_master, u32 addr)
+find_reg(const struct intel_engine_cs *engine, bool is_master, u32 addr)
 {
-       int i;
-       const struct drm_i915_reg_table *table;
-       const struct drm_i915_reg_descriptor *reg;
+       const struct drm_i915_reg_table *table = engine->reg_tables;
+       int count = engine->reg_table_count;
 
-       for (i = 0; i < count; i++) {
-               table = &tables[i];
+       do {
                if (!table->master || is_master) {
-                       reg = find_reg(table->regs, table->num_regs,
-                                      addr);
+                       const struct drm_i915_reg_descriptor *reg;
+
+                       reg = __find_reg(table->regs, table->num_regs, addr);
                        if (reg != NULL)
                                return reg;
                }
-       }
+       } while (table++, --count);
 
        return NULL;
 }
 
-static u32 *vmap_batch(struct drm_i915_gem_object *obj,
-                      unsigned start, unsigned len)
-{
-       int i;
-       void *addr = NULL;
-       struct sg_page_iter sg_iter;
-       int first_page = start >> PAGE_SHIFT;
-       int last_page = (len + start + 4095) >> PAGE_SHIFT;
-       int npages = last_page - first_page;
-       struct page **pages;
-
-       pages = drm_malloc_ab(npages, sizeof(*pages));
-       if (pages == NULL) {
-               DRM_DEBUG_DRIVER("Failed to get space for pages\n");
-               goto finish;
-       }
-
-       i = 0;
-       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, first_page) {
-               pages[i++] = sg_page_iter_page(&sg_iter);
-               if (i == npages)
-                       break;
-       }
-
-       addr = vmap(pages, i, 0, PAGE_KERNEL);
-       if (addr == NULL) {
-               DRM_DEBUG_DRIVER("Failed to vmap pages\n");
-               goto finish;
-       }
-
-finish:
-       if (pages)
-               drm_free_large(pages);
-       return (u32*)addr;
-}
-
-/* Returns a vmap'd pointer to dest_obj, which the caller must unmap */
-static u32 *copy_batch(struct drm_i915_gem_object *dest_obj,
+/* Returns a vmap'd pointer to dst_obj, which the caller must unmap */
+static u32 *copy_batch(struct drm_i915_gem_object *dst_obj,
                       struct drm_i915_gem_object *src_obj,
                       u32 batch_start_offset,
-                      u32 batch_len)
+                      u32 batch_len,
+                      bool *needs_clflush_after)
 {
-       int needs_clflush = 0;
-       void *src_base, *src;
-       void *dst = NULL;
+       unsigned int src_needs_clflush;
+       unsigned int dst_needs_clflush;
+       void *dst, *src;
        int ret;
 
-       if (batch_len > dest_obj->base.size ||
-           batch_len + batch_start_offset > src_obj->base.size)
-               return ERR_PTR(-E2BIG);
-
-       if (WARN_ON(dest_obj->pages_pin_count == 0))
-               return ERR_PTR(-ENODEV);
-
-       ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush);
-       if (ret) {
-               DRM_DEBUG_DRIVER("CMD: failed to prepare shadow batch\n");
+       ret = i915_gem_obj_prepare_shmem_read(src_obj, &src_needs_clflush);
+       if (ret)
                return ERR_PTR(ret);
-       }
 
-       src_base = vmap_batch(src_obj, batch_start_offset, batch_len);
-       if (!src_base) {
-               DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
-               ret = -ENOMEM;
+       ret = i915_gem_obj_prepare_shmem_write(dst_obj, &dst_needs_clflush);
+       if (ret) {
+               dst = ERR_PTR(ret);
                goto unpin_src;
        }
 
-       ret = i915_gem_object_set_to_cpu_domain(dest_obj, true);
-       if (ret) {
-               DRM_DEBUG_DRIVER("CMD: Failed to set shadow batch to CPU\n");
-               goto unmap_src;
+       dst = i915_gem_object_pin_map(dst_obj, I915_MAP_WB);
+       if (IS_ERR(dst))
+               goto unpin_dst;
+
+       src = ERR_PTR(-ENODEV);
+       if (src_needs_clflush &&
+           i915_memcpy_from_wc((void *)(uintptr_t)batch_start_offset, NULL, 0)) {
+               src = i915_gem_object_pin_map(src_obj, I915_MAP_WC);
+               if (!IS_ERR(src)) {
+                       i915_memcpy_from_wc(dst,
+                                           src + batch_start_offset,
+                                           ALIGN(batch_len, 16));
+                       i915_gem_object_unpin_map(src_obj);
+               }
        }
-
-       dst = vmap_batch(dest_obj, 0, batch_len);
-       if (!dst) {
-               DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n");
-               ret = -ENOMEM;
-               goto unmap_src;
+       if (IS_ERR(src)) {
+               void *ptr;
+               int offset, n;
+
+               offset = offset_in_page(batch_start_offset);
+
+               /* We can avoid clflushing partial cachelines before the write
+                * if we only every write full cache-lines. Since we know that
+                * both the source and destination are in multiples of
+                * PAGE_SIZE, we can simply round up to the next cacheline.
+                * We don't care about copying too much here as we only
+                * validate up to the end of the batch.
+                */
+               if (dst_needs_clflush & CLFLUSH_BEFORE)
+                       batch_len = roundup(batch_len,
+                                           boot_cpu_data.x86_clflush_size);
+
+               ptr = dst;
+               for (n = batch_start_offset >> PAGE_SHIFT; batch_len; n++) {
+                       int len = min_t(int, batch_len, PAGE_SIZE - offset);
+
+                       src = kmap_atomic(i915_gem_object_get_page(src_obj, n));
+                       if (src_needs_clflush)
+                               drm_clflush_virt_range(src + offset, len);
+                       memcpy(ptr, src + offset, len);
+                       kunmap_atomic(src);
+
+                       ptr += len;
+                       batch_len -= len;
+                       offset = 0;
+               }
        }
 
-       src = src_base + offset_in_page(batch_start_offset);
-       if (needs_clflush)
-               drm_clflush_virt_range(src, batch_len);
-
-       memcpy(dst, src, batch_len);
+       /* dst_obj is returned with vmap pinned */
+       *needs_clflush_after = dst_needs_clflush & CLFLUSH_AFTER;
 
-unmap_src:
-       vunmap(src_base);
+unpin_dst:
+       i915_gem_obj_finish_shmem_access(dst_obj);
 unpin_src:
-       i915_gem_object_unpin_pages(src_obj);
-
-       return ret ? ERR_PTR(ret) : dst;
+       i915_gem_obj_finish_shmem_access(src_obj);
+       return dst;
 }
 
 /**
- * i915_needs_cmd_parser() - should a given ring use software command parsing?
+ * intel_engine_needs_cmd_parser() - should a given engine use software
+ *                                   command parsing?
  * @engine: the engine in question
  *
  * Only certain platforms require software batch buffer command parsing, and
  * only when enabled via module parameter.
  *
- * Return: true if the ring requires software command parsing
+ * Return: true if the engine requires software command parsing
  */
-bool i915_needs_cmd_parser(struct intel_engine_cs *engine)
+bool intel_engine_needs_cmd_parser(struct intel_engine_cs *engine)
 {
        if (!engine->needs_cmd_parser)
                return false;
@@ -1048,6 +1063,9 @@ static bool check_cmd(const struct intel_engine_cs *engine,
                      const bool is_master,
                      bool *oacontrol_set)
 {
+       if (desc->flags & CMD_DESC_SKIP)
+               return true;
+
        if (desc->flags & CMD_DESC_REJECT) {
                DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd);
                return false;
@@ -1072,14 +1090,11 @@ static bool check_cmd(const struct intel_engine_cs *engine,
                     offset += step) {
                        const u32 reg_addr = cmd[offset] & desc->reg.mask;
                        const struct drm_i915_reg_descriptor *reg =
-                               find_reg_in_tables(engine->reg_tables,
-                                                  engine->reg_table_count,
-                                                  is_master,
-                                                  reg_addr);
+                               find_reg(engine, is_master, reg_addr);
 
                        if (!reg) {
-                               DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n",
-                                                reg_addr, *cmd, engine->id);
+                               DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (exec_id=%d)\n",
+                                                reg_addr, *cmd, engine->exec_id);
                                return false;
                        }
 
@@ -1159,11 +1174,11 @@ static bool check_cmd(const struct intel_engine_cs *engine,
                                desc->bits[i].mask;
 
                        if (dword != desc->bits[i].expected) {
-                               DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n",
+                               DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (exec_id=%d)\n",
                                                 *cmd,
                                                 desc->bits[i].mask,
                                                 desc->bits[i].expected,
-                                                dword, engine->id);
+                                                dword, engine->exec_id);
                                return false;
                        }
                }
@@ -1189,23 +1204,26 @@ static bool check_cmd(const struct intel_engine_cs *engine,
  * Return: non-zero if the parser finds violations or otherwise fails; -EACCES
  * if the batch appears legal but should use hardware parsing
  */
-int i915_parse_cmds(struct intel_engine_cs *engine,
-                   struct drm_i915_gem_object *batch_obj,
-                   struct drm_i915_gem_object *shadow_batch_obj,
-                   u32 batch_start_offset,
-                   u32 batch_len,
-                   bool is_master)
+int intel_engine_cmd_parser(struct intel_engine_cs *engine,
+                           struct drm_i915_gem_object *batch_obj,
+                           struct drm_i915_gem_object *shadow_batch_obj,
+                           u32 batch_start_offset,
+                           u32 batch_len,
+                           bool is_master)
 {
-       u32 *cmd, *batch_base, *batch_end;
-       struct drm_i915_cmd_descriptor default_desc = { 0 };
+       u32 *cmd, *batch_end;
+       struct drm_i915_cmd_descriptor default_desc = noop_desc;
+       const struct drm_i915_cmd_descriptor *desc = &default_desc;
        bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */
+       bool needs_clflush_after = false;
        int ret = 0;
 
-       batch_base = copy_batch(shadow_batch_obj, batch_obj,
-                               batch_start_offset, batch_len);
-       if (IS_ERR(batch_base)) {
+       cmd = copy_batch(shadow_batch_obj, batch_obj,
+                        batch_start_offset, batch_len,
+                        &needs_clflush_after);
+       if (IS_ERR(cmd)) {
                DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n");
-               return PTR_ERR(batch_base);
+               return PTR_ERR(cmd);
        }
 
        /*
@@ -1213,17 +1231,14 @@ int i915_parse_cmds(struct intel_engine_cs *engine,
         * large or larger and copy_batch() will write MI_NOPs to the extra
         * space. Parsing should be faster in some cases this way.
         */
-       batch_end = batch_base + (batch_len / sizeof(*batch_end));
-
-       cmd = batch_base;
+       batch_end = cmd + (batch_len / sizeof(*batch_end));
        while (cmd < batch_end) {
-               const struct drm_i915_cmd_descriptor *desc;
                u32 length;
 
                if (*cmd == MI_BATCH_BUFFER_END)
                        break;
 
-               desc = find_cmd(engine, *cmd, &default_desc);
+               desc = find_cmd(engine, *cmd, desc, &default_desc);
                if (!desc) {
                        DRM_DEBUG_DRIVER("CMD: Unrecognized command: 0x%08X\n",
                                         *cmd);
@@ -1274,7 +1289,9 @@ int i915_parse_cmds(struct intel_engine_cs *engine,
                ret = -EINVAL;
        }
 
-       vunmap(batch_base);
+       if (ret == 0 && needs_clflush_after)
+               drm_clflush_virt_range(shadow_batch_obj->mapping, batch_len);
+       i915_gem_object_unpin_map(shadow_batch_obj);
 
        return ret;
 }
@@ -1295,7 +1312,7 @@ int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv)
 
        /* If the command parser is not enabled, report 0 - unsupported */
        for_each_engine(engine, dev_priv) {
-               if (i915_needs_cmd_parser(engine)) {
+               if (intel_engine_needs_cmd_parser(engine)) {
                        active = true;
                        break;
                }
index 844fea7..27b0e34 100644 (file)
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
-enum {
-       ACTIVE_LIST,
-       INACTIVE_LIST,
-       PINNED_LIST,
-};
+static inline struct drm_i915_private *node_to_i915(struct drm_info_node *node)
+{
+       return to_i915(node->minor->dev);
+}
 
 /* As the drm_debugfs_init() routines are called before dev->dev_private is
  * allocated we need to hook into the minor for release. */
@@ -63,7 +62,7 @@ drm_add_fake_info_node(struct drm_minor *minor,
 
        node->minor = minor;
        node->dent = ent;
-       node->info_ent = (void *) key;
+       node->info_ent = (void *)key;
 
        mutex_lock(&minor->debugfs_lock);
        list_add(&node->list, &minor->debugfs_list);
@@ -74,12 +73,11 @@ drm_add_fake_info_node(struct drm_minor *minor,
 
 static int i915_capabilities(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       const struct intel_device_info *info = INTEL_INFO(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       const struct intel_device_info *info = INTEL_INFO(dev_priv);
 
-       seq_printf(m, "gen: %d\n", info->gen);
-       seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(dev));
+       seq_printf(m, "gen: %d\n", INTEL_GEN(dev_priv));
+       seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(dev_priv));
 #define PRINT_FLAG(x)  seq_printf(m, #x ": %s\n", yesno(info->x))
 #define SEP_SEMICOLON ;
        DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_SEMICOLON);
@@ -91,7 +89,7 @@ static int i915_capabilities(struct seq_file *m, void *data)
 
 static char get_active_flag(struct drm_i915_gem_object *obj)
 {
-       return obj->active ? '*' : ' ';
+       return i915_gem_object_is_active(obj) ? '*' : ' ';
 }
 
 static char get_pin_flag(struct drm_i915_gem_object *obj)
@@ -101,7 +99,7 @@ static char get_pin_flag(struct drm_i915_gem_object *obj)
 
 static char get_tiling_flag(struct drm_i915_gem_object *obj)
 {
-       switch (obj->tiling_mode) {
+       switch (i915_gem_object_get_tiling(obj)) {
        default:
        case I915_TILING_NONE: return ' ';
        case I915_TILING_X: return 'X';
@@ -111,7 +109,7 @@ static char get_tiling_flag(struct drm_i915_gem_object *obj)
 
 static char get_global_flag(struct drm_i915_gem_object *obj)
 {
-       return i915_gem_obj_to_ggtt(obj) ? 'g' : ' ';
+       return i915_gem_object_to_ggtt(obj, NULL) ?  'g' : ' ';
 }
 
 static char get_pin_mapped_flag(struct drm_i915_gem_object *obj)
@@ -125,7 +123,7 @@ static u64 i915_gem_obj_total_ggtt_size(struct drm_i915_gem_object *obj)
        struct i915_vma *vma;
 
        list_for_each_entry(vma, &obj->vma_list, obj_link) {
-               if (vma->is_ggtt && drm_mm_node_allocated(&vma->node))
+               if (i915_vma_is_ggtt(vma) && drm_mm_node_allocated(&vma->node))
                        size += vma->node.size;
        }
 
@@ -138,6 +136,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
        struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
        struct intel_engine_cs *engine;
        struct i915_vma *vma;
+       unsigned int frontbuffer_bits;
        int pin_count = 0;
        enum intel_engine_id id;
 
@@ -155,30 +154,36 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                   obj->base.write_domain);
        for_each_engine_id(engine, dev_priv, id)
                seq_printf(m, "%x ",
-                               i915_gem_request_get_seqno(obj->last_read_req[id]));
-       seq_printf(m, "] %x %x%s%s%s",
-                  i915_gem_request_get_seqno(obj->last_write_req),
-                  i915_gem_request_get_seqno(obj->last_fenced_req),
-                  i915_cache_level_str(to_i915(obj->base.dev), obj->cache_level),
+                          i915_gem_active_get_seqno(&obj->last_read[id],
+                                                    &obj->base.dev->struct_mutex));
+       seq_printf(m, "] %x %s%s%s",
+                  i915_gem_active_get_seqno(&obj->last_write,
+                                            &obj->base.dev->struct_mutex),
+                  i915_cache_level_str(dev_priv, obj->cache_level),
                   obj->dirty ? " dirty" : "",
                   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
        if (obj->base.name)
                seq_printf(m, " (name: %d)", obj->base.name);
        list_for_each_entry(vma, &obj->vma_list, obj_link) {
-               if (vma->pin_count > 0)
+               if (i915_vma_is_pinned(vma))
                        pin_count++;
        }
        seq_printf(m, " (pinned x %d)", pin_count);
        if (obj->pin_display)
                seq_printf(m, " (display)");
-       if (obj->fence_reg != I915_FENCE_REG_NONE)
-               seq_printf(m, " (fence: %d)", obj->fence_reg);
        list_for_each_entry(vma, &obj->vma_list, obj_link) {
+               if (!drm_mm_node_allocated(&vma->node))
+                       continue;
+
                seq_printf(m, " (%sgtt offset: %08llx, size: %08llx",
-                          vma->is_ggtt ? "g" : "pp",
+                          i915_vma_is_ggtt(vma) ? "g" : "pp",
                           vma->node.start, vma->node.size);
-               if (vma->is_ggtt)
+               if (i915_vma_is_ggtt(vma))
                        seq_printf(m, ", type: %u", vma->ggtt_view.type);
+               if (vma->fence)
+                       seq_printf(m, " , fence: %d%s",
+                                  vma->fence->id,
+                                  i915_gem_active_isset(&vma->last_fence) ? "*" : "");
                seq_puts(m, ")");
        }
        if (obj->stolen)
@@ -192,58 +197,15 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                *t = '\0';
                seq_printf(m, " (%s mappable)", s);
        }
-       if (obj->last_write_req != NULL)
-               seq_printf(m, " (%s)",
-                          i915_gem_request_get_engine(obj->last_write_req)->name);
-       if (obj->frontbuffer_bits)
-               seq_printf(m, " (frontbuffer: 0x%03x)", obj->frontbuffer_bits);
-}
-
-static int i915_gem_object_list_info(struct seq_file *m, void *data)
-{
-       struct drm_info_node *node = m->private;
-       uintptr_t list = (uintptr_t) node->info_ent->data;
-       struct list_head *head;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       struct i915_vma *vma;
-       u64 total_obj_size, total_gtt_size;
-       int count, ret;
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
+       engine = i915_gem_active_get_engine(&obj->last_write,
+                                           &dev_priv->drm.struct_mutex);
+       if (engine)
+               seq_printf(m, " (%s)", engine->name);
 
-       /* FIXME: the user of this interface might want more than just GGTT */
-       switch (list) {
-       case ACTIVE_LIST:
-               seq_puts(m, "Active:\n");
-               head = &ggtt->base.active_list;
-               break;
-       case INACTIVE_LIST:
-               seq_puts(m, "Inactive:\n");
-               head = &ggtt->base.inactive_list;
-               break;
-       default:
-               mutex_unlock(&dev->struct_mutex);
-               return -EINVAL;
-       }
-
-       total_obj_size = total_gtt_size = count = 0;
-       list_for_each_entry(vma, head, vm_link) {
-               seq_printf(m, "   ");
-               describe_obj(m, vma->obj);
-               seq_printf(m, "\n");
-               total_obj_size += vma->obj->base.size;
-               total_gtt_size += vma->node.size;
-               count++;
-       }
-       mutex_unlock(&dev->struct_mutex);
-
-       seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n",
-                  count, total_obj_size, total_gtt_size);
-       return 0;
+       frontbuffer_bits = atomic_read(&obj->frontbuffer_bits);
+       if (frontbuffer_bits)
+               seq_printf(m, " (frontbuffer: 0x%03x)", frontbuffer_bits);
 }
 
 static int obj_rank_by_stolen(void *priv,
@@ -263,9 +225,8 @@ static int obj_rank_by_stolen(void *priv,
 
 static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct drm_i915_gem_object *obj;
        u64 total_obj_size, total_gtt_size;
        LIST_HEAD(stolen);
@@ -311,17 +272,6 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
        return 0;
 }
 
-#define count_objects(list, member) do { \
-       list_for_each_entry(obj, list, member) { \
-               size += i915_gem_obj_total_ggtt_size(obj); \
-               ++count; \
-               if (obj->map_and_fenceable) { \
-                       mappable_size += i915_gem_obj_ggtt_size(obj); \
-                       ++mappable_count; \
-               } \
-       } \
-} while (0)
-
 struct file_stats {
        struct drm_i915_file_private *file_priv;
        unsigned long count;
@@ -338,46 +288,29 @@ static int per_file_stats(int id, void *ptr, void *data)
 
        stats->count++;
        stats->total += obj->base.size;
-
+       if (!obj->bind_count)
+               stats->unbound += obj->base.size;
        if (obj->base.name || obj->base.dma_buf)
                stats->shared += obj->base.size;
 
-       if (USES_FULL_PPGTT(obj->base.dev)) {
-               list_for_each_entry(vma, &obj->vma_list, obj_link) {
-                       struct i915_hw_ppgtt *ppgtt;
-
-                       if (!drm_mm_node_allocated(&vma->node))
-                               continue;
+       list_for_each_entry(vma, &obj->vma_list, obj_link) {
+               if (!drm_mm_node_allocated(&vma->node))
+                       continue;
 
-                       if (vma->is_ggtt) {
-                               stats->global += obj->base.size;
-                               continue;
-                       }
+               if (i915_vma_is_ggtt(vma)) {
+                       stats->global += vma->node.size;
+               } else {
+                       struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vma->vm);
 
-                       ppgtt = container_of(vma->vm, struct i915_hw_ppgtt, base);
-                       if (ppgtt->file_priv != stats->file_priv)
+                       if (ppgtt->base.file != stats->file_priv)
                                continue;
-
-                       if (obj->active) /* XXX per-vma statistic */
-                               stats->active += obj->base.size;
-                       else
-                               stats->inactive += obj->base.size;
-
-                       return 0;
-               }
-       } else {
-               if (i915_gem_obj_ggtt_bound(obj)) {
-                       stats->global += obj->base.size;
-                       if (obj->active)
-                               stats->active += obj->base.size;
-                       else
-                               stats->inactive += obj->base.size;
-                       return 0;
                }
-       }
 
-       if (!list_empty(&obj->global_list))
-               stats->unbound += obj->base.size;
+               if (i915_vma_is_active(vma))
+                       stats->active += vma->node.size;
+               else
+                       stats->inactive += vma->node.size;
+       }
 
        return 0;
 }
@@ -424,9 +357,9 @@ static int per_file_ctx_stats(int id, void *ptr, void *data)
 
        for (n = 0; n < ARRAY_SIZE(ctx->engine); n++) {
                if (ctx->engine[n].state)
-                       per_file_stats(0, ctx->engine[n].state, data);
-               if (ctx->engine[n].ringbuf)
-                       per_file_stats(0, ctx->engine[n].ringbuf->obj, data);
+                       per_file_stats(0, ctx->engine[n].state->obj, data);
+               if (ctx->engine[n].ring)
+                       per_file_stats(0, ctx->engine[n].ring->vma->obj, data);
        }
 
        return 0;
@@ -435,48 +368,34 @@ static int per_file_ctx_stats(int id, void *ptr, void *data)
 static void print_context_stats(struct seq_file *m,
                                struct drm_i915_private *dev_priv)
 {
+       struct drm_device *dev = &dev_priv->drm;
        struct file_stats stats;
        struct drm_file *file;
 
        memset(&stats, 0, sizeof(stats));
 
-       mutex_lock(&dev_priv->drm.struct_mutex);
+       mutex_lock(&dev->struct_mutex);
        if (dev_priv->kernel_context)
                per_file_ctx_stats(0, dev_priv->kernel_context, &stats);
 
-       list_for_each_entry(file, &dev_priv->drm.filelist, lhead) {
+       list_for_each_entry(file, &dev->filelist, lhead) {
                struct drm_i915_file_private *fpriv = file->driver_priv;
                idr_for_each(&fpriv->context_idr, per_file_ctx_stats, &stats);
        }
-       mutex_unlock(&dev_priv->drm.struct_mutex);
+       mutex_unlock(&dev->struct_mutex);
 
        print_file_stats(m, "[k]contexts", stats);
 }
 
-#define count_vmas(list, member) do { \
-       list_for_each_entry(vma, list, member) { \
-               size += i915_gem_obj_total_ggtt_size(vma->obj); \
-               ++count; \
-               if (vma->obj->map_and_fenceable) { \
-                       mappable_size += i915_gem_obj_ggtt_size(vma->obj); \
-                       ++mappable_count; \
-               } \
-       } \
-} while (0)
-
-static int i915_gem_object_info(struct seq_file *m, void* data)
+static int i915_gem_object_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       u32 count, mappable_count, purgeable_count;
-       u64 size, mappable_size, purgeable_size;
-       unsigned long pin_mapped_count = 0, pin_mapped_purgeable_count = 0;
-       u64 pin_mapped_size = 0, pin_mapped_purgeable_size = 0;
+       u32 count, mapped_count, purgeable_count, dpy_count;
+       u64 size, mapped_size, purgeable_size, dpy_size;
        struct drm_i915_gem_object *obj;
        struct drm_file *file;
-       struct i915_vma *vma;
        int ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -487,70 +406,53 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
                   dev_priv->mm.object_count,
                   dev_priv->mm.object_memory);
 
-       size = count = mappable_size = mappable_count = 0;
-       count_objects(&dev_priv->mm.bound_list, global_list);
-       seq_printf(m, "%u [%u] objects, %llu [%llu] bytes in gtt\n",
-                  count, mappable_count, size, mappable_size);
-
-       size = count = mappable_size = mappable_count = 0;
-       count_vmas(&ggtt->base.active_list, vm_link);
-       seq_printf(m, "  %u [%u] active objects, %llu [%llu] bytes\n",
-                  count, mappable_count, size, mappable_size);
+       size = count = 0;
+       mapped_size = mapped_count = 0;
+       purgeable_size = purgeable_count = 0;
+       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
+               size += obj->base.size;
+               ++count;
 
-       size = count = mappable_size = mappable_count = 0;
-       count_vmas(&ggtt->base.inactive_list, vm_link);
-       seq_printf(m, "  %u [%u] inactive objects, %llu [%llu] bytes\n",
-                  count, mappable_count, size, mappable_size);
+               if (obj->madv == I915_MADV_DONTNEED) {
+                       purgeable_size += obj->base.size;
+                       ++purgeable_count;
+               }
 
-       size = count = purgeable_size = purgeable_count = 0;
-       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
-               size += obj->base.size, ++count;
-               if (obj->madv == I915_MADV_DONTNEED)
-                       purgeable_size += obj->base.size, ++purgeable_count;
                if (obj->mapping) {
-                       pin_mapped_count++;
-                       pin_mapped_size += obj->base.size;
-                       if (obj->pages_pin_count == 0) {
-                               pin_mapped_purgeable_count++;
-                               pin_mapped_purgeable_size += obj->base.size;
-                       }
+                       mapped_count++;
+                       mapped_size += obj->base.size;
                }
        }
        seq_printf(m, "%u unbound objects, %llu bytes\n", count, size);
 
-       size = count = mappable_size = mappable_count = 0;
+       size = count = dpy_size = dpy_count = 0;
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (obj->fault_mappable) {
-                       size += i915_gem_obj_ggtt_size(obj);
-                       ++count;
-               }
+               size += obj->base.size;
+               ++count;
+
                if (obj->pin_display) {
-                       mappable_size += i915_gem_obj_ggtt_size(obj);
-                       ++mappable_count;
+                       dpy_size += obj->base.size;
+                       ++dpy_count;
                }
+
                if (obj->madv == I915_MADV_DONTNEED) {
                        purgeable_size += obj->base.size;
                        ++purgeable_count;
                }
+
                if (obj->mapping) {
-                       pin_mapped_count++;
-                       pin_mapped_size += obj->base.size;
-                       if (obj->pages_pin_count == 0) {
-                               pin_mapped_purgeable_count++;
-                               pin_mapped_purgeable_size += obj->base.size;
-                       }
+                       mapped_count++;
+                       mapped_size += obj->base.size;
                }
        }
+       seq_printf(m, "%u bound objects, %llu bytes\n",
+                  count, size);
        seq_printf(m, "%u purgeable objects, %llu bytes\n",
                   purgeable_count, purgeable_size);
-       seq_printf(m, "%u pinned mappable objects, %llu bytes\n",
-                  mappable_count, mappable_size);
-       seq_printf(m, "%u fault mappable objects, %llu bytes\n",
-                  count, size);
-       seq_printf(m,
-                  "%lu [%lu] pin mapped objects, %llu [%llu] bytes [purgeable]\n",
-                  pin_mapped_count, pin_mapped_purgeable_count,
-                  pin_mapped_size, pin_mapped_purgeable_size);
+       seq_printf(m, "%u mapped objects, %llu bytes\n",
+                  mapped_count, mapped_size);
+       seq_printf(m, "%u display objects (pinned), %llu bytes\n",
+                  dpy_count, dpy_size);
 
        seq_printf(m, "%llu [%llu] gtt total\n",
                   ggtt->base.total, ggtt->mappable_end - ggtt->base.start);
@@ -563,6 +465,8 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
        print_context_stats(m, dev_priv);
        list_for_each_entry_reverse(file, &dev->filelist, lhead) {
                struct file_stats stats;
+               struct drm_i915_file_private *file_priv = file->driver_priv;
+               struct drm_i915_gem_request *request;
                struct task_struct *task;
 
                memset(&stats, 0, sizeof(stats));
@@ -576,10 +480,17 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
                 * still alive (e.g. get_pid(current) => fork() => exit()).
                 * Therefore, we need to protect this ->comm access using RCU.
                 */
+               mutex_lock(&dev->struct_mutex);
+               request = list_first_entry_or_null(&file_priv->mm.request_list,
+                                                  struct drm_i915_gem_request,
+                                                  client_list);
                rcu_read_lock();
-               task = pid_task(file->pid, PIDTYPE_PID);
+               task = pid_task(request && request->ctx->pid ?
+                               request->ctx->pid : file->pid,
+                               PIDTYPE_PID);
                print_file_stats(m, task ? task->comm : "<unknown>", stats);
                rcu_read_unlock();
+               mutex_unlock(&dev->struct_mutex);
        }
        mutex_unlock(&dev->filelist_mutex);
 
@@ -589,9 +500,9 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
 static int i915_gem_gtt_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       uintptr_t list = (uintptr_t) node->info_ent->data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(node);
+       struct drm_device *dev = &dev_priv->drm;
+       bool show_pin_display_only = !!node->info_ent->data;
        struct drm_i915_gem_object *obj;
        u64 total_obj_size, total_gtt_size;
        int count, ret;
@@ -602,7 +513,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data)
 
        total_obj_size = total_gtt_size = count = 0;
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (list == PINNED_LIST && !i915_gem_obj_is_pinned(obj))
+               if (show_pin_display_only && !obj->pin_display)
                        continue;
 
                seq_puts(m, "   ");
@@ -623,9 +534,8 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data)
 
 static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_crtc *crtc;
        int ret;
 
@@ -672,7 +582,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
                                   intel_crtc_get_vblank_counter(crtc));
                        seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
 
-                       if (INTEL_INFO(dev)->gen >= 4)
+                       if (INTEL_GEN(dev_priv) >= 4)
                                addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
                        else
                                addr = I915_READ(DSPADDR(crtc->plane));
@@ -693,9 +603,8 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 
 static int i915_gem_batch_pool_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct drm_i915_gem_object *obj;
        struct intel_engine_cs *engine;
        int total = 0;
@@ -738,9 +647,8 @@ static int i915_gem_batch_pool_info(struct seq_file *m, void *data)
 
 static int i915_gem_request_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_engine_cs *engine;
        struct drm_i915_gem_request *req;
        int ret, any;
@@ -754,21 +662,20 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
                int count;
 
                count = 0;
-               list_for_each_entry(req, &engine->request_list, list)
+               list_for_each_entry(req, &engine->request_list, link)
                        count++;
                if (count == 0)
                        continue;
 
                seq_printf(m, "%s requests: %d\n", engine->name, count);
-               list_for_each_entry(req, &engine->request_list, list) {
+               list_for_each_entry(req, &engine->request_list, link) {
+                       struct pid *pid = req->ctx->pid;
                        struct task_struct *task;
 
                        rcu_read_lock();
-                       task = NULL;
-                       if (req->pid)
-                               task = pid_task(req->pid, PIDTYPE_PID);
+                       task = pid ? pid_task(pid, PIDTYPE_PID) : NULL;
                        seq_printf(m, "    %x @ %d: %s [%d]\n",
-                                  req->seqno,
+                                  req->fence.seqno,
                                   (int) (jiffies - req->emitted_jiffies),
                                   task ? task->comm : "<unknown>",
                                   task ? task->pid : -1);
@@ -793,8 +700,6 @@ static void i915_ring_seqno_info(struct seq_file *m,
 
        seq_printf(m, "Current sequence (%s): %x\n",
                   engine->name, intel_engine_get_seqno(engine));
-       seq_printf(m, "Current user interrupts (%s): %lx\n",
-                  engine->name, READ_ONCE(engine->breadcrumbs.irq_wakeups));
 
        spin_lock(&b->lock);
        for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
@@ -808,41 +713,25 @@ static void i915_ring_seqno_info(struct seq_file *m,
 
 static int i915_gem_seqno_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        struct intel_engine_cs *engine;
-       int ret;
-
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
-       intel_runtime_pm_get(dev_priv);
 
        for_each_engine(engine, dev_priv)
                i915_ring_seqno_info(m, engine);
 
-       intel_runtime_pm_put(dev_priv);
-       mutex_unlock(&dev->struct_mutex);
-
        return 0;
 }
 
 
 static int i915_interrupt_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        struct intel_engine_cs *engine;
-       int ret, i, pipe;
+       int i, pipe;
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
        intel_runtime_pm_get(dev_priv);
 
-       if (IS_CHERRYVIEW(dev)) {
+       if (IS_CHERRYVIEW(dev_priv)) {
                seq_printf(m, "Master Interrupt Control:\t%08x\n",
                           I915_READ(GEN8_MASTER_IRQ));
 
@@ -881,7 +770,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                           I915_READ(GEN8_PCU_IIR));
                seq_printf(m, "PCU interrupt enable:\t%08x\n",
                           I915_READ(GEN8_PCU_IER));
-       } else if (INTEL_INFO(dev)->gen >= 8) {
+       } else if (INTEL_GEN(dev_priv) >= 8) {
                seq_printf(m, "Master Interrupt Control:\t%08x\n",
                           I915_READ(GEN8_MASTER_IRQ));
 
@@ -937,7 +826,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                           I915_READ(GEN8_PCU_IIR));
                seq_printf(m, "PCU interrupt enable:\t%08x\n",
                           I915_READ(GEN8_PCU_IER));
-       } else if (IS_VALLEYVIEW(dev)) {
+       } else if (IS_VALLEYVIEW(dev_priv)) {
                seq_printf(m, "Display IER:\t%08x\n",
                           I915_READ(VLV_IER));
                seq_printf(m, "Display IIR:\t%08x\n",
@@ -975,7 +864,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                seq_printf(m, "DPINVGTT:\t%08x\n",
                           I915_READ(DPINVGTT));
 
-       } else if (!HAS_PCH_SPLIT(dev)) {
+       } else if (!HAS_PCH_SPLIT(dev_priv)) {
                seq_printf(m, "Interrupt enable:    %08x\n",
                           I915_READ(IER));
                seq_printf(m, "Interrupt identity:  %08x\n",
@@ -1007,7 +896,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                           I915_READ(GTIMR));
        }
        for_each_engine(engine, dev_priv) {
-               if (INTEL_INFO(dev)->gen >= 6) {
+               if (INTEL_GEN(dev_priv) >= 6) {
                        seq_printf(m,
                                   "Graphics Interrupt mask (%s):       %08x\n",
                                   engine->name, I915_READ_IMR(engine));
@@ -1015,16 +904,14 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                i915_ring_seqno_info(m, engine);
        }
        intel_runtime_pm_put(dev_priv);
-       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
 
 static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        int i, ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -1033,14 +920,14 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
 
        seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
-               struct drm_i915_gem_object *obj = dev_priv->fence_regs[i].obj;
+               struct i915_vma *vma = dev_priv->fence_regs[i].vma;
 
                seq_printf(m, "Fence %d, pin count = %d, object = ",
                           i, dev_priv->fence_regs[i].pin_count);
-               if (obj == NULL)
+               if (!vma)
                        seq_puts(m, "unused");
                else
-                       describe_obj(m, obj);
+                       describe_obj(m, vma->obj);
                seq_putc(m, '\n');
        }
 
@@ -1051,8 +938,7 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
 static int i915_hws_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(node);
        struct intel_engine_cs *engine;
        const u32 *hws;
        int i;
@@ -1077,33 +963,25 @@ i915_error_state_write(struct file *filp,
                       loff_t *ppos)
 {
        struct i915_error_state_file_priv *error_priv = filp->private_data;
-       struct drm_device *dev = error_priv->dev;
-       int ret;
 
        DRM_DEBUG_DRIVER("Resetting error state\n");
-
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
-
-       i915_destroy_error_state(dev);
-       mutex_unlock(&dev->struct_mutex);
+       i915_destroy_error_state(error_priv->dev);
 
        return cnt;
 }
 
 static int i915_error_state_open(struct inode *inode, struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = inode->i_private;
        struct i915_error_state_file_priv *error_priv;
 
        error_priv = kzalloc(sizeof(*error_priv), GFP_KERNEL);
        if (!error_priv)
                return -ENOMEM;
 
-       error_priv->dev = dev;
+       error_priv->dev = &dev_priv->drm;
 
-       i915_error_state_get(dev, error_priv);
+       i915_error_state_get(&dev_priv->drm, error_priv);
 
        file->private_data = error_priv;
 
@@ -1129,7 +1007,8 @@ static ssize_t i915_error_state_read(struct file *file, char __user *userbuf,
        ssize_t ret_count = 0;
        int ret;
 
-       ret = i915_error_state_buf_init(&error_str, to_i915(error_priv->dev), count, *pos);
+       ret = i915_error_state_buf_init(&error_str,
+                                       to_i915(error_priv->dev), count, *pos);
        if (ret)
                return ret;
 
@@ -1162,16 +1041,15 @@ static const struct file_operations i915_error_state_fops = {
 static int
 i915_next_seqno_get(void *data, u64 *val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
        int ret;
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
        if (ret)
                return ret;
 
        *val = dev_priv->next_seqno;
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->drm.struct_mutex);
 
        return 0;
 }
@@ -1179,7 +1057,8 @@ i915_next_seqno_get(void *data, u64 *val)
 static int
 i915_next_seqno_set(void *data, u64 val)
 {
-       struct drm_device *dev = data;
+       struct drm_i915_private *dev_priv = data;
+       struct drm_device *dev = &dev_priv->drm;
        int ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -1198,16 +1077,13 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_next_seqno_fops,
 
 static int i915_frequency_info(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        int ret = 0;
 
        intel_runtime_pm_get(dev_priv);
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
-       if (IS_GEN5(dev)) {
+       if (IS_GEN5(dev_priv)) {
                u16 rgvswctl = I915_READ16(MEMSWCTL);
                u16 rgvstat = I915_READ16(MEMSTAT_ILK);
 
@@ -1217,7 +1093,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                           MEMSTAT_VID_SHIFT);
                seq_printf(m, "Current P-state: %d\n",
                           (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
-       } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
+       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
                u32 freq_sts;
 
                mutex_lock(&dev_priv->rps.hw_lock);
@@ -1244,7 +1120,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                           "efficient (RPe) frequency: %d MHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
                mutex_unlock(&dev_priv->rps.hw_lock);
-       } else if (INTEL_INFO(dev)->gen >= 6) {
+       } else if (INTEL_GEN(dev_priv) >= 6) {
                u32 rp_state_limits;
                u32 gt_perf_status;
                u32 rp_state_cap;
@@ -1256,7 +1132,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                int max_freq;
 
                rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
-               if (IS_BROXTON(dev)) {
+               if (IS_BROXTON(dev_priv)) {
                        rp_state_cap = I915_READ(BXT_RP_STATE_CAP);
                        gt_perf_status = I915_READ(BXT_GT_PERF_STATUS);
                } else {
@@ -1272,11 +1148,11 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
                reqf = I915_READ(GEN6_RPNSWREQ);
-               if (IS_GEN9(dev))
+               if (IS_GEN9(dev_priv))
                        reqf >>= 23;
                else {
                        reqf &= ~GEN6_TURBO_DISABLE;
-                       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+                       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
                                reqf >>= 24;
                        else
                                reqf >>= 25;
@@ -1294,9 +1170,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                rpdownei = I915_READ(GEN6_RP_CUR_DOWN_EI) & GEN6_CURIAVG_MASK;
                rpcurdown = I915_READ(GEN6_RP_CUR_DOWN) & GEN6_CURBSYTAVG_MASK;
                rpprevdown = I915_READ(GEN6_RP_PREV_DOWN) & GEN6_CURBSYTAVG_MASK;
-               if (IS_GEN9(dev))
+               if (IS_GEN9(dev_priv))
                        cagf = (rpstat & GEN9_CAGF_MASK) >> GEN9_CAGF_SHIFT;
-               else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
                        cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
                else
                        cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
@@ -1305,7 +1181,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
                mutex_unlock(&dev->struct_mutex);
 
-               if (IS_GEN6(dev) || IS_GEN7(dev)) {
+               if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) {
                        pm_ier = I915_READ(GEN6_PMIER);
                        pm_imr = I915_READ(GEN6_PMIMR);
                        pm_isr = I915_READ(GEN6_PMISR);
@@ -1323,7 +1199,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                seq_printf(m, "pm_intr_keep: 0x%08x\n", dev_priv->rps.pm_intr_keep);
                seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
                seq_printf(m, "Render p-state ratio: %d\n",
-                          (gt_perf_status & (IS_GEN9(dev) ? 0x1ff00 : 0xff00)) >> 8);
+                          (gt_perf_status & (IS_GEN9(dev_priv) ? 0x1ff00 : 0xff00)) >> 8);
                seq_printf(m, "Render p-state VID: %d\n",
                           gt_perf_status & 0xff);
                seq_printf(m, "Render p-state limit: %d\n",
@@ -1352,22 +1228,22 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                seq_printf(m, "Down threshold: %d%%\n",
                           dev_priv->rps.down_threshold);
 
-               max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 0 :
+               max_freq = (IS_BROXTON(dev_priv) ? rp_state_cap >> 0 :
                            rp_state_cap >> 16) & 0xff;
-               max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+               max_freq *= (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) ?
                             GEN9_FREQ_SCALER : 1);
                seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, max_freq));
 
                max_freq = (rp_state_cap & 0xff00) >> 8;
-               max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+               max_freq *= (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) ?
                             GEN9_FREQ_SCALER : 1);
                seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, max_freq));
 
-               max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 16 :
+               max_freq = (IS_BROXTON(dev_priv) ? rp_state_cap >> 16 :
                            rp_state_cap >> 0) & 0xff;
-               max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+               max_freq *= (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) ?
                             GEN9_FREQ_SCALER : 1);
                seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, max_freq));
@@ -1381,6 +1257,8 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                           intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq));
                seq_printf(m, "Min freq: %d MHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.min_freq));
+               seq_printf(m, "Boost freq: %d MHz\n",
+                          intel_gpu_freq(dev_priv, dev_priv->rps.boost_freq));
                seq_printf(m, "Max freq: %d MHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
                seq_printf(m,
@@ -1401,9 +1279,7 @@ out:
 
 static int i915_hangcheck_info(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        struct intel_engine_cs *engine;
        u64 acthd[I915_NUM_ENGINES];
        u32 seqno[I915_NUM_ENGINES];
@@ -1411,6 +1287,15 @@ static int i915_hangcheck_info(struct seq_file *m, void *unused)
        enum intel_engine_id id;
        int j;
 
+       if (test_bit(I915_WEDGED, &dev_priv->gpu_error.flags))
+               seq_printf(m, "Wedged\n");
+       if (test_bit(I915_RESET_IN_PROGRESS, &dev_priv->gpu_error.flags))
+               seq_printf(m, "Reset in progress\n");
+       if (waitqueue_active(&dev_priv->gpu_error.wait_queue))
+               seq_printf(m, "Waiter holding struct mutex\n");
+       if (waitqueue_active(&dev_priv->gpu_error.reset_queue))
+               seq_printf(m, "struct_mutex blocked for reset\n");
+
        if (!i915.enable_hangcheck) {
                seq_printf(m, "Hangcheck disabled\n");
                return 0;
@@ -1419,7 +1304,7 @@ static int i915_hangcheck_info(struct seq_file *m, void *unused)
        intel_runtime_pm_get(dev_priv);
 
        for_each_engine_id(engine, dev_priv, id) {
-               acthd[id] = intel_ring_get_active_head(engine);
+               acthd[id] = intel_engine_get_active_head(engine);
                seqno[id] = intel_engine_get_seqno(engine);
        }
 
@@ -1440,11 +1325,10 @@ static int i915_hangcheck_info(struct seq_file *m, void *unused)
                           engine->hangcheck.seqno,
                           seqno[id],
                           engine->last_submitted_seqno);
-               seq_printf(m, "\twaiters? %d\n",
-                          intel_engine_has_waiter(engine));
-               seq_printf(m, "\tuser interrupts = %lx [current %lx]\n",
-                          engine->hangcheck.user_interrupts,
-                          READ_ONCE(engine->breadcrumbs.irq_wakeups));
+               seq_printf(m, "\twaiters? %s, fake irq active? %s\n",
+                          yesno(intel_engine_has_waiter(engine)),
+                          yesno(test_bit(engine->id,
+                                         &dev_priv->gpu_error.missed_irq_rings)));
                seq_printf(m, "\tACTHD = 0x%08llx [current 0x%08llx]\n",
                           (long long)engine->hangcheck.acthd,
                           (long long)acthd[id]);
@@ -1472,9 +1356,8 @@ static int i915_hangcheck_info(struct seq_file *m, void *unused)
 
 static int ironlake_drpc_info(struct seq_file *m)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        u32 rgvmodectl, rstdbyctl;
        u16 crstandvid;
        int ret;
@@ -1540,9 +1423,7 @@ static int ironlake_drpc_info(struct seq_file *m)
 
 static int i915_forcewake_domains(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        struct intel_uncore_forcewake_domain *fw_domain;
 
        spin_lock_irq(&dev_priv->uncore.lock);
@@ -1558,9 +1439,7 @@ static int i915_forcewake_domains(struct seq_file *m, void *data)
 
 static int vlv_drpc_info(struct seq_file *m)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        u32 rpmodectl1, rcctl1, pw_status;
 
        intel_runtime_pm_get(dev_priv);
@@ -1598,10 +1477,10 @@ static int vlv_drpc_info(struct seq_file *m)
 
 static int gen6_drpc_info(struct seq_file *m)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        u32 rpmodectl1, gt_core_status, rcctl1, rc6vids = 0;
+       u32 gen9_powergate_enable = 0, gen9_powergate_status = 0;
        unsigned forcewake_count;
        int count = 0, ret;
 
@@ -1629,6 +1508,10 @@ static int gen6_drpc_info(struct seq_file *m)
 
        rpmodectl1 = I915_READ(GEN6_RP_CONTROL);
        rcctl1 = I915_READ(GEN6_RC_CONTROL);
+       if (INTEL_GEN(dev_priv) >= 9) {
+               gen9_powergate_enable = I915_READ(GEN9_PG_ENABLE);
+               gen9_powergate_status = I915_READ(GEN9_PWRGT_DOMAIN_STATUS);
+       }
        mutex_unlock(&dev->struct_mutex);
        mutex_lock(&dev_priv->rps.hw_lock);
        sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
@@ -1647,6 +1530,12 @@ static int gen6_drpc_info(struct seq_file *m)
                   yesno(rcctl1 & GEN6_RC_CTL_RC1e_ENABLE));
        seq_printf(m, "RC6 Enabled: %s\n",
                   yesno(rcctl1 & GEN6_RC_CTL_RC6_ENABLE));
+       if (INTEL_GEN(dev_priv) >= 9) {
+               seq_printf(m, "Render Well Gating Enabled: %s\n",
+                       yesno(gen9_powergate_enable & GEN9_RENDER_PG_ENABLE));
+               seq_printf(m, "Media Well Gating Enabled: %s\n",
+                       yesno(gen9_powergate_enable & GEN9_MEDIA_PG_ENABLE));
+       }
        seq_printf(m, "Deep RC6 Enabled: %s\n",
                   yesno(rcctl1 & GEN6_RC_CTL_RC6p_ENABLE));
        seq_printf(m, "Deepest RC6 Enabled: %s\n",
@@ -1675,6 +1564,14 @@ static int gen6_drpc_info(struct seq_file *m)
 
        seq_printf(m, "Core Power Down: %s\n",
                   yesno(gt_core_status & GEN6_CORE_CPD_STATE_MASK));
+       if (INTEL_GEN(dev_priv) >= 9) {
+               seq_printf(m, "Render Power Well: %s\n",
+                       (gen9_powergate_status &
+                        GEN9_PWRGT_RENDER_STATUS_MASK) ? "Up" : "Down");
+               seq_printf(m, "Media Power Well: %s\n",
+                       (gen9_powergate_status &
+                        GEN9_PWRGT_MEDIA_STATUS_MASK) ? "Up" : "Down");
+       }
 
        /* Not exactly sure what this is */
        seq_printf(m, "RC6 \"Locked to RPn\" residency since boot: %u\n",
@@ -1692,17 +1589,16 @@ static int gen6_drpc_info(struct seq_file *m)
                   GEN6_DECODE_RC6_VID(((rc6vids >> 8) & 0xff)));
        seq_printf(m, "RC6++ voltage: %dmV\n",
                   GEN6_DECODE_RC6_VID(((rc6vids >> 16) & 0xff)));
-       return 0;
+       return i915_forcewake_domains(m, NULL);
 }
 
 static int i915_drpc_info(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
 
-       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                return vlv_drpc_info(m);
-       else if (INTEL_INFO(dev)->gen >= 6)
+       else if (INTEL_GEN(dev_priv) >= 6)
                return gen6_drpc_info(m);
        else
                return ironlake_drpc_info(m);
@@ -1710,9 +1606,7 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
 
 static int i915_frontbuffer_tracking(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
 
        seq_printf(m, "FB tracking busy bits: 0x%08x\n",
                   dev_priv->fb_tracking.busy_bits);
@@ -1725,11 +1619,9 @@ static int i915_frontbuffer_tracking(struct seq_file *m, void *unused)
 
 static int i915_fbc_status(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
 
-       if (!HAS_FBC(dev)) {
+       if (!HAS_FBC(dev_priv)) {
                seq_puts(m, "FBC unsupported on this chipset\n");
                return 0;
        }
@@ -1743,7 +1635,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
                seq_printf(m, "FBC disabled: %s\n",
                           dev_priv->fbc.no_fbc_reason);
 
-       if (INTEL_INFO(dev_priv)->gen >= 7)
+       if (INTEL_GEN(dev_priv) >= 7)
                seq_printf(m, "Compressing: %s\n",
                           yesno(I915_READ(FBC_STATUS2) &
                                 FBC_COMPRESSION_MASK));
@@ -1756,10 +1648,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
 
 static int i915_fbc_fc_get(void *data, u64 *val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
 
-       if (INTEL_INFO(dev)->gen < 7 || !HAS_FBC(dev))
+       if (INTEL_GEN(dev_priv) < 7 || !HAS_FBC(dev_priv))
                return -ENODEV;
 
        *val = dev_priv->fbc.false_color;
@@ -1769,11 +1660,10 @@ static int i915_fbc_fc_get(void *data, u64 *val)
 
 static int i915_fbc_fc_set(void *data, u64 val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
        u32 reg;
 
-       if (INTEL_INFO(dev)->gen < 7 || !HAS_FBC(dev))
+       if (INTEL_GEN(dev_priv) < 7 || !HAS_FBC(dev_priv))
                return -ENODEV;
 
        mutex_lock(&dev_priv->fbc.lock);
@@ -1795,11 +1685,9 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_fbc_fc_fops,
 
 static int i915_ips_status(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
 
-       if (!HAS_IPS(dev)) {
+       if (!HAS_IPS(dev_priv)) {
                seq_puts(m, "not supported\n");
                return 0;
        }
@@ -1809,7 +1697,7 @@ static int i915_ips_status(struct seq_file *m, void *unused)
        seq_printf(m, "Enabled by kernel parameter: %s\n",
                   yesno(i915.enable_ips));
 
-       if (INTEL_INFO(dev)->gen >= 8) {
+       if (INTEL_GEN(dev_priv) >= 8) {
                seq_puts(m, "Currently: unknown\n");
        } else {
                if (I915_READ(IPS_CTL) & IPS_ENABLE)
@@ -1825,23 +1713,21 @@ static int i915_ips_status(struct seq_file *m, void *unused)
 
 static int i915_sr_status(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        bool sr_enabled = false;
 
        intel_runtime_pm_get(dev_priv);
 
-       if (HAS_PCH_SPLIT(dev))
+       if (HAS_PCH_SPLIT(dev_priv))
                sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
-       else if (IS_CRESTLINE(dev) || IS_G4X(dev) ||
-                IS_I945G(dev) || IS_I945GM(dev))
+       else if (IS_CRESTLINE(dev_priv) || IS_G4X(dev_priv) ||
+                IS_I945G(dev_priv) || IS_I945GM(dev_priv))
                sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
-       else if (IS_I915GM(dev))
+       else if (IS_I915GM(dev_priv))
                sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
-       else if (IS_PINEVIEW(dev))
+       else if (IS_PINEVIEW(dev_priv))
                sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
-       else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
+       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                sr_enabled = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN;
 
        intel_runtime_pm_put(dev_priv);
@@ -1854,13 +1740,12 @@ static int i915_sr_status(struct seq_file *m, void *unused)
 
 static int i915_emon_status(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        unsigned long temp, chipset, gfx;
        int ret;
 
-       if (!IS_GEN5(dev))
+       if (!IS_GEN5(dev_priv))
                return -ENODEV;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -1882,27 +1767,23 @@ static int i915_emon_status(struct seq_file *m, void *unused)
 
 static int i915_ring_freq_table(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        int ret = 0;
        int gpu_freq, ia_freq;
        unsigned int max_gpu_freq, min_gpu_freq;
 
-       if (!HAS_CORE_RING_FREQ(dev)) {
+       if (!HAS_LLC(dev_priv)) {
                seq_puts(m, "unsupported on this chipset\n");
                return 0;
        }
 
        intel_runtime_pm_get(dev_priv);
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
        ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
                goto out;
 
-       if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
                /* Convert GT frequency to 50 HZ units */
                min_gpu_freq =
                        dev_priv->rps.min_freq_softlimit / GEN9_FREQ_SCALER;
@@ -1922,7 +1803,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
                                       &ia_freq);
                seq_printf(m, "%d\t\t%d\t\t\t\t%d\n",
                           intel_gpu_freq(dev_priv, (gpu_freq *
-                               (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+                               (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) ?
                                 GEN9_FREQ_SCALER : 1))),
                           ((ia_freq >> 0) & 0xff) * 100,
                           ((ia_freq >> 8) & 0xff) * 100);
@@ -1937,9 +1818,8 @@ out:
 
 static int i915_opregion(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_opregion *opregion = &dev_priv->opregion;
        int ret;
 
@@ -1958,10 +1838,7 @@ out:
 
 static int i915_vbt(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_opregion *opregion = &dev_priv->opregion;
+       struct intel_opregion *opregion = &node_to_i915(m->private)->opregion;
 
        if (opregion->vbt)
                seq_write(m, opregion->vbt, opregion->vbt_size);
@@ -1971,8 +1848,8 @@ static int i915_vbt(struct seq_file *m, void *unused)
 
 static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_framebuffer *fbdev_fb = NULL;
        struct drm_framebuffer *drm_fb;
        int ret;
@@ -1982,8 +1859,8 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
                return ret;
 
 #ifdef CONFIG_DRM_FBDEV_EMULATION
-       if (to_i915(dev)->fbdev) {
-               fbdev_fb = to_intel_framebuffer(to_i915(dev)->fbdev->helper.fb);
+       if (dev_priv->fbdev) {
+               fbdev_fb = to_intel_framebuffer(dev_priv->fbdev->helper.fb);
 
                seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
                           fbdev_fb->base.width,
@@ -2019,19 +1896,17 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
        return 0;
 }
 
-static void describe_ctx_ringbuf(struct seq_file *m,
-                                struct intel_ringbuffer *ringbuf)
+static void describe_ctx_ring(struct seq_file *m, struct intel_ring *ring)
 {
        seq_printf(m, " (ringbuffer, space: %d, head: %u, tail: %u, last head: %d)",
-                  ringbuf->space, ringbuf->head, ringbuf->tail,
-                  ringbuf->last_retired_head);
+                  ring->space, ring->head, ring->tail,
+                  ring->last_retired_head);
 }
 
 static int i915_context_status(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_engine_cs *engine;
        struct i915_gem_context *ctx;
        int ret;
@@ -2042,18 +1917,17 @@ static int i915_context_status(struct seq_file *m, void *unused)
 
        list_for_each_entry(ctx, &dev_priv->context_list, link) {
                seq_printf(m, "HW context %u ", ctx->hw_id);
-               if (IS_ERR(ctx->file_priv)) {
-                       seq_puts(m, "(deleted) ");
-               } else if (ctx->file_priv) {
-                       struct pid *pid = ctx->file_priv->file->pid;
+               if (ctx->pid) {
                        struct task_struct *task;
 
-                       task = get_pid_task(pid, PIDTYPE_PID);
+                       task = get_pid_task(ctx->pid, PIDTYPE_PID);
                        if (task) {
                                seq_printf(m, "(%s [%d]) ",
                                           task->comm, task->pid);
                                put_task_struct(task);
                        }
+               } else if (IS_ERR(ctx->file_priv)) {
+                       seq_puts(m, "(deleted) ");
                } else {
                        seq_puts(m, "(kernel) ");
                }
@@ -2067,9 +1941,9 @@ static int i915_context_status(struct seq_file *m, void *unused)
                        seq_printf(m, "%s: ", engine->name);
                        seq_putc(m, ce->initialised ? 'I' : 'i');
                        if (ce->state)
-                               describe_obj(m, ce->state);
-                       if (ce->ringbuf)
-                               describe_ctx_ringbuf(m, ce->ringbuf);
+                               describe_obj(m, ce->state->obj);
+                       if (ce->ring)
+                               describe_ctx_ring(m, ce->ring);
                        seq_putc(m, '\n');
                }
 
@@ -2085,36 +1959,34 @@ static void i915_dump_lrc_obj(struct seq_file *m,
                              struct i915_gem_context *ctx,
                              struct intel_engine_cs *engine)
 {
-       struct drm_i915_gem_object *ctx_obj = ctx->engine[engine->id].state;
+       struct i915_vma *vma = ctx->engine[engine->id].state;
        struct page *page;
-       uint32_t *reg_state;
        int j;
-       unsigned long ggtt_offset = 0;
 
        seq_printf(m, "CONTEXT: %s %u\n", engine->name, ctx->hw_id);
 
-       if (ctx_obj == NULL) {
-               seq_puts(m, "\tNot allocated\n");
+       if (!vma) {
+               seq_puts(m, "\tFake context\n");
                return;
        }
 
-       if (!i915_gem_obj_ggtt_bound(ctx_obj))
-               seq_puts(m, "\tNot bound in GGTT\n");
-       else
-               ggtt_offset = i915_gem_obj_ggtt_offset(ctx_obj);
+       if (vma->flags & I915_VMA_GLOBAL_BIND)
+               seq_printf(m, "\tBound in GGTT at 0x%08x\n",
+                          i915_ggtt_offset(vma));
 
-       if (i915_gem_object_get_pages(ctx_obj)) {
-               seq_puts(m, "\tFailed to get pages for context object\n");
+       if (i915_gem_object_get_pages(vma->obj)) {
+               seq_puts(m, "\tFailed to get pages for context object\n\n");
                return;
        }
 
-       page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
-       if (!WARN_ON(page == NULL)) {
-               reg_state = kmap_atomic(page);
+       page = i915_gem_object_get_page(vma->obj, LRC_STATE_PN);
+       if (page) {
+               u32 *reg_state = kmap_atomic(page);
 
                for (j = 0; j < 0x600 / sizeof(u32) / 4; j += 4) {
-                       seq_printf(m, "\t[0x%08lx] 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                  ggtt_offset + 4096 + (j * 4),
+                       seq_printf(m,
+                                  "\t[0x%04x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                                  j * 4,
                                   reg_state[j], reg_state[j + 1],
                                   reg_state[j + 2], reg_state[j + 3]);
                }
@@ -2126,9 +1998,8 @@ static void i915_dump_lrc_obj(struct seq_file *m,
 
 static int i915_dump_lrc(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_engine_cs *engine;
        struct i915_gem_context *ctx;
        int ret;
@@ -2153,9 +2024,8 @@ static int i915_dump_lrc(struct seq_file *m, void *unused)
 
 static int i915_execlists(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 drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_engine_cs *engine;
        u32 status_pointer;
        u8 read_pointer;
@@ -2190,7 +2060,7 @@ static int i915_execlists(struct seq_file *m, void *data)
                status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(engine));
                seq_printf(m, "\tStatus pointer: 0x%08X\n", status_pointer);
 
-               read_pointer = engine->next_context_status_buffer;
+               read_pointer = GEN8_CSB_READ_PTR(status_pointer);
                write_pointer = GEN8_CSB_WRITE_PTR(status_pointer);
                if (read_pointer > write_pointer)
                        write_pointer += GEN8_CSB_ENTRIES;
@@ -2256,9 +2126,8 @@ static const char *swizzle_string(unsigned swizzle)
 
 static int i915_swizzle_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        int ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -2271,7 +2140,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
        seq_printf(m, "bit6 swizzle for Y-tiling = %s\n",
                   swizzle_string(dev_priv->mm.bit_6_swizzle_y));
 
-       if (IS_GEN3(dev) || IS_GEN4(dev)) {
+       if (IS_GEN3(dev_priv) || IS_GEN4(dev_priv)) {
                seq_printf(m, "DDC = 0x%08x\n",
                           I915_READ(DCC));
                seq_printf(m, "DDC2 = 0x%08x\n",
@@ -2280,7 +2149,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
                           I915_READ16(C0DRB3));
                seq_printf(m, "C1DRB3 = 0x%04x\n",
                           I915_READ16(C1DRB3));
-       } else if (INTEL_INFO(dev)->gen >= 6) {
+       } else if (INTEL_GEN(dev_priv) >= 6) {
                seq_printf(m, "MAD_DIMM_C0 = 0x%08x\n",
                           I915_READ(MAD_DIMM_C0));
                seq_printf(m, "MAD_DIMM_C1 = 0x%08x\n",
@@ -2289,7 +2158,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
                           I915_READ(MAD_DIMM_C2));
                seq_printf(m, "TILECTL = 0x%08x\n",
                           I915_READ(TILECTL));
-               if (INTEL_INFO(dev)->gen >= 8)
+               if (INTEL_GEN(dev_priv) >= 8)
                        seq_printf(m, "GAMTARBMODE = 0x%08x\n",
                                   I915_READ(GAMTARBMODE));
                else
@@ -2329,9 +2198,9 @@ static int per_file_ctx(int id, void *ptr, void *data)
        return 0;
 }
 
-static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
+static void gen8_ppgtt_info(struct seq_file *m,
+                           struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_engine_cs *engine;
        struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
        int i;
@@ -2350,9 +2219,9 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
        }
 }
 
-static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
+static void gen6_ppgtt_info(struct seq_file *m,
+                           struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_engine_cs *engine;
 
        if (IS_GEN6(dev_priv))
@@ -2384,22 +2253,23 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
 
 static int i915_ppgtt_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct drm_file *file;
+       int ret;
 
-       int ret = mutex_lock_interruptible(&dev->struct_mutex);
+       mutex_lock(&dev->filelist_mutex);
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
-               return ret;
+               goto out_unlock;
+
        intel_runtime_pm_get(dev_priv);
 
-       if (INTEL_INFO(dev)->gen >= 8)
-               gen8_ppgtt_info(m, dev);
-       else if (INTEL_INFO(dev)->gen >= 6)
-               gen6_ppgtt_info(m, dev);
+       if (INTEL_GEN(dev_priv) >= 8)
+               gen8_ppgtt_info(m, dev_priv);
+       else if (INTEL_GEN(dev_priv) >= 6)
+               gen6_ppgtt_info(m, dev_priv);
 
-       mutex_lock(&dev->filelist_mutex);
        list_for_each_entry_reverse(file, &dev->filelist, lhead) {
                struct drm_i915_file_private *file_priv = file->driver_priv;
                struct task_struct *task;
@@ -2407,19 +2277,19 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
                task = get_pid_task(file->pid, PIDTYPE_PID);
                if (!task) {
                        ret = -ESRCH;
-                       goto out_unlock;
+                       goto out_rpm;
                }
                seq_printf(m, "\nproc: %s\n", task->comm);
                put_task_struct(task);
                idr_for_each(&file_priv->context_idr, per_file_ctx,
                             (void *)(unsigned long)m);
        }
-out_unlock:
-       mutex_unlock(&dev->filelist_mutex);
 
+out_rpm:
        intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev->struct_mutex);
-
+out_unlock:
+       mutex_unlock(&dev->filelist_mutex);
        return ret;
 }
 
@@ -2434,23 +2304,41 @@ static int count_irq_waiters(struct drm_i915_private *i915)
        return count;
 }
 
+static const char *rps_power_to_str(unsigned int power)
+{
+       static const char * const strings[] = {
+               [LOW_POWER] = "low power",
+               [BETWEEN] = "mixed",
+               [HIGH_POWER] = "high power",
+       };
+
+       if (power >= ARRAY_SIZE(strings) || !strings[power])
+               return "unknown";
+
+       return strings[power];
+}
+
 static int i915_rps_boost_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct drm_file *file;
 
        seq_printf(m, "RPS enabled? %d\n", dev_priv->rps.enabled);
        seq_printf(m, "GPU busy? %s [%x]\n",
                   yesno(dev_priv->gt.awake), dev_priv->gt.active_engines);
        seq_printf(m, "CPU waiting? %d\n", count_irq_waiters(dev_priv));
-       seq_printf(m, "Frequency requested %d; min hard:%d, soft:%d; max soft:%d, hard:%d\n",
-                  intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
+       seq_printf(m, "Frequency requested %d\n",
+                  intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq));
+       seq_printf(m, "  min hard:%d, soft:%d; max soft:%d, hard:%d\n",
                   intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
                   intel_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit),
                   intel_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit),
                   intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
+       seq_printf(m, "  idle:%d, efficient:%d, boost:%d\n",
+                  intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq),
+                  intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+                  intel_gpu_freq(dev_priv, dev_priv->rps.boost_freq));
 
        mutex_lock(&dev->filelist_mutex);
        spin_lock(&dev_priv->rps.client_lock);
@@ -2467,27 +2355,44 @@ static int i915_rps_boost_info(struct seq_file *m, void *data)
                           list_empty(&file_priv->rps.link) ? "" : ", active");
                rcu_read_unlock();
        }
-       seq_printf(m, "Semaphore boosts: %d%s\n",
-                  dev_priv->rps.semaphores.boosts,
-                  list_empty(&dev_priv->rps.semaphores.link) ? "" : ", active");
-       seq_printf(m, "MMIO flip boosts: %d%s\n",
-                  dev_priv->rps.mmioflips.boosts,
-                  list_empty(&dev_priv->rps.mmioflips.link) ? "" : ", active");
-       seq_printf(m, "Kernel boosts: %d\n", dev_priv->rps.boosts);
+       seq_printf(m, "Kernel (anonymous) boosts: %d\n", dev_priv->rps.boosts);
        spin_unlock(&dev_priv->rps.client_lock);
        mutex_unlock(&dev->filelist_mutex);
 
+       if (INTEL_GEN(dev_priv) >= 6 &&
+           dev_priv->rps.enabled &&
+           dev_priv->gt.active_engines) {
+               u32 rpup, rpupei;
+               u32 rpdown, rpdownei;
+
+               intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+               rpup = I915_READ_FW(GEN6_RP_CUR_UP) & GEN6_RP_EI_MASK;
+               rpupei = I915_READ_FW(GEN6_RP_CUR_UP_EI) & GEN6_RP_EI_MASK;
+               rpdown = I915_READ_FW(GEN6_RP_CUR_DOWN) & GEN6_RP_EI_MASK;
+               rpdownei = I915_READ_FW(GEN6_RP_CUR_DOWN_EI) & GEN6_RP_EI_MASK;
+               intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+
+               seq_printf(m, "\nRPS Autotuning (current \"%s\" window):\n",
+                          rps_power_to_str(dev_priv->rps.power));
+               seq_printf(m, "  Avg. up: %d%% [above threshold? %d%%]\n",
+                          100 * rpup / rpupei,
+                          dev_priv->rps.up_threshold);
+               seq_printf(m, "  Avg. down: %d%% [below threshold? %d%%]\n",
+                          100 * rpdown / rpdownei,
+                          dev_priv->rps.down_threshold);
+       } else {
+               seq_puts(m, "\nRPS Autotuning inactive\n");
+       }
+
        return 0;
 }
 
 static int i915_llc(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        const bool edram = INTEL_GEN(dev_priv) > 8;
 
-       seq_printf(m, "LLC: %s\n", yesno(HAS_LLC(dev)));
+       seq_printf(m, "LLC: %s\n", yesno(HAS_LLC(dev_priv)));
        seq_printf(m, "%s: %lluMB\n", edram ? "eDRAM" : "eLLC",
                   intel_uncore_edram_size(dev_priv)/1024/1024);
 
@@ -2496,8 +2401,7 @@ static int i915_llc(struct seq_file *m, void *data)
 
 static int i915_guc_load_status_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_i915_private *dev_priv = to_i915(node->minor->dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
        u32 tmp, i;
 
@@ -2543,6 +2447,7 @@ static void i915_guc_client_info(struct seq_file *m,
                                 struct i915_guc_client *client)
 {
        struct intel_engine_cs *engine;
+       enum intel_engine_id id;
        uint64_t tot = 0;
 
        seq_printf(m, "\tPriority %d, GuC ctx index: %u, PD offset 0x%x\n",
@@ -2553,27 +2458,26 @@ static void i915_guc_client_info(struct seq_file *m,
                client->wq_size, client->wq_offset, client->wq_tail);
 
        seq_printf(m, "\tWork queue full: %u\n", client->no_wq_space);
-       seq_printf(m, "\tFailed to queue: %u\n", client->q_fail);
        seq_printf(m, "\tFailed doorbell: %u\n", client->b_fail);
        seq_printf(m, "\tLast submission result: %d\n", client->retcode);
 
-       for_each_engine(engine, dev_priv) {
+       for_each_engine_id(engine, dev_priv, id) {
+               u64 submissions = client->submissions[id];
+               tot += submissions;
                seq_printf(m, "\tSubmissions: %llu %s\n",
-                               client->submissions[engine->id],
-                               engine->name);
-               tot += client->submissions[engine->id];
+                               submissions, engine->name);
        }
        seq_printf(m, "\tTotal: %llu\n", tot);
 }
 
 static int i915_guc_info(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_guc guc;
        struct i915_guc_client client = {};
        struct intel_engine_cs *engine;
+       enum intel_engine_id id;
        u64 total = 0;
 
        if (!HAS_GUC_SCHED(dev_priv))
@@ -2600,11 +2504,11 @@ static int i915_guc_info(struct seq_file *m, void *data)
        seq_printf(m, "GuC last action error code: %d\n", guc.action_err);
 
        seq_printf(m, "\nGuC submissions:\n");
-       for_each_engine(engine, dev_priv) {
+       for_each_engine_id(engine, dev_priv, id) {
+               u64 submissions = guc.submissions[id];
+               total += submissions;
                seq_printf(m, "\t%-24s: %10llu, last seqno 0x%08x\n",
-                       engine->name, guc.submissions[engine->id],
-                       guc.last_seqno[engine->id]);
-               total += guc.submissions[engine->id];
+                       engine->name, submissions, guc.last_seqno[id]);
        }
        seq_printf(m, "\t%s: %llu\n", "Total", total);
 
@@ -2618,18 +2522,16 @@ static int i915_guc_info(struct seq_file *m, void *data)
 
 static int i915_guc_log_dump(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_i915_gem_object *log_obj = dev_priv->guc.log_obj;
-       u32 *log;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_i915_gem_object *obj;
        int i = 0, pg;
 
-       if (!log_obj)
+       if (!dev_priv->guc.log_vma)
                return 0;
 
-       for (pg = 0; pg < log_obj->base.size / PAGE_SIZE; pg++) {
-               log = kmap_atomic(i915_gem_object_get_page(log_obj, pg));
+       obj = dev_priv->guc.log_vma->obj;
+       for (pg = 0; pg < obj->base.size / PAGE_SIZE; pg++) {
+               u32 *log = kmap_atomic(i915_gem_object_get_page(obj, pg));
 
                for (i = 0; i < PAGE_SIZE / sizeof(u32); i += 4)
                        seq_printf(m, "0x%08x 0x%08x 0x%08x 0x%08x\n",
@@ -2646,15 +2548,13 @@ static int i915_guc_log_dump(struct seq_file *m, void *data)
 
 static int i915_edp_psr_status(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        u32 psrperf = 0;
        u32 stat[3];
        enum pipe pipe;
        bool enabled = false;
 
-       if (!HAS_PSR(dev)) {
+       if (!HAS_PSR(dev_priv)) {
                seq_puts(m, "PSR not supported\n");
                return 0;
        }
@@ -2671,7 +2571,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
        seq_printf(m, "Re-enable work scheduled: %s\n",
                   yesno(work_busy(&dev_priv->psr.work.work)));
 
-       if (HAS_DDI(dev))
+       if (HAS_DDI(dev_priv))
                enabled = I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
        else {
                for_each_pipe(dev_priv, pipe) {
@@ -2688,7 +2588,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 
        seq_printf(m, "HW Enabled & Active bit: %s", yesno(enabled));
 
-       if (!HAS_DDI(dev))
+       if (!HAS_DDI(dev_priv))
                for_each_pipe(dev_priv, pipe) {
                        if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
                            (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
@@ -2700,7 +2600,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
         * VLV/CHV PSR has no kind of performance counter
         * SKL+ Perf counter is reset to 0 everytime DC state is entered
         */
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
                psrperf = I915_READ(EDP_PSR_PERF_CNT) &
                        EDP_PSR_PERF_CNT_MASK;
 
@@ -2714,8 +2614,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 
 static int i915_sink_crc(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_connector *connector;
        struct intel_dp *intel_dp = NULL;
        int ret;
@@ -2754,13 +2654,11 @@ out:
 
 static int i915_energy_uJ(struct seq_file *m, void *data)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        u64 power;
        u32 units;
 
-       if (INTEL_INFO(dev)->gen < 6)
+       if (INTEL_GEN(dev_priv) < 6)
                return -ENODEV;
 
        intel_runtime_pm_get(dev_priv);
@@ -2780,9 +2678,8 @@ static int i915_energy_uJ(struct seq_file *m, void *data)
 
 static int i915_runtime_pm_status(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
 
        if (!HAS_RUNTIME_PM(dev_priv))
                seq_puts(m, "Runtime power management not supported\n");
@@ -2792,22 +2689,20 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused)
                   yesno(!intel_irqs_enabled(dev_priv)));
 #ifdef CONFIG_PM
        seq_printf(m, "Usage count: %d\n",
-                  atomic_read(&dev->dev->power.usage_count));
+                  atomic_read(&dev_priv->drm.dev->power.usage_count));
 #else
        seq_printf(m, "Device Power Management (CONFIG_PM) disabled\n");
 #endif
        seq_printf(m, "PCI device power state: %s [%d]\n",
-                  pci_power_name(dev_priv->drm.pdev->current_state),
-                  dev_priv->drm.pdev->current_state);
+                  pci_power_name(pdev->current_state),
+                  pdev->current_state);
 
        return 0;
 }
 
 static int i915_power_domain_info(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        int i;
 
@@ -2840,12 +2735,10 @@ static int i915_power_domain_info(struct seq_file *m, void *unused)
 
 static int i915_dmc_info(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
        struct intel_csr *csr;
 
-       if (!HAS_CSR(dev)) {
+       if (!HAS_CSR(dev_priv)) {
                seq_puts(m, "not supported\n");
                return 0;
        }
@@ -2863,12 +2756,12 @@ static int i915_dmc_info(struct seq_file *m, void *unused)
        seq_printf(m, "version: %d.%d\n", CSR_VERSION_MAJOR(csr->version),
                   CSR_VERSION_MINOR(csr->version));
 
-       if (IS_SKYLAKE(dev) && csr->version >= CSR_VERSION(1, 6)) {
+       if (IS_SKYLAKE(dev_priv) && csr->version >= CSR_VERSION(1, 6)) {
                seq_printf(m, "DC3 -> DC5 count: %d\n",
                           I915_READ(SKL_CSR_DC3_DC5_COUNT));
                seq_printf(m, "DC5 -> DC6 count: %d\n",
                           I915_READ(SKL_CSR_DC5_DC6_COUNT));
-       } else if (IS_BROXTON(dev) && csr->version >= CSR_VERSION(1, 4)) {
+       } else if (IS_BROXTON(dev_priv) && csr->version >= CSR_VERSION(1, 4)) {
                seq_printf(m, "DC3 -> DC5 count: %d\n",
                           I915_READ(BXT_CSR_DC3_DC5_COUNT));
        }
@@ -2905,8 +2798,8 @@ static void intel_encoder_info(struct seq_file *m,
                               struct intel_crtc *intel_crtc,
                               struct intel_encoder *intel_encoder)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct drm_crtc *crtc = &intel_crtc->base;
        struct intel_connector *intel_connector;
        struct drm_encoder *encoder;
@@ -2932,8 +2825,8 @@ static void intel_encoder_info(struct seq_file *m,
 
 static void intel_crtc_info(struct seq_file *m, struct intel_crtc *intel_crtc)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct drm_crtc *crtc = &intel_crtc->base;
        struct intel_encoder *intel_encoder;
        struct drm_plane_state *plane_state = crtc->primary->state;
@@ -2967,6 +2860,9 @@ static void intel_dp_info(struct seq_file *m,
        seq_printf(m, "\taudio support: %s\n", yesno(intel_dp->has_audio));
        if (intel_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)
                intel_panel_info(m, &intel_connector->panel);
+
+       drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports,
+                               &intel_dp->aux);
 }
 
 static void intel_hdmi_info(struct seq_file *m,
@@ -3031,12 +2927,11 @@ static void intel_connector_info(struct seq_file *m,
                intel_seq_print_mode(m, 2, mode);
 }
 
-static bool cursor_active(struct drm_device *dev, int pipe)
+static bool cursor_active(struct drm_i915_private *dev_priv, int pipe)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u32 state;
 
-       if (IS_845G(dev) || IS_I865G(dev))
+       if (IS_845G(dev_priv) || IS_I865G(dev_priv))
                state = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE;
        else
                state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
@@ -3044,9 +2939,9 @@ static bool cursor_active(struct drm_device *dev, int pipe)
        return state;
 }
 
-static bool cursor_position(struct drm_device *dev, int pipe, int *x, int *y)
+static bool cursor_position(struct drm_i915_private *dev_priv,
+                           int pipe, int *x, int *y)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u32 pos;
 
        pos = I915_READ(CURPOS(pipe));
@@ -3059,7 +2954,7 @@ static bool cursor_position(struct drm_device *dev, int pipe, int *x, int *y)
        if (pos & (CURSOR_POS_SIGN << CURSOR_Y_SHIFT))
                *y = -*y;
 
-       return cursor_active(dev, pipe);
+       return cursor_active(dev_priv, pipe);
 }
 
 static const char *plane_type(enum drm_plane_type type)
@@ -3089,12 +2984,12 @@ static const char *plane_rotation(unsigned int rotation)
         */
        snprintf(buf, sizeof(buf),
                 "%s%s%s%s%s%s(0x%08x)",
-                (rotation & BIT(DRM_ROTATE_0)) ? "0 " : "",
-                (rotation & BIT(DRM_ROTATE_90)) ? "90 " : "",
-                (rotation & BIT(DRM_ROTATE_180)) ? "180 " : "",
-                (rotation & BIT(DRM_ROTATE_270)) ? "270 " : "",
-                (rotation & BIT(DRM_REFLECT_X)) ? "FLIPX " : "",
-                (rotation & BIT(DRM_REFLECT_Y)) ? "FLIPY " : "",
+                (rotation & DRM_ROTATE_0) ? "0 " : "",
+                (rotation & DRM_ROTATE_90) ? "90 " : "",
+                (rotation & DRM_ROTATE_180) ? "180 " : "",
+                (rotation & DRM_ROTATE_270) ? "270 " : "",
+                (rotation & DRM_REFLECT_X) ? "FLIPX " : "",
+                (rotation & DRM_REFLECT_Y) ? "FLIPY " : "",
                 rotation);
 
        return buf;
@@ -3102,13 +2997,14 @@ static const char *plane_rotation(unsigned int rotation)
 
 static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_plane *intel_plane;
 
        for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
                struct drm_plane_state *state;
                struct drm_plane *plane = &intel_plane->base;
+               char *format_name;
 
                if (!plane->state) {
                        seq_puts(m, "plane->state is NULL!\n");
@@ -3117,6 +3013,12 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc)
 
                state = plane->state;
 
+               if (state->fb) {
+                       format_name = drm_get_format_name(state->fb->pixel_format);
+               } else {
+                       format_name = kstrdup("N/A", GFP_KERNEL);
+               }
+
                seq_printf(m, "\t--Plane id %d: type=%s, crtc_pos=%4dx%4d, crtc_size=%4dx%4d, src_pos=%d.%04ux%d.%04u, src_size=%d.%04ux%d.%04u, format=%s, rotation=%s\n",
                           plane->base.id,
                           plane_type(intel_plane->base.type),
@@ -3130,8 +3032,10 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc)
                           ((state->src_w & 0xffff) * 15625) >> 10,
                           (state->src_h >> 16),
                           ((state->src_h & 0xffff) * 15625) >> 10,
-                          state->fb ? drm_get_format_name(state->fb->pixel_format) : "N/A",
+                          format_name,
                           plane_rotation(state->rotation));
+
+               kfree(format_name);
        }
 }
 
@@ -3165,9 +3069,8 @@ static void intel_scaler_info(struct seq_file *m, struct intel_crtc *intel_crtc)
 
 static int i915_display_info(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_crtc *crtc;
        struct drm_connector *connector;
 
@@ -3191,7 +3094,7 @@ static int i915_display_info(struct seq_file *m, void *unused)
                if (pipe_config->base.active) {
                        intel_crtc_info(m, crtc);
 
-                       active = cursor_position(dev, crtc->pipe, &x, &y);
+                       active = cursor_position(dev_priv, crtc->pipe, &x, &y);
                        seq_printf(m, "\tcursor visible? %s, position (%d, %d), size %dx%d, addr 0x%08x, active? %s\n",
                                   yesno(crtc->cursor_base),
                                   x, y, crtc->base.cursor->state->crtc_w,
@@ -3220,15 +3123,14 @@ static int i915_display_info(struct seq_file *m, void *unused)
 
 static int i915_semaphore_status(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_engine_cs *engine;
-       int num_rings = hweight32(INTEL_INFO(dev)->ring_mask);
+       int num_rings = INTEL_INFO(dev_priv)->num_rings;
        enum intel_engine_id id;
        int j, ret;
 
-       if (!i915_semaphore_is_enabled(dev_priv)) {
+       if (!i915.semaphores) {
                seq_puts(m, "Semaphores are disabled\n");
                return 0;
        }
@@ -3238,11 +3140,11 @@ static int i915_semaphore_status(struct seq_file *m, void *unused)
                return ret;
        intel_runtime_pm_get(dev_priv);
 
-       if (IS_BROADWELL(dev)) {
+       if (IS_BROADWELL(dev_priv)) {
                struct page *page;
                uint64_t *seqno;
 
-               page = i915_gem_object_get_page(dev_priv->semaphore_obj, 0);
+               page = i915_gem_object_get_page(dev_priv->semaphore->obj, 0);
 
                seqno = (uint64_t *)kmap_atomic(page);
                for_each_engine_id(engine, dev_priv, id) {
@@ -3293,9 +3195,8 @@ static int i915_semaphore_status(struct seq_file *m, void *unused)
 
 static int i915_shared_dplls_info(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        int i;
 
        drm_modeset_lock_all(dev);
@@ -3323,9 +3224,8 @@ static int i915_wa_registers(struct seq_file *m, void *unused)
        int i;
        int ret;
        struct intel_engine_cs *engine;
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct i915_workarounds *workarounds = &dev_priv->workarounds;
        enum intel_engine_id id;
 
@@ -3361,15 +3261,14 @@ static int i915_wa_registers(struct seq_file *m, void *unused)
 
 static int i915_ddb_info(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct skl_ddb_allocation *ddb;
        struct skl_ddb_entry *entry;
        enum pipe pipe;
        int plane;
 
-       if (INTEL_INFO(dev)->gen < 9)
+       if (INTEL_GEN(dev_priv) < 9)
                return 0;
 
        drm_modeset_lock_all(dev);
@@ -3399,7 +3298,8 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
 }
 
 static void drrs_status_per_crtc(struct seq_file *m,
-               struct drm_device *dev, struct intel_crtc *intel_crtc)
+                                struct drm_device *dev,
+                                struct intel_crtc *intel_crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_drrs *drrs = &dev_priv->drrs;
@@ -3468,8 +3368,8 @@ static void drrs_status_per_crtc(struct seq_file *m,
 
 static int i915_drrs_status(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = m->private;
-       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_crtc *intel_crtc;
        int active_crtc_cnt = 0;
 
@@ -3492,14 +3392,14 @@ static int i915_drrs_status(struct seq_file *m, void *unused)
 
 struct pipe_crc_info {
        const char *name;
-       struct drm_device *dev;
+       struct drm_i915_private *dev_priv;
        enum pipe pipe;
 };
 
 static int i915_dp_mst_info(struct seq_file *m, void *unused)
 {
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_encoder *intel_encoder;
        struct intel_digital_port *intel_dig_port;
        struct drm_connector *connector;
@@ -3528,10 +3428,10 @@ static int i915_dp_mst_info(struct seq_file *m, void *unused)
 static int i915_pipe_crc_open(struct inode *inode, struct file *filep)
 {
        struct pipe_crc_info *info = inode->i_private;
-       struct drm_i915_private *dev_priv = to_i915(info->dev);
+       struct drm_i915_private *dev_priv = info->dev_priv;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe];
 
-       if (info->pipe >= INTEL_INFO(info->dev)->num_pipes)
+       if (info->pipe >= INTEL_INFO(dev_priv)->num_pipes)
                return -ENODEV;
 
        spin_lock_irq(&pipe_crc->lock);
@@ -3552,7 +3452,7 @@ static int i915_pipe_crc_open(struct inode *inode, struct file *filep)
 static int i915_pipe_crc_release(struct inode *inode, struct file *filep)
 {
        struct pipe_crc_info *info = inode->i_private;
-       struct drm_i915_private *dev_priv = to_i915(info->dev);
+       struct drm_i915_private *dev_priv = info->dev_priv;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe];
 
        spin_lock_irq(&pipe_crc->lock);
@@ -3579,8 +3479,7 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count,
                   loff_t *pos)
 {
        struct pipe_crc_info *info = filep->private_data;
-       struct drm_device *dev = info->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = info->dev_priv;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe];
        char buf[PIPE_CRC_BUFFER_LEN];
        int n_entries;
@@ -3621,7 +3520,6 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count,
        while (n_entries > 0) {
                struct intel_pipe_crc_entry *entry =
                        &pipe_crc->entries[pipe_crc->tail];
-               int ret;
 
                if (CIRC_CNT(pipe_crc->head, pipe_crc->tail,
                             INTEL_PIPE_CRC_ENTRIES_NR) < 1)
@@ -3638,8 +3536,7 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count,
 
                spin_unlock_irq(&pipe_crc->lock);
 
-               ret = copy_to_user(user_buf, buf, PIPE_CRC_LINE_LEN);
-               if (ret == PIPE_CRC_LINE_LEN)
+               if (copy_to_user(user_buf, buf, PIPE_CRC_LINE_LEN))
                        return -EFAULT;
 
                user_buf += PIPE_CRC_LINE_LEN;
@@ -3678,11 +3575,11 @@ static struct pipe_crc_info i915_pipe_crc_data[I915_MAX_PIPES] = {
 static int i915_pipe_crc_create(struct dentry *root, struct drm_minor *minor,
                                enum pipe pipe)
 {
-       struct drm_device *dev = minor->dev;
+       struct drm_i915_private *dev_priv = to_i915(minor->dev);
        struct dentry *ent;
        struct pipe_crc_info *info = &i915_pipe_crc_data[pipe];
 
-       info->dev = dev;
+       info->dev_priv = dev_priv;
        ent = debugfs_create_file(info->name, S_IRUGO, root, info,
                                  &i915_pipe_crc_fops);
        if (!ent)
@@ -3712,8 +3609,7 @@ static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
 
 static int display_crc_ctl_show(struct seq_file *m, void *data)
 {
-       struct drm_device *dev = m->private;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = m->private;
        int i;
 
        for (i = 0; i < I915_MAX_PIPES; i++)
@@ -3725,9 +3621,7 @@ static int display_crc_ctl_show(struct seq_file *m, void *data)
 
 static int display_crc_ctl_open(struct inode *inode, struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
-
-       return single_open(file, display_crc_ctl_show, dev);
+       return single_open(file, display_crc_ctl_show, inode->i_private);
 }
 
 static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
@@ -3750,9 +3644,11 @@ static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
        return 0;
 }
 
-static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe,
+static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
+                                    enum pipe pipe,
                                     enum intel_pipe_crc_source *source)
 {
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_encoder *encoder;
        struct intel_crtc *crtc;
        struct intel_digital_port *dig_port;
@@ -3802,16 +3698,15 @@ static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe,
        return ret;
 }
 
-static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
+static int vlv_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
                                enum pipe pipe,
                                enum intel_pipe_crc_source *source,
                                uint32_t *val)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        bool need_stable_symbols = false;
 
        if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) {
-               int ret = i9xx_pipe_crc_auto_source(dev, pipe, source);
+               int ret = i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
                if (ret)
                        return ret;
        }
@@ -3829,7 +3724,7 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
                need_stable_symbols = true;
                break;
        case INTEL_PIPE_CRC_SOURCE_DP_D:
-               if (!IS_CHERRYVIEW(dev))
+               if (!IS_CHERRYVIEW(dev_priv))
                        return -EINVAL;
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_D_VLV;
                need_stable_symbols = true;
@@ -3873,16 +3768,15 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
        return 0;
 }
 
-static int i9xx_pipe_crc_ctl_reg(struct drm_device *dev,
+static int i9xx_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
                                 enum pipe pipe,
                                 enum intel_pipe_crc_source *source,
                                 uint32_t *val)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        bool need_stable_symbols = false;
 
        if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) {
-               int ret = i9xx_pipe_crc_auto_source(dev, pipe, source);
+               int ret = i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
                if (ret)
                        return ret;
        }
@@ -3892,24 +3786,24 @@ static int i9xx_pipe_crc_ctl_reg(struct drm_device *dev,
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PIPE_I9XX;
                break;
        case INTEL_PIPE_CRC_SOURCE_TV:
-               if (!SUPPORTS_TV(dev))
+               if (!SUPPORTS_TV(dev_priv))
                        return -EINVAL;
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_TV_PRE;
                break;
        case INTEL_PIPE_CRC_SOURCE_DP_B:
-               if (!IS_G4X(dev))
+               if (!IS_G4X(dev_priv))
                        return -EINVAL;
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_B_G4X;
                need_stable_symbols = true;
                break;
        case INTEL_PIPE_CRC_SOURCE_DP_C:
-               if (!IS_G4X(dev))
+               if (!IS_G4X(dev_priv))
                        return -EINVAL;
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_C_G4X;
                need_stable_symbols = true;
                break;
        case INTEL_PIPE_CRC_SOURCE_DP_D:
-               if (!IS_G4X(dev))
+               if (!IS_G4X(dev_priv))
                        return -EINVAL;
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_D_G4X;
                need_stable_symbols = true;
@@ -3933,7 +3827,7 @@ static int i9xx_pipe_crc_ctl_reg(struct drm_device *dev,
        if (need_stable_symbols) {
                uint32_t tmp = I915_READ(PORT_DFT2_G4X);
 
-               WARN_ON(!IS_G4X(dev));
+               WARN_ON(!IS_G4X(dev_priv));
 
                I915_WRITE(PORT_DFT_I9XX,
                           I915_READ(PORT_DFT_I9XX) | DC_BALANCE_RESET);
@@ -3949,10 +3843,9 @@ static int i9xx_pipe_crc_ctl_reg(struct drm_device *dev,
        return 0;
 }
 
-static void vlv_undo_pipe_scramble_reset(struct drm_device *dev,
+static void vlv_undo_pipe_scramble_reset(struct drm_i915_private *dev_priv,
                                         enum pipe pipe)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t tmp = I915_READ(PORT_DFT2_G4X);
 
        switch (pipe) {
@@ -3974,10 +3867,9 @@ static void vlv_undo_pipe_scramble_reset(struct drm_device *dev,
 
 }
 
-static void g4x_undo_pipe_scramble_reset(struct drm_device *dev,
+static void g4x_undo_pipe_scramble_reset(struct drm_i915_private *dev_priv,
                                         enum pipe pipe)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t tmp = I915_READ(PORT_DFT2_G4X);
 
        if (pipe == PIPE_A)
@@ -4018,9 +3910,10 @@ static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
        return 0;
 }
 
-static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev, bool enable)
+static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv,
+                                       bool enable)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_crtc *crtc =
                to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_A]);
        struct intel_crtc_state *pipe_config;
@@ -4054,7 +3947,7 @@ out:
                drm_atomic_state_free(state);
 }
 
-static int ivb_pipe_crc_ctl_reg(struct drm_device *dev,
+static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
                                enum pipe pipe,
                                enum intel_pipe_crc_source *source,
                                uint32_t *val)
@@ -4070,8 +3963,8 @@ static int ivb_pipe_crc_ctl_reg(struct drm_device *dev,
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB;
                break;
        case INTEL_PIPE_CRC_SOURCE_PF:
-               if (IS_HASWELL(dev) && pipe == PIPE_A)
-                       hsw_trans_edp_pipe_A_crc_wa(dev, true);
+               if (IS_HASWELL(dev_priv) && pipe == PIPE_A)
+                       hsw_trans_edp_pipe_A_crc_wa(dev_priv, true);
 
                *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB;
                break;
@@ -4085,13 +3978,14 @@ static int ivb_pipe_crc_ctl_reg(struct drm_device *dev,
        return 0;
 }
 
-static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
+static int pipe_crc_set_source(struct drm_i915_private *dev_priv,
+                              enum pipe pipe,
                               enum intel_pipe_crc_source source)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_device *dev = &dev_priv->drm;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
-       struct intel_crtc *crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev,
-                                                                       pipe));
+       struct intel_crtc *crtc =
+                       to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
        enum intel_display_power_domain power_domain;
        u32 val = 0; /* shut up gcc */
        int ret;
@@ -4109,16 +4003,16 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
                return -EIO;
        }
 
-       if (IS_GEN2(dev))
+       if (IS_GEN2(dev_priv))
                ret = i8xx_pipe_crc_ctl_reg(&source, &val);
-       else if (INTEL_INFO(dev)->gen < 5)
-               ret = i9xx_pipe_crc_ctl_reg(dev, pipe, &source, &val);
-       else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
-               ret = vlv_pipe_crc_ctl_reg(dev, pipe, &source, &val);
-       else if (IS_GEN5(dev) || IS_GEN6(dev))
+       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, pipe, &source, &val);
+               ret = ivb_pipe_crc_ctl_reg(dev_priv, pipe, &source, &val);
 
        if (ret != 0)
                goto out;
@@ -4182,12 +4076,12 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
 
                kfree(entries);
 
-               if (IS_G4X(dev))
-                       g4x_undo_pipe_scramble_reset(dev, pipe);
-               else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
-                       vlv_undo_pipe_scramble_reset(dev, pipe);
-               else if (IS_HASWELL(dev) && pipe == PIPE_A)
-                       hsw_trans_edp_pipe_A_crc_wa(dev, false);
+               if (IS_G4X(dev_priv))
+                       g4x_undo_pipe_scramble_reset(dev_priv, pipe);
+               else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+                       vlv_undo_pipe_scramble_reset(dev_priv, pipe);
+               else if (IS_HASWELL(dev_priv) && pipe == PIPE_A)
+                       hsw_trans_edp_pipe_A_crc_wa(dev_priv, false);
 
                hsw_enable_ips(crtc);
        }
@@ -4291,7 +4185,8 @@ display_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *s)
        return -EINVAL;
 }
 
-static int display_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len)
+static int display_crc_ctl_parse(struct drm_i915_private *dev_priv,
+                                char *buf, size_t len)
 {
 #define N_WORDS 3
        int n_words;
@@ -4322,14 +4217,14 @@ static int display_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len)
                return -EINVAL;
        }
 
-       return pipe_crc_set_source(dev, pipe, source);
+       return pipe_crc_set_source(dev_priv, pipe, source);
 }
 
 static ssize_t display_crc_ctl_write(struct file *file, const char __user *ubuf,
                                     size_t len, loff_t *offp)
 {
        struct seq_file *m = file->private_data;
-       struct drm_device *dev = m->private;
+       struct drm_i915_private *dev_priv = m->private;
        char *tmpbuf;
        int ret;
 
@@ -4352,7 +4247,7 @@ static ssize_t display_crc_ctl_write(struct file *file, const char __user *ubuf,
        }
        tmpbuf[len] = '\0';
 
-       ret = display_crc_ctl_parse(dev, tmpbuf, len);
+       ret = display_crc_ctl_parse(dev_priv, tmpbuf, len);
 
 out:
        kfree(tmpbuf);
@@ -4373,8 +4268,8 @@ static const struct file_operations i915_display_crc_ctl_fops = {
 };
 
 static ssize_t i915_displayport_test_active_write(struct file *file,
-                                           const char __user *ubuf,
-                                           size_t len, loff_t *offp)
+                                                 const char __user *ubuf,
+                                                 size_t len, loff_t *offp)
 {
        char *input_buffer;
        int status = 0;
@@ -4404,7 +4299,6 @@ static ssize_t i915_displayport_test_active_write(struct file *file,
        DRM_DEBUG_DRIVER("Copied %d bytes from user\n", (unsigned int)len);
 
        list_for_each_entry(connector, connector_list, head) {
-
                if (connector->connector_type !=
                    DRM_MODE_CONNECTOR_DisplayPort)
                        continue;
@@ -4442,7 +4336,6 @@ static int i915_displayport_test_active_show(struct seq_file *m, void *data)
        struct intel_dp *intel_dp;
 
        list_for_each_entry(connector, connector_list, head) {
-
                if (connector->connector_type !=
                    DRM_MODE_CONNECTOR_DisplayPort)
                        continue;
@@ -4462,11 +4355,12 @@ static int i915_displayport_test_active_show(struct seq_file *m, void *data)
 }
 
 static int i915_displayport_test_active_open(struct inode *inode,
-                                      struct file *file)
+                                            struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = inode->i_private;
 
-       return single_open(file, i915_displayport_test_active_show, dev);
+       return single_open(file, i915_displayport_test_active_show,
+                          &dev_priv->drm);
 }
 
 static const struct file_operations i915_displayport_test_active_fops = {
@@ -4486,7 +4380,6 @@ static int i915_displayport_test_data_show(struct seq_file *m, void *data)
        struct intel_dp *intel_dp;
 
        list_for_each_entry(connector, connector_list, head) {
-
                if (connector->connector_type !=
                    DRM_MODE_CONNECTOR_DisplayPort)
                        continue;
@@ -4502,11 +4395,12 @@ static int i915_displayport_test_data_show(struct seq_file *m, void *data)
        return 0;
 }
 static int i915_displayport_test_data_open(struct inode *inode,
-                                      struct file *file)
+                                          struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = inode->i_private;
 
-       return single_open(file, i915_displayport_test_data_show, dev);
+       return single_open(file, i915_displayport_test_data_show,
+                          &dev_priv->drm);
 }
 
 static const struct file_operations i915_displayport_test_data_fops = {
@@ -4525,7 +4419,6 @@ static int i915_displayport_test_type_show(struct seq_file *m, void *data)
        struct intel_dp *intel_dp;
 
        list_for_each_entry(connector, connector_list, head) {
-
                if (connector->connector_type !=
                    DRM_MODE_CONNECTOR_DisplayPort)
                        continue;
@@ -4544,9 +4437,10 @@ static int i915_displayport_test_type_show(struct seq_file *m, void *data)
 static int i915_displayport_test_type_open(struct inode *inode,
                                       struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = inode->i_private;
 
-       return single_open(file, i915_displayport_test_type_show, dev);
+       return single_open(file, i915_displayport_test_type_show,
+                          &dev_priv->drm);
 }
 
 static const struct file_operations i915_displayport_test_type_fops = {
@@ -4559,13 +4453,14 @@ static const struct file_operations i915_displayport_test_type_fops = {
 
 static void wm_latency_show(struct seq_file *m, const uint16_t wm[8])
 {
-       struct drm_device *dev = m->private;
+       struct drm_i915_private *dev_priv = m->private;
+       struct drm_device *dev = &dev_priv->drm;
        int level;
        int num_levels;
 
-       if (IS_CHERRYVIEW(dev))
+       if (IS_CHERRYVIEW(dev_priv))
                num_levels = 3;
-       else if (IS_VALLEYVIEW(dev))
+       else if (IS_VALLEYVIEW(dev_priv))
                num_levels = 1;
        else
                num_levels = ilk_wm_max_level(dev) + 1;
@@ -4579,8 +4474,8 @@ static void wm_latency_show(struct seq_file *m, const uint16_t wm[8])
                 * - WM1+ latency values in 0.5us units
                 * - latencies are in us on gen9/vlv/chv
                 */
-               if (INTEL_INFO(dev)->gen >= 9 || IS_VALLEYVIEW(dev) ||
-                   IS_CHERRYVIEW(dev))
+               if (INTEL_GEN(dev_priv) >= 9 || IS_VALLEYVIEW(dev_priv) ||
+                   IS_CHERRYVIEW(dev_priv))
                        latency *= 10;
                else if (level > 0)
                        latency *= 5;
@@ -4594,14 +4489,13 @@ static void wm_latency_show(struct seq_file *m, const uint16_t wm[8])
 
 static int pri_wm_latency_show(struct seq_file *m, void *data)
 {
-       struct drm_device *dev = m->private;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = m->private;
        const uint16_t *latencies;
 
-       if (INTEL_INFO(dev)->gen >= 9)
+       if (INTEL_GEN(dev_priv) >= 9)
                latencies = dev_priv->wm.skl_latency;
        else
-               latencies = to_i915(dev)->wm.pri_latency;
+               latencies = dev_priv->wm.pri_latency;
 
        wm_latency_show(m, latencies);
 
@@ -4610,14 +4504,13 @@ static int pri_wm_latency_show(struct seq_file *m, void *data)
 
 static int spr_wm_latency_show(struct seq_file *m, void *data)
 {
-       struct drm_device *dev = m->private;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = m->private;
        const uint16_t *latencies;
 
-       if (INTEL_INFO(dev)->gen >= 9)
+       if (INTEL_GEN(dev_priv) >= 9)
                latencies = dev_priv->wm.skl_latency;
        else
-               latencies = to_i915(dev)->wm.spr_latency;
+               latencies = dev_priv->wm.spr_latency;
 
        wm_latency_show(m, latencies);
 
@@ -4626,14 +4519,13 @@ static int spr_wm_latency_show(struct seq_file *m, void *data)
 
 static int cur_wm_latency_show(struct seq_file *m, void *data)
 {
-       struct drm_device *dev = m->private;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = m->private;
        const uint16_t *latencies;
 
-       if (INTEL_INFO(dev)->gen >= 9)
+       if (INTEL_GEN(dev_priv) >= 9)
                latencies = dev_priv->wm.skl_latency;
        else
-               latencies = to_i915(dev)->wm.cur_latency;
+               latencies = dev_priv->wm.cur_latency;
 
        wm_latency_show(m, latencies);
 
@@ -4642,48 +4534,49 @@ static int cur_wm_latency_show(struct seq_file *m, void *data)
 
 static int pri_wm_latency_open(struct inode *inode, struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = inode->i_private;
 
-       if (INTEL_INFO(dev)->gen < 5)
+       if (INTEL_GEN(dev_priv) < 5)
                return -ENODEV;
 
-       return single_open(file, pri_wm_latency_show, dev);
+       return single_open(file, pri_wm_latency_show, dev_priv);
 }
 
 static int spr_wm_latency_open(struct inode *inode, struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = inode->i_private;
 
-       if (HAS_GMCH_DISPLAY(dev))
+       if (HAS_GMCH_DISPLAY(dev_priv))
                return -ENODEV;
 
-       return single_open(file, spr_wm_latency_show, dev);
+       return single_open(file, spr_wm_latency_show, dev_priv);
 }
 
 static int cur_wm_latency_open(struct inode *inode, struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = inode->i_private;
 
-       if (HAS_GMCH_DISPLAY(dev))
+       if (HAS_GMCH_DISPLAY(dev_priv))
                return -ENODEV;
 
-       return single_open(file, cur_wm_latency_show, dev);
+       return single_open(file, cur_wm_latency_show, dev_priv);
 }
 
 static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
                                size_t len, loff_t *offp, uint16_t wm[8])
 {
        struct seq_file *m = file->private_data;
-       struct drm_device *dev = m->private;
+       struct drm_i915_private *dev_priv = m->private;
+       struct drm_device *dev = &dev_priv->drm;
        uint16_t new[8] = { 0 };
        int num_levels;
        int level;
        int ret;
        char tmp[32];
 
-       if (IS_CHERRYVIEW(dev))
+       if (IS_CHERRYVIEW(dev_priv))
                num_levels = 3;
-       else if (IS_VALLEYVIEW(dev))
+       else if (IS_VALLEYVIEW(dev_priv))
                num_levels = 1;
        else
                num_levels = ilk_wm_max_level(dev) + 1;
@@ -4717,14 +4610,13 @@ static ssize_t pri_wm_latency_write(struct file *file, const char __user *ubuf,
                                    size_t len, loff_t *offp)
 {
        struct seq_file *m = file->private_data;
-       struct drm_device *dev = m->private;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = m->private;
        uint16_t *latencies;
 
-       if (INTEL_INFO(dev)->gen >= 9)
+       if (INTEL_GEN(dev_priv) >= 9)
                latencies = dev_priv->wm.skl_latency;
        else
-               latencies = to_i915(dev)->wm.pri_latency;
+               latencies = dev_priv->wm.pri_latency;
 
        return wm_latency_write(file, ubuf, len, offp, latencies);
 }
@@ -4733,14 +4625,13 @@ static ssize_t spr_wm_latency_write(struct file *file, const char __user *ubuf,
                                    size_t len, loff_t *offp)
 {
        struct seq_file *m = file->private_data;
-       struct drm_device *dev = m->private;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = m->private;
        uint16_t *latencies;
 
-       if (INTEL_INFO(dev)->gen >= 9)
+       if (INTEL_GEN(dev_priv) >= 9)
                latencies = dev_priv->wm.skl_latency;
        else
-               latencies = to_i915(dev)->wm.spr_latency;
+               latencies = dev_priv->wm.spr_latency;
 
        return wm_latency_write(file, ubuf, len, offp, latencies);
 }
@@ -4749,14 +4640,13 @@ static ssize_t cur_wm_latency_write(struct file *file, const char __user *ubuf,
                                    size_t len, loff_t *offp)
 {
        struct seq_file *m = file->private_data;
-       struct drm_device *dev = m->private;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = m->private;
        uint16_t *latencies;
 
-       if (INTEL_INFO(dev)->gen >= 9)
+       if (INTEL_GEN(dev_priv) >= 9)
                latencies = dev_priv->wm.skl_latency;
        else
-               latencies = to_i915(dev)->wm.cur_latency;
+               latencies = dev_priv->wm.cur_latency;
 
        return wm_latency_write(file, ubuf, len, offp, latencies);
 }
@@ -4791,8 +4681,7 @@ static const struct file_operations i915_cur_wm_latency_fops = {
 static int
 i915_wedged_get(void *data, u64 *val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
 
        *val = i915_terminally_wedged(&dev_priv->gpu_error);
 
@@ -4802,8 +4691,7 @@ i915_wedged_get(void *data, u64 *val)
 static int
 i915_wedged_set(void *data, u64 val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
 
        /*
         * There is no safeguard against this debugfs entry colliding
@@ -4833,8 +4721,7 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_wedged_fops,
 static int
 i915_ring_missed_irq_get(void *data, u64 *val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
 
        *val = dev_priv->gpu_error.missed_irq_rings;
        return 0;
@@ -4843,8 +4730,8 @@ i915_ring_missed_irq_get(void *data, u64 *val)
 static int
 i915_ring_missed_irq_set(void *data, u64 val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
+       struct drm_device *dev = &dev_priv->drm;
        int ret;
 
        /* Lock against concurrent debugfs callers */
@@ -4864,8 +4751,7 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_ring_missed_irq_fops,
 static int
 i915_ring_test_irq_get(void *data, u64 *val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
 
        *val = dev_priv->gpu_error.test_irq_rings;
 
@@ -4875,8 +4761,7 @@ i915_ring_test_irq_get(void *data, u64 *val)
 static int
 i915_ring_test_irq_set(void *data, u64 val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
 
        val &= INTEL_INFO(dev_priv)->ring_mask;
        DRM_DEBUG_DRIVER("Masking interrupts on rings 0x%08llx\n", val);
@@ -4908,8 +4793,8 @@ i915_drop_caches_get(void *data, u64 *val)
 static int
 i915_drop_caches_set(void *data, u64 val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
+       struct drm_device *dev = &dev_priv->drm;
        int ret;
 
        DRM_DEBUG("Dropping caches: 0x%08llx\n", val);
@@ -4921,7 +4806,9 @@ i915_drop_caches_set(void *data, u64 val)
                return ret;
 
        if (val & DROP_ACTIVE) {
-               ret = i915_gem_wait_for_idle(dev_priv);
+               ret = i915_gem_wait_for_idle(dev_priv,
+                                            I915_WAIT_INTERRUPTIBLE |
+                                            I915_WAIT_LOCKED);
                if (ret)
                        goto unlock;
        }
@@ -4948,38 +4835,25 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_drop_caches_fops,
 static int
 i915_max_freq_get(void *data, u64 *val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret;
+       struct drm_i915_private *dev_priv = data;
 
-       if (INTEL_INFO(dev)->gen < 6)
+       if (INTEL_GEN(dev_priv) < 6)
                return -ENODEV;
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
-       ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
-       if (ret)
-               return ret;
-
        *val = intel_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
-       mutex_unlock(&dev_priv->rps.hw_lock);
-
        return 0;
 }
 
 static int
 i915_max_freq_set(void *data, u64 val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
        u32 hw_max, hw_min;
        int ret;
 
-       if (INTEL_INFO(dev)->gen < 6)
+       if (INTEL_GEN(dev_priv) < 6)
                return -ENODEV;
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
        DRM_DEBUG_DRIVER("Manually setting max freq to %llu\n", val);
 
        ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
@@ -5015,38 +4889,25 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_max_freq_fops,
 static int
 i915_min_freq_get(void *data, u64 *val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret;
+       struct drm_i915_private *dev_priv = data;
 
-       if (INTEL_INFO(dev)->gen < 6)
+       if (INTEL_GEN(dev_priv) < 6)
                return -ENODEV;
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
-       ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
-       if (ret)
-               return ret;
-
        *val = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
-       mutex_unlock(&dev_priv->rps.hw_lock);
-
        return 0;
 }
 
 static int
 i915_min_freq_set(void *data, u64 val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
        u32 hw_max, hw_min;
        int ret;
 
-       if (INTEL_INFO(dev)->gen < 6)
+       if (INTEL_GEN(dev_priv) < 6)
                return -ENODEV;
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
        DRM_DEBUG_DRIVER("Manually setting min freq to %llu\n", val);
 
        ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
@@ -5061,7 +4922,8 @@ i915_min_freq_set(void *data, u64 val)
        hw_max = dev_priv->rps.max_freq;
        hw_min = dev_priv->rps.min_freq;
 
-       if (val < hw_min || val > hw_max || val > dev_priv->rps.max_freq_softlimit) {
+       if (val < hw_min ||
+           val > hw_max || val > dev_priv->rps.max_freq_softlimit) {
                mutex_unlock(&dev_priv->rps.hw_lock);
                return -EINVAL;
        }
@@ -5082,12 +4944,12 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_min_freq_fops,
 static int
 i915_cache_sharing_get(void *data, u64 *val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
+       struct drm_device *dev = &dev_priv->drm;
        u32 snpcr;
        int ret;
 
-       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+       if (!(IS_GEN6(dev_priv) || IS_GEN7(dev_priv)))
                return -ENODEV;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -5098,7 +4960,7 @@ i915_cache_sharing_get(void *data, u64 *val)
        snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
 
        intel_runtime_pm_put(dev_priv);
-       mutex_unlock(&dev_priv->drm.struct_mutex);
+       mutex_unlock(&dev->struct_mutex);
 
        *val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT;
 
@@ -5108,11 +4970,10 @@ i915_cache_sharing_get(void *data, u64 *val)
 static int
 i915_cache_sharing_set(void *data, u64 val)
 {
-       struct drm_device *dev = data;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = data;
        u32 snpcr;
 
-       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+       if (!(IS_GEN6(dev_priv) || IS_GEN7(dev_priv)))
                return -ENODEV;
 
        if (val > 3)
@@ -5135,18 +4996,9 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops,
                        i915_cache_sharing_get, i915_cache_sharing_set,
                        "%llu\n");
 
-struct sseu_dev_status {
-       unsigned int slice_total;
-       unsigned int subslice_total;
-       unsigned int subslice_per_slice;
-       unsigned int eu_total;
-       unsigned int eu_per_subslice;
-};
-
-static void cherryview_sseu_device_status(struct drm_device *dev,
-                                         struct sseu_dev_status *stat)
+static void cherryview_sseu_device_status(struct drm_i915_private *dev_priv,
+                                         struct sseu_dev_info *sseu)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        int ss_max = 2;
        int ss;
        u32 sig1[ss_max], sig2[ss_max];
@@ -5163,28 +5015,27 @@ static void cherryview_sseu_device_status(struct drm_device *dev,
                        /* skip disabled subslice */
                        continue;
 
-               stat->slice_total = 1;
-               stat->subslice_per_slice++;
+               sseu->slice_mask = BIT(0);
+               sseu->subslice_mask |= BIT(ss);
                eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +
                         ((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +
                         ((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +
                         ((sig2[ss] & CHV_EU311_PG_ENABLE) ? 0 : 2);
-               stat->eu_total += eu_cnt;
-               stat->eu_per_subslice = max(stat->eu_per_subslice, eu_cnt);
+               sseu->eu_total += eu_cnt;
+               sseu->eu_per_subslice = max_t(unsigned int,
+                                             sseu->eu_per_subslice, eu_cnt);
        }
-       stat->subslice_total = stat->subslice_per_slice;
 }
 
-static void gen9_sseu_device_status(struct drm_device *dev,
-                                   struct sseu_dev_status *stat)
+static void gen9_sseu_device_status(struct drm_i915_private *dev_priv,
+                                   struct sseu_dev_info *sseu)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        int s_max = 3, ss_max = 4;
        int s, ss;
        u32 s_reg[s_max], eu_reg[2*s_max], eu_mask[2];
 
        /* BXT has a single slice and at most 3 subslices. */
-       if (IS_BROXTON(dev)) {
+       if (IS_BROXTON(dev_priv)) {
                s_max = 1;
                ss_max = 3;
        }
@@ -5205,126 +5056,134 @@ static void gen9_sseu_device_status(struct drm_device *dev,
                     GEN9_PGCTL_SSB_EU311_ACK;
 
        for (s = 0; s < s_max; s++) {
-               unsigned int ss_cnt = 0;
-
                if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
                        /* skip disabled slice */
                        continue;
 
-               stat->slice_total++;
+               sseu->slice_mask |= BIT(s);
 
-               if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
-                       ss_cnt = INTEL_INFO(dev)->subslice_per_slice;
+               if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+                       sseu->subslice_mask =
+                               INTEL_INFO(dev_priv)->sseu.subslice_mask;
 
                for (ss = 0; ss < ss_max; ss++) {
                        unsigned int eu_cnt;
 
-                       if (IS_BROXTON(dev) &&
-                           !(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
-                               /* skip disabled subslice */
-                               continue;
+                       if (IS_BROXTON(dev_priv)) {
+                               if (!(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
+                                       /* skip disabled subslice */
+                                       continue;
 
-                       if (IS_BROXTON(dev))
-                               ss_cnt++;
+                               sseu->subslice_mask |= BIT(ss);
+                       }
 
                        eu_cnt = 2 * hweight32(eu_reg[2*s + ss/2] &
                                               eu_mask[ss%2]);
-                       stat->eu_total += eu_cnt;
-                       stat->eu_per_subslice = max(stat->eu_per_subslice,
-                                                   eu_cnt);
+                       sseu->eu_total += eu_cnt;
+                       sseu->eu_per_subslice = max_t(unsigned int,
+                                                     sseu->eu_per_subslice,
+                                                     eu_cnt);
                }
-
-               stat->subslice_total += ss_cnt;
-               stat->subslice_per_slice = max(stat->subslice_per_slice,
-                                              ss_cnt);
        }
 }
 
-static void broadwell_sseu_device_status(struct drm_device *dev,
-                                        struct sseu_dev_status *stat)
+static void broadwell_sseu_device_status(struct drm_i915_private *dev_priv,
+                                        struct sseu_dev_info *sseu)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int s;
        u32 slice_info = I915_READ(GEN8_GT_SLICE_INFO);
+       int s;
 
-       stat->slice_total = hweight32(slice_info & GEN8_LSLICESTAT_MASK);
+       sseu->slice_mask = slice_info & GEN8_LSLICESTAT_MASK;
 
-       if (stat->slice_total) {
-               stat->subslice_per_slice = INTEL_INFO(dev)->subslice_per_slice;
-               stat->subslice_total = stat->slice_total *
-                                      stat->subslice_per_slice;
-               stat->eu_per_subslice = INTEL_INFO(dev)->eu_per_subslice;
-               stat->eu_total = stat->eu_per_subslice * stat->subslice_total;
+       if (sseu->slice_mask) {
+               sseu->subslice_mask = INTEL_INFO(dev_priv)->sseu.subslice_mask;
+               sseu->eu_per_subslice =
+                               INTEL_INFO(dev_priv)->sseu.eu_per_subslice;
+               sseu->eu_total = sseu->eu_per_subslice *
+                                sseu_subslice_total(sseu);
 
                /* subtract fused off EU(s) from enabled slice(s) */
-               for (s = 0; s < stat->slice_total; s++) {
-                       u8 subslice_7eu = INTEL_INFO(dev)->subslice_7eu[s];
+               for (s = 0; s < fls(sseu->slice_mask); s++) {
+                       u8 subslice_7eu =
+                               INTEL_INFO(dev_priv)->sseu.subslice_7eu[s];
 
-                       stat->eu_total -= hweight8(subslice_7eu);
+                       sseu->eu_total -= hweight8(subslice_7eu);
                }
        }
 }
 
-static int i915_sseu_status(struct seq_file *m, void *unused)
+static void i915_print_sseu_info(struct seq_file *m, bool is_available_info,
+                                const struct sseu_dev_info *sseu)
 {
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct sseu_dev_status stat;
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       const char *type = is_available_info ? "Available" : "Enabled";
 
-       if (INTEL_INFO(dev)->gen < 8)
-               return -ENODEV;
+       seq_printf(m, "  %s Slice Mask: %04x\n", type,
+                  sseu->slice_mask);
+       seq_printf(m, "  %s Slice Total: %u\n", type,
+                  hweight8(sseu->slice_mask));
+       seq_printf(m, "  %s Subslice Total: %u\n", type,
+                  sseu_subslice_total(sseu));
+       seq_printf(m, "  %s Subslice Mask: %04x\n", type,
+                  sseu->subslice_mask);
+       seq_printf(m, "  %s Subslice Per Slice: %u\n", type,
+                  hweight8(sseu->subslice_mask));
+       seq_printf(m, "  %s EU Total: %u\n", type,
+                  sseu->eu_total);
+       seq_printf(m, "  %s EU Per Subslice: %u\n", type,
+                  sseu->eu_per_subslice);
+
+       if (!is_available_info)
+               return;
+
+       seq_printf(m, "  Has Pooled EU: %s\n", yesno(HAS_POOLED_EU(dev_priv)));
+       if (HAS_POOLED_EU(dev_priv))
+               seq_printf(m, "  Min EU in pool: %u\n", sseu->min_eu_in_pool);
 
-       seq_puts(m, "SSEU Device Info\n");
-       seq_printf(m, "  Available Slice Total: %u\n",
-                  INTEL_INFO(dev)->slice_total);
-       seq_printf(m, "  Available Subslice Total: %u\n",
-                  INTEL_INFO(dev)->subslice_total);
-       seq_printf(m, "  Available Subslice Per Slice: %u\n",
-                  INTEL_INFO(dev)->subslice_per_slice);
-       seq_printf(m, "  Available EU Total: %u\n",
-                  INTEL_INFO(dev)->eu_total);
-       seq_printf(m, "  Available EU Per Subslice: %u\n",
-                  INTEL_INFO(dev)->eu_per_subslice);
-       seq_printf(m, "  Has Pooled EU: %s\n", yesno(HAS_POOLED_EU(dev)));
-       if (HAS_POOLED_EU(dev))
-               seq_printf(m, "  Min EU in pool: %u\n",
-                          INTEL_INFO(dev)->min_eu_in_pool);
        seq_printf(m, "  Has Slice Power Gating: %s\n",
-                  yesno(INTEL_INFO(dev)->has_slice_pg));
+                  yesno(sseu->has_slice_pg));
        seq_printf(m, "  Has Subslice Power Gating: %s\n",
-                  yesno(INTEL_INFO(dev)->has_subslice_pg));
+                  yesno(sseu->has_subslice_pg));
        seq_printf(m, "  Has EU Power Gating: %s\n",
-                  yesno(INTEL_INFO(dev)->has_eu_pg));
+                  yesno(sseu->has_eu_pg));
+}
+
+static int i915_sseu_status(struct seq_file *m, void *unused)
+{
+       struct drm_i915_private *dev_priv = node_to_i915(m->private);
+       struct sseu_dev_info sseu;
+
+       if (INTEL_GEN(dev_priv) < 8)
+               return -ENODEV;
+
+       seq_puts(m, "SSEU Device Info\n");
+       i915_print_sseu_info(m, true, &INTEL_INFO(dev_priv)->sseu);
 
        seq_puts(m, "SSEU Device Status\n");
-       memset(&stat, 0, sizeof(stat));
-       if (IS_CHERRYVIEW(dev)) {
-               cherryview_sseu_device_status(dev, &stat);
-       } else if (IS_BROADWELL(dev)) {
-               broadwell_sseu_device_status(dev, &stat);
-       } else if (INTEL_INFO(dev)->gen >= 9) {
-               gen9_sseu_device_status(dev, &stat);
-       }
-       seq_printf(m, "  Enabled Slice Total: %u\n",
-                  stat.slice_total);
-       seq_printf(m, "  Enabled Subslice Total: %u\n",
-                  stat.subslice_total);
-       seq_printf(m, "  Enabled Subslice Per Slice: %u\n",
-                  stat.subslice_per_slice);
-       seq_printf(m, "  Enabled EU Total: %u\n",
-                  stat.eu_total);
-       seq_printf(m, "  Enabled EU Per Subslice: %u\n",
-                  stat.eu_per_subslice);
+       memset(&sseu, 0, sizeof(sseu));
+
+       intel_runtime_pm_get(dev_priv);
+
+       if (IS_CHERRYVIEW(dev_priv)) {
+               cherryview_sseu_device_status(dev_priv, &sseu);
+       } else if (IS_BROADWELL(dev_priv)) {
+               broadwell_sseu_device_status(dev_priv, &sseu);
+       } else if (INTEL_GEN(dev_priv) >= 9) {
+               gen9_sseu_device_status(dev_priv, &sseu);
+       }
+
+       intel_runtime_pm_put(dev_priv);
+
+       i915_print_sseu_info(m, false, &sseu);
 
        return 0;
 }
 
 static int i915_forcewake_open(struct inode *inode, struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = inode->i_private;
 
-       if (INTEL_INFO(dev)->gen < 6)
+       if (INTEL_GEN(dev_priv) < 6)
                return 0;
 
        intel_runtime_pm_get(dev_priv);
@@ -5335,10 +5194,9 @@ static int i915_forcewake_open(struct inode *inode, struct file *file)
 
 static int i915_forcewake_release(struct inode *inode, struct file *file)
 {
-       struct drm_device *dev = inode->i_private;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = inode->i_private;
 
-       if (INTEL_INFO(dev)->gen < 6)
+       if (INTEL_GEN(dev_priv) < 6)
                return 0;
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
@@ -5355,12 +5213,11 @@ static const struct file_operations i915_forcewake_fops = {
 
 static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
 {
-       struct drm_device *dev = minor->dev;
        struct dentry *ent;
 
        ent = debugfs_create_file("i915_forcewake_user",
                                  S_IRUSR,
-                                 root, dev,
+                                 root, to_i915(minor->dev),
                                  &i915_forcewake_fops);
        if (!ent)
                return -ENOMEM;
@@ -5373,12 +5230,11 @@ static int i915_debugfs_create(struct dentry *root,
                               const char *name,
                               const struct file_operations *fops)
 {
-       struct drm_device *dev = minor->dev;
        struct dentry *ent;
 
        ent = debugfs_create_file(name,
                                  S_IRUGO | S_IWUSR,
-                                 root, dev,
+                                 root, to_i915(minor->dev),
                                  fops);
        if (!ent)
                return -ENOMEM;
@@ -5390,9 +5246,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_capabilities", i915_capabilities, 0},
        {"i915_gem_objects", i915_gem_object_info, 0},
        {"i915_gem_gtt", i915_gem_gtt_info, 0},
-       {"i915_gem_pinned", i915_gem_gtt_info, 0, (void *) PINNED_LIST},
-       {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
-       {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
+       {"i915_gem_pin_display", i915_gem_gtt_info, 0, (void *)1},
        {"i915_gem_stolen", i915_gem_stolen_list_info },
        {"i915_gem_pageflip", i915_gem_pageflip_info, 0},
        {"i915_gem_request", i915_gem_request_info, 0},
@@ -5467,9 +5321,8 @@ static const struct i915_debugfs_files {
        {"i915_dp_test_active", &i915_displayport_test_active_fops}
 };
 
-void intel_display_crc_init(struct drm_device *dev)
+void intel_display_crc_init(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        enum pipe pipe;
 
        for_each_pipe(dev_priv, pipe) {
@@ -5517,7 +5370,7 @@ void i915_debugfs_unregister(struct drm_i915_private *dev_priv)
        drm_debugfs_remove_files(i915_debugfs_list,
                                 I915_DEBUGFS_ENTRIES, minor);
 
-       drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops,
+       drm_debugfs_remove_files((struct drm_info_list *)&i915_forcewake_fops,
                                 1, minor);
 
        for (i = 0; i < ARRAY_SIZE(i915_pipe_crc_data); i++) {
@@ -5529,7 +5382,7 @@ void i915_debugfs_unregister(struct drm_i915_private *dev_priv)
 
        for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) {
                struct drm_info_list *info_list =
-                       (struct drm_info_list *) i915_debugfs_files[i].fops;
+                       (struct drm_info_list *)i915_debugfs_files[i].fops;
 
                drm_debugfs_remove_files(info_list, 1, minor);
        }
@@ -5609,6 +5462,40 @@ static const struct file_operations i915_dpcd_fops = {
        .release = single_release,
 };
 
+static int i915_panel_show(struct seq_file *m, void *data)
+{
+       struct drm_connector *connector = m->private;
+       struct intel_dp *intel_dp =
+               enc_to_intel_dp(&intel_attached_encoder(connector)->base);
+
+       if (connector->status != connector_status_connected)
+               return -ENODEV;
+
+       seq_printf(m, "Panel power up delay: %d\n",
+                  intel_dp->panel_power_up_delay);
+       seq_printf(m, "Panel power down delay: %d\n",
+                  intel_dp->panel_power_down_delay);
+       seq_printf(m, "Backlight on delay: %d\n",
+                  intel_dp->backlight_on_delay);
+       seq_printf(m, "Backlight off delay: %d\n",
+                  intel_dp->backlight_off_delay);
+
+       return 0;
+}
+
+static int i915_panel_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, i915_panel_show, inode->i_private);
+}
+
+static const struct file_operations i915_panel_fops = {
+       .owner = THIS_MODULE,
+       .open = i915_panel_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 /**
  * i915_debugfs_connector_add - add i915 specific connector debugfs files
  * @connector: pointer to a registered drm_connector
@@ -5628,8 +5515,12 @@ int i915_debugfs_connector_add(struct drm_connector *connector)
 
        if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
            connector->connector_type == DRM_MODE_CONNECTOR_eDP)
-               debugfs_create_file("i915_dpcd", S_IRUGO, root, connector,
-                                   &i915_dpcd_fops);
+               debugfs_create_file("i915_dpcd", S_IRUGO, root,
+                                   connector, &i915_dpcd_fops);
+
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+               debugfs_create_file("i915_panel_timings", S_IRUGO, root,
+                                   connector, &i915_panel_fops);
 
        return 0;
 }
index 5de36d8..bfb2efd 100644 (file)
@@ -77,7 +77,7 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level,
              const char *fmt, ...)
 {
        static bool shown_bug_once;
-       struct device *dev = dev_priv->drm.dev;
+       struct device *kdev = dev_priv->drm.dev;
        bool is_error = level[1] <= KERN_ERR[1];
        bool is_debug = level[1] == KERN_DEBUG[1];
        struct va_format vaf;
@@ -91,11 +91,11 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level,
        vaf.fmt = fmt;
        vaf.va = &args;
 
-       dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV",
+       dev_printk(level, kdev, "[" DRM_NAME ":%ps] %pV",
                   __builtin_return_address(0), &vaf);
 
        if (is_error && !shown_bug_once) {
-               dev_notice(dev, "%s", FDO_BUG_MSG);
+               dev_notice(kdev, "%s", FDO_BUG_MSG);
                shown_bug_once = true;
        }
 
@@ -228,31 +228,11 @@ static void intel_detect_pch(struct drm_device *dev)
        pci_dev_put(pch);
 }
 
-bool i915_semaphore_is_enabled(struct drm_i915_private *dev_priv)
-{
-       if (INTEL_GEN(dev_priv) < 6)
-               return false;
-
-       if (i915.semaphores >= 0)
-               return i915.semaphores;
-
-       /* TODO: make semaphores and Execlists play nicely together */
-       if (i915.enable_execlists)
-               return false;
-
-#ifdef CONFIG_INTEL_IOMMU
-       /* Enable semaphores on SNB when IO remapping is off */
-       if (IS_GEN6(dev_priv) && intel_iommu_gfx_mapped)
-               return false;
-#endif
-
-       return true;
-}
-
 static int i915_getparam(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        drm_i915_getparam_t *param = data;
        int value;
 
@@ -263,13 +243,10 @@ static int i915_getparam(struct drm_device *dev, void *data,
                /* Reject all old ums/dri params. */
                return -ENODEV;
        case I915_PARAM_CHIPSET_ID:
-               value = dev->pdev->device;
+               value = pdev->device;
                break;
        case I915_PARAM_REVISION:
-               value = dev->pdev->revision;
-               break;
-       case I915_PARAM_HAS_GEM:
-               value = 1;
+               value = pdev->revision;
                break;
        case I915_PARAM_NUM_FENCES_AVAIL:
                value = dev_priv->num_fence_regs;
@@ -277,13 +254,6 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_HAS_OVERLAY:
                value = dev_priv->overlay ? 1 : 0;
                break;
-       case I915_PARAM_HAS_PAGEFLIPPING:
-               value = 1;
-               break;
-       case I915_PARAM_HAS_EXECBUF2:
-               /* depends on GEM */
-               value = 1;
-               break;
        case I915_PARAM_HAS_BSD:
                value = intel_engine_initialized(&dev_priv->engine[VCS]);
                break;
@@ -296,67 +266,34 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_HAS_BSD2:
                value = intel_engine_initialized(&dev_priv->engine[VCS2]);
                break;
-       case I915_PARAM_HAS_RELAXED_FENCING:
-               value = 1;
-               break;
-       case I915_PARAM_HAS_COHERENT_RINGS:
-               value = 1;
-               break;
        case I915_PARAM_HAS_EXEC_CONSTANTS:
-               value = INTEL_INFO(dev)->gen >= 4;
-               break;
-       case I915_PARAM_HAS_RELAXED_DELTA:
-               value = 1;
-               break;
-       case I915_PARAM_HAS_GEN7_SOL_RESET:
-               value = 1;
+               value = INTEL_GEN(dev_priv) >= 4;
                break;
        case I915_PARAM_HAS_LLC:
-               value = HAS_LLC(dev);
+               value = HAS_LLC(dev_priv);
                break;
        case I915_PARAM_HAS_WT:
-               value = HAS_WT(dev);
+               value = HAS_WT(dev_priv);
                break;
        case I915_PARAM_HAS_ALIASING_PPGTT:
-               value = USES_PPGTT(dev);
-               break;
-       case I915_PARAM_HAS_WAIT_TIMEOUT:
-               value = 1;
+               value = USES_PPGTT(dev_priv);
                break;
        case I915_PARAM_HAS_SEMAPHORES:
-               value = i915_semaphore_is_enabled(dev_priv);
-               break;
-       case I915_PARAM_HAS_PRIME_VMAP_FLUSH:
-               value = 1;
+               value = i915.semaphores;
                break;
        case I915_PARAM_HAS_SECURE_BATCHES:
                value = capable(CAP_SYS_ADMIN);
                break;
-       case I915_PARAM_HAS_PINNED_BATCHES:
-               value = 1;
-               break;
-       case I915_PARAM_HAS_EXEC_NO_RELOC:
-               value = 1;
-               break;
-       case I915_PARAM_HAS_EXEC_HANDLE_LUT:
-               value = 1;
-               break;
        case I915_PARAM_CMD_PARSER_VERSION:
                value = i915_cmd_parser_get_version(dev_priv);
                break;
-       case I915_PARAM_HAS_COHERENT_PHYS_GTT:
-               value = 1;
-               break;
-       case I915_PARAM_MMAP_VERSION:
-               value = 1;
-               break;
        case I915_PARAM_SUBSLICE_TOTAL:
-               value = INTEL_INFO(dev)->subslice_total;
+               value = sseu_subslice_total(&INTEL_INFO(dev_priv)->sseu);
                if (!value)
                        return -ENODEV;
                break;
        case I915_PARAM_EU_TOTAL:
-               value = INTEL_INFO(dev)->eu_total;
+               value = INTEL_INFO(dev_priv)->sseu.eu_total;
                if (!value)
                        return -ENODEV;
                break;
@@ -364,16 +301,43 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = i915.enable_hangcheck && intel_has_gpu_reset(dev_priv);
                break;
        case I915_PARAM_HAS_RESOURCE_STREAMER:
-               value = HAS_RESOURCE_STREAMER(dev);
-               break;
-       case I915_PARAM_HAS_EXEC_SOFTPIN:
-               value = 1;
+               value = HAS_RESOURCE_STREAMER(dev_priv);
                break;
        case I915_PARAM_HAS_POOLED_EU:
-               value = HAS_POOLED_EU(dev);
+               value = HAS_POOLED_EU(dev_priv);
                break;
        case I915_PARAM_MIN_EU_IN_POOL:
-               value = INTEL_INFO(dev)->min_eu_in_pool;
+               value = INTEL_INFO(dev_priv)->sseu.min_eu_in_pool;
+               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
+                * the ioctl will report EINVAL for the unknown param!
+                */
+               value = i915_gem_mmap_gtt_version();
+               break;
+       case I915_PARAM_MMAP_VERSION:
+               /* Remember to bump this if the version changes! */
+       case I915_PARAM_HAS_GEM:
+       case I915_PARAM_HAS_PAGEFLIPPING:
+       case I915_PARAM_HAS_EXECBUF2: /* depends on GEM */
+       case I915_PARAM_HAS_RELAXED_FENCING:
+       case I915_PARAM_HAS_COHERENT_RINGS:
+       case I915_PARAM_HAS_RELAXED_DELTA:
+       case I915_PARAM_HAS_GEN7_SOL_RESET:
+       case I915_PARAM_HAS_WAIT_TIMEOUT:
+       case I915_PARAM_HAS_PRIME_VMAP_FLUSH:
+       case I915_PARAM_HAS_PINNED_BATCHES:
+       case I915_PARAM_HAS_EXEC_NO_RELOC:
+       case I915_PARAM_HAS_EXEC_HANDLE_LUT:
+       case I915_PARAM_HAS_COHERENT_PHYS_GTT:
+       case I915_PARAM_HAS_EXEC_SOFTPIN:
+               /* For the time being all of these are always true;
+                * if some supported hardware does not have one of these
+                * features this value needs to be provided from
+                * INTEL_INFO(), a feature macro, or similar.
+                */
+               value = 1;
                break;
        default:
                DRM_DEBUG("Unknown parameter %d\n", param->param);
@@ -537,7 +501,7 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
                pr_info("switched on\n");
                dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
                /* i915 resume handler doesn't set to D0 */
-               pci_set_power_state(dev->pdev, PCI_D0);
+               pci_set_power_state(pdev, PCI_D0);
                i915_resume_switcheroo(dev);
                dev->switch_power_state = DRM_SWITCH_POWER_ON;
        } else {
@@ -595,7 +559,6 @@ static void i915_gem_fini(struct drm_device *dev)
        }
 
        mutex_lock(&dev->struct_mutex);
-       i915_gem_reset(dev);
        i915_gem_cleanup_engines(dev);
        i915_gem_context_fini(dev);
        mutex_unlock(&dev->struct_mutex);
@@ -606,6 +569,7 @@ static void i915_gem_fini(struct drm_device *dev)
 static int i915_load_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        int ret;
 
        if (i915_inject_load_failure())
@@ -622,13 +586,13 @@ static int i915_load_modeset_init(struct drm_device *dev)
         * then we do not take part in VGA arbitration and the
         * vga_client_register() fails with -ENODEV.
         */
-       ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
+       ret = vga_client_register(pdev, dev, NULL, i915_vga_set_decode);
        if (ret && ret != -ENODEV)
                goto out;
 
        intel_register_dsm_handler();
 
-       ret = vga_switcheroo_register_client(dev->pdev, &i915_switcheroo_ops, false);
+       ret = vga_switcheroo_register_client(pdev, &i915_switcheroo_ops, false);
        if (ret)
                goto cleanup_vga_client;
 
@@ -680,9 +644,9 @@ cleanup_irq:
 cleanup_csr:
        intel_csr_ucode_fini(dev_priv);
        intel_power_domains_fini(dev_priv);
-       vga_switcheroo_unregister_client(dev->pdev);
+       vga_switcheroo_unregister_client(pdev);
 cleanup_vga_client:
-       vga_client_register(dev->pdev, NULL, NULL, NULL);
+       vga_client_register(pdev, NULL, NULL, NULL);
 out:
        return ret;
 }
@@ -706,7 +670,7 @@ static int i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
        primary =
                pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 
-       ret = remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
+       ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
 
        kfree(ap);
 
@@ -848,6 +812,8 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
        mutex_init(&dev_priv->wm.wm_mutex);
        mutex_init(&dev_priv->pps_mutex);
 
+       i915_memcpy_init_early(dev_priv);
+
        ret = i915_workqueues_init(dev_priv);
        if (ret < 0)
                return ret;
@@ -868,7 +834,7 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
        intel_init_audio_hooks(dev_priv);
        i915_gem_load_init(&dev_priv->drm);
 
-       intel_display_crc_init(&dev_priv->drm);
+       intel_display_crc_init(dev_priv);
 
        intel_device_info_dump(dev_priv);
 
@@ -900,6 +866,7 @@ static void i915_driver_cleanup_early(struct drm_i915_private *dev_priv)
 static int i915_mmio_setup(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        int mmio_bar;
        int mmio_size;
 
@@ -916,7 +883,7 @@ static int i915_mmio_setup(struct drm_device *dev)
                mmio_size = 512 * 1024;
        else
                mmio_size = 2 * 1024 * 1024;
-       dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
+       dev_priv->regs = pci_iomap(pdev, mmio_bar, mmio_size);
        if (dev_priv->regs == NULL) {
                DRM_ERROR("failed to map registers\n");
 
@@ -932,9 +899,10 @@ static int i915_mmio_setup(struct drm_device *dev)
 static void i915_mmio_cleanup(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
 
        intel_teardown_mchbar(dev);
-       pci_iounmap(dev->pdev, dev_priv->regs);
+       pci_iounmap(pdev, dev_priv->regs);
 }
 
 /**
@@ -999,6 +967,9 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv)
        i915.enable_ppgtt =
                intel_sanitize_enable_ppgtt(dev_priv, i915.enable_ppgtt);
        DRM_DEBUG_DRIVER("ppgtt mode: %i\n", i915.enable_ppgtt);
+
+       i915.semaphores = intel_sanitize_semaphores(dev_priv, i915.semaphores);
+       DRM_DEBUG_DRIVER("use GPU sempahores? %s\n", yesno(i915.semaphores));
 }
 
 /**
@@ -1010,9 +981,8 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv)
  */
 static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
 {
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        struct drm_device *dev = &dev_priv->drm;
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       uint32_t aperture_size;
        int ret;
 
        if (i915_inject_load_failure())
@@ -1022,16 +992,10 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
 
        intel_sanitize_options(dev_priv);
 
-       ret = i915_ggtt_init_hw(dev);
+       ret = i915_ggtt_probe_hw(dev_priv);
        if (ret)
                return ret;
 
-       ret = i915_ggtt_enable_hw(dev);
-       if (ret) {
-               DRM_ERROR("failed to enable GGTT\n");
-               goto out_ggtt;
-       }
-
        /* WARNING: Apparently we must kick fbdev drivers before vgacon,
         * otherwise the vga fbdev driver falls over. */
        ret = i915_kick_out_firmware_fb(dev_priv);
@@ -1046,11 +1010,21 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
                goto out_ggtt;
        }
 
-       pci_set_master(dev->pdev);
+       ret = i915_ggtt_init_hw(dev_priv);
+       if (ret)
+               return ret;
+
+       ret = i915_ggtt_enable_hw(dev_priv);
+       if (ret) {
+               DRM_ERROR("failed to enable GGTT\n");
+               goto out_ggtt;
+       }
+
+       pci_set_master(pdev);
 
        /* overlay on gen2 is broken and can't address above 1G */
        if (IS_GEN2(dev)) {
-               ret = dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
+               ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(30));
                if (ret) {
                        DRM_ERROR("failed to set DMA mask\n");
 
@@ -1058,7 +1032,6 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
                }
        }
 
-
        /* 965GM sometimes incorrectly writes to hardware status page (HWS)
         * using 32bit addressing, overwriting memory if HWS is located
         * above 4GB.
@@ -1068,7 +1041,7 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
         * which also needs to be handled carefully.
         */
        if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) {
-               ret = dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
+               ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
 
                if (ret) {
                        DRM_ERROR("failed to set DMA mask\n");
@@ -1077,19 +1050,6 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
                }
        }
 
-       aperture_size = ggtt->mappable_end;
-
-       ggtt->mappable =
-               io_mapping_create_wc(ggtt->mappable_base,
-                                    aperture_size);
-       if (!ggtt->mappable) {
-               ret = -EIO;
-               goto out_ggtt;
-       }
-
-       ggtt->mtrr = arch_phys_wc_add(ggtt->mappable_base,
-                                             aperture_size);
-
        pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY,
                           PM_QOS_DEFAULT_VALUE);
 
@@ -1111,14 +1071,14 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
         * stuck interrupts on some machines.
         */
        if (!IS_I945G(dev) && !IS_I945GM(dev)) {
-               if (pci_enable_msi(dev->pdev) < 0)
+               if (pci_enable_msi(pdev) < 0)
                        DRM_DEBUG_DRIVER("can't enable MSI");
        }
 
        return 0;
 
 out_ggtt:
-       i915_ggtt_cleanup_hw(dev);
+       i915_ggtt_cleanup_hw(dev_priv);
 
        return ret;
 }
@@ -1129,16 +1089,13 @@ out_ggtt:
  */
 static void i915_driver_cleanup_hw(struct drm_i915_private *dev_priv)
 {
-       struct drm_device *dev = &dev_priv->drm;
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
+       struct pci_dev *pdev = dev_priv->drm.pdev;
 
-       if (dev->pdev->msi_enabled)
-               pci_disable_msi(dev->pdev);
+       if (pdev->msi_enabled)
+               pci_disable_msi(pdev);
 
        pm_qos_remove_request(&dev_priv->pm_qos);
-       arch_phys_wc_del(ggtt->mtrr);
-       io_mapping_free(ggtt->mappable);
-       i915_ggtt_cleanup_hw(dev);
+       i915_ggtt_cleanup_hw(dev_priv);
 }
 
 /**
@@ -1164,7 +1121,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_setup_sysfs(dev);
+               i915_setup_sysfs(dev_priv);
        } else
                DRM_ERROR("Failed to register driver for userspace access!\n");
 
@@ -1201,7 +1158,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
        acpi_video_unregister();
        intel_opregion_unregister(dev_priv);
 
-       i915_teardown_sysfs(&dev_priv->drm);
+       i915_teardown_sysfs(dev_priv);
        i915_debugfs_unregister(dev_priv);
        drm_dev_unregister(&dev_priv->drm);
 
@@ -1310,6 +1267,7 @@ out_free_priv:
 void i915_driver_unload(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
 
        intel_fbdev_fini(dev);
 
@@ -1338,8 +1296,8 @@ void i915_driver_unload(struct drm_device *dev)
        kfree(dev_priv->vbt.lfp_lvds_vbt_mode);
        dev_priv->vbt.lfp_lvds_vbt_mode = NULL;
 
-       vga_switcheroo_unregister_client(dev->pdev);
-       vga_client_register(dev->pdev, NULL, NULL, NULL);
+       vga_switcheroo_unregister_client(pdev);
+       vga_client_register(pdev, NULL, NULL, NULL);
 
        intel_csr_ucode_fini(dev_priv);
 
@@ -1348,7 +1306,7 @@ void i915_driver_unload(struct drm_device *dev)
        i915_destroy_error_state(dev);
 
        /* Flush any outstanding unpin_work. */
-       flush_workqueue(dev_priv->wq);
+       drain_workqueue(dev_priv->wq);
 
        intel_guc_fini(dev);
        i915_gem_fini(dev);
@@ -1436,6 +1394,7 @@ static bool suspend_to_idle(struct drm_i915_private *dev_priv)
 static int i915_drm_suspend(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        pci_power_t opregion_target_state;
        int error;
 
@@ -1452,19 +1411,17 @@ static int i915_drm_suspend(struct drm_device *dev)
 
        drm_kms_helper_poll_disable(dev);
 
-       pci_save_state(dev->pdev);
+       pci_save_state(pdev);
 
        error = i915_gem_suspend(dev);
        if (error) {
-               dev_err(&dev->pdev->dev,
+               dev_err(&pdev->dev,
                        "GEM idle failed, resume might fail\n");
                goto out;
        }
 
        intel_guc_suspend(dev);
 
-       intel_suspend_gt_powersave(dev_priv);
-
        intel_display_suspend(dev);
 
        intel_dp_mst_suspend(dev);
@@ -1500,9 +1457,10 @@ out:
        return error;
 }
 
-static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
+static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
 {
-       struct drm_i915_private *dev_priv = to_i915(drm_dev);
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        bool fw_csr;
        int ret;
 
@@ -1536,7 +1494,7 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
                goto out;
        }
 
-       pci_disable_device(drm_dev->pdev);
+       pci_disable_device(pdev);
        /*
         * During hibernation on some platforms the BIOS may try to access
         * the device even though it's already in D3 and hang the machine. So
@@ -1550,7 +1508,7 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
         * Acer Aspire 1830T
         */
        if (!(hibernation && INTEL_INFO(dev_priv)->gen < 6))
-               pci_set_power_state(drm_dev->pdev, PCI_D3hot);
+               pci_set_power_state(pdev, PCI_D3hot);
 
        dev_priv->suspended_to_idle = suspend_to_idle(dev_priv);
 
@@ -1590,18 +1548,18 @@ static int i915_drm_resume(struct drm_device *dev)
        int ret;
 
        disable_rpm_wakeref_asserts(dev_priv);
+       intel_sanitize_gt_powersave(dev_priv);
 
-       ret = i915_ggtt_enable_hw(dev);
+       ret = i915_ggtt_enable_hw(dev_priv);
        if (ret)
                DRM_ERROR("failed to re-enable GGTT\n");
 
        intel_csr_ucode_resume(dev_priv);
 
-       mutex_lock(&dev->struct_mutex);
-       i915_gem_restore_gtt_mappings(dev);
-       mutex_unlock(&dev->struct_mutex);
+       i915_gem_resume(dev);
 
        i915_restore_state(dev);
+       intel_pps_unlock_regs_wa(dev_priv);
        intel_opregion_setup(dev_priv);
 
        intel_init_pch_refclk(dev);
@@ -1620,7 +1578,7 @@ static int i915_drm_resume(struct drm_device *dev)
        mutex_lock(&dev->struct_mutex);
        if (i915_gem_init_hw(dev)) {
                DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n");
-               atomic_or(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
+               i915_gem_set_wedged(dev_priv);
        }
        mutex_unlock(&dev->struct_mutex);
 
@@ -1657,6 +1615,7 @@ static int i915_drm_resume(struct drm_device *dev)
 
        intel_opregion_notify_adapter(dev_priv, PCI_D0);
 
+       intel_autoenable_gt_powersave(dev_priv);
        drm_kms_helper_poll_enable(dev);
 
        enable_rpm_wakeref_asserts(dev_priv);
@@ -1667,6 +1626,7 @@ static int i915_drm_resume(struct drm_device *dev)
 static int i915_drm_resume_early(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        int ret;
 
        /*
@@ -1689,7 +1649,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
         * the device powered we can also remove the following set power state
         * call.
         */
-       ret = pci_set_power_state(dev->pdev, PCI_D0);
+       ret = pci_set_power_state(pdev, PCI_D0);
        if (ret) {
                DRM_ERROR("failed to set PCI D0 power state (%d)\n", ret);
                goto out;
@@ -1708,12 +1668,12 @@ static int i915_drm_resume_early(struct drm_device *dev)
         * depend on the device enable refcount we can't anyway depend on them
         * disabling/enabling the device.
         */
-       if (pci_enable_device(dev->pdev)) {
+       if (pci_enable_device(pdev)) {
                ret = -EIO;
                goto out;
        }
 
-       pci_set_master(dev->pdev);
+       pci_set_master(pdev);
 
        disable_rpm_wakeref_asserts(dev_priv);
 
@@ -1765,8 +1725,10 @@ int i915_resume_switcheroo(struct drm_device *dev)
  * i915_reset - reset chip after a hang
  * @dev: drm device to reset
  *
- * Reset the chip.  Useful if a hang is detected. Returns zero on successful
- * reset or otherwise an error code.
+ * Reset the chip.  Useful if a hang is detected. Marks the device as wedged
+ * on failure.
+ *
+ * Caller must hold the struct_mutex.
  *
  * Procedure is fairly simple:
  *   - reset the chip using the reset reg
@@ -1776,31 +1738,22 @@ int i915_resume_switcheroo(struct drm_device *dev)
  *   - re-init interrupt state
  *   - re-init display
  */
-int i915_reset(struct drm_i915_private *dev_priv)
+void i915_reset(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = &dev_priv->drm;
        struct i915_gpu_error *error = &dev_priv->gpu_error;
-       unsigned reset_counter;
        int ret;
 
-       intel_reset_gt_powersave(dev_priv);
+       lockdep_assert_held(&dev->struct_mutex);
 
-       mutex_lock(&dev->struct_mutex);
+       if (!test_and_clear_bit(I915_RESET_IN_PROGRESS, &error->flags))
+               return;
 
        /* Clear any previous failed attempts at recovery. Time to try again. */
-       atomic_andnot(I915_WEDGED, &error->reset_counter);
-
-       /* Clear the reset-in-progress flag and increment the reset epoch. */
-       reset_counter = atomic_inc_return(&error->reset_counter);
-       if (WARN_ON(__i915_reset_in_progress(reset_counter))) {
-               ret = -EIO;
-               goto error;
-       }
+       __clear_bit(I915_WEDGED, &error->flags);
+       error->reset_count++;
 
        pr_notice("drm/i915: Resetting chip after gpu hang\n");
-
-       i915_gem_reset(dev);
-
        ret = intel_gpu_reset(dev_priv, ALL_ENGINES);
        if (ret) {
                if (ret != -ENODEV)
@@ -1810,6 +1763,7 @@ int i915_reset(struct drm_i915_private *dev_priv)
                goto error;
        }
 
+       i915_gem_reset(dev_priv);
        intel_overlay_reset(dev_priv);
 
        /* Ok, now get things going again... */
@@ -1832,44 +1786,34 @@ int i915_reset(struct drm_i915_private *dev_priv)
                goto error;
        }
 
-       mutex_unlock(&dev->struct_mutex);
-
-       /*
-        * rps/rc6 re-init is necessary to restore state lost after the
-        * reset and the re-install of gt irqs. Skip for ironlake per
-        * previous concerns that it doesn't respond well to some forms
-        * of re-init after reset.
-        */
-       if (INTEL_INFO(dev)->gen > 5)
-               intel_enable_gt_powersave(dev_priv);
-
-       return 0;
+wakeup:
+       wake_up_bit(&error->flags, I915_RESET_IN_PROGRESS);
+       return;
 
 error:
-       atomic_or(I915_WEDGED, &error->reset_counter);
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
+       i915_gem_set_wedged(dev_priv);
+       goto wakeup;
 }
 
-static int i915_pm_suspend(struct device *dev)
+static int i915_pm_suspend(struct device *kdev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct drm_device *dev = pci_get_drvdata(pdev);
 
-       if (!drm_dev) {
-               dev_err(dev, "DRM not initialized, aborting suspend.\n");
+       if (!dev) {
+               dev_err(kdev, "DRM not initialized, aborting suspend.\n");
                return -ENODEV;
        }
 
-       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+       if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       return i915_drm_suspend(drm_dev);
+       return i915_drm_suspend(dev);
 }
 
-static int i915_pm_suspend_late(struct device *dev)
+static int i915_pm_suspend_late(struct device *kdev)
 {
-       struct drm_device *drm_dev = &dev_to_i915(dev)->drm;
+       struct drm_device *dev = &kdev_to_i915(kdev)->drm;
 
        /*
         * We have a suspend ordering issue with the snd-hda driver also
@@ -1880,57 +1824,67 @@ static int i915_pm_suspend_late(struct device *dev)
         * FIXME: This should be solved with a special hdmi sink device or
         * similar so that power domains can be employed.
         */
-       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+       if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       return i915_drm_suspend_late(drm_dev, false);
+       return i915_drm_suspend_late(dev, false);
 }
 
-static int i915_pm_poweroff_late(struct device *dev)
+static int i915_pm_poweroff_late(struct device *kdev)
 {
-       struct drm_device *drm_dev = &dev_to_i915(dev)->drm;
+       struct drm_device *dev = &kdev_to_i915(kdev)->drm;
 
-       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+       if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       return i915_drm_suspend_late(drm_dev, true);
+       return i915_drm_suspend_late(dev, true);
 }
 
-static int i915_pm_resume_early(struct device *dev)
+static int i915_pm_resume_early(struct device *kdev)
 {
-       struct drm_device *drm_dev = &dev_to_i915(dev)->drm;
+       struct drm_device *dev = &kdev_to_i915(kdev)->drm;
 
-       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+       if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       return i915_drm_resume_early(drm_dev);
+       return i915_drm_resume_early(dev);
 }
 
-static int i915_pm_resume(struct device *dev)
+static int i915_pm_resume(struct device *kdev)
 {
-       struct drm_device *drm_dev = &dev_to_i915(dev)->drm;
+       struct drm_device *dev = &kdev_to_i915(kdev)->drm;
 
-       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+       if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       return i915_drm_resume(drm_dev);
+       return i915_drm_resume(dev);
 }
 
 /* freeze: before creating the hibernation_image */
-static int i915_pm_freeze(struct device *dev)
+static int i915_pm_freeze(struct device *kdev)
 {
-       return i915_pm_suspend(dev);
+       int ret;
+
+       ret = i915_pm_suspend(kdev);
+       if (ret)
+               return ret;
+
+       ret = i915_gem_freeze(kdev_to_i915(kdev));
+       if (ret)
+               return ret;
+
+       return 0;
 }
 
-static int i915_pm_freeze_late(struct device *dev)
+static int i915_pm_freeze_late(struct device *kdev)
 {
        int ret;
 
-       ret = i915_pm_suspend_late(dev);
+       ret = i915_pm_suspend_late(kdev);
        if (ret)
                return ret;
 
-       ret = i915_gem_freeze_late(dev_to_i915(dev));
+       ret = i915_gem_freeze_late(kdev_to_i915(kdev));
        if (ret)
                return ret;
 
@@ -1938,25 +1892,25 @@ static int i915_pm_freeze_late(struct device *dev)
 }
 
 /* thaw: called after creating the hibernation image, but before turning off. */
-static int i915_pm_thaw_early(struct device *dev)
+static int i915_pm_thaw_early(struct device *kdev)
 {
-       return i915_pm_resume_early(dev);
+       return i915_pm_resume_early(kdev);
 }
 
-static int i915_pm_thaw(struct device *dev)
+static int i915_pm_thaw(struct device *kdev)
 {
-       return i915_pm_resume(dev);
+       return i915_pm_resume(kdev);
 }
 
 /* restore: called after loading the hibernation image. */
-static int i915_pm_restore_early(struct device *dev)
+static int i915_pm_restore_early(struct device *kdev)
 {
-       return i915_pm_resume_early(dev);
+       return i915_pm_resume_early(kdev);
 }
 
-static int i915_pm_restore(struct device *dev)
+static int i915_pm_restore(struct device *kdev)
 {
-       return i915_pm_resume(dev);
+       return i915_pm_resume(kdev);
 }
 
 /*
@@ -2318,9 +2272,9 @@ static int vlv_resume_prepare(struct drm_i915_private *dev_priv,
        return ret;
 }
 
-static int intel_runtime_suspend(struct device *device)
+static int intel_runtime_suspend(struct device *kdev)
 {
-       struct pci_dev *pdev = to_pci_dev(device);
+       struct pci_dev *pdev = to_pci_dev(kdev);
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct drm_i915_private *dev_priv = to_i915(dev);
        int ret;
@@ -2346,7 +2300,7 @@ static int intel_runtime_suspend(struct device *device)
                 * Bump the expiration timestamp, otherwise the suspend won't
                 * be rescheduled.
                 */
-               pm_runtime_mark_last_busy(device);
+               pm_runtime_mark_last_busy(kdev);
 
                return -EAGAIN;
        }
@@ -2425,9 +2379,9 @@ static int intel_runtime_suspend(struct device *device)
        return 0;
 }
 
-static int intel_runtime_resume(struct device *device)
+static int intel_runtime_resume(struct device *kdev)
 {
-       struct pci_dev *pdev = to_pci_dev(device);
+       struct pci_dev *pdev = to_pci_dev(kdev);
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct drm_i915_private *dev_priv = to_i915(dev);
        int ret = 0;
@@ -2467,7 +2421,6 @@ static int intel_runtime_resume(struct device *device)
         * we can do is to hope that things will still work (and disable RPM).
         */
        i915_gem_init_swizzling(dev);
-       gen6_update_ring_freq(dev_priv);
 
        intel_runtime_pm_enable_interrupts(dev_priv);
 
@@ -2623,6 +2576,7 @@ static struct drm_driver driver = {
        .postclose = i915_driver_postclose,
        .set_busid = drm_pci_set_busid,
 
+       .gem_close_object = i915_gem_close_object,
        .gem_free_object = i915_gem_free_object,
        .gem_vm_ops = &i915_gem_vm_ops,
 
index f68c789..8b9ee4e 100644 (file)
@@ -61,6 +61,7 @@
 #include "i915_gem.h"
 #include "i915_gem_gtt.h"
 #include "i915_gem_render_state.h"
+#include "i915_gem_request.h"
 
 #include "intel_gvt.h"
 
@@ -69,7 +70,7 @@
 
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20160711"
+#define DRIVER_DATE            "20160919"
 
 #undef WARN_ON
 /* Many gcc seem to no see through this and fall over :( */
@@ -401,7 +402,7 @@ struct drm_i915_file_private {
                unsigned boosts;
        } rps;
 
-       unsigned int bsd_ring;
+       unsigned int bsd_engine;
 };
 
 /* Used by dp and fdi links */
@@ -431,8 +432,6 @@ void intel_link_compute_m_n(int bpp, int nlanes,
 #define DRIVER_MINOR           6
 #define DRIVER_PATCHLEVEL      0
 
-#define WATCH_LISTS    0
-
 struct opregion_header;
 struct opregion_acpi;
 struct opregion_swsci;
@@ -456,15 +455,21 @@ struct intel_opregion {
 struct intel_overlay;
 struct intel_overlay_error_state;
 
-#define I915_FENCE_REG_NONE -1
-#define I915_MAX_NUM_FENCES 32
-/* 32 fences + sign bit for FENCE_REG_NONE */
-#define I915_MAX_NUM_FENCE_BITS 6
-
 struct drm_i915_fence_reg {
-       struct list_head lru_list;
-       struct drm_i915_gem_object *obj;
+       struct list_head link;
+       struct drm_i915_private *i915;
+       struct i915_vma *vma;
        int pin_count;
+       int id;
+       /**
+        * Whether the tiling parameters for the currently
+        * associated fence register have changed. Note that
+        * for the purposes of tracking tiling changes we also
+        * treat the unfenced register, the register slot that
+        * the object occupies whilst it executes a fenced
+        * command (such as BLT on gen2/3), as a "fence".
+        */
+       bool dirty;
 };
 
 struct sdvo_device_mapping {
@@ -476,130 +481,6 @@ struct sdvo_device_mapping {
        u8 ddc_pin;
 };
 
-struct intel_display_error_state;
-
-struct drm_i915_error_state {
-       struct kref ref;
-       struct timeval time;
-
-       char error_msg[128];
-       bool simulated;
-       int iommu;
-       u32 reset_count;
-       u32 suspend_count;
-
-       /* Generic register state */
-       u32 eir;
-       u32 pgtbl_er;
-       u32 ier;
-       u32 gtier[4];
-       u32 ccid;
-       u32 derrmr;
-       u32 forcewake;
-       u32 error; /* gen6+ */
-       u32 err_int; /* gen7 */
-       u32 fault_data0; /* gen8, gen9 */
-       u32 fault_data1; /* gen8, gen9 */
-       u32 done_reg;
-       u32 gac_eco;
-       u32 gam_ecochk;
-       u32 gab_ctl;
-       u32 gfx_mode;
-       u32 extra_instdone[I915_NUM_INSTDONE_REG];
-       u64 fence[I915_MAX_NUM_FENCES];
-       struct intel_overlay_error_state *overlay;
-       struct intel_display_error_state *display;
-       struct drm_i915_error_object *semaphore_obj;
-
-       struct drm_i915_error_ring {
-               bool valid;
-               /* Software tracked state */
-               bool waiting;
-               int num_waiters;
-               int hangcheck_score;
-               enum intel_ring_hangcheck_action hangcheck_action;
-               int num_requests;
-
-               /* our own tracking of ring head and tail */
-               u32 cpu_ring_head;
-               u32 cpu_ring_tail;
-
-               u32 last_seqno;
-               u32 semaphore_seqno[I915_NUM_ENGINES - 1];
-
-               /* Register state */
-               u32 start;
-               u32 tail;
-               u32 head;
-               u32 ctl;
-               u32 hws;
-               u32 ipeir;
-               u32 ipehr;
-               u32 instdone;
-               u32 bbstate;
-               u32 instpm;
-               u32 instps;
-               u32 seqno;
-               u64 bbaddr;
-               u64 acthd;
-               u32 fault_reg;
-               u64 faddr;
-               u32 rc_psmi; /* sleep state */
-               u32 semaphore_mboxes[I915_NUM_ENGINES - 1];
-
-               struct drm_i915_error_object {
-                       int page_count;
-                       u64 gtt_offset;
-                       u32 *pages[0];
-               } *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page;
-
-               struct drm_i915_error_object *wa_ctx;
-
-               struct drm_i915_error_request {
-                       long jiffies;
-                       u32 seqno;
-                       u32 tail;
-               } *requests;
-
-               struct drm_i915_error_waiter {
-                       char comm[TASK_COMM_LEN];
-                       pid_t pid;
-                       u32 seqno;
-               } *waiters;
-
-               struct {
-                       u32 gfx_mode;
-                       union {
-                               u64 pdp[4];
-                               u32 pp_dir_base;
-                       };
-               } vm_info;
-
-               pid_t pid;
-               char comm[TASK_COMM_LEN];
-       } ring[I915_NUM_ENGINES];
-
-       struct drm_i915_error_buffer {
-               u32 size;
-               u32 name;
-               u32 rseqno[I915_NUM_ENGINES], wseqno;
-               u64 gtt_offset;
-               u32 read_domains;
-               u32 write_domain;
-               s32 fence_reg:I915_MAX_NUM_FENCE_BITS;
-               s32 pinned:2;
-               u32 tiling:2;
-               u32 dirty:1;
-               u32 purgeable:1;
-               u32 userptr:1;
-               s32 ring:4;
-               u32 cache_level:3;
-       } **active_bo, **pinned_bo;
-
-       u32 *active_bo_count, *pinned_bo_count;
-       u32 vm_count;
-};
-
 struct intel_connector;
 struct intel_encoder;
 struct intel_crtc_state;
@@ -629,8 +510,12 @@ struct drm_i915_display_funcs {
                                         struct intel_initial_plane_config *);
        int (*crtc_compute_clock)(struct intel_crtc *crtc,
                                  struct intel_crtc_state *crtc_state);
-       void (*crtc_enable)(struct drm_crtc *crtc);
-       void (*crtc_disable)(struct drm_crtc *crtc);
+       void (*crtc_enable)(struct intel_crtc_state *pipe_config,
+                           struct drm_atomic_state *old_state);
+       void (*crtc_disable)(struct intel_crtc_state *old_crtc_state,
+                            struct drm_atomic_state *old_state);
+       void (*update_crtcs)(struct drm_atomic_state *state,
+                            unsigned int *crtc_vblank_mask);
        void (*audio_codec_enable)(struct drm_connector *connector,
                                   struct intel_encoder *encoder,
                                   const struct drm_display_mode *adjusted_mode);
@@ -694,8 +579,6 @@ struct intel_uncore_funcs {
                                uint16_t val, bool trace);
        void (*mmio_writel)(struct drm_i915_private *dev_priv, i915_reg_t r,
                                uint32_t val, bool trace);
-       void (*mmio_writeq)(struct drm_i915_private *dev_priv, i915_reg_t r,
-                               uint64_t val, bool trace);
 };
 
 struct intel_uncore {
@@ -756,7 +639,7 @@ struct intel_csr {
        func(is_i915g) sep \
        func(is_i945gm) sep \
        func(is_g33) sep \
-       func(need_gfx_hws) sep \
+       func(hws_needs_physical) sep \
        func(is_g4x) sep \
        func(is_pineview) sep \
        func(is_broadwater) sep \
@@ -771,6 +654,19 @@ struct intel_csr {
        func(is_kabylake) sep \
        func(is_preliminary) sep \
        func(has_fbc) sep \
+       func(has_psr) sep \
+       func(has_runtime_pm) sep \
+       func(has_csr) sep \
+       func(has_resource_streamer) sep \
+       func(has_rc6) sep \
+       func(has_rc6p) sep \
+       func(has_dp_mst) sep \
+       func(has_gmbus_irq) sep \
+       func(has_hw_contexts) sep \
+       func(has_logical_ring_contexts) sep \
+       func(has_l3_dpf) sep \
+       func(has_gmch_display) sep \
+       func(has_guc) sep \
        func(has_pipe_cxsr) sep \
        func(has_hotplug) sep \
        func(cursor_needs_physical) sep \
@@ -786,6 +682,24 @@ struct intel_csr {
 #define DEFINE_FLAG(name) u8 name:1
 #define SEP_SEMICOLON ;
 
+struct sseu_dev_info {
+       u8 slice_mask;
+       u8 subslice_mask;
+       u8 eu_total;
+       u8 eu_per_subslice;
+       u8 min_eu_in_pool;
+       /* For each slice, which subslice(s) has(have) 7 EUs (bitfield)? */
+       u8 subslice_7eu[3];
+       u8 has_slice_pg:1;
+       u8 has_subslice_pg:1;
+       u8 has_eu_pg:1;
+};
+
+static inline unsigned int sseu_subslice_total(const struct sseu_dev_info *sseu)
+{
+       return hweight8(sseu->slice_mask) * hweight8(sseu->subslice_mask);
+}
+
 struct intel_device_info {
        u32 display_mmio_offset;
        u16 device_id;
@@ -794,7 +708,9 @@ struct intel_device_info {
        u8 gen;
        u16 gen_mask;
        u8 ring_mask; /* Rings supported by the HW */
+       u8 num_rings;
        DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON);
+       u16 ddb_size; /* in blocks */
        /* Register offsets for the various display pipes and transcoders */
        int pipe_offsets[I915_MAX_TRANSCODERS];
        int trans_offsets[I915_MAX_TRANSCODERS];
@@ -802,17 +718,7 @@ struct intel_device_info {
        int cursor_offsets[I915_MAX_PIPES];
 
        /* Slice/subslice/EU info */
-       u8 slice_total;
-       u8 subslice_total;
-       u8 subslice_per_slice;
-       u8 eu_total;
-       u8 eu_per_subslice;
-       u8 min_eu_in_pool;
-       /* For each slice, which subslice(s) has(have) 7 EUs (bitfield)? */
-       u8 subslice_7eu[3];
-       u8 has_slice_pg:1;
-       u8 has_subslice_pg:1;
-       u8 has_eu_pg:1;
+       struct sseu_dev_info sseu;
 
        struct color_luts {
                u16 degamma_lut_size;
@@ -823,6 +729,134 @@ struct intel_device_info {
 #undef DEFINE_FLAG
 #undef SEP_SEMICOLON
 
+struct intel_display_error_state;
+
+struct drm_i915_error_state {
+       struct kref ref;
+       struct timeval time;
+
+       char error_msg[128];
+       bool simulated;
+       int iommu;
+       u32 reset_count;
+       u32 suspend_count;
+       struct intel_device_info device_info;
+
+       /* Generic register state */
+       u32 eir;
+       u32 pgtbl_er;
+       u32 ier;
+       u32 gtier[4];
+       u32 ccid;
+       u32 derrmr;
+       u32 forcewake;
+       u32 error; /* gen6+ */
+       u32 err_int; /* gen7 */
+       u32 fault_data0; /* gen8, gen9 */
+       u32 fault_data1; /* gen8, gen9 */
+       u32 done_reg;
+       u32 gac_eco;
+       u32 gam_ecochk;
+       u32 gab_ctl;
+       u32 gfx_mode;
+       u32 extra_instdone[I915_NUM_INSTDONE_REG];
+       u64 fence[I915_MAX_NUM_FENCES];
+       struct intel_overlay_error_state *overlay;
+       struct intel_display_error_state *display;
+       struct drm_i915_error_object *semaphore;
+
+       struct drm_i915_error_engine {
+               int engine_id;
+               /* Software tracked state */
+               bool waiting;
+               int num_waiters;
+               int hangcheck_score;
+               enum intel_engine_hangcheck_action hangcheck_action;
+               struct i915_address_space *vm;
+               int num_requests;
+
+               /* our own tracking of ring head and tail */
+               u32 cpu_ring_head;
+               u32 cpu_ring_tail;
+
+               u32 last_seqno;
+               u32 semaphore_seqno[I915_NUM_ENGINES - 1];
+
+               /* Register state */
+               u32 start;
+               u32 tail;
+               u32 head;
+               u32 ctl;
+               u32 mode;
+               u32 hws;
+               u32 ipeir;
+               u32 ipehr;
+               u32 instdone;
+               u32 bbstate;
+               u32 instpm;
+               u32 instps;
+               u32 seqno;
+               u64 bbaddr;
+               u64 acthd;
+               u32 fault_reg;
+               u64 faddr;
+               u32 rc_psmi; /* sleep state */
+               u32 semaphore_mboxes[I915_NUM_ENGINES - 1];
+
+               struct drm_i915_error_object {
+                       int page_count;
+                       u64 gtt_offset;
+                       u64 gtt_size;
+                       u32 *pages[0];
+               } *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page;
+
+               struct drm_i915_error_object *wa_ctx;
+
+               struct drm_i915_error_request {
+                       long jiffies;
+                       pid_t pid;
+                       u32 seqno;
+                       u32 head;
+                       u32 tail;
+               } *requests;
+
+               struct drm_i915_error_waiter {
+                       char comm[TASK_COMM_LEN];
+                       pid_t pid;
+                       u32 seqno;
+               } *waiters;
+
+               struct {
+                       u32 gfx_mode;
+                       union {
+                               u64 pdp[4];
+                               u32 pp_dir_base;
+                       };
+               } vm_info;
+
+               pid_t pid;
+               char comm[TASK_COMM_LEN];
+       } engine[I915_NUM_ENGINES];
+
+       struct drm_i915_error_buffer {
+               u32 size;
+               u32 name;
+               u32 rseqno[I915_NUM_ENGINES], wseqno;
+               u64 gtt_offset;
+               u32 read_domains;
+               u32 write_domain;
+               s32 fence_reg:I915_MAX_NUM_FENCE_BITS;
+               u32 tiling:2;
+               u32 dirty:1;
+               u32 purgeable:1;
+               u32 userptr:1;
+               s32 engine:4;
+               u32 cache_level:3;
+       } *active_bo[I915_NUM_ENGINES], *pinned_bo;
+       u32 active_bo_count[I915_NUM_ENGINES], pinned_bo_count;
+       struct i915_address_space *active_vm[I915_NUM_ENGINES];
+};
+
 enum i915_cache_level {
        I915_CACHE_NONE = 0,
        I915_CACHE_LLC, /* also used for snoopable memory on non-LLC */
@@ -879,6 +913,7 @@ struct i915_gem_context {
        struct drm_i915_private *i915;
        struct drm_i915_file_private *file_priv;
        struct i915_hw_ppgtt *ppgtt;
+       struct pid *pid;
 
        struct i915_ctx_hang_stats hang_stats;
 
@@ -893,9 +928,8 @@ struct i915_gem_context {
        u32 ggtt_alignment;
 
        struct intel_context {
-               struct drm_i915_gem_object *state;
-               struct intel_ringbuffer *ringbuf;
-               struct i915_vma *lrc_vma;
+               struct i915_vma *state;
+               struct intel_ring *ring;
                uint32_t *lrc_reg_state;
                u64 lrc_desc;
                int pin_count;
@@ -909,6 +943,7 @@ struct i915_gem_context {
        struct list_head link;
 
        u8 remap_slice;
+       bool closed:1;
 };
 
 enum fb_op_origin {
@@ -1062,13 +1097,6 @@ struct intel_gmbus {
 
 struct i915_suspend_saved_registers {
        u32 saveDSPARB;
-       u32 saveLVDS;
-       u32 savePP_ON_DELAYS;
-       u32 savePP_OFF_DELAYS;
-       u32 savePP_ON;
-       u32 savePP_OFF;
-       u32 savePP_CONTROL;
-       u32 savePP_DIVISOR;
        u32 saveFBC_CONTROL;
        u32 saveCACHE_MODE_0;
        u32 saveMI_ARB_STATE;
@@ -1157,6 +1185,7 @@ struct intel_gen6_power_mgmt {
        bool interrupts_enabled;
        u32 pm_iir;
 
+       /* PM interrupt bits that should never be masked */
        u32 pm_intr_keep;
 
        /* Frequencies are stored in potentially platform dependent multiples.
@@ -1174,6 +1203,7 @@ struct intel_gen6_power_mgmt {
        u8 max_freq_softlimit;  /* Max frequency permitted by the driver */
        u8 max_freq;            /* Maximum frequency, RP0 if not overclocking */
        u8 min_freq;            /* AKA RPn. Minimum frequency */
+       u8 boost_freq;          /* Frequency to request when wait boosting */
        u8 idle_freq;           /* Frequency to request when we are idle */
        u8 efficient_freq;      /* AKA RPe. Pre-determined balanced frequency */
        u8 rp1_freq;            /* "less than" RP0 power/freqency */
@@ -1191,11 +1221,9 @@ struct intel_gen6_power_mgmt {
        bool client_boost;
 
        bool enabled;
-       struct delayed_work delayed_resume_work;
+       struct delayed_work autoenable_work;
        unsigned boosts;
 
-       struct intel_rps_client semaphores, mmioflips;
-
        /* manual wa residency calculations */
        struct intel_rps_ei up_ei, down_ei;
 
@@ -1320,7 +1348,6 @@ struct i915_gem_mm {
        struct notifier_block oom_notifier;
        struct notifier_block vmap_notifier;
        struct shrinker shrinker;
-       bool shrinker_no_lock_stealing;
 
        /** LRU list of objects with fence regs on them. */
        struct list_head fence_list;
@@ -1332,7 +1359,7 @@ struct i915_gem_mm {
        bool interruptible;
 
        /* the indicator for dispatch video commands on two BSD rings */
-       unsigned int bsd_ring_dispatch_index;
+       atomic_t bsd_engine_dispatch_index;
 
        /** Bit 6 swizzling required for X tiling */
        uint32_t bit_6_swizzle_x;
@@ -1380,9 +1407,10 @@ struct i915_gpu_error {
         * State variable controlling the reset flow and count
         *
         * This is a counter which gets incremented when reset is triggered,
-        * and again when reset has been handled. So odd values (lowest bit set)
-        * means that reset is in progress and even values that
-        * (reset_counter >> 1):th reset was successfully completed.
+        *
+        * Before the reset commences, the I915_RESET_IN_PROGRESS bit is set
+        * meaning that any waiters holding onto the struct_mutex should
+        * relinquish the lock immediately in order for the reset to start.
         *
         * If reset is not completed succesfully, the I915_WEDGE bit is
         * set meaning that hardware is terminally sour and there is no
@@ -1397,10 +1425,11 @@ struct i915_gpu_error {
         * naturally enforces the correct ordering between the bail-out of the
         * waiter and the gpu reset work code.
         */
-       atomic_t reset_counter;
+       unsigned long reset_count;
 
-#define I915_RESET_IN_PROGRESS_FLAG    1
-#define I915_WEDGED                    (1 << 31)
+       unsigned long flags;
+#define I915_RESET_IN_PROGRESS 0
+#define I915_WEDGED            (BITS_PER_LONG - 1)
 
        /**
         * Waitqueue to signal when a hang is detected. Used to for waiters
@@ -1671,7 +1700,7 @@ struct intel_pipe_crc {
 };
 
 struct i915_frontbuffer_tracking {
-       struct mutex lock;
+       spinlock_t lock;
 
        /*
         * Tracking bits for delayed frontbuffer flushing du to gpu activity or
@@ -1706,18 +1735,6 @@ struct i915_virtual_gpu {
        bool active;
 };
 
-struct i915_execbuffer_params {
-       struct drm_device               *dev;
-       struct drm_file                 *file;
-       uint32_t                        dispatch_flags;
-       uint32_t                        args_batch_start_offset;
-       uint64_t                        batch_obj_vm_offset;
-       struct intel_engine_cs *engine;
-       struct drm_i915_gem_object      *batch_obj;
-       struct i915_gem_context            *ctx;
-       struct drm_i915_gem_request     *request;
-};
-
 /* used in computing the new watermarks state */
 struct intel_wm_config {
        unsigned int num_pipes_active;
@@ -1764,13 +1781,15 @@ struct drm_i915_private {
 
        uint32_t psr_mmio_base;
 
+       uint32_t pps_mmio_base;
+
        wait_queue_head_t gmbus_wait_queue;
 
        struct pci_dev *bridge_dev;
        struct i915_gem_context *kernel_context;
        struct intel_engine_cs engine[I915_NUM_ENGINES];
-       struct drm_i915_gem_object *semaphore_obj;
-       uint32_t last_seqno, next_seqno;
+       struct i915_vma *semaphore;
+       u32 next_seqno;
 
        struct drm_dma_handle *status_page_dmah;
        struct resource mch_res;
@@ -1965,11 +1984,11 @@ struct drm_i915_private {
        struct vlv_s0ix_state vlv_s0ix_state;
 
        enum {
-               I915_SKL_SAGV_UNKNOWN = 0,
-               I915_SKL_SAGV_DISABLED,
-               I915_SKL_SAGV_ENABLED,
-               I915_SKL_SAGV_NOT_CONTROLLED
-       } skl_sagv_status;
+               I915_SAGV_UNKNOWN = 0,
+               I915_SAGV_DISABLED,
+               I915_SAGV_ENABLED,
+               I915_SAGV_NOT_CONTROLLED
+       } sagv_status;
 
        struct {
                /*
@@ -2025,12 +2044,8 @@ struct drm_i915_private {
 
        /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
        struct {
-               int (*execbuf_submit)(struct i915_execbuffer_params *params,
-                                     struct drm_i915_gem_execbuffer2 *args,
-                                     struct list_head *vmas);
-               int (*init_engines)(struct drm_device *dev);
+               void (*resume)(struct drm_i915_private *);
                void (*cleanup_engine)(struct intel_engine_cs *engine);
-               void (*stop_engine)(struct intel_engine_cs *engine);
 
                /**
                 * Is the GPU currently considered idle, or busy executing
@@ -2077,9 +2092,9 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
        return container_of(dev, struct drm_i915_private, drm);
 }
 
-static inline struct drm_i915_private *dev_to_i915(struct device *dev)
+static inline struct drm_i915_private *kdev_to_i915(struct device *kdev)
 {
-       return to_i915(dev_get_drvdata(dev));
+       return to_i915(dev_get_drvdata(kdev));
 }
 
 static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
@@ -2102,13 +2117,16 @@ static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
                for_each_if (((id__) = (engine__)->id, \
                              intel_engine_initialized(engine__)))
 
+#define __mask_next_bit(mask) ({                                       \
+       int __idx = ffs(mask) - 1;                                      \
+       mask &= ~BIT(__idx);                                            \
+       __idx;                                                          \
+})
+
 /* Iterator over subset of engines selected by mask */
-#define for_each_engine_masked(engine__, dev_priv__, mask__) \
-       for ((engine__) = &(dev_priv__)->engine[0]; \
-            (engine__) < &(dev_priv__)->engine[I915_NUM_ENGINES]; \
-            (engine__)++) \
-               for_each_if (((mask__) & intel_engine_flag(engine__)) && \
-                            intel_engine_initialized(engine__))
+#define for_each_engine_masked(engine__, dev_priv__, mask__, tmp__) \
+       for (tmp__ = mask__ & INTEL_INFO(dev_priv__)->ring_mask;        \
+            tmp__ ? (engine__ = &(dev_priv__)->engine[__mask_next_bit(tmp__)]), 1 : 0; )
 
 enum hdmi_force_audio {
        HDMI_AUDIO_OFF_DVI = -2,        /* no aux data for HDMI-DVI converter */
@@ -2153,8 +2171,6 @@ struct drm_i915_gem_object_ops {
  */
 #define INTEL_MAX_SPRITE_BITS_PER_PIPE 5
 #define INTEL_FRONTBUFFER_BITS_PER_PIPE 8
-#define INTEL_FRONTBUFFER_BITS \
-       (INTEL_FRONTBUFFER_BITS_PER_PIPE * I915_MAX_PIPES)
 #define INTEL_FRONTBUFFER_PRIMARY(pipe) \
        (1 << (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))
 #define INTEL_FRONTBUFFER_CURSOR(pipe) \
@@ -2178,18 +2194,21 @@ struct drm_i915_gem_object {
        struct drm_mm_node *stolen;
        struct list_head global_list;
 
-       struct list_head engine_list[I915_NUM_ENGINES];
        /** Used in execbuf to temporarily hold a ref */
        struct list_head obj_exec_link;
 
        struct list_head batch_pool_link;
 
+       unsigned long flags;
        /**
         * This is set if the object is on the active lists (has pending
         * rendering and so a non-zero seqno), and is not set if it i s on
         * inactive (ready to be unbound) list.
         */
-       unsigned int active:I915_NUM_ENGINES;
+#define I915_BO_ACTIVE_SHIFT 0
+#define I915_BO_ACTIVE_MASK ((1 << I915_NUM_ENGINES) - 1)
+#define __I915_BO_ACTIVE(bo) \
+       ((READ_ONCE((bo)->flags) >> I915_BO_ACTIVE_SHIFT) & I915_BO_ACTIVE_MASK)
 
        /**
         * This is set if the object has been written to since last bound
@@ -2197,37 +2216,11 @@ struct drm_i915_gem_object {
         */
        unsigned int dirty:1;
 
-       /**
-        * Fence register bits (if any) for this object.  Will be set
-        * as needed when mapped into the GTT.
-        * Protected by dev->struct_mutex.
-        */
-       signed int fence_reg:I915_MAX_NUM_FENCE_BITS;
-
        /**
         * Advice: are the backing pages purgeable?
         */
        unsigned int madv:2;
 
-       /**
-        * Current tiling mode for the object.
-        */
-       unsigned int tiling_mode:2;
-       /**
-        * Whether the tiling parameters for the currently associated fence
-        * register have changed. Note that for the purposes of tracking
-        * tiling changes we also treat the unfenced register, the register
-        * slot that the object occupies whilst it executes a fenced
-        * command (such as BLT on gen2/3), as a "fence".
-        */
-       unsigned int fence_dirty:1;
-
-       /**
-        * Is the object at the current location in the gtt mappable and
-        * fenceable? Used to avoid costly recalculations.
-        */
-       unsigned int map_and_fenceable:1;
-
        /**
         * Whether the current gtt mapping needs to be mappable (and isn't just
         * mappable by accident). Track pin and fault separate for a more
@@ -2243,9 +2236,17 @@ struct drm_i915_gem_object {
        unsigned int cache_level:3;
        unsigned int cache_dirty:1;
 
-       unsigned int frontbuffer_bits:INTEL_FRONTBUFFER_BITS;
+       atomic_t frontbuffer_bits;
+       unsigned int frontbuffer_ggtt_origin; /* write once */
+
+       /** Current tiling stride for the object, if it's tiled. */
+       unsigned int tiling_and_stride;
+#define FENCE_MINIMUM_STRIDE 128 /* See i915_tiling_ok() */
+#define TILING_MASK (FENCE_MINIMUM_STRIDE-1)
+#define STRIDE_MASK (~TILING_MASK)
 
-       unsigned int has_wc_mmap;
+       /** Count of VMA actually bound by this object */
+       unsigned int bind_count;
        unsigned int pin_display;
 
        struct sg_table *pages;
@@ -2265,14 +2266,9 @@ struct drm_i915_gem_object {
         * requests on one ring where the write request is older than the
         * read request. This allows for the CPU to read from an active
         * buffer by only waiting for the write to complete.
-        * */
-       struct drm_i915_gem_request *last_read_req[I915_NUM_ENGINES];
-       struct drm_i915_gem_request *last_write_req;
-       /** Breadcrumb of last fenced GPU access to the buffer. */
-       struct drm_i915_gem_request *last_fenced_req;
-
-       /** Current tiling stride for the object, if it's tiled. */
-       uint32_t stride;
+        */
+       struct i915_gem_active last_read[I915_NUM_ENGINES];
+       struct i915_gem_active last_write;
 
        /** References from framebuffers, locks out tiling changes. */
        unsigned long framebuffer_references;
@@ -2280,23 +2276,70 @@ struct drm_i915_gem_object {
        /** Record of address bit 17 of each page at last unbind. */
        unsigned long *bit_17;
 
-       union {
-               /** for phy allocated objects */
-               struct drm_dma_handle *phys_handle;
-
-               struct i915_gem_userptr {
-                       uintptr_t ptr;
-                       unsigned read_only :1;
-                       unsigned workers :4;
+       struct i915_gem_userptr {
+               uintptr_t ptr;
+               unsigned read_only :1;
+               unsigned workers :4;
 #define I915_GEM_USERPTR_MAX_WORKERS 15
 
-                       struct i915_mm_struct *mm;
-                       struct i915_mmu_object *mmu_object;
-                       struct work_struct *work;
-               } userptr;
-       };
+               struct i915_mm_struct *mm;
+               struct i915_mmu_object *mmu_object;
+               struct work_struct *work;
+       } userptr;
+
+       /** for phys allocated objects */
+       struct drm_dma_handle *phys_handle;
 };
-#define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
+
+static inline struct drm_i915_gem_object *
+to_intel_bo(struct drm_gem_object *gem)
+{
+       /* Assert that to_intel_bo(NULL) == NULL */
+       BUILD_BUG_ON(offsetof(struct drm_i915_gem_object, base));
+
+       return container_of(gem, struct drm_i915_gem_object, base);
+}
+
+static inline struct drm_i915_gem_object *
+i915_gem_object_lookup(struct drm_file *file, u32 handle)
+{
+       return to_intel_bo(drm_gem_object_lookup(file, handle));
+}
+
+__deprecated
+extern struct drm_gem_object *
+drm_gem_object_lookup(struct drm_file *file, u32 handle);
+
+__attribute__((nonnull))
+static inline struct drm_i915_gem_object *
+i915_gem_object_get(struct drm_i915_gem_object *obj)
+{
+       drm_gem_object_reference(&obj->base);
+       return obj;
+}
+
+__deprecated
+extern void drm_gem_object_reference(struct drm_gem_object *);
+
+__attribute__((nonnull))
+static inline void
+i915_gem_object_put(struct drm_i915_gem_object *obj)
+{
+       drm_gem_object_unreference(&obj->base);
+}
+
+__deprecated
+extern void drm_gem_object_unreference(struct drm_gem_object *);
+
+__attribute__((nonnull))
+static inline void
+i915_gem_object_put_unlocked(struct drm_i915_gem_object *obj)
+{
+       drm_gem_object_unreference_unlocked(&obj->base);
+}
+
+__deprecated
+extern void drm_gem_object_unreference_unlocked(struct drm_gem_object *);
 
 static inline bool
 i915_gem_object_has_struct_page(const struct drm_i915_gem_object *obj)
@@ -2304,6 +2347,67 @@ i915_gem_object_has_struct_page(const struct drm_i915_gem_object *obj)
        return obj->ops->flags & I915_GEM_OBJECT_HAS_STRUCT_PAGE;
 }
 
+static inline unsigned long
+i915_gem_object_get_active(const struct drm_i915_gem_object *obj)
+{
+       return (obj->flags >> I915_BO_ACTIVE_SHIFT) & I915_BO_ACTIVE_MASK;
+}
+
+static inline bool
+i915_gem_object_is_active(const struct drm_i915_gem_object *obj)
+{
+       return i915_gem_object_get_active(obj);
+}
+
+static inline void
+i915_gem_object_set_active(struct drm_i915_gem_object *obj, int engine)
+{
+       obj->flags |= BIT(engine + I915_BO_ACTIVE_SHIFT);
+}
+
+static inline void
+i915_gem_object_clear_active(struct drm_i915_gem_object *obj, int engine)
+{
+       obj->flags &= ~BIT(engine + I915_BO_ACTIVE_SHIFT);
+}
+
+static inline bool
+i915_gem_object_has_active_engine(const struct drm_i915_gem_object *obj,
+                                 int engine)
+{
+       return obj->flags & BIT(engine + I915_BO_ACTIVE_SHIFT);
+}
+
+static inline unsigned int
+i915_gem_object_get_tiling(struct drm_i915_gem_object *obj)
+{
+       return obj->tiling_and_stride & TILING_MASK;
+}
+
+static inline bool
+i915_gem_object_is_tiled(struct drm_i915_gem_object *obj)
+{
+       return i915_gem_object_get_tiling(obj) != I915_TILING_NONE;
+}
+
+static inline unsigned int
+i915_gem_object_get_stride(struct drm_i915_gem_object *obj)
+{
+       return obj->tiling_and_stride & STRIDE_MASK;
+}
+
+static inline struct i915_vma *i915_vma_get(struct i915_vma *vma)
+{
+       i915_gem_object_get(vma->obj);
+       return vma;
+}
+
+static inline void i915_vma_put(struct i915_vma *vma)
+{
+       lockdep_assert_held(&vma->vm->dev->struct_mutex);
+       i915_gem_object_put(vma->obj);
+}
+
 /*
  * Optimised SGL iterator for GEM objects
  */
@@ -2374,171 +2478,6 @@ static inline struct scatterlist *__sg_next(struct scatterlist *sg)
             (((__iter).curr += PAGE_SIZE) < (__iter).max) ||           \
             ((__iter) = __sgt_iter(__sg_next((__iter).sgp), false), 0))
 
-/**
- * Request queue structure.
- *
- * The request queue allows us to note sequence numbers that have been emitted
- * and may be associated with active buffers to be retired.
- *
- * By keeping this list, we can avoid having to do questionable sequence
- * number comparisons on buffer last_read|write_seqno. It also allows an
- * emission time to be associated with the request for tracking how far ahead
- * of the GPU the submission is.
- *
- * The requests are reference counted, so upon creation they should have an
- * initial reference taken using kref_init
- */
-struct drm_i915_gem_request {
-       struct kref ref;
-
-       /** On Which ring this request was generated */
-       struct drm_i915_private *i915;
-       struct intel_engine_cs *engine;
-       struct intel_signal_node signaling;
-
-        /** GEM sequence number associated with the previous request,
-         * when the HWS breadcrumb is equal to this the GPU is processing
-         * this request.
-         */
-       u32 previous_seqno;
-
-        /** GEM sequence number associated with this request,
-         * when the HWS breadcrumb is equal or greater than this the GPU
-         * has finished processing this request.
-         */
-       u32 seqno;
-
-       /** Position in the ringbuffer of the start of the request */
-       u32 head;
-
-       /**
-        * Position in the ringbuffer of the start of the postfix.
-        * This is required to calculate the maximum available ringbuffer
-        * space without overwriting the postfix.
-        */
-        u32 postfix;
-
-       /** Position in the ringbuffer of the end of the whole request */
-       u32 tail;
-
-       /** Preallocate space in the ringbuffer for the emitting the request */
-       u32 reserved_space;
-
-       /**
-        * Context and ring buffer related to this request
-        * Contexts are refcounted, so when this request is associated with a
-        * context, we must increment the context's refcount, to guarantee that
-        * it persists while any request is linked to it. Requests themselves
-        * are also refcounted, so the request will only be freed when the last
-        * reference to it is dismissed, and the code in
-        * i915_gem_request_free() will then decrement the refcount on the
-        * context.
-        */
-       struct i915_gem_context *ctx;
-       struct intel_ringbuffer *ringbuf;
-
-       /**
-        * Context related to the previous request.
-        * As the contexts are accessed by the hardware until the switch is
-        * completed to a new context, the hardware may still be writing
-        * to the context object after the breadcrumb is visible. We must
-        * not unpin/unbind/prune that object whilst still active and so
-        * we keep the previous context pinned until the following (this)
-        * request is retired.
-        */
-       struct i915_gem_context *previous_context;
-
-       /** Batch buffer related to this request if any (used for
-           error state dump only) */
-       struct drm_i915_gem_object *batch_obj;
-
-       /** Time at which this request was emitted, in jiffies. */
-       unsigned long emitted_jiffies;
-
-       /** global list entry for this request */
-       struct list_head list;
-
-       struct drm_i915_file_private *file_priv;
-       /** file_priv list entry for this request */
-       struct list_head client_list;
-
-       /** process identifier submitting this request */
-       struct pid *pid;
-
-       /**
-        * The ELSP only accepts two elements at a time, so we queue
-        * context/tail pairs on a given queue (ring->execlist_queue) until the
-        * hardware is available. The queue serves a double purpose: we also use
-        * it to keep track of the up to 2 contexts currently in the hardware
-        * (usually one in execution and the other queued up by the GPU): We
-        * only remove elements from the head of the queue when the hardware
-        * informs us that an element has been completed.
-        *
-        * All accesses to the queue are mediated by a spinlock
-        * (ring->execlist_lock).
-        */
-
-       /** Execlist link in the submission queue.*/
-       struct list_head execlist_link;
-
-       /** Execlists no. of times this request has been sent to the ELSP */
-       int elsp_submitted;
-
-       /** Execlists context hardware id. */
-       unsigned ctx_hw_id;
-};
-
-struct drm_i915_gem_request * __must_check
-i915_gem_request_alloc(struct intel_engine_cs *engine,
-                      struct i915_gem_context *ctx);
-void i915_gem_request_free(struct kref *req_ref);
-int i915_gem_request_add_to_client(struct drm_i915_gem_request *req,
-                                  struct drm_file *file);
-
-static inline uint32_t
-i915_gem_request_get_seqno(struct drm_i915_gem_request *req)
-{
-       return req ? req->seqno : 0;
-}
-
-static inline struct intel_engine_cs *
-i915_gem_request_get_engine(struct drm_i915_gem_request *req)
-{
-       return req ? req->engine : NULL;
-}
-
-static inline struct drm_i915_gem_request *
-i915_gem_request_reference(struct drm_i915_gem_request *req)
-{
-       if (req)
-               kref_get(&req->ref);
-       return req;
-}
-
-static inline void
-i915_gem_request_unreference(struct drm_i915_gem_request *req)
-{
-       kref_put(&req->ref, i915_gem_request_free);
-}
-
-static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
-                                          struct drm_i915_gem_request *src)
-{
-       if (src)
-               i915_gem_request_reference(src);
-
-       if (*pdst)
-               i915_gem_request_unreference(*pdst);
-
-       *pdst = src;
-}
-
-/*
- * XXX: i915_gem_request_completed should be here but currently needs the
- * definition of i915_seqno_passed() which is below. It will be moved in
- * a later patch when the call to i915_seqno_passed() is obsoleted...
- */
-
 /*
  * A command that requires special handling by the command parser.
  */
@@ -2626,8 +2565,9 @@ struct drm_i915_cmd_descriptor {
 /*
  * A table of commands requiring special handling by the command parser.
  *
- * Each ring has an array of tables. Each table consists of an array of command
- * descriptors, which must be sorted with command opcodes in ascending order.
+ * Each engine has an array of tables. Each table consists of an array of
+ * command descriptors, which must be sorted with command opcodes in
+ * ascending order.
  */
 struct drm_i915_cmd_table {
        const struct drm_i915_cmd_descriptor *table;
@@ -2645,7 +2585,7 @@ struct drm_i915_cmd_table {
                BUILD_BUG(); \
        __p; \
 })
-#define INTEL_INFO(p)  (&__I915__(p)->info)
+#define INTEL_INFO(p)  (&__I915__(p)->info)
 #define INTEL_GEN(p)   (INTEL_INFO(p)->gen)
 #define INTEL_DEVID(p) (INTEL_INFO(p)->device_id)
 
@@ -2812,10 +2752,10 @@ struct drm_i915_cmd_table {
 #define HAS_EDRAM(dev)         (!!(__I915__(dev)->edram_cap & EDRAM_ENABLED))
 #define HAS_WT(dev)            ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && \
                                 HAS_EDRAM(dev))
-#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
+#define HWS_NEEDS_PHYSICAL(dev)        (INTEL_INFO(dev)->hws_needs_physical)
 
-#define HAS_HW_CONTEXTS(dev)   (INTEL_INFO(dev)->gen >= 6)
-#define HAS_LOGICAL_RING_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 8)
+#define HAS_HW_CONTEXTS(dev)   (INTEL_INFO(dev)->has_hw_contexts)
+#define HAS_LOGICAL_RING_CONTEXTS(dev) (INTEL_INFO(dev)->has_logical_ring_contexts)
 #define USES_PPGTT(dev)                (i915.enable_ppgtt)
 #define USES_FULL_PPGTT(dev)   (i915.enable_ppgtt >= 2)
 #define USES_FULL_48BIT_PPGTT(dev)     (i915.enable_ppgtt == 3)
@@ -2839,7 +2779,7 @@ struct drm_i915_cmd_table {
  * interrupt source and so prevents the other device from working properly.
  */
 #define HAS_AUX_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
-#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
+#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->has_gmbus_irq)
 
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
  * rows, which changed the alignment requirements and fence programming.
@@ -2855,38 +2795,27 @@ struct drm_i915_cmd_table {
 
 #define HAS_IPS(dev)           (IS_HSW_ULT(dev) || IS_BROADWELL(dev))
 
-#define HAS_DP_MST(dev)                (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
-                                INTEL_INFO(dev)->gen >= 9)
+#define HAS_DP_MST(dev)        (INTEL_INFO(dev)->has_dp_mst)
 
 #define HAS_DDI(dev)           (INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)    (INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)           (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
-                                IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || \
-                                IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
-#define HAS_RUNTIME_PM(dev)    (IS_GEN6(dev) || IS_HASWELL(dev) || \
-                                IS_BROADWELL(dev) || IS_VALLEYVIEW(dev) || \
-                                IS_CHERRYVIEW(dev) || IS_SKYLAKE(dev) || \
-                                IS_KABYLAKE(dev) || IS_BROXTON(dev))
-#define HAS_RC6(dev)           (INTEL_INFO(dev)->gen >= 6)
-#define HAS_RC6p(dev)          (IS_GEN6(dev) || IS_IVYBRIDGE(dev))
-
-#define HAS_CSR(dev)   (IS_GEN9(dev))
+#define HAS_PSR(dev)           (INTEL_INFO(dev)->has_psr)
+#define HAS_RUNTIME_PM(dev)    (INTEL_INFO(dev)->has_runtime_pm)
+#define HAS_RC6(dev)           (INTEL_INFO(dev)->has_rc6)
+#define HAS_RC6p(dev)          (INTEL_INFO(dev)->has_rc6p)
+
+#define HAS_CSR(dev)   (INTEL_INFO(dev)->has_csr)
 
 /*
  * For now, anything with a GuC requires uCode loading, and then supports
  * command submission once loaded. But these are logically independent
  * properties, so we have separate macros to test them.
  */
-#define HAS_GUC(dev)           (IS_GEN9(dev))
+#define HAS_GUC(dev)           (INTEL_INFO(dev)->has_guc)
 #define HAS_GUC_UCODE(dev)     (HAS_GUC(dev))
 #define HAS_GUC_SCHED(dev)     (HAS_GUC(dev))
 
-#define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \
-                                   INTEL_INFO(dev)->gen >= 8)
-
-#define HAS_CORE_RING_FREQ(dev)        (INTEL_INFO(dev)->gen >= 6 && \
-                                !IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) && \
-                                !IS_BROXTON(dev))
+#define HAS_RESOURCE_STREAMER(dev) (INTEL_INFO(dev)->has_resource_streamer)
 
 #define HAS_POOLED_EU(dev)     (INTEL_INFO(dev)->has_pooled_eu)
 
@@ -2914,11 +2843,10 @@ struct drm_i915_cmd_table {
 #define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP)
 #define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE)
 
-#define HAS_GMCH_DISPLAY(dev) (INTEL_INFO(dev)->gen < 5 || \
-                              IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
+#define HAS_GMCH_DISPLAY(dev) (INTEL_INFO(dev)->has_gmch_display)
 
 /* DPF == dynamic parity feature */
-#define HAS_L3_DPF(dev) (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
+#define HAS_L3_DPF(dev) (INTEL_INFO(dev)->has_l3_dpf)
 #define NUM_L3_SLICES(dev) (IS_HSW_GT3(dev) ? 2 : HAS_L3_DPF(dev))
 
 #define GT_FREQUENCY_MULTIPLIER 50
@@ -2939,7 +2867,9 @@ extern int i915_suspend_switcheroo(struct drm_device *dev, pm_message_t state);
 extern int i915_resume_switcheroo(struct drm_device *dev);
 
 int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
-                               int enable_ppgtt);
+                               int enable_ppgtt);
+
+bool intel_sanitize_semaphores(struct drm_i915_private *dev_priv, int value);
 
 /* i915_drv.c */
 void __printf(3, 4)
@@ -2955,7 +2885,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
 #endif
 extern int intel_gpu_reset(struct drm_i915_private *dev_priv, u32 engine_mask);
 extern bool intel_has_gpu_reset(struct drm_i915_private *dev_priv);
-extern int i915_reset(struct drm_i915_private *dev_priv);
+extern void i915_reset(struct drm_i915_private *dev_priv);
 extern int intel_guc_reset(struct drm_i915_private *dev_priv);
 extern void intel_engine_init_hangcheck(struct intel_engine_cs *engine);
 extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
@@ -3116,11 +3046,6 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
                             struct drm_file *file_priv);
-void i915_gem_execbuffer_move_to_active(struct list_head *vmas,
-                                       struct drm_i915_gem_request *req);
-int i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
-                                  struct drm_i915_gem_execbuffer2 *args,
-                                  struct list_head *vmas);
 int i915_gem_execbuffer(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 int i915_gem_execbuffer2(struct drm_device *dev, void *data,
@@ -3149,6 +3074,7 @@ int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
 void i915_gem_load_init(struct drm_device *dev);
 void i915_gem_load_cleanup(struct drm_device *dev);
 void i915_gem_load_init_fences(struct drm_i915_private *dev_priv);
+int i915_gem_freeze(struct drm_i915_private *dev_priv);
 int i915_gem_freeze_late(struct drm_i915_private *dev_priv);
 
 void *i915_gem_object_alloc(struct drm_device *dev);
@@ -3159,47 +3085,28 @@ struct drm_i915_gem_object *i915_gem_object_create(struct drm_device *dev,
                                                  size_t size);
 struct drm_i915_gem_object *i915_gem_object_create_from_data(
                struct drm_device *dev, const void *data, size_t size);
+void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file);
 void i915_gem_free_object(struct drm_gem_object *obj);
-void i915_gem_vma_destroy(struct i915_vma *vma);
-
-/* Flags used by pin/bind&friends. */
-#define PIN_MAPPABLE   (1<<0)
-#define PIN_NONBLOCK   (1<<1)
-#define PIN_GLOBAL     (1<<2)
-#define PIN_OFFSET_BIAS        (1<<3)
-#define PIN_USER       (1<<4)
-#define PIN_UPDATE     (1<<5)
-#define PIN_ZONE_4G    (1<<6)
-#define PIN_HIGH       (1<<7)
-#define PIN_OFFSET_FIXED       (1<<8)
-#define PIN_OFFSET_MASK (~4095)
-int __must_check
-i915_gem_object_pin(struct drm_i915_gem_object *obj,
-                   struct i915_address_space *vm,
-                   uint32_t alignment,
-                   uint64_t flags);
-int __must_check
+
+struct i915_vma * __must_check
 i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
                         const struct i915_ggtt_view *view,
-                        uint32_t alignment,
-                        uint64_t flags);
+                        u64 size,
+                        u64 alignment,
+                        u64 flags);
 
 int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
                  u32 flags);
 void __i915_vma_set_map_and_fenceable(struct i915_vma *vma);
 int __must_check i915_vma_unbind(struct i915_vma *vma);
-/*
- * BEWARE: Do not use the function below unless you can _absolutely_
- * _guarantee_ VMA in question is _not in use_ anywhere.
- */
-int __must_check __i915_vma_unbind_no_wait(struct i915_vma *vma);
+void i915_vma_close(struct i915_vma *vma);
+void i915_vma_destroy(struct i915_vma *vma);
+
+int i915_gem_object_unbind(struct drm_i915_gem_object *obj);
 int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
 void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
 void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
 
-int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
-                                   int *needs_clflush);
-
 int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
 
 static inline int __sg_page_count(struct scatterlist *sg)
@@ -3259,13 +3166,20 @@ static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
        obj->pages_pin_count--;
 }
 
+enum i915_map_type {
+       I915_MAP_WB = 0,
+       I915_MAP_WC,
+};
+
 /**
  * i915_gem_object_pin_map - return a contiguous mapping of the entire object
  * @obj - the object to map into kernel address space
+ * @type - the type of mapping, used to select pgprot_t
  *
  * Calls i915_gem_object_pin_pages() to prevent reaping of the object's
  * pages and then returns a contiguous mapping of the backing storage into
- * the kernel address space.
+ * the kernel address space. Based on the @type of mapping, the PTE will be
+ * set to either WriteBack or WriteCombine (via pgprot_t).
  *
  * The caller must hold the struct_mutex, and is responsible for calling
  * i915_gem_object_unpin_map() when the mapping is no longer required.
@@ -3273,7 +3187,8 @@ static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
  * Returns the pointer through which to access the mapped object, or an
  * ERR_PTR() on error.
  */
-void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj);
+void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
+                                          enum i915_map_type type);
 
 /**
  * i915_gem_object_unpin_map - releases an earlier mapping
@@ -3292,122 +3207,73 @@ static inline void i915_gem_object_unpin_map(struct drm_i915_gem_object *obj)
        i915_gem_object_unpin_pages(obj);
 }
 
+int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
+                                   unsigned int *needs_clflush);
+int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj,
+                                    unsigned int *needs_clflush);
+#define CLFLUSH_BEFORE 0x1
+#define CLFLUSH_AFTER 0x2
+#define CLFLUSH_FLAGS (CLFLUSH_BEFORE | CLFLUSH_AFTER)
+
+static inline void
+i915_gem_obj_finish_shmem_access(struct drm_i915_gem_object *obj)
+{
+       i915_gem_object_unpin_pages(obj);
+}
+
 int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
-int i915_gem_object_sync(struct drm_i915_gem_object *obj,
-                        struct intel_engine_cs *to,
-                        struct drm_i915_gem_request **to_req);
 void i915_vma_move_to_active(struct i915_vma *vma,
-                            struct drm_i915_gem_request *req);
+                            struct drm_i915_gem_request *req,
+                            unsigned int flags);
 int i915_gem_dumb_create(struct drm_file *file_priv,
                         struct drm_device *dev,
                         struct drm_mode_create_dumb *args);
 int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev,
                      uint32_t handle, uint64_t *offset);
+int i915_gem_mmap_gtt_version(void);
 
 void i915_gem_track_fb(struct drm_i915_gem_object *old,
                       struct drm_i915_gem_object *new,
                       unsigned frontbuffer_bits);
 
-/**
- * Returns true if seq1 is later than seq2.
- */
-static inline bool
-i915_seqno_passed(uint32_t seq1, uint32_t seq2)
-{
-       return (int32_t)(seq1 - seq2) >= 0;
-}
-
-static inline bool i915_gem_request_started(const struct drm_i915_gem_request *req)
-{
-       return i915_seqno_passed(intel_engine_get_seqno(req->engine),
-                                req->previous_seqno);
-}
-
-static inline bool i915_gem_request_completed(const struct drm_i915_gem_request *req)
-{
-       return i915_seqno_passed(intel_engine_get_seqno(req->engine),
-                                req->seqno);
-}
-
-bool __i915_spin_request(const struct drm_i915_gem_request *request,
-                        int state, unsigned long timeout_us);
-static inline bool i915_spin_request(const struct drm_i915_gem_request *request,
-                                    int state, unsigned long timeout_us)
-{
-       return (i915_gem_request_started(request) &&
-               __i915_spin_request(request, state, timeout_us));
-}
-
-int __must_check i915_gem_get_seqno(struct drm_i915_private *dev_priv, u32 *seqno);
 int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno);
 
 struct drm_i915_gem_request *
 i915_gem_find_active_request(struct intel_engine_cs *engine);
 
 void i915_gem_retire_requests(struct drm_i915_private *dev_priv);
-void i915_gem_retire_requests_ring(struct intel_engine_cs *engine);
-
-static inline u32 i915_reset_counter(struct i915_gpu_error *error)
-{
-       return atomic_read(&error->reset_counter);
-}
-
-static inline bool __i915_reset_in_progress(u32 reset)
-{
-       return unlikely(reset & I915_RESET_IN_PROGRESS_FLAG);
-}
-
-static inline bool __i915_reset_in_progress_or_wedged(u32 reset)
-{
-       return unlikely(reset & (I915_RESET_IN_PROGRESS_FLAG | I915_WEDGED));
-}
-
-static inline bool __i915_terminally_wedged(u32 reset)
-{
-       return unlikely(reset & I915_WEDGED);
-}
 
 static inline bool i915_reset_in_progress(struct i915_gpu_error *error)
 {
-       return __i915_reset_in_progress(i915_reset_counter(error));
+       return unlikely(test_bit(I915_RESET_IN_PROGRESS, &error->flags));
 }
 
-static inline bool i915_reset_in_progress_or_wedged(struct i915_gpu_error *error)
+static inline bool i915_terminally_wedged(struct i915_gpu_error *error)
 {
-       return __i915_reset_in_progress_or_wedged(i915_reset_counter(error));
+       return unlikely(test_bit(I915_WEDGED, &error->flags));
 }
 
-static inline bool i915_terminally_wedged(struct i915_gpu_error *error)
+static inline bool i915_reset_in_progress_or_wedged(struct i915_gpu_error *error)
 {
-       return __i915_terminally_wedged(i915_reset_counter(error));
+       return i915_reset_in_progress(error) | i915_terminally_wedged(error);
 }
 
 static inline u32 i915_reset_count(struct i915_gpu_error *error)
 {
-       return ((i915_reset_counter(error) & ~I915_WEDGED) + 1) / 2;
+       return READ_ONCE(error->reset_count);
 }
 
-void i915_gem_reset(struct drm_device *dev);
+void i915_gem_reset(struct drm_i915_private *dev_priv);
+void i915_gem_set_wedged(struct drm_i915_private *dev_priv);
 bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
 int __must_check i915_gem_init(struct drm_device *dev);
-int i915_gem_init_engines(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
 void i915_gem_init_swizzling(struct drm_device *dev);
 void i915_gem_cleanup_engines(struct drm_device *dev);
-int __must_check i915_gem_wait_for_idle(struct drm_i915_private *dev_priv);
+int __must_check i915_gem_wait_for_idle(struct drm_i915_private *dev_priv,
+                                       unsigned int flags);
 int __must_check i915_gem_suspend(struct drm_device *dev);
-void __i915_add_request(struct drm_i915_gem_request *req,
-                       struct drm_i915_gem_object *batch_obj,
-                       bool flush_caches);
-#define i915_add_request(req) \
-       __i915_add_request(req, NULL, true)
-#define i915_add_request_no_flush(req) \
-       __i915_add_request(req, NULL, false)
-int __i915_wait_request(struct drm_i915_gem_request *req,
-                       bool interruptible,
-                       s64 *timeout,
-                       struct intel_rps_client *rps);
-int __must_check i915_wait_request(struct drm_i915_gem_request *req);
+void i915_gem_resume(struct drm_device *dev);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int __must_check
 i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
@@ -3417,22 +3283,20 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
                                  bool write);
 int __must_check
 i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write);
-int __must_check
+struct i915_vma * __must_check
 i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
                                     const struct i915_ggtt_view *view);
-void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
-                                             const struct i915_ggtt_view *view);
+void i915_gem_object_unpin_from_display_plane(struct i915_vma *vma);
 int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
                                int align);
 int i915_gem_open(struct drm_device *dev, struct drm_file *file);
 void i915_gem_release(struct drm_device *dev, struct drm_file *file);
 
-uint32_t
-i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode);
-uint32_t
-i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size,
-                           int tiling_mode, bool fenced);
+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);
@@ -3443,86 +3307,82 @@ 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);
 
-u64 i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
-                                 const struct i915_ggtt_view *view);
-u64 i915_gem_obj_offset(struct drm_i915_gem_object *o,
-                       struct i915_address_space *vm);
-static inline u64
-i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *o)
-{
-       return i915_gem_obj_ggtt_offset_view(o, &i915_ggtt_view_normal);
-}
-
-bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o);
-bool i915_gem_obj_ggtt_bound_view(struct drm_i915_gem_object *o,
-                                 const struct i915_ggtt_view *view);
-bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
-                       struct i915_address_space *vm);
-
 struct i915_vma *
 i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
-                   struct i915_address_space *vm);
-struct i915_vma *
-i915_gem_obj_to_ggtt_view(struct drm_i915_gem_object *obj,
-                         const struct i915_ggtt_view *view);
+                    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);
-struct i915_vma *
-i915_gem_obj_lookup_or_create_ggtt_vma(struct drm_i915_gem_object *obj,
-                                      const struct i915_ggtt_view *view);
-
-static inline struct i915_vma *
-i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
-{
-       return i915_gem_obj_to_ggtt_view(obj, &i915_ggtt_view_normal);
-}
-bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj);
+                                 struct i915_address_space *vm,
+                                 const struct i915_ggtt_view *view);
 
-/* Some GGTT VM helpers */
 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 bool i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *obj)
+static inline unsigned long
+i915_gem_object_ggtt_offset(struct drm_i915_gem_object *o,
+                           const struct i915_ggtt_view *view)
 {
-       return i915_gem_obj_ggtt_bound_view(obj, &i915_ggtt_view_normal);
+       return i915_ggtt_offset(i915_gem_object_to_ggtt(o, view));
 }
 
-unsigned long
-i915_gem_obj_ggtt_size(struct drm_i915_gem_object *obj);
+/* i915_gem_fence.c */
+int __must_check i915_vma_get_fence(struct i915_vma *vma);
+int __must_check i915_vma_put_fence(struct i915_vma *vma);
 
-static inline int __must_check
-i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj,
-                     uint32_t alignment,
-                     unsigned flags)
+/**
+ * i915_vma_pin_fence - pin fencing state
+ * @vma: vma to pin fencing for
+ *
+ * This pins the fencing state (whether tiled or untiled) to make sure the
+ * vma (and its object) is ready to be used as a scanout target. Fencing
+ * status must be synchronize first by calling i915_vma_get_fence():
+ *
+ * The resulting fence pin reference must be released again with
+ * i915_vma_unpin_fence().
+ *
+ * Returns:
+ *
+ * True if the vma has a fence, false otherwise.
+ */
+static inline bool
+i915_vma_pin_fence(struct i915_vma *vma)
 {
-       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-
-       return i915_gem_object_pin(obj, &ggtt->base,
-                                  alignment, flags | PIN_GLOBAL);
+       if (vma->fence) {
+               vma->fence->pin_count++;
+               return true;
+       } else
+               return false;
 }
 
-void i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj,
-                                    const struct i915_ggtt_view *view);
+/**
+ * i915_vma_unpin_fence - unpin fencing state
+ * @vma: vma to unpin fencing for
+ *
+ * This releases the fence pin reference acquired through
+ * i915_vma_pin_fence. It will handle both objects with and without an
+ * attached fence correctly, callers do not need to distinguish this.
+ */
 static inline void
-i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
+i915_vma_unpin_fence(struct i915_vma *vma)
 {
-       i915_gem_object_ggtt_unpin_view(obj, &i915_ggtt_view_normal);
+       if (vma->fence) {
+               GEM_BUG_ON(vma->fence->pin_count <= 0);
+               vma->fence->pin_count--;
+       }
 }
 
-/* i915_gem_fence.c */
-int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
-int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj);
-
-bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj);
-void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj);
-
 void i915_gem_restore_fences(struct drm_device *dev);
 
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
@@ -3533,10 +3393,10 @@ void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_context_init(struct drm_device *dev);
 void i915_gem_context_lost(struct drm_i915_private *dev_priv);
 void i915_gem_context_fini(struct drm_device *dev);
-void i915_gem_context_reset(struct drm_device *dev);
 int i915_gem_context_open(struct drm_device *dev, struct drm_file *file);
 void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
 int i915_switch_context(struct drm_i915_gem_request *req);
+int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv);
 void i915_gem_context_free(struct kref *ctx_ref);
 struct drm_i915_gem_object *
 i915_gem_alloc_context_obj(struct drm_device *dev, size_t size);
@@ -3557,12 +3417,14 @@ i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
        return ctx;
 }
 
-static inline void i915_gem_context_reference(struct i915_gem_context *ctx)
+static inline struct i915_gem_context *
+i915_gem_context_get(struct i915_gem_context *ctx)
 {
        kref_get(&ctx->ref);
+       return ctx;
 }
 
-static inline void i915_gem_context_unreference(struct i915_gem_context *ctx)
+static inline void i915_gem_context_put(struct i915_gem_context *ctx)
 {
        lockdep_assert_held(&ctx->i915->drm.struct_mutex);
        kref_put(&ctx->ref, i915_gem_context_free);
@@ -3585,13 +3447,10 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev, void *data,
                                       struct drm_file *file);
 
 /* i915_gem_evict.c */
-int __must_check i915_gem_evict_something(struct drm_device *dev,
-                                         struct i915_address_space *vm,
-                                         int min_size,
-                                         unsigned alignment,
+int __must_check i915_gem_evict_something(struct i915_address_space *vm,
+                                         u64 min_size, u64 alignment,
                                          unsigned cache_level,
-                                         unsigned long start,
-                                         unsigned long end,
+                                         u64 start, u64 end,
                                          unsigned flags);
 int __must_check i915_gem_evict_for_vma(struct i915_vma *target);
 int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
@@ -3644,28 +3503,21 @@ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_objec
        struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
 
        return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 &&
-               obj->tiling_mode != I915_TILING_NONE;
+               i915_gem_object_is_tiled(obj);
 }
 
-/* i915_gem_debug.c */
-#if WATCH_LISTS
-int i915_verify_lists(struct drm_device *dev);
-#else
-#define i915_verify_lists(dev) 0
-#endif
-
 /* i915_debugfs.c */
 #ifdef CONFIG_DEBUG_FS
 int i915_debugfs_register(struct drm_i915_private *dev_priv);
 void i915_debugfs_unregister(struct drm_i915_private *dev_priv);
 int i915_debugfs_connector_add(struct drm_connector *connector);
-void intel_display_crc_init(struct drm_device *dev);
+void intel_display_crc_init(struct drm_i915_private *dev_priv);
 #else
 static inline int i915_debugfs_register(struct drm_i915_private *dev_priv) {return 0;}
 static inline void i915_debugfs_unregister(struct drm_i915_private *dev_priv) {}
 static inline int i915_debugfs_connector_add(struct drm_connector *connector)
 { return 0; }
-static inline void intel_display_crc_init(struct drm_device *dev) {}
+static inline void intel_display_crc_init(struct drm_i915_private *dev_priv) {}
 #endif
 
 /* i915_gpu_error.c */
@@ -3694,23 +3546,23 @@ const char *i915_cache_level_str(struct drm_i915_private *i915, int type);
 
 /* i915_cmd_parser.c */
 int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv);
-int i915_cmd_parser_init_ring(struct intel_engine_cs *engine);
-void i915_cmd_parser_fini_ring(struct intel_engine_cs *engine);
-bool i915_needs_cmd_parser(struct intel_engine_cs *engine);
-int i915_parse_cmds(struct intel_engine_cs *engine,
-                   struct drm_i915_gem_object *batch_obj,
-                   struct drm_i915_gem_object *shadow_batch_obj,
-                   u32 batch_start_offset,
-                   u32 batch_len,
-                   bool is_master);
+void intel_engine_init_cmd_parser(struct intel_engine_cs *engine);
+void intel_engine_cleanup_cmd_parser(struct intel_engine_cs *engine);
+bool intel_engine_needs_cmd_parser(struct intel_engine_cs *engine);
+int intel_engine_cmd_parser(struct intel_engine_cs *engine,
+                           struct drm_i915_gem_object *batch_obj,
+                           struct drm_i915_gem_object *shadow_batch_obj,
+                           u32 batch_start_offset,
+                           u32 batch_len,
+                           bool is_master);
 
 /* i915_suspend.c */
 extern int i915_save_state(struct drm_device *dev);
 extern int i915_restore_state(struct drm_device *dev);
 
 /* i915_sysfs.c */
-void i915_setup_sysfs(struct drm_device *dev_priv);
-void i915_teardown_sysfs(struct drm_device *dev_priv);
+void i915_setup_sysfs(struct drm_i915_private *dev_priv);
+void i915_teardown_sysfs(struct drm_i915_private *dev_priv);
 
 /* intel_i2c.c */
 extern int intel_setup_gmbus(struct drm_device *dev);
@@ -3810,7 +3662,6 @@ extern void intel_set_rps(struct drm_i915_private *dev_priv, u8 val);
 extern void intel_set_memory_cxsr(struct drm_i915_private *dev_priv,
                                  bool enable);
 
-extern bool i915_semaphore_is_enabled(struct drm_i915_private *dev_priv);
 int i915_reg_read_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file);
 
@@ -3888,9 +3739,16 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
  * will be implemented using 2 32-bit writes in an arbitrary order with
  * an arbitrary delay between them. This can cause the hardware to
  * act upon the intermediate value, possibly leading to corruption and
- * machine death. You have been warned.
+ * machine death. For this reason we do not support I915_WRITE64, or
+ * dev_priv->uncore.funcs.mmio_writeq.
+ *
+ * When reading a 64-bit value as two 32-bit values, the delay may cause
+ * the two reads to mismatch, e.g. a timestamp overflowing. Also note that
+ * occasionally a 64-bit register does not actualy support a full readq
+ * and must be read using two 32-bit reads.
+ *
+ * You have been warned.
  */
-#define I915_WRITE64(reg, val) dev_priv->uncore.funcs.mmio_writeq(dev_priv, (reg), (val), true)
 #define I915_READ64(reg)       dev_priv->uncore.funcs.mmio_readq(dev_priv, (reg), true)
 
 #define I915_READ64_2x32(lower_reg, upper_reg) ({                      \
@@ -3933,7 +3791,7 @@ __raw_write(64, q)
 #undef __raw_write
 
 /* These are untraced mmio-accessors that are only valid to be used inside
- * criticial sections inside IRQ handlers where forcewake is explicitly
+ * critical sections inside IRQ handlers where forcewake is explicitly
  * controlled.
  * Think twice, and think again, before using these.
  * Note: Should only be used between intel_uncore_forcewake_irqlock() and
@@ -4005,7 +3863,9 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
                            schedule_timeout_uninterruptible(remaining_jiffies);
        }
 }
-static inline bool __i915_request_irq_complete(struct drm_i915_gem_request *req)
+
+static inline bool
+__i915_request_irq_complete(struct drm_i915_gem_request *req)
 {
        struct intel_engine_cs *engine = req->engine;
 
@@ -4027,7 +3887,7 @@ static inline bool __i915_request_irq_complete(struct drm_i915_gem_request *req)
         * is woken.
         */
        if (engine->irq_seqno_barrier &&
-           READ_ONCE(engine->breadcrumbs.irq_seqno_bh) == current &&
+           rcu_access_pointer(engine->breadcrumbs.irq_seqno_bh) == current &&
            cmpxchg_relaxed(&engine->breadcrumbs.irq_posted, 1, 0)) {
                struct task_struct *tsk;
 
@@ -4052,7 +3912,7 @@ static inline bool __i915_request_irq_complete(struct drm_i915_gem_request *req)
                 * irq_posted == false but we are still running).
                 */
                rcu_read_lock();
-               tsk = READ_ONCE(engine->breadcrumbs.irq_seqno_bh);
+               tsk = rcu_dereference(engine->breadcrumbs.irq_seqno_bh);
                if (tsk && tsk != current)
                        /* Note that if the bottom-half is changed as we
                         * are sending the wake-up, the new bottom-half will
@@ -4067,18 +3927,35 @@ static inline bool __i915_request_irq_complete(struct drm_i915_gem_request *req)
                        return true;
        }
 
-       /* We need to check whether any gpu reset happened in between
-        * the request being submitted and now. If a reset has occurred,
-        * the seqno will have been advance past ours and our request
-        * is complete. If we are in the process of handling a reset,
-        * the request is effectively complete as the rendering will
-        * be discarded, but we need to return in order to drop the
-        * struct_mutex.
-        */
-       if (i915_reset_in_progress(&req->i915->gpu_error))
-               return true;
-
        return false;
 }
 
+void i915_memcpy_init_early(struct drm_i915_private *dev_priv);
+bool i915_memcpy_from_wc(void *dst, const void *src, unsigned long len);
+
+/* i915_mm.c */
+int remap_io_mapping(struct vm_area_struct *vma,
+                    unsigned long addr, unsigned long pfn, unsigned long size,
+                    struct io_mapping *iomap);
+
+#define ptr_mask_bits(ptr) ({                                          \
+       unsigned long __v = (unsigned long)(ptr);                       \
+       (typeof(ptr))(__v & PAGE_MASK);                                 \
+})
+
+#define ptr_unpack_bits(ptr, bits) ({                                  \
+       unsigned long __v = (unsigned long)(ptr);                       \
+       (bits) = __v & ~PAGE_MASK;                                      \
+       (typeof(ptr))(__v & PAGE_MASK);                                 \
+})
+
+#define ptr_pack_bits(ptr, bits)                                       \
+       ((typeof(ptr))((unsigned long)(ptr) | (bits)))
+
+#define fetch_and_zero(ptr) ({                                         \
+       typeof(*ptr) __T = *(ptr);                                      \
+       *(ptr) = (typeof(*ptr))0;                                       \
+       __T;                                                            \
+})
+
 #endif
index ccf56c6..947e82c 100644 (file)
 #include <drm/drm_vma_manager.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+#include "i915_gem_dmabuf.h"
 #include "i915_vgpu.h"
 #include "i915_trace.h"
 #include "intel_drv.h"
+#include "intel_frontbuffer.h"
 #include "intel_mocs.h"
+#include <linux/reservation.h>
 #include <linux/shmem_fs.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
 
 static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
 static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj);
-static void
-i915_gem_object_retire__write(struct drm_i915_gem_object *obj);
-static void
-i915_gem_object_retire__read(struct drm_i915_gem_object *obj, int ring);
 
 static bool cpu_cache_is_coherent(struct drm_device *dev,
                                  enum i915_cache_level level)
@@ -139,7 +138,6 @@ int i915_mutex_lock_interruptible(struct drm_device *dev)
        if (ret)
                return ret;
 
-       WARN_ON(i915_verify_lists(dev));
        return 0;
 }
 
@@ -156,10 +154,10 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
        pinned = 0;
        mutex_lock(&dev->struct_mutex);
        list_for_each_entry(vma, &ggtt->base.active_list, vm_link)
-               if (vma->pin_count)
+               if (i915_vma_is_pinned(vma))
                        pinned += vma->node.size;
        list_for_each_entry(vma, &ggtt->base.inactive_list, vm_link)
-               if (vma->pin_count)
+               if (i915_vma_is_pinned(vma))
                        pinned += vma->node.size;
        mutex_unlock(&dev->struct_mutex);
 
@@ -281,23 +279,129 @@ static const struct drm_i915_gem_object_ops i915_gem_phys_ops = {
        .release = i915_gem_object_release_phys,
 };
 
-static int
-drop_pages(struct drm_i915_gem_object *obj)
+int i915_gem_object_unbind(struct drm_i915_gem_object *obj)
 {
-       struct i915_vma *vma, *next;
+       struct i915_vma *vma;
+       LIST_HEAD(still_in_list);
        int ret;
 
-       drm_gem_object_reference(&obj->base);
-       list_for_each_entry_safe(vma, next, &obj->vma_list, obj_link)
-               if (i915_vma_unbind(vma))
-                       break;
+       lockdep_assert_held(&obj->base.dev->struct_mutex);
 
-       ret = i915_gem_object_put_pages(obj);
-       drm_gem_object_unreference(&obj->base);
+       /* Closed vma are removed from the obj->vma_list - but they may
+        * still have an active binding on the object. To remove those we
+        * must wait for all rendering to complete to the object (as unbinding
+        * must anyway), and retire the requests.
+        */
+       ret = i915_gem_object_wait_rendering(obj, false);
+       if (ret)
+               return ret;
+
+       i915_gem_retire_requests(to_i915(obj->base.dev));
+
+       while ((vma = list_first_entry_or_null(&obj->vma_list,
+                                              struct i915_vma,
+                                              obj_link))) {
+               list_move_tail(&vma->obj_link, &still_in_list);
+               ret = i915_vma_unbind(vma);
+               if (ret)
+                       break;
+       }
+       list_splice(&still_in_list, &obj->vma_list);
 
        return ret;
 }
 
+/**
+ * Ensures that all rendering to the object has completed and the object is
+ * safe to unbind from the GTT or access from the CPU.
+ * @obj: i915 gem object
+ * @readonly: waiting for just read access or read-write access
+ */
+int
+i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
+                              bool readonly)
+{
+       struct reservation_object *resv;
+       struct i915_gem_active *active;
+       unsigned long active_mask;
+       int idx;
+
+       lockdep_assert_held(&obj->base.dev->struct_mutex);
+
+       if (!readonly) {
+               active = obj->last_read;
+               active_mask = i915_gem_object_get_active(obj);
+       } else {
+               active_mask = 1;
+               active = &obj->last_write;
+       }
+
+       for_each_active(active_mask, idx) {
+               int ret;
+
+               ret = i915_gem_active_wait(&active[idx],
+                                          &obj->base.dev->struct_mutex);
+               if (ret)
+                       return ret;
+       }
+
+       resv = i915_gem_object_get_dmabuf_resv(obj);
+       if (resv) {
+               long err;
+
+               err = reservation_object_wait_timeout_rcu(resv, !readonly, true,
+                                                         MAX_SCHEDULE_TIMEOUT);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* A nonblocking variant of the above wait. Must be called prior to
+ * acquiring the mutex for the object, as the object state may change
+ * during this call. A reference must be held by the caller for the object.
+ */
+static __must_check int
+__unsafe_wait_rendering(struct drm_i915_gem_object *obj,
+                       struct intel_rps_client *rps,
+                       bool readonly)
+{
+       struct i915_gem_active *active;
+       unsigned long active_mask;
+       int idx;
+
+       active_mask = __I915_BO_ACTIVE(obj);
+       if (!active_mask)
+               return 0;
+
+       if (!readonly) {
+               active = obj->last_read;
+       } else {
+               active_mask = 1;
+               active = &obj->last_write;
+       }
+
+       for_each_active(active_mask, idx) {
+               int ret;
+
+               ret = i915_gem_active_wait_unlocked(&active[idx],
+                                                   I915_WAIT_INTERRUPTIBLE,
+                                                   NULL, rps);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static struct intel_rps_client *to_rps_client(struct drm_file *file)
+{
+       struct drm_i915_file_private *fpriv = file->driver_priv;
+
+       return &fpriv->rps;
+}
+
 int
 i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
                            int align)
@@ -318,7 +422,11 @@ i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
        if (obj->base.filp == NULL)
                return -EINVAL;
 
-       ret = drop_pages(obj);
+       ret = i915_gem_object_unbind(obj);
+       if (ret)
+               return ret;
+
+       ret = i915_gem_object_put_pages(obj);
        if (ret)
                return ret;
 
@@ -408,7 +516,7 @@ i915_gem_create(struct drm_file *file,
 
        ret = drm_gem_handle_create(file, &obj->base, &handle);
        /* drop reference from allocate - handle holds it now */
-       drm_gem_object_unreference_unlocked(&obj->base);
+       i915_gem_object_put_unlocked(obj);
        if (ret)
                return ret;
 
@@ -502,33 +610,106 @@ __copy_from_user_swizzled(char *gpu_vaddr, int gpu_offset,
  * flush the object from the CPU cache.
  */
 int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
-                                   int *needs_clflush)
+                                   unsigned int *needs_clflush)
 {
        int ret;
 
        *needs_clflush = 0;
 
-       if (WARN_ON(!i915_gem_object_has_struct_page(obj)))
-               return -EINVAL;
+       if (!i915_gem_object_has_struct_page(obj))
+               return -ENODEV;
+
+       ret = i915_gem_object_wait_rendering(obj, true);
+       if (ret)
+               return ret;
+
+       ret = i915_gem_object_get_pages(obj);
+       if (ret)
+               return ret;
+
+       i915_gem_object_pin_pages(obj);
+
+       i915_gem_object_flush_gtt_write_domain(obj);
 
-       if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) {
-               /* If we're not in the cpu read domain, set ourself into the gtt
-                * read domain and manually flush cachelines (if required). This
-                * optimizes for the case when the gpu will dirty the data
-                * anyway again before the next pread happens. */
+       /* If we're not in the cpu read domain, set ourself into the gtt
+        * read domain and manually flush cachelines (if required). This
+        * optimizes for the case when the gpu will dirty the data
+        * anyway again before the next pread happens.
+        */
+       if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU))
                *needs_clflush = !cpu_cache_is_coherent(obj->base.dev,
                                                        obj->cache_level);
-               ret = i915_gem_object_wait_rendering(obj, true);
+
+       if (*needs_clflush && !static_cpu_has(X86_FEATURE_CLFLUSH)) {
+               ret = i915_gem_object_set_to_cpu_domain(obj, false);
                if (ret)
-                       return ret;
+                       goto err_unpin;
+
+               *needs_clflush = 0;
        }
 
+       /* return with the pages pinned */
+       return 0;
+
+err_unpin:
+       i915_gem_object_unpin_pages(obj);
+       return ret;
+}
+
+int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj,
+                                    unsigned int *needs_clflush)
+{
+       int ret;
+
+       *needs_clflush = 0;
+       if (!i915_gem_object_has_struct_page(obj))
+               return -ENODEV;
+
+       ret = i915_gem_object_wait_rendering(obj, false);
+       if (ret)
+               return ret;
+
        ret = i915_gem_object_get_pages(obj);
        if (ret)
                return ret;
 
        i915_gem_object_pin_pages(obj);
 
+       i915_gem_object_flush_gtt_write_domain(obj);
+
+       /* If we're not in the cpu write domain, set ourself into the
+        * gtt write domain and manually flush cachelines (as required).
+        * This optimizes for the case when the gpu will use the data
+        * right away and we therefore have to clflush anyway.
+        */
+       if (obj->base.write_domain != I915_GEM_DOMAIN_CPU)
+               *needs_clflush |= cpu_write_needs_clflush(obj) << 1;
+
+       /* Same trick applies to invalidate partially written cachelines read
+        * before writing.
+        */
+       if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU))
+               *needs_clflush |= !cpu_cache_is_coherent(obj->base.dev,
+                                                        obj->cache_level);
+
+       if (*needs_clflush && !static_cpu_has(X86_FEATURE_CLFLUSH)) {
+               ret = i915_gem_object_set_to_cpu_domain(obj, true);
+               if (ret)
+                       goto err_unpin;
+
+               *needs_clflush = 0;
+       }
+
+       if ((*needs_clflush & CLFLUSH_AFTER) == 0)
+               obj->cache_dirty = true;
+
+       intel_fb_obj_invalidate(obj, ORIGIN_CPU);
+       obj->dirty = 1;
+       /* return with the pages pinned */
+       return 0;
+
+err_unpin:
+       i915_gem_object_unpin_pages(obj);
        return ret;
 }
 
@@ -638,14 +819,24 @@ i915_gem_gtt_pread(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
+       struct i915_vma *vma;
        struct drm_mm_node node;
        char __user *user_data;
        uint64_t remain;
        uint64_t offset;
        int ret;
 
-       ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_MAPPABLE);
-       if (ret) {
+       vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
+       if (!IS_ERR(vma)) {
+               node.start = i915_ggtt_offset(vma);
+               node.allocated = false;
+               ret = i915_vma_put_fence(vma);
+               if (ret) {
+                       i915_vma_unpin(vma);
+                       vma = ERR_PTR(ret);
+               }
+       }
+       if (IS_ERR(vma)) {
                ret = insert_mappable_node(dev_priv, &node, PAGE_SIZE);
                if (ret)
                        goto out;
@@ -657,12 +848,6 @@ i915_gem_gtt_pread(struct drm_device *dev,
                }
 
                i915_gem_object_pin_pages(obj);
-       } else {
-               node.start = i915_gem_obj_ggtt_offset(obj);
-               node.allocated = false;
-               ret = i915_gem_object_put_fence(obj);
-               if (ret)
-                       goto out_unpin;
        }
 
        ret = i915_gem_object_set_to_gtt_domain(obj, false);
@@ -707,7 +892,7 @@ i915_gem_gtt_pread(struct drm_device *dev,
                 * and write to user memory which may result into page
                 * faults, and so we cannot perform this under struct_mutex.
                 */
-               if (slow_user_access(ggtt->mappable, page_base,
+               if (slow_user_access(&ggtt->mappable, page_base,
                                     page_offset, user_data,
                                     page_length, false)) {
                        ret = -EFAULT;
@@ -739,7 +924,7 @@ out_unpin:
                i915_gem_object_unpin_pages(obj);
                remove_mappable_node(&node);
        } else {
-               i915_gem_object_ggtt_unpin(obj);
+               i915_vma_unpin(vma);
        }
 out:
        return ret;
@@ -760,19 +945,14 @@ i915_gem_shmem_pread(struct drm_device *dev,
        int needs_clflush = 0;
        struct sg_page_iter sg_iter;
 
-       if (!i915_gem_object_has_struct_page(obj))
-               return -ENODEV;
-
-       user_data = u64_to_user_ptr(args->data_ptr);
-       remain = args->size;
-
-       obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
-
        ret = i915_gem_obj_prepare_shmem_read(obj, &needs_clflush);
        if (ret)
                return ret;
 
+       obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
+       user_data = u64_to_user_ptr(args->data_ptr);
        offset = args->offset;
+       remain = args->size;
 
        for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
                         offset >> PAGE_SHIFT) {
@@ -828,7 +1008,7 @@ next_page:
        }
 
 out:
-       i915_gem_object_unpin_pages(obj);
+       i915_gem_obj_finish_shmem_access(obj);
 
        return ret;
 }
@@ -857,25 +1037,27 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
                       args->size))
                return -EFAULT;
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
-
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->handle));
-       if (&obj->base == NULL) {
-               ret = -ENOENT;
-               goto unlock;
-       }
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj)
+               return -ENOENT;
 
        /* Bounds check source.  */
        if (args->offset > obj->base.size ||
            args->size > obj->base.size - args->offset) {
                ret = -EINVAL;
-               goto out;
+               goto err;
        }
 
        trace_i915_gem_object_pread(obj, args->offset, args->size);
 
+       ret = __unsafe_wait_rendering(obj, to_rps_client(file), true);
+       if (ret)
+               goto err;
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               goto err;
+
        ret = i915_gem_shmem_pread(dev, obj, args, file);
 
        /* pread for non shmem backed objects */
@@ -886,10 +1068,13 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
                intel_runtime_pm_put(to_i915(dev));
        }
 
-out:
-       drm_gem_object_unreference(&obj->base);
-unlock:
+       i915_gem_object_put(obj);
        mutex_unlock(&dev->struct_mutex);
+
+       return ret;
+
+err:
+       i915_gem_object_put_unlocked(obj);
        return ret;
 }
 
@@ -919,7 +1104,7 @@ fast_user_write(struct io_mapping *mapping,
 /**
  * This is the fast pwrite path, where we copy the data directly from the
  * user into the GTT, uncached.
- * @dev: drm device pointer
+ * @i915: i915 device private data
  * @obj: i915 gem object
  * @args: pwrite arguments structure
  * @file: drm file pointer
@@ -932,17 +1117,28 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_private *i915,
 {
        struct i915_ggtt *ggtt = &i915->ggtt;
        struct drm_device *dev = obj->base.dev;
+       struct i915_vma *vma;
        struct drm_mm_node node;
        uint64_t remain, offset;
        char __user *user_data;
        int ret;
        bool hit_slow_path = false;
 
-       if (obj->tiling_mode != I915_TILING_NONE)
+       if (i915_gem_object_is_tiled(obj))
                return -EFAULT;
 
-       ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_MAPPABLE | PIN_NONBLOCK);
-       if (ret) {
+       vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
+                                      PIN_MAPPABLE | PIN_NONBLOCK);
+       if (!IS_ERR(vma)) {
+               node.start = i915_ggtt_offset(vma);
+               node.allocated = false;
+               ret = i915_vma_put_fence(vma);
+               if (ret) {
+                       i915_vma_unpin(vma);
+                       vma = ERR_PTR(ret);
+               }
+       }
+       if (IS_ERR(vma)) {
                ret = insert_mappable_node(i915, &node, PAGE_SIZE);
                if (ret)
                        goto out;
@@ -954,19 +1150,13 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_private *i915,
                }
 
                i915_gem_object_pin_pages(obj);
-       } else {
-               node.start = i915_gem_obj_ggtt_offset(obj);
-               node.allocated = false;
-               ret = i915_gem_object_put_fence(obj);
-               if (ret)
-                       goto out_unpin;
        }
 
        ret = i915_gem_object_set_to_gtt_domain(obj, true);
        if (ret)
                goto out_unpin;
 
-       intel_fb_obj_invalidate(obj, ORIGIN_GTT);
+       intel_fb_obj_invalidate(obj, ORIGIN_CPU);
        obj->dirty = true;
 
        user_data = u64_to_user_ptr(args->data_ptr);
@@ -998,11 +1188,11 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_private *i915,
                 * If the object is non-shmem backed, we retry again with the
                 * path that handles page fault.
                 */
-               if (fast_user_write(ggtt->mappable, page_base,
+               if (fast_user_write(&ggtt->mappable, page_base,
                                    page_offset, user_data, page_length)) {
                        hit_slow_path = true;
                        mutex_unlock(&dev->struct_mutex);
-                       if (slow_user_access(ggtt->mappable,
+                       if (slow_user_access(&ggtt->mappable,
                                             page_base,
                                             page_offset, user_data,
                                             page_length, true)) {
@@ -1033,7 +1223,7 @@ out_flush:
                }
        }
 
-       intel_fb_obj_flush(obj, false, ORIGIN_GTT);
+       intel_fb_obj_flush(obj, false, ORIGIN_CPU);
 out_unpin:
        if (node.allocated) {
                wmb();
@@ -1043,7 +1233,7 @@ out_unpin:
                i915_gem_object_unpin_pages(obj);
                remove_mappable_node(&node);
        } else {
-               i915_gem_object_ggtt_unpin(obj);
+               i915_vma_unpin(vma);
        }
 out:
        return ret;
@@ -1126,41 +1316,17 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
        int shmem_page_offset, page_length, ret = 0;
        int obj_do_bit17_swizzling, page_do_bit17_swizzling;
        int hit_slowpath = 0;
-       int needs_clflush_after = 0;
-       int needs_clflush_before = 0;
+       unsigned int needs_clflush;
        struct sg_page_iter sg_iter;
 
-       user_data = u64_to_user_ptr(args->data_ptr);
-       remain = args->size;
-
-       obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
-
-       if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
-               /* If we're not in the cpu write domain, set ourself into the gtt
-                * write domain and manually flush cachelines (if required). This
-                * optimizes for the case when the gpu will use the data
-                * right away and we therefore have to clflush anyway. */
-               needs_clflush_after = cpu_write_needs_clflush(obj);
-               ret = i915_gem_object_wait_rendering(obj, false);
-               if (ret)
-                       return ret;
-       }
-       /* Same trick applies to invalidate partially written cachelines read
-        * before writing. */
-       if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0)
-               needs_clflush_before =
-                       !cpu_cache_is_coherent(dev, obj->cache_level);
-
-       ret = i915_gem_object_get_pages(obj);
+       ret = i915_gem_obj_prepare_shmem_write(obj, &needs_clflush);
        if (ret)
                return ret;
 
-       intel_fb_obj_invalidate(obj, ORIGIN_CPU);
-
-       i915_gem_object_pin_pages(obj);
-
+       obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
+       user_data = u64_to_user_ptr(args->data_ptr);
        offset = args->offset;
-       obj->dirty = 1;
+       remain = args->size;
 
        for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
                         offset >> PAGE_SHIFT) {
@@ -1184,7 +1350,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
                /* If we don't overwrite a cacheline completely we need to be
                 * careful to have up-to-date data by first clflushing. Don't
                 * overcomplicate things and flush the entire patch. */
-               partial_cacheline_write = needs_clflush_before &&
+               partial_cacheline_write = needs_clflush & CLFLUSH_BEFORE &&
                        ((shmem_page_offset | page_length)
                                & (boot_cpu_data.x86_clflush_size - 1));
 
@@ -1194,7 +1360,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
                ret = shmem_pwrite_fast(page, shmem_page_offset, page_length,
                                        user_data, page_do_bit17_swizzling,
                                        partial_cacheline_write,
-                                       needs_clflush_after);
+                                       needs_clflush & CLFLUSH_AFTER);
                if (ret == 0)
                        goto next_page;
 
@@ -1203,7 +1369,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
                ret = shmem_pwrite_slow(page, shmem_page_offset, page_length,
                                        user_data, page_do_bit17_swizzling,
                                        partial_cacheline_write,
-                                       needs_clflush_after);
+                                       needs_clflush & CLFLUSH_AFTER);
 
                mutex_lock(&dev->struct_mutex);
 
@@ -1217,7 +1383,7 @@ next_page:
        }
 
 out:
-       i915_gem_object_unpin_pages(obj);
+       i915_gem_obj_finish_shmem_access(obj);
 
        if (hit_slowpath) {
                /*
@@ -1225,17 +1391,15 @@ out:
                 * cachelines in-line while writing and the object moved
                 * out of the cpu write domain while we've dropped the lock.
                 */
-               if (!needs_clflush_after &&
+               if (!(needs_clflush & CLFLUSH_AFTER) &&
                    obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
                        if (i915_gem_clflush_object(obj, obj->pin_display))
-                               needs_clflush_after = true;
+                               needs_clflush |= CLFLUSH_AFTER;
                }
        }
 
-       if (needs_clflush_after)
+       if (needs_clflush & CLFLUSH_AFTER)
                i915_gem_chipset_flush(to_i915(dev));
-       else
-               obj->cache_dirty = true;
 
        intel_fb_obj_flush(obj, false, ORIGIN_CPU);
        return ret;
@@ -1273,27 +1437,29 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                        return -EFAULT;
        }
 
-       intel_runtime_pm_get(dev_priv);
-
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               goto put_rpm;
-
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->handle));
-       if (&obj->base == NULL) {
-               ret = -ENOENT;
-               goto unlock;
-       }
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj)
+               return -ENOENT;
 
        /* Bounds check destination. */
        if (args->offset > obj->base.size ||
            args->size > obj->base.size - args->offset) {
                ret = -EINVAL;
-               goto out;
+               goto err;
        }
 
        trace_i915_gem_object_pwrite(obj, args->offset, args->size);
 
+       ret = __unsafe_wait_rendering(obj, to_rps_client(file), false);
+       if (ret)
+               goto err;
+
+       intel_runtime_pm_get(dev_priv);
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               goto err_rpm;
+
        ret = -EFAULT;
        /* We can only do the GTT pwrite on untiled buffers, as otherwise
         * it would end up going through the fenced access, and we'll get
@@ -1312,505 +1478,28 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
        if (ret == -EFAULT || ret == -ENOSPC) {
                if (obj->phys_handle)
                        ret = i915_gem_phys_pwrite(obj, args, file);
-               else if (i915_gem_object_has_struct_page(obj))
-                       ret = i915_gem_shmem_pwrite(dev, obj, args, file);
                else
-                       ret = -ENODEV;
+                       ret = i915_gem_shmem_pwrite(dev, obj, args, file);
        }
 
-out:
-       drm_gem_object_unreference(&obj->base);
-unlock:
+       i915_gem_object_put(obj);
        mutex_unlock(&dev->struct_mutex);
-put_rpm:
        intel_runtime_pm_put(dev_priv);
 
        return ret;
-}
-
-static int
-i915_gem_check_wedge(unsigned reset_counter, bool interruptible)
-{
-       if (__i915_terminally_wedged(reset_counter))
-               return -EIO;
-
-       if (__i915_reset_in_progress(reset_counter)) {
-               /* Non-interruptible callers can't handle -EAGAIN, hence return
-                * -EIO unconditionally for these. */
-               if (!interruptible)
-                       return -EIO;
-
-               return -EAGAIN;
-       }
 
-       return 0;
+err_rpm:
+       intel_runtime_pm_put(dev_priv);
+err:
+       i915_gem_object_put_unlocked(obj);
+       return ret;
 }
 
-static unsigned long local_clock_us(unsigned *cpu)
+static inline enum fb_op_origin
+write_origin(struct drm_i915_gem_object *obj, unsigned domain)
 {
-       unsigned long t;
-
-       /* Cheaply and approximately convert from nanoseconds to microseconds.
-        * The result and subsequent calculations are also defined in the same
-        * approximate microseconds units. The principal source of timing
-        * error here is from the simple truncation.
-        *
-        * Note that local_clock() is only defined wrt to the current CPU;
-        * the comparisons are no longer valid if we switch CPUs. Instead of
-        * blocking preemption for the entire busywait, we can detect the CPU
-        * switch and use that as indicator of system load and a reason to
-        * stop busywaiting, see busywait_stop().
-        */
-       *cpu = get_cpu();
-       t = local_clock() >> 10;
-       put_cpu();
-
-       return t;
-}
-
-static bool busywait_stop(unsigned long timeout, unsigned cpu)
-{
-       unsigned this_cpu;
-
-       if (time_after(local_clock_us(&this_cpu), timeout))
-               return true;
-
-       return this_cpu != cpu;
-}
-
-bool __i915_spin_request(const struct drm_i915_gem_request *req,
-                        int state, unsigned long timeout_us)
-{
-       unsigned cpu;
-
-       /* When waiting for high frequency requests, e.g. during synchronous
-        * rendering split between the CPU and GPU, the finite amount of time
-        * required to set up the irq and wait upon it limits the response
-        * rate. By busywaiting on the request completion for a short while we
-        * can service the high frequency waits as quick as possible. However,
-        * if it is a slow request, we want to sleep as quickly as possible.
-        * The tradeoff between waiting and sleeping is roughly the time it
-        * takes to sleep on a request, on the order of a microsecond.
-        */
-
-       timeout_us += local_clock_us(&cpu);
-       do {
-               if (i915_gem_request_completed(req))
-                       return true;
-
-               if (signal_pending_state(state, current))
-                       break;
-
-               if (busywait_stop(timeout_us, cpu))
-                       break;
-
-               cpu_relax_lowlatency();
-       } while (!need_resched());
-
-       return false;
-}
-
-/**
- * __i915_wait_request - wait until execution of request has finished
- * @req: duh!
- * @interruptible: do an interruptible wait (normally yes)
- * @timeout: in - how long to wait (NULL forever); out - how much time remaining
- * @rps: RPS client
- *
- * Note: It is of utmost importance that the passed in seqno and reset_counter
- * values have been read by the caller in an smp safe manner. Where read-side
- * locks are involved, it is sufficient to read the reset_counter before
- * unlocking the lock that protects the seqno. For lockless tricks, the
- * reset_counter _must_ be read before, and an appropriate smp_rmb must be
- * inserted.
- *
- * Returns 0 if the request was found within the alloted time. Else returns the
- * errno with remaining time filled in timeout argument.
- */
-int __i915_wait_request(struct drm_i915_gem_request *req,
-                       bool interruptible,
-                       s64 *timeout,
-                       struct intel_rps_client *rps)
-{
-       int state = interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
-       DEFINE_WAIT(reset);
-       struct intel_wait wait;
-       unsigned long timeout_remain;
-       s64 before = 0; /* Only to silence a compiler warning. */
-       int ret = 0;
-
-       might_sleep();
-
-       if (list_empty(&req->list))
-               return 0;
-
-       if (i915_gem_request_completed(req))
-               return 0;
-
-       timeout_remain = MAX_SCHEDULE_TIMEOUT;
-       if (timeout) {
-               if (WARN_ON(*timeout < 0))
-                       return -EINVAL;
-
-               if (*timeout == 0)
-                       return -ETIME;
-
-               timeout_remain = nsecs_to_jiffies_timeout(*timeout);
-
-               /*
-                * Record current time in case interrupted by signal, or wedged.
-                */
-               before = ktime_get_raw_ns();
-       }
-
-       trace_i915_gem_request_wait_begin(req);
-
-       /* This client is about to stall waiting for the GPU. In many cases
-        * this is undesirable and limits the throughput of the system, as
-        * many clients cannot continue processing user input/output whilst
-        * blocked. RPS autotuning may take tens of milliseconds to respond
-        * to the GPU load and thus incurs additional latency for the client.
-        * We can circumvent that by promoting the GPU frequency to maximum
-        * before we wait. This makes the GPU throttle up much more quickly
-        * (good for benchmarks and user experience, e.g. window animations),
-        * but at a cost of spending more power processing the workload
-        * (bad for battery). Not all clients even want their results
-        * immediately and for them we should just let the GPU select its own
-        * frequency to maximise efficiency. To prevent a single client from
-        * forcing the clocks too high for the whole system, we only allow
-        * each client to waitboost once in a busy period.
-        */
-       if (INTEL_INFO(req->i915)->gen >= 6)
-               gen6_rps_boost(req->i915, rps, req->emitted_jiffies);
-
-       /* Optimistic spin for the next ~jiffie before touching IRQs */
-       if (i915_spin_request(req, state, 5))
-               goto complete;
-
-       set_current_state(state);
-       add_wait_queue(&req->i915->gpu_error.wait_queue, &reset);
-
-       intel_wait_init(&wait, req->seqno);
-       if (intel_engine_add_wait(req->engine, &wait))
-               /* In order to check that we haven't missed the interrupt
-                * as we enabled it, we need to kick ourselves to do a
-                * coherent check on the seqno before we sleep.
-                */
-               goto wakeup;
-
-       for (;;) {
-               if (signal_pending_state(state, current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-
-               timeout_remain = io_schedule_timeout(timeout_remain);
-               if (timeout_remain == 0) {
-                       ret = -ETIME;
-                       break;
-               }
-
-               if (intel_wait_complete(&wait))
-                       break;
-
-               set_current_state(state);
-
-wakeup:
-               /* Carefully check if the request is complete, giving time
-                * for the seqno to be visible following the interrupt.
-                * We also have to check in case we are kicked by the GPU
-                * reset in order to drop the struct_mutex.
-                */
-               if (__i915_request_irq_complete(req))
-                       break;
-
-               /* Only spin if we know the GPU is processing this request */
-               if (i915_spin_request(req, state, 2))
-                       break;
-       }
-       remove_wait_queue(&req->i915->gpu_error.wait_queue, &reset);
-
-       intel_engine_remove_wait(req->engine, &wait);
-       __set_current_state(TASK_RUNNING);
-complete:
-       trace_i915_gem_request_wait_end(req);
-
-       if (timeout) {
-               s64 tres = *timeout - (ktime_get_raw_ns() - before);
-
-               *timeout = tres < 0 ? 0 : tres;
-
-               /*
-                * Apparently ktime isn't accurate enough and occasionally has a
-                * bit of mismatch in the jiffies<->nsecs<->ktime loop. So patch
-                * things up to make the test happy. We allow up to 1 jiffy.
-                *
-                * This is a regrssion from the timespec->ktime conversion.
-                */
-               if (ret == -ETIME && *timeout < jiffies_to_usecs(1)*1000)
-                       *timeout = 0;
-       }
-
-       if (rps && req->seqno == req->engine->last_submitted_seqno) {
-               /* The GPU is now idle and this client has stalled.
-                * Since no other client has submitted a request in the
-                * meantime, assume that this client is the only one
-                * supplying work to the GPU but is unable to keep that
-                * work supplied because it is waiting. Since the GPU is
-                * then never kept fully busy, RPS autoclocking will
-                * keep the clocks relatively low, causing further delays.
-                * Compensate by giving the synchronous client credit for
-                * a waitboost next time.
-                */
-               spin_lock(&req->i915->rps.client_lock);
-               list_del_init(&rps->link);
-               spin_unlock(&req->i915->rps.client_lock);
-       }
-
-       return ret;
-}
-
-int i915_gem_request_add_to_client(struct drm_i915_gem_request *req,
-                                  struct drm_file *file)
-{
-       struct drm_i915_file_private *file_priv;
-
-       WARN_ON(!req || !file || req->file_priv);
-
-       if (!req || !file)
-               return -EINVAL;
-
-       if (req->file_priv)
-               return -EINVAL;
-
-       file_priv = file->driver_priv;
-
-       spin_lock(&file_priv->mm.lock);
-       req->file_priv = file_priv;
-       list_add_tail(&req->client_list, &file_priv->mm.request_list);
-       spin_unlock(&file_priv->mm.lock);
-
-       req->pid = get_pid(task_pid(current));
-
-       return 0;
-}
-
-static inline void
-i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
-{
-       struct drm_i915_file_private *file_priv = request->file_priv;
-
-       if (!file_priv)
-               return;
-
-       spin_lock(&file_priv->mm.lock);
-       list_del(&request->client_list);
-       request->file_priv = NULL;
-       spin_unlock(&file_priv->mm.lock);
-
-       put_pid(request->pid);
-       request->pid = NULL;
-}
-
-static void i915_gem_request_retire(struct drm_i915_gem_request *request)
-{
-       trace_i915_gem_request_retire(request);
-
-       /* We know the GPU must have read the request to have
-        * sent us the seqno + interrupt, so use the position
-        * of tail of the request to update the last known position
-        * of the GPU head.
-        *
-        * Note this requires that we are always called in request
-        * completion order.
-        */
-       request->ringbuf->last_retired_head = request->postfix;
-
-       list_del_init(&request->list);
-       i915_gem_request_remove_from_client(request);
-
-       if (request->previous_context) {
-               if (i915.enable_execlists)
-                       intel_lr_context_unpin(request->previous_context,
-                                              request->engine);
-       }
-
-       i915_gem_context_unreference(request->ctx);
-       i915_gem_request_unreference(request);
-}
-
-static void
-__i915_gem_request_retire__upto(struct drm_i915_gem_request *req)
-{
-       struct intel_engine_cs *engine = req->engine;
-       struct drm_i915_gem_request *tmp;
-
-       lockdep_assert_held(&engine->i915->drm.struct_mutex);
-
-       if (list_empty(&req->list))
-               return;
-
-       do {
-               tmp = list_first_entry(&engine->request_list,
-                                      typeof(*tmp), list);
-
-               i915_gem_request_retire(tmp);
-       } while (tmp != req);
-
-       WARN_ON(i915_verify_lists(engine->dev));
-}
-
-/**
- * Waits for a request to be signaled, and cleans up the
- * request and object lists appropriately for that event.
- * @req: request to wait on
- */
-int
-i915_wait_request(struct drm_i915_gem_request *req)
-{
-       struct drm_i915_private *dev_priv = req->i915;
-       bool interruptible;
-       int ret;
-
-       interruptible = dev_priv->mm.interruptible;
-
-       BUG_ON(!mutex_is_locked(&dev_priv->drm.struct_mutex));
-
-       ret = __i915_wait_request(req, interruptible, NULL, NULL);
-       if (ret)
-               return ret;
-
-       /* If the GPU hung, we want to keep the requests to find the guilty. */
-       if (!i915_reset_in_progress(&dev_priv->gpu_error))
-               __i915_gem_request_retire__upto(req);
-
-       return 0;
-}
-
-/**
- * Ensures that all rendering to the object has completed and the object is
- * safe to unbind from the GTT or access from the CPU.
- * @obj: i915 gem object
- * @readonly: waiting for read access or write
- */
-int
-i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
-                              bool readonly)
-{
-       int ret, i;
-
-       if (!obj->active)
-               return 0;
-
-       if (readonly) {
-               if (obj->last_write_req != NULL) {
-                       ret = i915_wait_request(obj->last_write_req);
-                       if (ret)
-                               return ret;
-
-                       i = obj->last_write_req->engine->id;
-                       if (obj->last_read_req[i] == obj->last_write_req)
-                               i915_gem_object_retire__read(obj, i);
-                       else
-                               i915_gem_object_retire__write(obj);
-               }
-       } else {
-               for (i = 0; i < I915_NUM_ENGINES; i++) {
-                       if (obj->last_read_req[i] == NULL)
-                               continue;
-
-                       ret = i915_wait_request(obj->last_read_req[i]);
-                       if (ret)
-                               return ret;
-
-                       i915_gem_object_retire__read(obj, i);
-               }
-               GEM_BUG_ON(obj->active);
-       }
-
-       return 0;
-}
-
-static void
-i915_gem_object_retire_request(struct drm_i915_gem_object *obj,
-                              struct drm_i915_gem_request *req)
-{
-       int ring = req->engine->id;
-
-       if (obj->last_read_req[ring] == req)
-               i915_gem_object_retire__read(obj, ring);
-       else if (obj->last_write_req == req)
-               i915_gem_object_retire__write(obj);
-
-       if (!i915_reset_in_progress(&req->i915->gpu_error))
-               __i915_gem_request_retire__upto(req);
-}
-
-/* A nonblocking variant of the above wait. This is a highly dangerous routine
- * as the object state may change during this call.
- */
-static __must_check int
-i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj,
-                                           struct intel_rps_client *rps,
-                                           bool readonly)
-{
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_i915_gem_request *requests[I915_NUM_ENGINES];
-       int ret, i, n = 0;
-
-       BUG_ON(!mutex_is_locked(&dev->struct_mutex));
-       BUG_ON(!dev_priv->mm.interruptible);
-
-       if (!obj->active)
-               return 0;
-
-       if (readonly) {
-               struct drm_i915_gem_request *req;
-
-               req = obj->last_write_req;
-               if (req == NULL)
-                       return 0;
-
-               requests[n++] = i915_gem_request_reference(req);
-       } else {
-               for (i = 0; i < I915_NUM_ENGINES; i++) {
-                       struct drm_i915_gem_request *req;
-
-                       req = obj->last_read_req[i];
-                       if (req == NULL)
-                               continue;
-
-                       requests[n++] = i915_gem_request_reference(req);
-               }
-       }
-
-       mutex_unlock(&dev->struct_mutex);
-       ret = 0;
-       for (i = 0; ret == 0 && i < n; i++)
-               ret = __i915_wait_request(requests[i], true, NULL, rps);
-       mutex_lock(&dev->struct_mutex);
-
-       for (i = 0; i < n; i++) {
-               if (ret == 0)
-                       i915_gem_object_retire_request(obj, requests[i]);
-               i915_gem_request_unreference(requests[i]);
-       }
-
-       return ret;
-}
-
-static struct intel_rps_client *to_rps_client(struct drm_file *file)
-{
-       struct drm_i915_file_private *fpriv = file->driver_priv;
-       return &fpriv->rps;
-}
-
-static enum fb_op_origin
-write_origin(struct drm_i915_gem_object *obj, unsigned domain)
-{
-       return domain == I915_GEM_DOMAIN_GTT && !obj->has_wc_mmap ?
-              ORIGIN_GTT : ORIGIN_CPU;
+       return (domain == I915_GEM_DOMAIN_GTT ?
+               obj->frontbuffer_ggtt_origin : ORIGIN_CPU);
 }
 
 /**
@@ -1831,10 +1520,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        int ret;
 
        /* Only handle setting domains to types used by the CPU. */
-       if (write_domain & I915_GEM_GPU_DOMAINS)
-               return -EINVAL;
-
-       if (read_domains & I915_GEM_GPU_DOMAINS)
+       if ((write_domain | read_domains) & I915_GEM_GPU_DOMAINS)
                return -EINVAL;
 
        /* Having something in the write domain implies it's in the read
@@ -1843,25 +1529,21 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        if (write_domain != 0 && read_domains != write_domain)
                return -EINVAL;
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
-
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->handle));
-       if (&obj->base == NULL) {
-               ret = -ENOENT;
-               goto unlock;
-       }
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj)
+               return -ENOENT;
 
        /* Try to flush the object off the GPU without holding the lock.
         * We will repeat the flush holding the lock in the normal manner
         * to catch cases where we are gazumped.
         */
-       ret = i915_gem_object_wait_rendering__nonblocking(obj,
-                                                         to_rps_client(file),
-                                                         !write_domain);
+       ret = __unsafe_wait_rendering(obj, to_rps_client(file), !write_domain);
        if (ret)
-               goto unref;
+               goto err;
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               goto err;
 
        if (read_domains & I915_GEM_DOMAIN_GTT)
                ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
@@ -1871,11 +1553,13 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        if (write_domain != 0)
                intel_fb_obj_invalidate(obj, write_origin(obj, write_domain));
 
-unref:
-       drm_gem_object_unreference(&obj->base);
-unlock:
+       i915_gem_object_put(obj);
        mutex_unlock(&dev->struct_mutex);
        return ret;
+
+err:
+       i915_gem_object_put_unlocked(obj);
+       return ret;
 }
 
 /**
@@ -1890,26 +1574,23 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 {
        struct drm_i915_gem_sw_finish *args = data;
        struct drm_i915_gem_object *obj;
-       int ret = 0;
-
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
+       int err = 0;
 
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->handle));
-       if (&obj->base == NULL) {
-               ret = -ENOENT;
-               goto unlock;
-       }
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj)
+               return -ENOENT;
 
        /* Pinned buffers may be scanout, so flush the cache */
-       if (obj->pin_display)
-               i915_gem_object_flush_cpu_write_domain(obj);
+       if (READ_ONCE(obj->pin_display)) {
+               err = i915_mutex_lock_interruptible(dev);
+               if (!err) {
+                       i915_gem_object_flush_cpu_write_domain(obj);
+                       mutex_unlock(&dev->struct_mutex);
+               }
+       }
 
-       drm_gem_object_unreference(&obj->base);
-unlock:
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
+       i915_gem_object_put_unlocked(obj);
+       return err;
 }
 
 /**
@@ -1937,7 +1618,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
                    struct drm_file *file)
 {
        struct drm_i915_gem_mmap *args = data;
-       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj;
        unsigned long addr;
 
        if (args->flags & ~(I915_MMAP_WC))
@@ -1946,19 +1627,19 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
        if (args->flags & I915_MMAP_WC && !boot_cpu_has(X86_FEATURE_PAT))
                return -ENODEV;
 
-       obj = drm_gem_object_lookup(file, args->handle);
-       if (obj == NULL)
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj)
                return -ENOENT;
 
        /* prime objects have no backing filp to GEM mmap
         * pages from.
         */
-       if (!obj->filp) {
-               drm_gem_object_unreference_unlocked(obj);
+       if (!obj->base.filp) {
+               i915_gem_object_put_unlocked(obj);
                return -EINVAL;
        }
 
-       addr = vm_mmap(obj->filp, 0, args->size,
+       addr = vm_mmap(obj->base.filp, 0, args->size,
                       PROT_READ | PROT_WRITE, MAP_SHARED,
                       args->offset);
        if (args->flags & I915_MMAP_WC) {
@@ -1966,7 +1647,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
                struct vm_area_struct *vma;
 
                if (down_write_killable(&mm->mmap_sem)) {
-                       drm_gem_object_unreference_unlocked(obj);
+                       i915_gem_object_put_unlocked(obj);
                        return -EINTR;
                }
                vma = find_vma(mm, addr);
@@ -1978,9 +1659,9 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
                up_write(&mm->mmap_sem);
 
                /* This may race, but that's ok, it only gets set */
-               WRITE_ONCE(to_intel_bo(obj)->has_wc_mmap, true);
+               WRITE_ONCE(obj->frontbuffer_ggtt_origin, ORIGIN_CPU);
        }
-       drm_gem_object_unreference_unlocked(obj);
+       i915_gem_object_put_unlocked(obj);
        if (IS_ERR((void *)addr))
                return addr;
 
@@ -1989,9 +1670,69 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
        return 0;
 }
 
+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;
+}
+
+/**
+ * i915_gem_mmap_gtt_version - report the current feature set for GTT mmaps
+ *
+ * A history of the GTT mmap interface:
+ *
+ * 0 - Everything had to fit into the GTT. Both parties of a memcpy had to
+ *     aligned and suitable for fencing, and still fit into the available
+ *     mappable space left by the pinned display objects. A classic problem
+ *     we called the page-fault-of-doom where we would ping-pong between
+ *     two objects that could not fit inside the GTT and so the memcpy
+ *     would page one object in at the expense of the other between every
+ *     single byte.
+ *
+ * 1 - Objects can be any size, and have any compatible fencing (X Y, or none
+ *     as set via i915_gem_set_tiling() [DRM_I915_GEM_SET_TILING]). If the
+ *     object is too large for the available space (or simply too large
+ *     for the mappable aperture!), a view is created instead and faulted
+ *     into userspace. (This view is aligned and sized appropriately for
+ *     fenced access.)
+ *
+ * Restrictions:
+ *
+ *  * snoopable objects cannot be accessed via the GTT. It can cause machine
+ *    hangs on some architectures, corruption on others. An attempt to service
+ *    a GTT page fault from a snoopable object will generate a SIGBUS.
+ *
+ *  * the object must be able to fit into RAM (physical memory, though no
+ *    limited to the mappable aperture).
+ *
+ *
+ * Caveats:
+ *
+ *  * a new GTT page fault will synchronize rendering from the GPU and flush
+ *    all data to system memory. Subsequent access will not be synchronized.
+ *
+ *  * all mappings are revoked on runtime device suspend.
+ *
+ *  * there are only 8, 16 or 32 fence registers to share between all users
+ *    (older machines require fence register for display and blitter access
+ *    as well). Contention of the fence registers will cause the previous users
+ *    to be unmapped and any new access will generate new page faults.
+ *
+ *  * running out of memory while servicing a fault may generate a SIGBUS,
+ *    rather than the expected SIGSEGV.
+ */
+int i915_gem_mmap_gtt_version(void)
+{
+       return 1;
+}
+
 /**
  * i915_gem_fault - fault a page into the GTT
- * @vma: VMA in question
+ * @area: CPU VMA in question
  * @vmf: fault info
  *
  * The fault handler is set up by drm_gem_mmap() when a object is GTT mapped
@@ -2004,122 +1745,120 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
  * from the GTT and/or fence registers to make room.  So performance may
  * suffer if the GTT working set is large or there are few fence registers
  * left.
+ *
+ * The current feature set supported by i915_gem_fault() and thus GTT mmaps
+ * is exposed via I915_PARAM_MMAP_GTT_VERSION (see i915_gem_mmap_gtt_version).
  */
-int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf)
 {
-       struct drm_i915_gem_object *obj = to_intel_bo(vma->vm_private_data);
+#define MIN_CHUNK_PAGES ((1 << 20) >> PAGE_SHIFT) /* 1 MiB */
+       struct drm_i915_gem_object *obj = to_intel_bo(area->vm_private_data);
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       struct i915_ggtt_view view = i915_ggtt_view_normal;
-       pgoff_t page_offset;
-       unsigned long pfn;
-       int ret = 0;
        bool write = !!(vmf->flags & FAULT_FLAG_WRITE);
-
-       intel_runtime_pm_get(dev_priv);
+       struct i915_vma *vma;
+       pgoff_t page_offset;
+       unsigned int flags;
+       int ret;
 
        /* We don't use vmf->pgoff since that has the fake offset */
-       page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
+       page_offset = ((unsigned long)vmf->virtual_address - area->vm_start) >>
                PAGE_SHIFT;
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               goto out;
-
        trace_i915_gem_object_fault(obj, page_offset, true, write);
 
        /* Try to flush the object off the GPU first without holding the lock.
-        * Upon reacquiring the lock, we will perform our sanity checks and then
+        * Upon acquiring the lock, we will perform our sanity checks and then
         * repeat the flush holding the lock in the normal manner to catch cases
         * where we are gazumped.
         */
-       ret = i915_gem_object_wait_rendering__nonblocking(obj, NULL, !write);
+       ret = __unsafe_wait_rendering(obj, NULL, !write);
        if (ret)
-               goto unlock;
+               goto err;
+
+       intel_runtime_pm_get(dev_priv);
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               goto err_rpm;
 
        /* Access to snoopable pages through the GTT is incoherent. */
        if (obj->cache_level != I915_CACHE_NONE && !HAS_LLC(dev)) {
                ret = -EFAULT;
-               goto unlock;
+               goto err_unlock;
        }
 
-       /* Use a partial view if the object is bigger than the aperture. */
-       if (obj->base.size >= ggtt->mappable_end &&
-           obj->tiling_mode == I915_TILING_NONE) {
-               static const unsigned int chunk_size = 256; // 1 MiB
+       /* If the object is smaller than a couple of partial vma, it is
+        * not worth only creating a single partial vma - we may as well
+        * clear enough space for the full object.
+        */
+       flags = PIN_MAPPABLE;
+       if (obj->base.size > 2 * MIN_CHUNK_PAGES << PAGE_SHIFT)
+               flags |= PIN_NONBLOCK | PIN_NONFAULT;
+
+       /* 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 = max(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->vm_end - vma->vm_start)/PAGE_SIZE -
+                       min_t(unsigned int, chunk_size,
+                             (area->vm_end - area->vm_start) / PAGE_SIZE -
                              view.params.partial.offset);
-       }
 
-       /* Now pin it into the GTT if needed */
-       ret = i915_gem_object_ggtt_pin(obj, &view, 0, PIN_MAPPABLE);
-       if (ret)
-               goto unlock;
+               /* 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;
+
+               /* Userspace is now writing through an untracked VMA, abandon
+                * all hope that the hardware is able to track future writes.
+                */
+               obj->frontbuffer_ggtt_origin = ORIGIN_CPU;
+
+               vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE);
+       }
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
+               goto err_unlock;
+       }
 
        ret = i915_gem_object_set_to_gtt_domain(obj, write);
        if (ret)
-               goto unpin;
+               goto err_unpin;
 
-       ret = i915_gem_object_get_fence(obj);
+       ret = i915_vma_get_fence(vma);
        if (ret)
-               goto unpin;
+               goto err_unpin;
 
        /* Finally, remap it using the new GTT offset */
-       pfn = ggtt->mappable_base +
-               i915_gem_obj_ggtt_offset_view(obj, &view);
-       pfn >>= PAGE_SHIFT;
-
-       if (unlikely(view.type == I915_GGTT_VIEW_PARTIAL)) {
-               /* Overriding existing pages in partial view does not cause
-                * us any trouble as TLBs are still valid because the fault
-                * is due to userspace losing part of the mapping or never
-                * having accessed it before (at this partials' range).
-                */
-               unsigned long base = vma->vm_start +
-                                    (view.params.partial.offset << PAGE_SHIFT);
-               unsigned int i;
-
-               for (i = 0; i < view.params.partial.size; i++) {
-                       ret = vm_insert_pfn(vma, base + i * PAGE_SIZE, pfn + i);
-                       if (ret)
-                               break;
-               }
-
-               obj->fault_mappable = true;
-       } else {
-               if (!obj->fault_mappable) {
-                       unsigned long size = min_t(unsigned long,
-                                                  vma->vm_end - vma->vm_start,
-                                                  obj->base.size);
-                       int i;
-
-                       for (i = 0; i < size >> PAGE_SHIFT; i++) {
-                               ret = vm_insert_pfn(vma,
-                                                   (unsigned long)vma->vm_start + i * PAGE_SIZE,
-                                                   pfn + i);
-                               if (ret)
-                                       break;
-                       }
+       ret = remap_io_mapping(area,
+                              area->vm_start + (vma->ggtt_view.params.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);
+       if (ret)
+               goto err_unpin;
 
-                       obj->fault_mappable = true;
-               } else
-                       ret = vm_insert_pfn(vma,
-                                           (unsigned long)vmf->virtual_address,
-                                           pfn + page_offset);
-       }
-unpin:
-       i915_gem_object_ggtt_unpin_view(obj, &view);
-unlock:
+       obj->fault_mappable = true;
+err_unpin:
+       __i915_vma_unpin(vma);
+err_unlock:
        mutex_unlock(&dev->struct_mutex);
-out:
+err_rpm:
+       intel_runtime_pm_put(dev_priv);
+err:
        switch (ret) {
        case -EIO:
                /*
@@ -2160,8 +1899,6 @@ out:
                ret = VM_FAULT_SIGBUS;
                break;
        }
-
-       intel_runtime_pm_put(dev_priv);
        return ret;
 }
 
@@ -2215,46 +1952,58 @@ i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv)
                i915_gem_release_mmap(obj);
 }
 
-uint32_t
-i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode)
+/**
+ * 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)
 {
-       uint32_t gtt_size;
+       u64 ggtt_size;
+
+       GEM_BUG_ON(size == 0);
 
-       if (INTEL_INFO(dev)->gen >= 4 ||
+       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))
-               gtt_size = 1024*1024;
+       if (IS_GEN3(dev_priv))
+               ggtt_size = 1024*1024;
        else
-               gtt_size = 512*1024;
+               ggtt_size = 512*1024;
 
-       while (gtt_size < size)
-               gtt_size <<= 1;
+       while (ggtt_size < size)
+               ggtt_size <<= 1;
 
-       return gtt_size;
+       return ggtt_size;
 }
 
 /**
- * i915_gem_get_gtt_alignment - return required GTT alignment for an object
- * @dev: drm device
+ * i915_gem_get_ggtt_alignment - return required global GTT alignment
+ * @dev_priv: i915 device
  * @size: object size
  * @tiling_mode: tiling mode
- * @fenced: is fenced alignemned required or not
+ * @fenced: is fenced alignment required or not
  *
- * Return the required GTT alignment for an object, taking into account
+ * Return the required global GTT alignment for an object, taking into account
  * potential fence register mapping.
  */
-uint32_t
-i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size,
-                          int tiling_mode, bool fenced)
+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_INFO(dev)->gen >= 4 || (!fenced && IS_G33(dev)) ||
+       if (INTEL_GEN(dev_priv) >= 4 || (!fenced && IS_G33(dev_priv)) ||
            tiling_mode == I915_TILING_NONE)
                return 4096;
 
@@ -2262,42 +2011,34 @@ i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size,
         * Previous chips need to be aligned to the size of the smallest
         * fence register that can contain the object.
         */
-       return i915_gem_get_gtt_size(dev, size, tiling_mode);
+       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);
-       int ret;
-
-       dev_priv->mm.shrinker_no_lock_stealing = true;
+       int err;
 
-       ret = drm_gem_create_mmap_offset(&obj->base);
-       if (ret != -ENOSPC)
-               goto out;
+       err = drm_gem_create_mmap_offset(&obj->base);
+       if (!err)
+               return 0;
 
-       /* Badly fragmented mmap space? The only way we can recover
-        * space is by destroying unwanted objects. We can't randomly release
-        * mmap_offsets as userspace expects them to be persistent for the
-        * lifetime of the objects. The closest we can is to release the
-        * offsets on purgeable objects by truncating it and marking it purged,
-        * which prevents userspace from ever using that object again.
+       /* We can idle the GPU locklessly to flush stale objects, but in order
+        * to claim that space for ourselves, we need to take the big
+        * struct_mutex to free the requests+objects and allocate our slot.
         */
-       i915_gem_shrink(dev_priv,
-                       obj->base.size >> PAGE_SHIFT,
-                       I915_SHRINK_BOUND |
-                       I915_SHRINK_UNBOUND |
-                       I915_SHRINK_PURGEABLE);
-       ret = drm_gem_create_mmap_offset(&obj->base);
-       if (ret != -ENOSPC)
-               goto out;
+       err = i915_gem_wait_for_idle(dev_priv, I915_WAIT_INTERRUPTIBLE);
+       if (err)
+               return err;
 
-       i915_gem_shrink_all(dev_priv);
-       ret = drm_gem_create_mmap_offset(&obj->base);
-out:
-       dev_priv->mm.shrinker_no_lock_stealing = false;
+       err = i915_mutex_lock_interruptible(&dev_priv->drm);
+       if (!err) {
+               i915_gem_retire_requests(dev_priv);
+               err = drm_gem_create_mmap_offset(&obj->base);
+               mutex_unlock(&dev_priv->drm.struct_mutex);
+       }
 
-       return ret;
+       return err;
 }
 
 static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj)
@@ -2314,32 +2055,15 @@ i915_gem_mmap_gtt(struct drm_file *file,
        struct drm_i915_gem_object *obj;
        int ret;
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
-
-       obj = to_intel_bo(drm_gem_object_lookup(file, handle));
-       if (&obj->base == NULL) {
-               ret = -ENOENT;
-               goto unlock;
-       }
-
-       if (obj->madv != I915_MADV_WILLNEED) {
-               DRM_DEBUG("Attempting to mmap a purgeable buffer\n");
-               ret = -EFAULT;
-               goto out;
-       }
+       obj = i915_gem_object_lookup(file, handle);
+       if (!obj)
+               return -ENOENT;
 
        ret = i915_gem_object_create_mmap_offset(obj);
-       if (ret)
-               goto out;
+       if (ret == 0)
+               *offset = drm_vma_node_offset_addr(&obj->base.vma_node);
 
-       *offset = drm_vma_node_offset_addr(&obj->base.vma_node);
-
-out:
-       drm_gem_object_unreference(&obj->base);
-unlock:
-       mutex_unlock(&dev->struct_mutex);
+       i915_gem_object_put_unlocked(obj);
        return ret;
 }
 
@@ -2457,7 +2181,7 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
        if (obj->pages_pin_count)
                return -EBUSY;
 
-       BUG_ON(i915_gem_obj_bound_any(obj));
+       GEM_BUG_ON(obj->bind_count);
 
        /* ->put_pages might need to allocate memory for the bit17 swizzle
         * array, hence protect them from being reaped by removing them from gtt
@@ -2465,10 +2189,14 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
        list_del(&obj->global_list);
 
        if (obj->mapping) {
-               if (is_vmalloc_addr(obj->mapping))
-                       vunmap(obj->mapping);
+               void *ptr;
+
+               ptr = ptr_mask_bits(obj->mapping);
+               if (is_vmalloc_addr(ptr))
+                       vunmap(ptr);
                else
-                       kunmap(kmap_to_page(obj->mapping));
+                       kunmap(kmap_to_page(ptr));
+
                obj->mapping = NULL;
        }
 
@@ -2577,7 +2305,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
        if (i915_gem_object_needs_bit17_swizzle(obj))
                i915_gem_object_do_bit_17_swizzle(obj);
 
-       if (obj->tiling_mode != I915_TILING_NONE &&
+       if (i915_gem_object_is_tiled(obj) &&
            dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES)
                i915_gem_object_pin_pages(obj);
 
@@ -2641,7 +2369,8 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
 }
 
 /* The 'mapping' part of i915_gem_object_pin_map() below */
-static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
+static void *i915_gem_object_map(const struct drm_i915_gem_object *obj,
+                                enum i915_map_type type)
 {
        unsigned long n_pages = obj->base.size >> PAGE_SHIFT;
        struct sg_table *sgt = obj->pages;
@@ -2650,10 +2379,11 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
        struct page *stack_pages[32];
        struct page **pages = stack_pages;
        unsigned long i = 0;
+       pgprot_t pgprot;
        void *addr;
 
        /* A single page can always be kmapped */
-       if (n_pages == 1)
+       if (n_pages == 1 && type == I915_MAP_WB)
                return kmap(sg_page(sgt->sgl));
 
        if (n_pages > ARRAY_SIZE(stack_pages)) {
@@ -2669,7 +2399,15 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
        /* Check that we have the expected number of pages */
        GEM_BUG_ON(i != n_pages);
 
-       addr = vmap(pages, n_pages, 0, PAGE_KERNEL);
+       switch (type) {
+       case I915_MAP_WB:
+               pgprot = PAGE_KERNEL;
+               break;
+       case I915_MAP_WC:
+               pgprot = pgprot_writecombine(PAGE_KERNEL_IO);
+               break;
+       }
+       addr = vmap(pages, n_pages, 0, pgprot);
 
        if (pages != stack_pages)
                drm_free_large(pages);
@@ -2678,276 +2416,89 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
 }
 
 /* get, pin, and map the pages of the object into kernel space */
-void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj)
+void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
+                             enum i915_map_type type)
 {
+       enum i915_map_type has_type;
+       bool pinned;
+       void *ptr;
        int ret;
 
        lockdep_assert_held(&obj->base.dev->struct_mutex);
+       GEM_BUG_ON(!i915_gem_object_has_struct_page(obj));
 
        ret = i915_gem_object_get_pages(obj);
        if (ret)
                return ERR_PTR(ret);
 
        i915_gem_object_pin_pages(obj);
+       pinned = obj->pages_pin_count > 1;
 
-       if (!obj->mapping) {
-               obj->mapping = i915_gem_object_map(obj);
-               if (!obj->mapping) {
-                       i915_gem_object_unpin_pages(obj);
-                       return ERR_PTR(-ENOMEM);
+       ptr = ptr_unpack_bits(obj->mapping, has_type);
+       if (ptr && has_type != type) {
+               if (pinned) {
+                       ret = -EBUSY;
+                       goto err;
                }
-       }
-
-       return obj->mapping;
-}
 
-void i915_vma_move_to_active(struct i915_vma *vma,
-                            struct drm_i915_gem_request *req)
-{
-       struct drm_i915_gem_object *obj = vma->obj;
-       struct intel_engine_cs *engine;
-
-       engine = i915_gem_request_get_engine(req);
-
-       /* Add a reference if we're newly entering the active list. */
-       if (obj->active == 0)
-               drm_gem_object_reference(&obj->base);
-       obj->active |= intel_engine_flag(engine);
-
-       list_move_tail(&obj->engine_list[engine->id], &engine->active_list);
-       i915_gem_request_assign(&obj->last_read_req[engine->id], req);
-
-       list_move_tail(&vma->vm_link, &vma->vm->active_list);
-}
-
-static void
-i915_gem_object_retire__write(struct drm_i915_gem_object *obj)
-{
-       GEM_BUG_ON(obj->last_write_req == NULL);
-       GEM_BUG_ON(!(obj->active & intel_engine_flag(obj->last_write_req->engine)));
-
-       i915_gem_request_assign(&obj->last_write_req, NULL);
-       intel_fb_obj_flush(obj, true, ORIGIN_CS);
-}
-
-static void
-i915_gem_object_retire__read(struct drm_i915_gem_object *obj, int ring)
-{
-       struct i915_vma *vma;
-
-       GEM_BUG_ON(obj->last_read_req[ring] == NULL);
-       GEM_BUG_ON(!(obj->active & (1 << ring)));
-
-       list_del_init(&obj->engine_list[ring]);
-       i915_gem_request_assign(&obj->last_read_req[ring], NULL);
-
-       if (obj->last_write_req && obj->last_write_req->engine->id == ring)
-               i915_gem_object_retire__write(obj);
-
-       obj->active &= ~(1 << ring);
-       if (obj->active)
-               return;
-
-       /* Bump our place on the bound list to keep it roughly in LRU order
-        * so that we don't steal from recently used but inactive objects
-        * (unless we are forced to ofc!)
-        */
-       list_move_tail(&obj->global_list,
-                      &to_i915(obj->base.dev)->mm.bound_list);
-
-       list_for_each_entry(vma, &obj->vma_list, obj_link) {
-               if (!list_empty(&vma->vm_link))
-                       list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
-       }
-
-       i915_gem_request_assign(&obj->last_fenced_req, NULL);
-       drm_gem_object_unreference(&obj->base);
-}
-
-static int
-i915_gem_init_seqno(struct drm_i915_private *dev_priv, u32 seqno)
-{
-       struct intel_engine_cs *engine;
-       int ret;
-
-       /* Carefully retire all requests without writing to the rings */
-       for_each_engine(engine, dev_priv) {
-               ret = intel_engine_idle(engine);
-               if (ret)
-                       return ret;
-       }
-       i915_gem_retire_requests(dev_priv);
+               if (is_vmalloc_addr(ptr))
+                       vunmap(ptr);
+               else
+                       kunmap(kmap_to_page(ptr));
 
-       /* If the seqno wraps around, we need to clear the breadcrumb rbtree */
-       if (!i915_seqno_passed(seqno, dev_priv->next_seqno)) {
-               while (intel_kick_waiters(dev_priv) ||
-                      intel_kick_signalers(dev_priv))
-                       yield();
+               ptr = obj->mapping = NULL;
        }
 
-       /* Finally reset hw state */
-       for_each_engine(engine, dev_priv)
-               intel_ring_init_seqno(engine, seqno);
-
-       return 0;
-}
-
-int i915_gem_set_seqno(struct drm_device *dev, u32 seqno)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret;
-
-       if (seqno == 0)
-               return -EINVAL;
-
-       /* HWS page needs to be set less than what we
-        * will inject to ring
-        */
-       ret = i915_gem_init_seqno(dev_priv, seqno - 1);
-       if (ret)
-               return ret;
-
-       /* Carefully set the last_seqno value so that wrap
-        * detection still works
-        */
-       dev_priv->next_seqno = seqno;
-       dev_priv->last_seqno = seqno - 1;
-       if (dev_priv->last_seqno == 0)
-               dev_priv->last_seqno--;
-
-       return 0;
-}
-
-int
-i915_gem_get_seqno(struct drm_i915_private *dev_priv, u32 *seqno)
-{
-       /* reserve 0 for non-seqno */
-       if (dev_priv->next_seqno == 0) {
-               int ret = i915_gem_init_seqno(dev_priv, 0);
-               if (ret)
-                       return ret;
+       if (!ptr) {
+               ptr = i915_gem_object_map(obj, type);
+               if (!ptr) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
 
-               dev_priv->next_seqno = 1;
+               obj->mapping = ptr_pack_bits(ptr, type);
        }
 
-       *seqno = dev_priv->last_seqno = dev_priv->next_seqno++;
-       return 0;
-}
-
-static void i915_gem_mark_busy(const struct intel_engine_cs *engine)
-{
-       struct drm_i915_private *dev_priv = engine->i915;
-
-       dev_priv->gt.active_engines |= intel_engine_flag(engine);
-       if (dev_priv->gt.awake)
-               return;
-
-       intel_runtime_pm_get_noresume(dev_priv);
-       dev_priv->gt.awake = true;
-
-       i915_update_gfx_val(dev_priv);
-       if (INTEL_GEN(dev_priv) >= 6)
-               gen6_rps_busy(dev_priv);
+       return ptr;
 
-       queue_delayed_work(dev_priv->wq,
-                          &dev_priv->gt.retire_work,
-                          round_jiffies_up_relative(HZ));
+err:
+       i915_gem_object_unpin_pages(obj);
+       return ERR_PTR(ret);
 }
 
-/*
- * NB: This function is not allowed to fail. Doing so would mean the the
- * request is not being tracked for completion but the work itself is
- * going to happen on the hardware. This would be a Bad Thing(tm).
- */
-void __i915_add_request(struct drm_i915_gem_request *request,
-                       struct drm_i915_gem_object *obj,
-                       bool flush_caches)
+static void
+i915_gem_object_retire__write(struct i915_gem_active *active,
+                             struct drm_i915_gem_request *request)
 {
-       struct intel_engine_cs *engine;
-       struct intel_ringbuffer *ringbuf;
-       u32 request_start;
-       u32 reserved_tail;
-       int ret;
-
-       if (WARN_ON(request == NULL))
-               return;
-
-       engine = request->engine;
-       ringbuf = request->ringbuf;
-
-       /*
-        * To ensure that this call will not fail, space for its emissions
-        * should already have been reserved in the ring buffer. Let the ring
-        * know that it is time to use that space up.
-        */
-       request_start = intel_ring_get_tail(ringbuf);
-       reserved_tail = request->reserved_space;
-       request->reserved_space = 0;
-
-       /*
-        * Emit any outstanding flushes - execbuf can fail to emit the flush
-        * after having emitted the batchbuffer command. Hence we need to fix
-        * things up similar to emitting the lazy request. The difference here
-        * is that the flush _must_ happen before the next request, no matter
-        * what.
-        */
-       if (flush_caches) {
-               if (i915.enable_execlists)
-                       ret = logical_ring_flush_all_caches(request);
-               else
-                       ret = intel_ring_flush_all_caches(request);
-               /* Not allowed to fail! */
-               WARN(ret, "*_ring_flush_all_caches failed: %d!\n", ret);
-       }
-
-       trace_i915_gem_request_add(request);
+       struct drm_i915_gem_object *obj =
+               container_of(active, struct drm_i915_gem_object, last_write);
 
-       request->head = request_start;
+       intel_fb_obj_flush(obj, true, ORIGIN_CS);
+}
 
-       /* Whilst this request exists, batch_obj will be on the
-        * active_list, and so will hold the active reference. Only when this
-        * request is retired will the the batch_obj be moved onto the
-        * inactive_list and lose its active reference. Hence we do not need
-        * to explicitly hold another reference here.
-        */
-       request->batch_obj = obj;
+static void
+i915_gem_object_retire__read(struct i915_gem_active *active,
+                            struct drm_i915_gem_request *request)
+{
+       int idx = request->engine->id;
+       struct drm_i915_gem_object *obj =
+               container_of(active, struct drm_i915_gem_object, last_read[idx]);
 
-       /* Seal the request and mark it as pending execution. Note that
-        * we may inspect this state, without holding any locks, during
-        * hangcheck. Hence we apply the barrier to ensure that we do not
-        * see a more recent value in the hws than we are tracking.
-        */
-       request->emitted_jiffies = jiffies;
-       request->previous_seqno = engine->last_submitted_seqno;
-       smp_store_mb(engine->last_submitted_seqno, request->seqno);
-       list_add_tail(&request->list, &engine->request_list);
-
-       /* Record the position of the start of the request so that
-        * should we detect the updated seqno part-way through the
-        * GPU processing the request, we never over-estimate the
-        * position of the head.
-        */
-       request->postfix = intel_ring_get_tail(ringbuf);
+       GEM_BUG_ON(!i915_gem_object_has_active_engine(obj, idx));
 
-       if (i915.enable_execlists)
-               ret = engine->emit_request(request);
-       else {
-               ret = engine->add_request(request);
+       i915_gem_object_clear_active(obj, idx);
+       if (i915_gem_object_is_active(obj))
+               return;
 
-               request->tail = intel_ring_get_tail(ringbuf);
-       }
-       /* Not allowed to fail! */
-       WARN(ret, "emit|add_request failed: %d!\n", ret);
-       /* Sanity check that the reserved size was large enough. */
-       ret = intel_ring_get_tail(ringbuf) - request_start;
-       if (ret < 0)
-               ret += ringbuf->size;
-       WARN_ONCE(ret > reserved_tail,
-                 "Not enough space reserved (%d bytes) "
-                 "for adding the request (%d bytes)\n",
-                 reserved_tail, ret);
+       /* Bump our place on the bound list to keep it roughly in LRU order
+        * so that we don't steal from recently used but inactive objects
+        * (unless we are forced to ofc!)
+        */
+       if (obj->bind_count)
+               list_move_tail(&obj->global_list,
+                              &request->i915->mm.bound_list);
 
-       i915_gem_mark_busy(engine);
+       i915_gem_object_put(obj);
 }
 
 static bool i915_context_is_banned(const struct i915_gem_context *ctx)
@@ -2981,101 +2532,6 @@ static void i915_set_reset_status(struct i915_gem_context *ctx,
        }
 }
 
-void i915_gem_request_free(struct kref *req_ref)
-{
-       struct drm_i915_gem_request *req = container_of(req_ref,
-                                                typeof(*req), ref);
-       kmem_cache_free(req->i915->requests, req);
-}
-
-static inline int
-__i915_gem_request_alloc(struct intel_engine_cs *engine,
-                        struct i915_gem_context *ctx,
-                        struct drm_i915_gem_request **req_out)
-{
-       struct drm_i915_private *dev_priv = engine->i915;
-       unsigned reset_counter = i915_reset_counter(&dev_priv->gpu_error);
-       struct drm_i915_gem_request *req;
-       int ret;
-
-       if (!req_out)
-               return -EINVAL;
-
-       *req_out = NULL;
-
-       /* 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.
-        */
-       ret = i915_gem_check_wedge(reset_counter, dev_priv->mm.interruptible);
-       if (ret)
-               return ret;
-
-       req = kmem_cache_zalloc(dev_priv->requests, GFP_KERNEL);
-       if (req == NULL)
-               return -ENOMEM;
-
-       ret = i915_gem_get_seqno(engine->i915, &req->seqno);
-       if (ret)
-               goto err;
-
-       kref_init(&req->ref);
-       req->i915 = dev_priv;
-       req->engine = engine;
-       req->ctx  = ctx;
-       i915_gem_context_reference(req->ctx);
-
-       /*
-        * Reserve space in the ring buffer for all the commands required to
-        * eventually emit this request. This is to guarantee that the
-        * i915_add_request() call can't fail. Note that the reserve may need
-        * to be redone if the request is not actually submitted straight
-        * away, e.g. because a GPU scheduler has deferred it.
-        */
-       req->reserved_space = MIN_SPACE_FOR_ADD_REQUEST;
-
-       if (i915.enable_execlists)
-               ret = intel_logical_ring_alloc_request_extras(req);
-       else
-               ret = intel_ring_alloc_request_extras(req);
-       if (ret)
-               goto err_ctx;
-
-       *req_out = req;
-       return 0;
-
-err_ctx:
-       i915_gem_context_unreference(ctx);
-err:
-       kmem_cache_free(dev_priv->requests, req);
-       return ret;
-}
-
-/**
- * i915_gem_request_alloc - allocate a request structure
- *
- * @engine: engine that we wish to issue the request on.
- * @ctx: context that the request will be associated with.
- *       This can be NULL if the request is not directly related to
- *       any specific user context, in which case this function will
- *       choose an appropriate context to use.
- *
- * Returns a pointer to the allocated request if successful,
- * or an error code if not.
- */
-struct drm_i915_gem_request *
-i915_gem_request_alloc(struct intel_engine_cs *engine,
-                      struct i915_gem_context *ctx)
-{
-       struct drm_i915_gem_request *req;
-       int err;
-
-       if (ctx == NULL)
-               ctx = engine->i915->kernel_context;
-       err = __i915_gem_request_alloc(engine, ctx, &req);
-       return err ? ERR_PTR(err) : req;
-}
-
 struct drm_i915_gem_request *
 i915_gem_find_active_request(struct intel_engine_cs *engine)
 {
@@ -3089,185 +2545,143 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
         * extra delay for a recent interrupt is pointless. Hence, we do
         * not need an engine->irq_seqno_barrier() before the seqno reads.
         */
-       list_for_each_entry(request, &engine->request_list, list) {
+       list_for_each_entry(request, &engine->request_list, link) {
                if (i915_gem_request_completed(request))
                        continue;
 
+               if (!i915_sw_fence_done(&request->submit))
+                       break;
+
                return request;
        }
 
        return NULL;
 }
 
-static void i915_gem_reset_engine_status(struct intel_engine_cs *engine)
+static void reset_request(struct drm_i915_gem_request *request)
+{
+       void *vaddr = request->ring->vaddr;
+       u32 head;
+
+       /* As this request likely depends on state from the lost
+        * context, clear out all the user operations leaving the
+        * breadcrumb at the end (so we get the fence notifications).
+        */
+       head = request->head;
+       if (request->postfix < head) {
+               memset(vaddr + head, 0, request->ring->size - head);
+               head = 0;
+       }
+       memset(vaddr + head, 0, request->postfix - head);
+}
+
+static void i915_gem_reset_engine(struct intel_engine_cs *engine)
 {
        struct drm_i915_gem_request *request;
+       struct i915_gem_context *incomplete_ctx;
        bool ring_hung;
 
+       /* Ensure irq handler finishes, and not run again. */
+       tasklet_kill(&engine->irq_tasklet);
+       if (engine->irq_seqno_barrier)
+               engine->irq_seqno_barrier(engine);
+
        request = i915_gem_find_active_request(engine);
-       if (request == NULL)
+       if (!request)
                return;
 
        ring_hung = engine->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG;
-
        i915_set_reset_status(request->ctx, ring_hung);
-       list_for_each_entry_continue(request, &engine->request_list, list)
-               i915_set_reset_status(request->ctx, false);
-}
-
-static void i915_gem_reset_engine_cleanup(struct intel_engine_cs *engine)
-{
-       struct intel_ringbuffer *buffer;
-
-       while (!list_empty(&engine->active_list)) {
-               struct drm_i915_gem_object *obj;
-
-               obj = list_first_entry(&engine->active_list,
-                                      struct drm_i915_gem_object,
-                                      engine_list[engine->id]);
-
-               i915_gem_object_retire__read(obj, engine->id);
-       }
-
-       /*
-        * Clear the execlists queue up before freeing the requests, as those
-        * are the ones that keep the context and ringbuffer backing objects
-        * pinned in place.
-        */
-
-       if (i915.enable_execlists) {
-               /* Ensure irq handler finishes or is cancelled. */
-               tasklet_kill(&engine->irq_tasklet);
-
-               intel_execlists_cancel_requests(engine);
-       }
-
-       /*
-        * We must free the requests after all the corresponding objects have
-        * been moved off active lists. Which is the same order as the normal
-        * retire_requests function does. This is important if object hold
-        * implicit references on things like e.g. ppgtt address spaces through
-        * the request.
-        */
-       while (!list_empty(&engine->request_list)) {
-               struct drm_i915_gem_request *request;
+       if (!ring_hung)
+               return;
 
-               request = list_first_entry(&engine->request_list,
-                                          struct drm_i915_gem_request,
-                                          list);
+       DRM_DEBUG_DRIVER("resetting %s to restart from tail of request 0x%x\n",
+                        engine->name, request->fence.seqno);
 
-               i915_gem_request_retire(request);
-       }
+       /* Setup the CS to resume from the breadcrumb of the hung request */
+       engine->reset_hw(engine, request);
 
-       /* Having flushed all requests from all queues, we know that all
-        * ringbuffers must now be empty. However, since we do not reclaim
-        * all space when retiring the request (to prevent HEADs colliding
-        * with rapid ringbuffer wraparound) the amount of available space
-        * upon reset is less than when we start. Do one more pass over
-        * all the ringbuffers to reset last_retired_head.
+       /* 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.
         */
-       list_for_each_entry(buffer, &engine->buffers, link) {
-               buffer->last_retired_head = buffer->tail;
-               intel_ring_update_space(buffer);
-       }
-
-       intel_ring_init_seqno(engine, engine->last_submitted_seqno);
+       incomplete_ctx = request->ctx;
+       if (i915_gem_context_is_default(incomplete_ctx))
+               return;
 
-       engine->i915->gt.active_engines &= ~intel_engine_flag(engine);
+       list_for_each_entry_continue(request, &engine->request_list, link)
+               if (request->ctx == incomplete_ctx)
+                       reset_request(request);
 }
 
-void i915_gem_reset(struct drm_device *dev)
+void i915_gem_reset(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_engine_cs *engine;
 
-       /*
-        * Before we free the objects from the requests, we need to inspect
-        * them for finding the guilty party. As the requests only borrow
-        * their reference to the objects, the inspection must be done first.
-        */
-       for_each_engine(engine, dev_priv)
-               i915_gem_reset_engine_status(engine);
+       i915_gem_retire_requests(dev_priv);
 
        for_each_engine(engine, dev_priv)
-               i915_gem_reset_engine_cleanup(engine);
-       mod_delayed_work(dev_priv->wq, &dev_priv->gt.idle_work, 0);
+               i915_gem_reset_engine(engine);
 
-       i915_gem_context_reset(dev);
+       i915_gem_restore_fences(&dev_priv->drm);
 
-       i915_gem_restore_fences(dev);
+       if (dev_priv->gt.awake) {
+               intel_sanitize_gt_powersave(dev_priv);
+               intel_enable_gt_powersave(dev_priv);
+               if (INTEL_GEN(dev_priv) >= 6)
+                       gen6_rps_busy(dev_priv);
+       }
+}
 
-       WARN_ON(i915_verify_lists(dev));
+static void nop_submit_request(struct drm_i915_gem_request *request)
+{
 }
 
-/**
- * This function clears the request list as sequence numbers are passed.
- * @engine: engine to retire requests on
- */
-void
-i915_gem_retire_requests_ring(struct intel_engine_cs *engine)
+static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)
 {
-       WARN_ON(i915_verify_lists(engine->dev));
+       engine->submit_request = nop_submit_request;
 
-       /* Retire requests first as we use it above for the early return.
-        * If we retire requests last, we may use a later seqno and so clear
-        * the requests lists without clearing the active list, leading to
-        * confusion.
+       /* Mark all pending requests as complete so that any concurrent
+        * (lockless) lookup doesn't try and wait upon the request as we
+        * reset it.
         */
-       while (!list_empty(&engine->request_list)) {
-               struct drm_i915_gem_request *request;
-
-               request = list_first_entry(&engine->request_list,
-                                          struct drm_i915_gem_request,
-                                          list);
-
-               if (!i915_gem_request_completed(request))
-                       break;
-
-               i915_gem_request_retire(request);
-       }
+       intel_engine_init_seqno(engine, engine->last_submitted_seqno);
 
-       /* Move any buffers on the active list that are no longer referenced
-        * by the ringbuffer to the flushing/inactive lists as appropriate,
-        * before we free the context associated with the requests.
+       /*
+        * Clear the execlists queue up before freeing the requests, as those
+        * are the ones that keep the context and ringbuffer backing objects
+        * pinned in place.
         */
-       while (!list_empty(&engine->active_list)) {
-               struct drm_i915_gem_object *obj;
 
-               obj = list_first_entry(&engine->active_list,
-                                      struct drm_i915_gem_object,
-                                      engine_list[engine->id]);
-
-               if (!list_empty(&obj->last_read_req[engine->id]->list))
-                       break;
-
-               i915_gem_object_retire__read(obj, engine->id);
+       if (i915.enable_execlists) {
+               spin_lock(&engine->execlist_lock);
+               INIT_LIST_HEAD(&engine->execlist_queue);
+               i915_gem_request_put(engine->execlist_port[0].request);
+               i915_gem_request_put(engine->execlist_port[1].request);
+               memset(engine->execlist_port, 0, sizeof(engine->execlist_port));
+               spin_unlock(&engine->execlist_lock);
        }
 
-       WARN_ON(i915_verify_lists(engine->dev));
+       engine->i915->gt.active_engines &= ~intel_engine_flag(engine);
 }
 
-void i915_gem_retire_requests(struct drm_i915_private *dev_priv)
+void i915_gem_set_wedged(struct drm_i915_private *dev_priv)
 {
        struct intel_engine_cs *engine;
 
        lockdep_assert_held(&dev_priv->drm.struct_mutex);
+       set_bit(I915_WEDGED, &dev_priv->gpu_error.flags);
 
-       if (dev_priv->gt.active_engines == 0)
-               return;
-
-       GEM_BUG_ON(!dev_priv->gt.awake);
-
-       for_each_engine(engine, dev_priv) {
-               i915_gem_retire_requests_ring(engine);
-               if (list_empty(&engine->request_list))
-                       dev_priv->gt.active_engines &= ~intel_engine_flag(engine);
-       }
+       i915_gem_context_lost(dev_priv);
+       for_each_engine(engine, dev_priv)
+               i915_gem_cleanup_engine(engine);
+       mod_delayed_work(dev_priv->wq, &dev_priv->gt.idle_work, 0);
 
-       if (dev_priv->gt.active_engines == 0)
-               queue_delayed_work(dev_priv->wq,
-                                  &dev_priv->gt.idle_work,
-                                  msecs_to_jiffies(100));
+       i915_gem_retire_requests(dev_priv);
 }
 
 static void
@@ -3287,10 +2701,12 @@ i915_gem_retire_work_handler(struct work_struct *work)
         * We do not need to do this test under locking as in the worst-case
         * we queue the retire worker once too often.
         */
-       if (READ_ONCE(dev_priv->gt.awake))
+       if (READ_ONCE(dev_priv->gt.awake)) {
+               i915_queue_hangcheck(dev_priv);
                queue_delayed_work(dev_priv->wq,
                                   &dev_priv->gt.retire_work,
                                   round_jiffies_up_relative(HZ));
+       }
 }
 
 static void
@@ -3300,7 +2716,6 @@ i915_gem_idle_work_handler(struct work_struct *work)
                container_of(work, typeof(*dev_priv), gt.idle_work.work);
        struct drm_device *dev = &dev_priv->drm;
        struct intel_engine_cs *engine;
-       unsigned int stuck_engines;
        bool rearm_hangcheck;
 
        if (!READ_ONCE(dev_priv->gt.awake))
@@ -3321,303 +2736,98 @@ i915_gem_idle_work_handler(struct work_struct *work)
        }
 
        if (dev_priv->gt.active_engines)
-               goto out_unlock;
-
-       for_each_engine(engine, dev_priv)
-               i915_gem_batch_pool_fini(&engine->batch_pool);
-
-       GEM_BUG_ON(!dev_priv->gt.awake);
-       dev_priv->gt.awake = false;
-       rearm_hangcheck = false;
-
-       stuck_engines = intel_kick_waiters(dev_priv);
-       if (unlikely(stuck_engines)) {
-               DRM_DEBUG_DRIVER("kicked stuck waiters...missed irq\n");
-               dev_priv->gpu_error.missed_irq_rings |= stuck_engines;
-       }
-
-       if (INTEL_GEN(dev_priv) >= 6)
-               gen6_rps_idle(dev_priv);
-       intel_runtime_pm_put(dev_priv);
-out_unlock:
-       mutex_unlock(&dev->struct_mutex);
-
-out_rearm:
-       if (rearm_hangcheck) {
-               GEM_BUG_ON(!dev_priv->gt.awake);
-               i915_queue_hangcheck(dev_priv);
-       }
-}
-
-/**
- * Ensures that an object will eventually get non-busy by flushing any required
- * write domains, emitting any outstanding lazy request and retiring and
- * completed requests.
- * @obj: object to flush
- */
-static int
-i915_gem_object_flush_active(struct drm_i915_gem_object *obj)
-{
-       int i;
-
-       if (!obj->active)
-               return 0;
-
-       for (i = 0; i < I915_NUM_ENGINES; i++) {
-               struct drm_i915_gem_request *req;
-
-               req = obj->last_read_req[i];
-               if (req == NULL)
-                       continue;
-
-               if (i915_gem_request_completed(req))
-                       i915_gem_object_retire__read(obj, i);
-       }
-
-       return 0;
-}
-
-/**
- * i915_gem_wait_ioctl - implements DRM_IOCTL_I915_GEM_WAIT
- * @dev: drm device pointer
- * @data: ioctl data blob
- * @file: drm file pointer
- *
- * Returns 0 if successful, else an error is returned with the remaining time in
- * the timeout parameter.
- *  -ETIME: object is still busy after timeout
- *  -ERESTARTSYS: signal interrupted the wait
- *  -ENONENT: object doesn't exist
- * Also possible, but rare:
- *  -EAGAIN: GPU wedged
- *  -ENOMEM: damn
- *  -ENODEV: Internal IRQ fail
- *  -E?: The add request failed
- *
- * The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any
- * non-zero timeout parameter the wait ioctl will wait for the given number of
- * nanoseconds on an object becoming unbusy. Since the wait itself does so
- * without holding struct_mutex the object may become re-busied before this
- * function completes. A similar but shorter * race condition exists in the busy
- * ioctl
- */
-int
-i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
-{
-       struct drm_i915_gem_wait *args = data;
-       struct drm_i915_gem_object *obj;
-       struct drm_i915_gem_request *req[I915_NUM_ENGINES];
-       int i, n = 0;
-       int ret;
-
-       if (args->flags != 0)
-               return -EINVAL;
-
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
-
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->bo_handle));
-       if (&obj->base == NULL) {
-               mutex_unlock(&dev->struct_mutex);
-               return -ENOENT;
-       }
-
-       /* Need to make sure the object gets inactive eventually. */
-       ret = i915_gem_object_flush_active(obj);
-       if (ret)
-               goto out;
-
-       if (!obj->active)
-               goto out;
-
-       /* Do this after OLR check to make sure we make forward progress polling
-        * on this IOCTL with a timeout == 0 (like busy ioctl)
-        */
-       if (args->timeout_ns == 0) {
-               ret = -ETIME;
-               goto out;
-       }
-
-       drm_gem_object_unreference(&obj->base);
-
-       for (i = 0; i < I915_NUM_ENGINES; i++) {
-               if (obj->last_read_req[i] == NULL)
-                       continue;
-
-               req[n++] = i915_gem_request_reference(obj->last_read_req[i]);
-       }
-
-       mutex_unlock(&dev->struct_mutex);
-
-       for (i = 0; i < n; i++) {
-               if (ret == 0)
-                       ret = __i915_wait_request(req[i], true,
-                                                 args->timeout_ns > 0 ? &args->timeout_ns : NULL,
-                                                 to_rps_client(file));
-               i915_gem_request_unreference(req[i]);
-       }
-       return ret;
-
-out:
-       drm_gem_object_unreference(&obj->base);
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
-}
-
-static int
-__i915_gem_object_sync(struct drm_i915_gem_object *obj,
-                      struct intel_engine_cs *to,
-                      struct drm_i915_gem_request *from_req,
-                      struct drm_i915_gem_request **to_req)
-{
-       struct intel_engine_cs *from;
-       int ret;
-
-       from = i915_gem_request_get_engine(from_req);
-       if (to == from)
-               return 0;
-
-       if (i915_gem_request_completed(from_req))
-               return 0;
-
-       if (!i915_semaphore_is_enabled(to_i915(obj->base.dev))) {
-               struct drm_i915_private *i915 = to_i915(obj->base.dev);
-               ret = __i915_wait_request(from_req,
-                                         i915->mm.interruptible,
-                                         NULL,
-                                         &i915->rps.semaphores);
-               if (ret)
-                       return ret;
-
-               i915_gem_object_retire_request(obj, from_req);
-       } else {
-               int idx = intel_ring_sync_index(from, to);
-               u32 seqno = i915_gem_request_get_seqno(from_req);
-
-               WARN_ON(!to_req);
-
-               if (seqno <= from->semaphore.sync_seqno[idx])
-                       return 0;
-
-               if (*to_req == NULL) {
-                       struct drm_i915_gem_request *req;
+               goto out_unlock;
 
-                       req = i915_gem_request_alloc(to, NULL);
-                       if (IS_ERR(req))
-                               return PTR_ERR(req);
+       for_each_engine(engine, dev_priv)
+               i915_gem_batch_pool_fini(&engine->batch_pool);
 
-                       *to_req = req;
-               }
+       GEM_BUG_ON(!dev_priv->gt.awake);
+       dev_priv->gt.awake = false;
+       rearm_hangcheck = false;
 
-               trace_i915_gem_ring_sync_to(*to_req, from, from_req);
-               ret = to->semaphore.sync_to(*to_req, from, seqno);
-               if (ret)
-                       return ret;
+       if (INTEL_GEN(dev_priv) >= 6)
+               gen6_rps_idle(dev_priv);
+       intel_runtime_pm_put(dev_priv);
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
 
-               /* We use last_read_req because sync_to()
-                * might have just caused seqno wrap under
-                * the radar.
-                */
-               from->semaphore.sync_seqno[idx] =
-                       i915_gem_request_get_seqno(obj->last_read_req[from->id]);
+out_rearm:
+       if (rearm_hangcheck) {
+               GEM_BUG_ON(!dev_priv->gt.awake);
+               i915_queue_hangcheck(dev_priv);
        }
+}
 
-       return 0;
+void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
+{
+       struct drm_i915_gem_object *obj = to_intel_bo(gem);
+       struct drm_i915_file_private *fpriv = file->driver_priv;
+       struct i915_vma *vma, *vn;
+
+       mutex_lock(&obj->base.dev->struct_mutex);
+       list_for_each_entry_safe(vma, vn, &obj->vma_list, obj_link)
+               if (vma->vm->file == fpriv)
+                       i915_vma_close(vma);
+       mutex_unlock(&obj->base.dev->struct_mutex);
 }
 
 /**
- * i915_gem_object_sync - sync an object to a ring.
- *
- * @obj: object which may be in use on another ring.
- * @to: ring we wish to use the object on. May be NULL.
- * @to_req: request we wish to use the object for. See below.
- *          This will be allocated and returned if a request is
- *          required but not passed in.
- *
- * This code is meant to abstract object synchronization with the GPU.
- * Calling with NULL implies synchronizing the object with the CPU
- * rather than a particular GPU ring. Conceptually we serialise writes
- * between engines inside the GPU. We only allow one engine to write
- * into a buffer at any time, but multiple readers. To ensure each has
- * a coherent view of memory, we must:
- *
- * - If there is an outstanding write request to the object, the new
- *   request must wait for it to complete (either CPU or in hw, requests
- *   on the same ring will be naturally ordered).
- *
- * - If we are a write request (pending_write_domain is set), the new
- *   request must wait for outstanding read requests to complete.
+ * i915_gem_wait_ioctl - implements DRM_IOCTL_I915_GEM_WAIT
+ * @dev: drm device pointer
+ * @data: ioctl data blob
+ * @file: drm file pointer
  *
- * For CPU synchronisation (NULL to) no request is required. For syncing with
- * rings to_req must be non-NULL. However, a request does not have to be
- * pre-allocated. If *to_req is NULL and sync commands will be emitted then a
- * request will be allocated automatically and returned through *to_req. Note
- * that it is not guaranteed that commands will be emitted (because the system
- * might already be idle). Hence there is no need to create a request that
- * might never have any work submitted. Note further that if a request is
- * returned in *to_req, it is the responsibility of the caller to submit
- * that request (after potentially adding more work to it).
+ * Returns 0 if successful, else an error is returned with the remaining time in
+ * the timeout parameter.
+ *  -ETIME: object is still busy after timeout
+ *  -ERESTARTSYS: signal interrupted the wait
+ *  -ENONENT: object doesn't exist
+ * Also possible, but rare:
+ *  -EAGAIN: GPU wedged
+ *  -ENOMEM: damn
+ *  -ENODEV: Internal IRQ fail
+ *  -E?: The add request failed
  *
- * Returns 0 if successful, else propagates up the lower layer error.
+ * The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any
+ * non-zero timeout parameter the wait ioctl will wait for the given number of
+ * nanoseconds on an object becoming unbusy. Since the wait itself does so
+ * without holding struct_mutex the object may become re-busied before this
+ * function completes. A similar but shorter * race condition exists in the busy
+ * ioctl
  */
 int
-i915_gem_object_sync(struct drm_i915_gem_object *obj,
-                    struct intel_engine_cs *to,
-                    struct drm_i915_gem_request **to_req)
+i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 {
-       const bool readonly = obj->base.pending_write_domain == 0;
-       struct drm_i915_gem_request *req[I915_NUM_ENGINES];
-       int ret, i, n;
+       struct drm_i915_gem_wait *args = data;
+       struct intel_rps_client *rps = to_rps_client(file);
+       struct drm_i915_gem_object *obj;
+       unsigned long active;
+       int idx, ret = 0;
 
-       if (!obj->active)
-               return 0;
+       if (args->flags != 0)
+               return -EINVAL;
 
-       if (to == NULL)
-               return i915_gem_object_wait_rendering(obj, readonly);
+       obj = i915_gem_object_lookup(file, args->bo_handle);
+       if (!obj)
+               return -ENOENT;
 
-       n = 0;
-       if (readonly) {
-               if (obj->last_write_req)
-                       req[n++] = obj->last_write_req;
-       } else {
-               for (i = 0; i < I915_NUM_ENGINES; i++)
-                       if (obj->last_read_req[i])
-                               req[n++] = obj->last_read_req[i];
-       }
-       for (i = 0; i < n; i++) {
-               ret = __i915_gem_object_sync(obj, to, req[i], to_req);
+       active = __I915_BO_ACTIVE(obj);
+       for_each_active(active, idx) {
+               s64 *timeout = args->timeout_ns >= 0 ? &args->timeout_ns : NULL;
+               ret = i915_gem_active_wait_unlocked(&obj->last_read[idx],
+                                                   I915_WAIT_INTERRUPTIBLE,
+                                                   timeout, rps);
                if (ret)
-                       return ret;
+                       break;
        }
 
-       return 0;
-}
-
-static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj)
-{
-       u32 old_write_domain, old_read_domains;
-
-       /* Force a pagefault for domain tracking on next user access */
-       i915_gem_release_mmap(obj);
-
-       if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0)
-               return;
-
-       old_read_domains = obj->base.read_domains;
-       old_write_domain = obj->base.write_domain;
-
-       obj->base.read_domains &= ~I915_GEM_DOMAIN_GTT;
-       obj->base.write_domain &= ~I915_GEM_DOMAIN_GTT;
-
-       trace_i915_gem_object_change_domain(obj,
-                                           old_read_domains,
-                                           old_write_domain);
+       i915_gem_object_put_unlocked(obj);
+       return ret;
 }
 
 static void __i915_vma_iounmap(struct i915_vma *vma)
 {
-       GEM_BUG_ON(vma->pin_count);
+       GEM_BUG_ON(i915_vma_is_pinned(vma));
 
        if (vma->iomap == NULL)
                return;
@@ -3626,65 +2836,83 @@ static void __i915_vma_iounmap(struct i915_vma *vma)
        vma->iomap = NULL;
 }
 
-static int __i915_vma_unbind(struct i915_vma *vma, bool wait)
+int i915_vma_unbind(struct i915_vma *vma)
 {
        struct drm_i915_gem_object *obj = vma->obj;
-       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
+       unsigned long active;
        int ret;
 
-       if (list_empty(&vma->obj_link))
-               return 0;
-
-       if (!drm_mm_node_allocated(&vma->node)) {
-               i915_gem_vma_destroy(vma);
-               return 0;
-       }
-
-       if (vma->pin_count)
-               return -EBUSY;
+       /* First wait upon any activity as retiring the request may
+        * have side-effects such as unpinning or even unbinding this vma.
+        */
+       active = i915_vma_get_active(vma);
+       if (active) {
+               int idx;
+
+               /* When a closed VMA is retired, it is unbound - eek.
+                * In order to prevent it from being recursively closed,
+                * take a pin on the vma so that the second unbind is
+                * aborted.
+                */
+               __i915_vma_pin(vma);
 
-       BUG_ON(obj->pages == NULL);
+               for_each_active(active, idx) {
+                       ret = i915_gem_active_retire(&vma->last_read[idx],
+                                                  &vma->vm->dev->struct_mutex);
+                       if (ret)
+                               break;
+               }
 
-       if (wait) {
-               ret = i915_gem_object_wait_rendering(obj, false);
+               __i915_vma_unpin(vma);
                if (ret)
                        return ret;
+
+               GEM_BUG_ON(i915_vma_is_active(vma));
        }
 
-       if (vma->is_ggtt && vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
-               i915_gem_object_finish_gtt(obj);
+       if (i915_vma_is_pinned(vma))
+               return -EBUSY;
+
+       if (!drm_mm_node_allocated(&vma->node))
+               goto destroy;
+
+       GEM_BUG_ON(obj->bind_count == 0);
+       GEM_BUG_ON(!obj->pages);
 
+       if (i915_vma_is_map_and_fenceable(vma)) {
                /* release the fence reg _after_ flushing */
-               ret = i915_gem_object_put_fence(obj);
+               ret = i915_vma_put_fence(vma);
                if (ret)
                        return ret;
 
+               /* Force a pagefault for domain tracking on next user access */
+               i915_gem_release_mmap(obj);
+
                __i915_vma_iounmap(vma);
+               vma->flags &= ~I915_VMA_CAN_FENCE;
        }
 
-       trace_i915_vma_unbind(vma);
-
-       vma->vm->unbind_vma(vma);
-       vma->bound = 0;
-
-       list_del_init(&vma->vm_link);
-       if (vma->is_ggtt) {
-               if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
-                       obj->map_and_fenceable = false;
-               } else if (vma->ggtt_view.pages) {
-                       sg_free_table(vma->ggtt_view.pages);
-                       kfree(vma->ggtt_view.pages);
-               }
-               vma->ggtt_view.pages = NULL;
+       if (likely(!vma->vm->closed)) {
+               trace_i915_vma_unbind(vma);
+               vma->vm->unbind_vma(vma);
        }
+       vma->flags &= ~(I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND);
 
        drm_mm_remove_node(&vma->node);
-       i915_gem_vma_destroy(vma);
+       list_move_tail(&vma->vm_link, &vma->vm->unbound_list);
+
+       if (vma->pages != obj->pages) {
+               GEM_BUG_ON(!vma->pages);
+               sg_free_table(vma->pages);
+               kfree(vma->pages);
+       }
+       vma->pages = NULL;
 
        /* Since the unbound list is global, only move to that list if
         * no more VMAs exist. */
-       if (list_empty(&obj->vma_list))
-               list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
+       if (--obj->bind_count == 0)
+               list_move_tail(&obj->global_list,
+                              &to_i915(obj->base.dev)->mm.unbound_list);
 
        /* And finally now the object is completely decoupled from this vma,
         * we can drop its hold on the backing storage and allow it to be
@@ -3692,36 +2920,28 @@ static int __i915_vma_unbind(struct i915_vma *vma, bool wait)
         */
        i915_gem_object_unpin_pages(obj);
 
-       return 0;
-}
-
-int i915_vma_unbind(struct i915_vma *vma)
-{
-       return __i915_vma_unbind(vma, true);
-}
+destroy:
+       if (unlikely(i915_vma_is_closed(vma)))
+               i915_vma_destroy(vma);
 
-int __i915_vma_unbind_no_wait(struct i915_vma *vma)
-{
-       return __i915_vma_unbind(vma, false);
+       return 0;
 }
 
-int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv)
+int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv,
+                          unsigned int flags)
 {
        struct intel_engine_cs *engine;
        int ret;
 
-       lockdep_assert_held(&dev_priv->drm.struct_mutex);
-
        for_each_engine(engine, dev_priv) {
                if (engine->last_context == NULL)
                        continue;
 
-               ret = intel_engine_idle(engine);
+               ret = intel_engine_idle(engine, flags);
                if (ret)
                        return ret;
        }
 
-       WARN_ON(i915_verify_lists(dev));
        return 0;
 }
 
@@ -3759,128 +2979,87 @@ static bool i915_gem_valid_gtt_space(struct i915_vma *vma,
 }
 
 /**
- * Finds free space in the GTT aperture and binds the object or a view of it
- * there.
- * @obj: object to bind
- * @vm: address space to bind into
- * @ggtt_view: global gtt view if applicable
- * @alignment: requested alignment
+ * i915_vma_insert - finds a slot for the vma in its address space
+ * @vma: the vma
+ * @size: requested size in bytes (can be larger than the VMA)
+ * @alignment: required alignment
  * @flags: mask of PIN_* flags to use
+ *
+ * First we try to allocate some free space that meets the requirements for
+ * the VMA. Failiing that, if the flags permit, it will evict an old VMA,
+ * preferrably the oldest idle entry to make room for the new VMA.
+ *
+ * Returns:
+ * 0 on success, negative error code otherwise.
  */
-static struct i915_vma *
-i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
-                          struct i915_address_space *vm,
-                          const struct i915_ggtt_view *ggtt_view,
-                          unsigned alignment,
-                          uint64_t flags)
+static int
+i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       u32 fence_alignment, unfenced_alignment;
-       u32 search_flag, alloc_flag;
+       struct drm_i915_private *dev_priv = to_i915(vma->vm->dev);
+       struct drm_i915_gem_object *obj = vma->obj;
        u64 start, end;
-       u64 size, fence_size;
-       struct i915_vma *vma;
        int ret;
 
-       if (i915_is_ggtt(vm)) {
-               u32 view_size;
-
-               if (WARN_ON(!ggtt_view))
-                       return ERR_PTR(-EINVAL);
-
-               view_size = i915_ggtt_view_size(obj, ggtt_view);
-
-               fence_size = i915_gem_get_gtt_size(dev,
-                                                  view_size,
-                                                  obj->tiling_mode);
-               fence_alignment = i915_gem_get_gtt_alignment(dev,
-                                                            view_size,
-                                                            obj->tiling_mode,
-                                                            true);
-               unfenced_alignment = i915_gem_get_gtt_alignment(dev,
-                                                               view_size,
-                                                               obj->tiling_mode,
-                                                               false);
-               size = flags & PIN_MAPPABLE ? fence_size : view_size;
-       } else {
-               fence_size = i915_gem_get_gtt_size(dev,
-                                                  obj->base.size,
-                                                  obj->tiling_mode);
-               fence_alignment = i915_gem_get_gtt_alignment(dev,
-                                                            obj->base.size,
-                                                            obj->tiling_mode,
-                                                            true);
-               unfenced_alignment =
-                       i915_gem_get_gtt_alignment(dev,
-                                                  obj->base.size,
-                                                  obj->tiling_mode,
-                                                  false);
-               size = flags & PIN_MAPPABLE ? fence_size : obj->base.size;
-       }
+       GEM_BUG_ON(vma->flags & (I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND));
+       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(max(alignment, vma->display_alignment),
+                       i915_gem_get_ggtt_alignment(dev_priv, size,
+                                                   i915_gem_object_get_tiling(obj),
+                                                   flags & PIN_MAPPABLE));
 
        start = flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0;
-       end = vm->total;
+
+       end = vma->vm->total;
        if (flags & PIN_MAPPABLE)
-               end = min_t(u64, end, ggtt->mappable_end);
+               end = min_t(u64, end, dev_priv->ggtt.mappable_end);
        if (flags & PIN_ZONE_4G)
                end = min_t(u64, end, (1ULL << 32) - PAGE_SIZE);
 
-       if (alignment == 0)
-               alignment = flags & PIN_MAPPABLE ? fence_alignment :
-                                               unfenced_alignment;
-       if (flags & PIN_MAPPABLE && alignment & (fence_alignment - 1)) {
-               DRM_DEBUG("Invalid object (view type=%u) alignment requested %u\n",
-                         ggtt_view ? ggtt_view->type : 0,
-                         alignment);
-               return ERR_PTR(-EINVAL);
-       }
-
        /* If binding the object/GGTT view requires more space than the entire
         * aperture has, reject it early before evicting everything in a vain
         * attempt to find space.
         */
        if (size > end) {
-               DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%llu > %s aperture=%llu\n",
-                         ggtt_view ? ggtt_view->type : 0,
-                         size,
+               DRM_DEBUG("Attempting to bind an object larger than the aperture: request=%llu [object=%zd] > %s aperture=%llu\n",
+                         size, obj->base.size,
                          flags & PIN_MAPPABLE ? "mappable" : "total",
                          end);
-               return ERR_PTR(-E2BIG);
+               return -E2BIG;
        }
 
        ret = i915_gem_object_get_pages(obj);
        if (ret)
-               return ERR_PTR(ret);
+               return ret;
 
        i915_gem_object_pin_pages(obj);
 
-       vma = ggtt_view ? i915_gem_obj_lookup_or_create_ggtt_vma(obj, ggtt_view) :
-                         i915_gem_obj_lookup_or_create_vma(obj, vm);
-
-       if (IS_ERR(vma))
-               goto err_unpin;
-
        if (flags & PIN_OFFSET_FIXED) {
-               uint64_t offset = flags & PIN_OFFSET_MASK;
-
-               if (offset & (alignment - 1) || offset + size > end) {
+               u64 offset = flags & PIN_OFFSET_MASK;
+               if (offset & (alignment - 1) || offset > end - size) {
                        ret = -EINVAL;
-                       goto err_free_vma;
+                       goto err_unpin;
                }
+
                vma->node.start = offset;
                vma->node.size = size;
                vma->node.color = obj->cache_level;
-               ret = drm_mm_reserve_node(&vm->mm, &vma->node);
+               ret = drm_mm_reserve_node(&vma->vm->mm, &vma->node);
                if (ret) {
                        ret = i915_gem_evict_for_vma(vma);
                        if (ret == 0)
-                               ret = drm_mm_reserve_node(&vm->mm, &vma->node);
+                               ret = drm_mm_reserve_node(&vma->vm->mm, &vma->node);
+                       if (ret)
+                               goto err_unpin;
                }
-               if (ret)
-                       goto err_free_vma;
        } else {
+               u32 search_flag, alloc_flag;
+
                if (flags & PIN_HIGH) {
                        search_flag = DRM_MM_SEARCH_BELOW;
                        alloc_flag = DRM_MM_CREATE_TOP;
@@ -3889,47 +3068,45 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
                        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(&vm->mm, &vma->node,
+               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(dev, vm, size, alignment,
+                       ret = i915_gem_evict_something(vma->vm, size, alignment,
                                                       obj->cache_level,
                                                       start, end,
                                                       flags);
                        if (ret == 0)
                                goto search_free;
 
-                       goto err_free_vma;
+                       goto err_unpin;
                }
        }
-       if (WARN_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level))) {
-               ret = -EINVAL;
-               goto err_remove_node;
-       }
-
-       trace_i915_vma_bind(vma, flags);
-       ret = i915_vma_bind(vma, obj->cache_level, flags);
-       if (ret)
-               goto err_remove_node;
+       GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level));
 
        list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
-       list_add_tail(&vma->vm_link, &vm->inactive_list);
+       list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
+       obj->bind_count++;
 
-       return vma;
+       return 0;
 
-err_remove_node:
-       drm_mm_remove_node(&vma->node);
-err_free_vma:
-       i915_gem_vma_destroy(vma);
-       vma = ERR_PTR(ret);
 err_unpin:
        i915_gem_object_unpin_pages(obj);
-       return vma;
+       return ret;
 }
 
 bool
@@ -3974,51 +3151,72 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj,
 static void
 i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj)
 {
-       uint32_t old_write_domain;
+       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
 
        if (obj->base.write_domain != I915_GEM_DOMAIN_GTT)
                return;
 
        /* No actual flushing is required for the GTT write domain.  Writes
-        * to it immediately go to main memory as far as we know, so there's
+        * to it "immediately" go to main memory as far as we know, so there's
         * no chipset flush.  It also doesn't land in render cache.
         *
         * However, we do have to enforce the order so that all writes through
         * the GTT land before any writes to the device, such as updates to
         * the GATT itself.
+        *
+        * We also have to wait a bit for the writes to land from the GTT.
+        * An uncached read (i.e. mmio) seems to be ideal for the round-trip
+        * timing. This issue has only been observed when switching quickly
+        * between GTT writes and CPU reads from inside the kernel on recent hw,
+        * and it appears to only affect discrete GTT blocks (i.e. on LLC
+        * system agents we cannot reproduce this behaviour).
         */
        wmb();
+       if (INTEL_GEN(dev_priv) >= 6 && !HAS_LLC(dev_priv))
+               POSTING_READ(RING_ACTHD(dev_priv->engine[RCS].mmio_base));
 
-       old_write_domain = obj->base.write_domain;
-       obj->base.write_domain = 0;
-
-       intel_fb_obj_flush(obj, false, ORIGIN_GTT);
+       intel_fb_obj_flush(obj, false, write_origin(obj, I915_GEM_DOMAIN_GTT));
 
+       obj->base.write_domain = 0;
        trace_i915_gem_object_change_domain(obj,
                                            obj->base.read_domains,
-                                           old_write_domain);
+                                           I915_GEM_DOMAIN_GTT);
 }
 
 /** Flushes the CPU write domain for the object if it's dirty. */
 static void
 i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj)
 {
-       uint32_t old_write_domain;
-
        if (obj->base.write_domain != I915_GEM_DOMAIN_CPU)
                return;
 
        if (i915_gem_clflush_object(obj, obj->pin_display))
                i915_gem_chipset_flush(to_i915(obj->base.dev));
 
-       old_write_domain = obj->base.write_domain;
-       obj->base.write_domain = 0;
-
        intel_fb_obj_flush(obj, false, ORIGIN_CPU);
 
+       obj->base.write_domain = 0;
        trace_i915_gem_object_change_domain(obj,
                                            obj->base.read_domains,
-                                           old_write_domain);
+                                           I915_GEM_DOMAIN_CPU);
+}
+
+static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj)
+{
+       struct i915_vma *vma;
+
+       list_for_each_entry(vma, &obj->vma_list, obj_link) {
+               if (!i915_vma_is_ggtt(vma))
+                       continue;
+
+               if (i915_vma_is_active(vma))
+                       continue;
+
+               if (!drm_mm_node_allocated(&vma->node))
+                       continue;
+
+               list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
+       }
 }
 
 /**
@@ -4032,20 +3230,16 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj)
 int
 i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
        uint32_t old_write_domain, old_read_domains;
-       struct i915_vma *vma;
        int ret;
 
-       if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
-               return 0;
-
        ret = i915_gem_object_wait_rendering(obj, !write);
        if (ret)
                return ret;
 
+       if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
+               return 0;
+
        /* Flush and acquire obj->pages so that we are coherent through
         * direct access in memory with previous cached writes through
         * shmemfs and that our cache domain tracking remains valid.
@@ -4086,10 +3280,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
                                            old_write_domain);
 
        /* And bump the LRU for this access */
-       vma = i915_gem_obj_to_ggtt(obj);
-       if (vma && drm_mm_node_allocated(&vma->node) && !obj->active)
-               list_move_tail(&vma->vm_link,
-                              &ggtt->base.inactive_list);
+       i915_gem_object_bump_inactive_ggtt(obj);
 
        return 0;
 }
@@ -4112,9 +3303,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
                                    enum i915_cache_level cache_level)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct i915_vma *vma, *next;
-       bool bound = false;
+       struct i915_vma *vma;
        int ret = 0;
 
        if (obj->cache_level == cache_level)
@@ -4125,21 +3314,28 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
         * catch the issue of the CS prefetch crossing page boundaries and
         * reading an invalid PTE on older architectures.
         */
-       list_for_each_entry_safe(vma, next, &obj->vma_list, obj_link) {
+restart:
+       list_for_each_entry(vma, &obj->vma_list, obj_link) {
                if (!drm_mm_node_allocated(&vma->node))
                        continue;
 
-               if (vma->pin_count) {
+               if (i915_vma_is_pinned(vma)) {
                        DRM_DEBUG("can not change the cache level of pinned objects\n");
                        return -EBUSY;
                }
 
-               if (!i915_gem_valid_gtt_space(vma, cache_level)) {
-                       ret = i915_vma_unbind(vma);
-                       if (ret)
-                               return ret;
-               } else
-                       bound = true;
+               if (i915_gem_valid_gtt_space(vma, cache_level))
+                       continue;
+
+               ret = i915_vma_unbind(vma);
+               if (ret)
+                       return ret;
+
+               /* As unbinding may affect other elements in the
+                * obj->vma_list (due to side-effects from retiring
+                * an active vma), play safe and restart the iterator.
+                */
+               goto restart;
        }
 
        /* We can reuse the existing drm_mm nodes but need to change the
@@ -4149,7 +3345,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
         * rewrite the PTE in the belief that doing so tramples upon less
         * state and so involves less work.
         */
-       if (bound) {
+       if (obj->bind_count) {
                /* Before we change the PTE, the GPU must not be accessing it.
                 * If we wait upon the object, we know that all the bound
                 * VMA are no longer active.
@@ -4158,7 +3354,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
                if (ret)
                        return ret;
 
-               if (!HAS_LLC(dev) && cache_level != I915_CACHE_NONE) {
+               if (!HAS_LLC(obj->base.dev) && cache_level != I915_CACHE_NONE) {
                        /* Access to snoopable pages through the GTT is
                         * incoherent and on some machines causes a hard
                         * lockup. Relinquish the CPU mmaping to force
@@ -4175,9 +3371,11 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
                         * dropped the fence as all snoopable access is
                         * supposed to be linear.
                         */
-                       ret = i915_gem_object_put_fence(obj);
-                       if (ret)
-                               return ret;
+                       list_for_each_entry(vma, &obj->vma_list, obj_link) {
+                               ret = i915_vma_put_fence(vma);
+                               if (ret)
+                                       return ret;
+                       }
                } else {
                        /* We either have incoherent backing store and
                         * so no GTT access or the architecture is fully
@@ -4221,8 +3419,8 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_caching *args = data;
        struct drm_i915_gem_object *obj;
 
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->handle));
-       if (&obj->base == NULL)
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj)
                return -ENOENT;
 
        switch (obj->cache_level) {
@@ -4240,7 +3438,7 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
                break;
        }
 
-       drm_gem_object_unreference_unlocked(&obj->base);
+       i915_gem_object_put_unlocked(obj);
        return 0;
 }
 
@@ -4282,15 +3480,15 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
        if (ret)
                goto rpm_put;
 
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->handle));
-       if (&obj->base == NULL) {
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj) {
                ret = -ENOENT;
                goto unlock;
        }
 
        ret = i915_gem_object_set_cache_level(obj, level);
 
-       drm_gem_object_unreference(&obj->base);
+       i915_gem_object_put(obj);
 unlock:
        mutex_unlock(&dev->struct_mutex);
 rpm_put:
@@ -4304,11 +3502,12 @@ rpm_put:
  * Can be called from an uninterruptible phase (modesetting) and allows
  * any flushes to be pipelined (for pageflips).
  */
-int
+struct i915_vma *
 i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
                                     const struct i915_ggtt_view *view)
 {
+       struct i915_vma *vma;
        u32 old_read_domains, old_write_domain;
        int ret;
 
@@ -4328,19 +3527,31 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
         */
        ret = i915_gem_object_set_cache_level(obj,
                                              HAS_WT(obj->base.dev) ? I915_CACHE_WT : I915_CACHE_NONE);
-       if (ret)
+       if (ret) {
+               vma = ERR_PTR(ret);
                goto err_unpin_display;
+       }
 
        /* As the user may map the buffer once pinned in the display plane
         * (e.g. libkms for the bootup splash), we have to ensure that we
-        * always use map_and_fenceable for all scanout buffers.
+        * always use map_and_fenceable for all scanout buffers. However,
+        * it may simply be too big to fit into mappable, in which case
+        * put it anyway and hope that userspace can cope (but always first
+        * try to preserve the existing ABI).
         */
-       ret = i915_gem_object_ggtt_pin(obj, view, alignment,
-                                      view->type == I915_GGTT_VIEW_NORMAL ?
-                                      PIN_MAPPABLE : 0);
-       if (ret)
+       vma = ERR_PTR(-ENOSPC);
+       if (view->type == I915_GGTT_VIEW_NORMAL)
+               vma = i915_gem_object_ggtt_pin(obj, view, 0, alignment,
+                                              PIN_MAPPABLE | PIN_NONBLOCK);
+       if (IS_ERR(vma))
+               vma = i915_gem_object_ggtt_pin(obj, view, 0, alignment, 0);
+       if (IS_ERR(vma))
                goto err_unpin_display;
 
+       vma->display_alignment = max_t(u64, vma->display_alignment, alignment);
+
+       WARN_ON(obj->pin_display > i915_vma_pin_count(vma));
+
        i915_gem_object_flush_cpu_write_domain(obj);
 
        old_write_domain = obj->base.write_domain;
@@ -4356,23 +3567,28 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                            old_read_domains,
                                            old_write_domain);
 
-       return 0;
+       return vma;
 
 err_unpin_display:
        obj->pin_display--;
-       return ret;
+       return vma;
 }
 
 void
-i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
-                                        const struct i915_ggtt_view *view)
+i915_gem_object_unpin_from_display_plane(struct i915_vma *vma)
 {
-       if (WARN_ON(obj->pin_display == 0))
+       if (WARN_ON(vma->obj->pin_display == 0))
                return;
 
-       i915_gem_object_ggtt_unpin_view(obj, view);
+       if (--vma->obj->pin_display == 0)
+               vma->display_alignment = 0;
 
-       obj->pin_display--;
+       /* 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_vma_unpin(vma);
+       WARN_ON(vma->obj->pin_display > i915_vma_pin_count(vma));
 }
 
 /**
@@ -4389,13 +3605,13 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
        uint32_t old_write_domain, old_read_domains;
        int ret;
 
-       if (obj->base.write_domain == I915_GEM_DOMAIN_CPU)
-               return 0;
-
        ret = i915_gem_object_wait_rendering(obj, !write);
        if (ret)
                return ret;
 
+       if (obj->base.write_domain == I915_GEM_DOMAIN_CPU)
+               return 0;
+
        i915_gem_object_flush_gtt_write_domain(obj);
 
        old_write_domain = obj->base.write_domain;
@@ -4470,28 +3686,31 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
                target = request;
        }
        if (target)
-               i915_gem_request_reference(target);
+               i915_gem_request_get(target);
        spin_unlock(&file_priv->mm.lock);
 
        if (target == NULL)
                return 0;
 
-       ret = __i915_wait_request(target, true, NULL, NULL);
-       i915_gem_request_unreference(target);
+       ret = i915_wait_request(target, I915_WAIT_INTERRUPTIBLE, NULL, NULL);
+       i915_gem_request_put(target);
 
        return ret;
 }
 
 static bool
-i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
+i915_vma_misplaced(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
 {
-       struct drm_i915_gem_object *obj = vma->obj;
+       if (!drm_mm_node_allocated(&vma->node))
+               return false;
 
-       if (alignment &&
-           vma->node.start & (alignment - 1))
+       if (vma->node.size < size)
                return true;
 
-       if (flags & PIN_MAPPABLE && !obj->map_and_fenceable)
+       if (alignment && vma->node.start & (alignment - 1))
+               return true;
+
+       if (flags & PIN_MAPPABLE && !i915_vma_is_map_and_fenceable(vma))
                return true;
 
        if (flags & PIN_OFFSET_BIAS &&
@@ -4508,135 +3727,208 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t 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_gtt_size(obj->base.dev,
-                                          obj->base.size,
-                                          obj->tiling_mode);
-       fence_alignment = i915_gem_get_gtt_alignment(obj->base.dev,
-                                                    obj->base.size,
-                                                    obj->tiling_mode,
-                                                    true);
+       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 <=
-                   to_i915(obj->base.dev)->ggtt.mappable_end);
+                   dev_priv->ggtt.mappable_end);
 
-       obj->map_and_fenceable = mappable && fenceable;
+       if (mappable && fenceable)
+               vma->flags |= I915_VMA_CAN_FENCE;
+       else
+               vma->flags &= ~I915_VMA_CAN_FENCE;
 }
 
-static int
-i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
-                      struct i915_address_space *vm,
-                      const struct i915_ggtt_view *ggtt_view,
-                      uint32_t alignment,
-                      uint64_t flags)
+int __i915_vma_do_pin(struct i915_vma *vma,
+                     u64 size, u64 alignment, u64 flags)
 {
-       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
-       struct i915_vma *vma;
-       unsigned bound;
+       unsigned int bound = vma->flags;
        int ret;
 
-       if (WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base))
-               return -ENODEV;
-
-       if (WARN_ON(flags & (PIN_GLOBAL | PIN_MAPPABLE) && !i915_is_ggtt(vm)))
-               return -EINVAL;
+       GEM_BUG_ON((flags & (PIN_GLOBAL | PIN_USER)) == 0);
+       GEM_BUG_ON((flags & PIN_GLOBAL) && !i915_vma_is_ggtt(vma));
 
-       if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE))
-               return -EINVAL;
+       if (WARN_ON(bound & I915_VMA_PIN_OVERFLOW)) {
+               ret = -EBUSY;
+               goto err;
+       }
 
-       if (WARN_ON(i915_is_ggtt(vm) != !!ggtt_view))
-               return -EINVAL;
+       if ((bound & I915_VMA_BIND_MASK) == 0) {
+               ret = i915_vma_insert(vma, size, alignment, flags);
+               if (ret)
+                       goto err;
+       }
 
-       vma = ggtt_view ? i915_gem_obj_to_ggtt_view(obj, ggtt_view) :
-                         i915_gem_obj_to_vma(obj, vm);
+       ret = i915_vma_bind(vma, vma->obj->cache_level, flags);
+       if (ret)
+               goto err;
 
-       if (vma) {
-               if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
-                       return -EBUSY;
+       if ((bound ^ vma->flags) & I915_VMA_GLOBAL_BIND)
+               __i915_vma_set_map_and_fenceable(vma);
 
-               if (i915_vma_misplaced(vma, alignment, flags)) {
-                       WARN(vma->pin_count,
-                            "bo is already pinned in %s with incorrect alignment:"
-                            " offset=%08x %08x, req.alignment=%x, req.map_and_fenceable=%d,"
-                            " obj->map_and_fenceable=%d\n",
-                            ggtt_view ? "ggtt" : "ppgtt",
-                            upper_32_bits(vma->node.start),
-                            lower_32_bits(vma->node.start),
-                            alignment,
-                            !!(flags & PIN_MAPPABLE),
-                            obj->map_and_fenceable);
-                       ret = i915_vma_unbind(vma);
-                       if (ret)
-                               return ret;
+       GEM_BUG_ON(i915_vma_misplaced(vma, size, alignment, flags));
+       return 0;
 
-                       vma = NULL;
-               }
-       }
+err:
+       __i915_vma_unpin(vma);
+       return ret;
+}
 
-       bound = vma ? vma->bound : 0;
-       if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
-               vma = i915_gem_object_bind_to_vm(obj, vm, ggtt_view, alignment,
-                                                flags);
-               if (IS_ERR(vma))
-                       return PTR_ERR(vma);
-       } else {
-               ret = i915_vma_bind(vma, obj->cache_level, flags);
+struct i915_vma *
+i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
+                        const struct i915_ggtt_view *view,
+                        u64 size,
+                        u64 alignment,
+                        u64 flags)
+{
+       struct i915_address_space *vm = &to_i915(obj->base.dev)->ggtt.base;
+       struct i915_vma *vma;
+       int ret;
+
+       vma = i915_gem_obj_lookup_or_create_vma(obj, vm, view);
+       if (IS_ERR(vma))
+               return vma;
+
+       if (i915_vma_misplaced(vma, size, alignment, flags)) {
+               if (flags & PIN_NONBLOCK &&
+                   (i915_vma_is_pinned(vma) || i915_vma_is_active(vma)))
+                       return ERR_PTR(-ENOSPC);
+
+               WARN(i915_vma_is_pinned(vma),
+                    "bo is already pinned in ggtt with incorrect alignment:"
+                    " offset=%08x, req.alignment=%llx,"
+                    " req.map_and_fenceable=%d, vma->map_and_fenceable=%d\n",
+                    i915_ggtt_offset(vma), alignment,
+                    !!(flags & PIN_MAPPABLE),
+                    i915_vma_is_map_and_fenceable(vma));
+               ret = i915_vma_unbind(vma);
                if (ret)
-                       return ret;
+                       return ERR_PTR(ret);
        }
 
-       if (ggtt_view && ggtt_view->type == I915_GGTT_VIEW_NORMAL &&
-           (bound ^ vma->bound) & GLOBAL_BIND) {
-               __i915_vma_set_map_and_fenceable(vma);
-               WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable);
-       }
+       ret = i915_vma_pin(vma, size, alignment, flags | PIN_GLOBAL);
+       if (ret)
+               return ERR_PTR(ret);
 
-       vma->pin_count++;
-       return 0;
+       return vma;
 }
 
-int
-i915_gem_object_pin(struct drm_i915_gem_object *obj,
-                   struct i915_address_space *vm,
-                   uint32_t alignment,
-                   uint64_t flags)
+static __always_inline unsigned int __busy_read_flag(unsigned int id)
 {
-       return i915_gem_object_do_pin(obj, vm,
-                                     i915_is_ggtt(vm) ? &i915_ggtt_view_normal : NULL,
-                                     alignment, flags);
+       /* Note that we could alias engines in the execbuf API, but
+        * that would be very unwise as it prevents userspace from
+        * fine control over engine selection. Ahem.
+        *
+        * This should be something like EXEC_MAX_ENGINE instead of
+        * I915_NUM_ENGINES.
+        */
+       BUILD_BUG_ON(I915_NUM_ENGINES > 16);
+       return 0x10000 << id;
 }
 
-int
-i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
-                        const struct i915_ggtt_view *view,
-                        uint32_t alignment,
-                        uint64_t flags)
+static __always_inline unsigned int __busy_write_id(unsigned int id)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
+       /* The uABI guarantees an active writer is also amongst the read
+        * engines. This would be true if we accessed the activity tracking
+        * under the lock, but as we perform the lookup of the object and
+        * its activity locklessly we can not guarantee that the last_write
+        * being active implies that we have set the same engine flag from
+        * last_read - hence we always set both read and write busy for
+        * last_write.
+        */
+       return id | __busy_read_flag(id);
+}
+
+static __always_inline unsigned int
+__busy_set_if_active(const struct i915_gem_active *active,
+                    unsigned int (*flag)(unsigned int id))
+{
+       struct drm_i915_gem_request *request;
 
-       BUG_ON(!view);
+       request = rcu_dereference(active->request);
+       if (!request || i915_gem_request_completed(request))
+               return 0;
 
-       return i915_gem_object_do_pin(obj, &ggtt->base, view,
-                                     alignment, flags | PIN_GLOBAL);
+       /* This is racy. See __i915_gem_active_get_rcu() for an in detail
+        * discussion of how to handle the race correctly, but for reporting
+        * the busy state we err on the side of potentially reporting the
+        * wrong engine as being busy (but we guarantee that the result
+        * is at least self-consistent).
+        *
+        * As we use SLAB_DESTROY_BY_RCU, the request may be reallocated
+        * whilst we are inspecting it, even under the RCU read lock as we are.
+        * This means that there is a small window for the engine and/or the
+        * seqno to have been overwritten. The seqno will always be in the
+        * future compared to the intended, and so we know that if that
+        * seqno is idle (on whatever engine) our request is idle and the
+        * return 0 above is correct.
+        *
+        * The issue is that if the engine is switched, it is just as likely
+        * to report that it is busy (but since the switch happened, we know
+        * the request should be idle). So there is a small chance that a busy
+        * result is actually the wrong engine.
+        *
+        * So why don't we care?
+        *
+        * For starters, the busy ioctl is a heuristic that is by definition
+        * racy. Even with perfect serialisation in the driver, the hardware
+        * state is constantly advancing - the state we report to the user
+        * is stale.
+        *
+        * The critical information for the busy-ioctl is whether the object
+        * is idle as userspace relies on that to detect whether its next
+        * access will stall, or if it has missed submitting commands to
+        * the hardware allowing the GPU to stall. We never generate a
+        * false-positive for idleness, thus busy-ioctl is reliable at the
+        * most fundamental level, and we maintain the guarantee that a
+        * busy object left to itself will eventually become idle (and stay
+        * idle!).
+        *
+        * We allow ourselves the leeway of potentially misreporting the busy
+        * state because that is an optimisation heuristic that is constantly
+        * in flux. Being quickly able to detect the busy/idle state is much
+        * more important than accurate logging of exactly which engines were
+        * busy.
+        *
+        * For accuracy in reporting the engine, we could use
+        *
+        *      result = 0;
+        *      request = __i915_gem_active_get_rcu(active);
+        *      if (request) {
+        *              if (!i915_gem_request_completed(request))
+        *                      result = flag(request->engine->exec_id);
+        *              i915_gem_request_put(request);
+        *      }
+        *
+        * but that still remains susceptible to both hardware and userspace
+        * races. So we accept making the result of that race slightly worse,
+        * given the rarity of the race and its low impact on the result.
+        */
+       return flag(READ_ONCE(request->engine->exec_id));
 }
 
-void
-i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj,
-                               const struct i915_ggtt_view *view)
+static __always_inline unsigned int
+busy_check_reader(const struct i915_gem_active *active)
 {
-       struct i915_vma *vma = i915_gem_obj_to_ggtt_view(obj, view);
-
-       WARN_ON(vma->pin_count == 0);
-       WARN_ON(!i915_gem_obj_ggtt_bound_view(obj, view));
+       return __busy_set_if_active(active, __busy_read_flag);
+}
 
-       --vma->pin_count;
+static __always_inline unsigned int
+busy_check_writer(const struct i915_gem_active *active)
+{
+       return __busy_set_if_active(active, __busy_write_id);
 }
 
 int
@@ -4645,47 +3937,64 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 {
        struct drm_i915_gem_busy *args = data;
        struct drm_i915_gem_object *obj;
-       int ret;
+       unsigned long active;
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj)
+               return -ENOENT;
 
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->handle));
-       if (&obj->base == NULL) {
-               ret = -ENOENT;
-               goto unlock;
-       }
+       args->busy = 0;
+       active = __I915_BO_ACTIVE(obj);
+       if (active) {
+               int idx;
 
-       /* Count all active objects as busy, even if they are currently not used
-        * by the gpu. Users of this interface expect objects to eventually
-        * become non-busy without any further actions, therefore emit any
-        * necessary flushes here.
-        */
-       ret = i915_gem_object_flush_active(obj);
-       if (ret)
-               goto unref;
+               /* Yes, the lookups are intentionally racy.
+                *
+                * First, we cannot simply rely on __I915_BO_ACTIVE. We have
+                * to regard the value as stale and as our ABI guarantees
+                * forward progress, we confirm the status of each active
+                * request with the hardware.
+                *
+                * Even though we guard the pointer lookup by RCU, that only
+                * guarantees that the pointer and its contents remain
+                * dereferencable and does *not* mean that the request we
+                * have is the same as the one being tracked by the object.
+                *
+                * Consider that we lookup the request just as it is being
+                * retired and freed. We take a local copy of the pointer,
+                * but before we add its engine into the busy set, the other
+                * thread reallocates it and assigns it to a task on another
+                * engine with a fresh and incomplete seqno. Guarding against
+                * that requires careful serialisation and reference counting,
+                * i.e. using __i915_gem_active_get_request_rcu(). We don't,
+                * instead we expect that if the result is busy, which engines
+                * are busy is not completely reliable - we only guarantee
+                * that the object was busy.
+                */
+               rcu_read_lock();
 
-       args->busy = 0;
-       if (obj->active) {
-               int i;
+               for_each_active(active, idx)
+                       args->busy |= busy_check_reader(&obj->last_read[idx]);
 
-               for (i = 0; i < I915_NUM_ENGINES; i++) {
-                       struct drm_i915_gem_request *req;
+               /* For ABI sanity, we only care that the write engine is in
+                * the set of read engines. This should be ensured by the
+                * ordering of setting last_read/last_write in
+                * i915_vma_move_to_active(), and then in reverse in retire.
+                * However, for good measure, we always report the last_write
+                * request as a busy read as well as being a busy write.
+                *
+                * We don't care that the set of active read/write engines
+                * may change during construction of the result, as it is
+                * equally liable to change before userspace can inspect
+                * the result.
+                */
+               args->busy |= busy_check_writer(&obj->last_write);
 
-                       req = obj->last_read_req[i];
-                       if (req)
-                               args->busy |= 1 << (16 + req->engine->exec_id);
-               }
-               if (obj->last_write_req)
-                       args->busy |= obj->last_write_req->engine->exec_id;
+               rcu_read_unlock();
        }
 
-unref:
-       drm_gem_object_unreference(&obj->base);
-unlock:
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
+       i915_gem_object_put_unlocked(obj);
+       return 0;
 }
 
 int
@@ -4716,19 +4025,14 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
        if (ret)
                return ret;
 
-       obj = to_intel_bo(drm_gem_object_lookup(file_priv, args->handle));
-       if (&obj->base == NULL) {
+       obj = i915_gem_object_lookup(file_priv, args->handle);
+       if (!obj) {
                ret = -ENOENT;
                goto unlock;
        }
 
-       if (i915_gem_obj_is_pinned(obj)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
        if (obj->pages &&
-           obj->tiling_mode != I915_TILING_NONE &&
+           i915_gem_object_is_tiled(obj) &&
            dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES) {
                if (obj->madv == I915_MADV_WILLNEED)
                        i915_gem_object_unpin_pages(obj);
@@ -4745,8 +4049,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
 
        args->retained = obj->madv != __I915_MADV_PURGED;
 
-out:
-       drm_gem_object_unreference(&obj->base);
+       i915_gem_object_put(obj);
 unlock:
        mutex_unlock(&dev->struct_mutex);
        return ret;
@@ -4759,14 +4062,17 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
 
        INIT_LIST_HEAD(&obj->global_list);
        for (i = 0; i < I915_NUM_ENGINES; i++)
-               INIT_LIST_HEAD(&obj->engine_list[i]);
+               init_request_active(&obj->last_read[i],
+                                   i915_gem_object_retire__read);
+       init_request_active(&obj->last_write,
+                           i915_gem_object_retire__write);
        INIT_LIST_HEAD(&obj->obj_exec_link);
        INIT_LIST_HEAD(&obj->vma_list);
        INIT_LIST_HEAD(&obj->batch_pool_link);
 
        obj->ops = ops;
 
-       obj->fence_reg = I915_FENCE_REG_NONE;
+       obj->frontbuffer_ggtt_origin = ORIGIN_GTT;
        obj->madv = I915_MADV_WILLNEED;
 
        i915_gem_info_add_obj(to_i915(obj->base.dev), obj->base.size);
@@ -4871,33 +4177,31 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
 
        trace_i915_gem_object_destroy(obj);
 
+       /* All file-owned VMA should have been released by this point through
+        * i915_gem_close_object(), or earlier by i915_gem_context_close().
+        * However, the object may also be bound into the global GTT (e.g.
+        * older GPUs without per-process support, or for direct access through
+        * the GTT either for the user or for scanout). Those VMA still need to
+        * unbound now.
+        */
        list_for_each_entry_safe(vma, next, &obj->vma_list, obj_link) {
-               int ret;
-
-               vma->pin_count = 0;
-               ret = i915_vma_unbind(vma);
-               if (WARN_ON(ret == -ERESTARTSYS)) {
-                       bool was_interruptible;
-
-                       was_interruptible = dev_priv->mm.interruptible;
-                       dev_priv->mm.interruptible = false;
-
-                       WARN_ON(i915_vma_unbind(vma));
-
-                       dev_priv->mm.interruptible = was_interruptible;
-               }
+               GEM_BUG_ON(!i915_vma_is_ggtt(vma));
+               GEM_BUG_ON(i915_vma_is_active(vma));
+               vma->flags &= ~I915_VMA_PIN_MASK;
+               i915_vma_close(vma);
        }
+       GEM_BUG_ON(obj->bind_count);
 
        /* Stolen objects don't hold a ref, but do hold pin count. Fix that up
         * before progressing. */
        if (obj->stolen)
                i915_gem_object_unpin_pages(obj);
 
-       WARN_ON(obj->frontbuffer_bits);
+       WARN_ON(atomic_read(&obj->frontbuffer_bits));
 
        if (obj->pages && obj->madv == I915_MADV_WILLNEED &&
            dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES &&
-           obj->tiling_mode != I915_TILING_NONE)
+           i915_gem_object_is_tiled(obj))
                i915_gem_object_unpin_pages(obj);
 
        if (WARN_ON(obj->pages_pin_count))
@@ -4905,7 +4209,6 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
        if (discard_backing_storage(obj))
                obj->madv = I915_MADV_DONTNEED;
        i915_gem_object_put_pages(obj);
-       i915_gem_object_free_mmap_offset(obj);
 
        BUG_ON(obj->pages);
 
@@ -4924,71 +4227,35 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
        intel_runtime_pm_put(dev_priv);
 }
 
-struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
-                                    struct i915_address_space *vm)
-{
-       struct i915_vma *vma;
-       list_for_each_entry(vma, &obj->vma_list, obj_link) {
-               if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL &&
-                   vma->vm == vm)
-                       return vma;
-       }
-       return NULL;
-}
-
-struct i915_vma *i915_gem_obj_to_ggtt_view(struct drm_i915_gem_object *obj,
-                                          const struct i915_ggtt_view *view)
-{
-       struct i915_vma *vma;
-
-       GEM_BUG_ON(!view);
-
-       list_for_each_entry(vma, &obj->vma_list, obj_link)
-               if (vma->is_ggtt && i915_ggtt_view_equal(&vma->ggtt_view, view))
-                       return vma;
-       return NULL;
-}
-
-void i915_gem_vma_destroy(struct i915_vma *vma)
-{
-       WARN_ON(vma->node.allocated);
-
-       /* Keep the vma as a placeholder in the execbuffer reservation lists */
-       if (!list_empty(&vma->exec_list))
-               return;
-
-       if (!vma->is_ggtt)
-               i915_ppgtt_put(i915_vm_to_ppgtt(vma->vm));
-
-       list_del(&vma->obj_link);
-
-       kmem_cache_free(to_i915(vma->obj->base.dev)->vmas, vma);
-}
-
-static void
-i915_gem_stop_engines(struct drm_device *dev)
+int i915_gem_suspend(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_engine_cs *engine;
-
-       for_each_engine(engine, dev_priv)
-               dev_priv->gt.stop_engine(engine);
-}
+       int ret;
 
-int
-i915_gem_suspend(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret = 0;
+       intel_suspend_gt_powersave(dev_priv);
 
        mutex_lock(&dev->struct_mutex);
-       ret = i915_gem_wait_for_idle(dev_priv);
+
+       /* We have to flush all the executing contexts to main memory so
+        * that they can saved in the hibernation image. To ensure the last
+        * context image is coherent, we have to switch away from it. That
+        * leaves the dev_priv->kernel_context still active when
+        * we actually suspend, and its image in memory may not match the GPU
+        * state. Fortunately, the kernel_context is disposable and we do
+        * not rely on its state.
+        */
+       ret = i915_gem_switch_to_kernel_context(dev_priv);
+       if (ret)
+               goto err;
+
+       ret = i915_gem_wait_for_idle(dev_priv,
+                                    I915_WAIT_INTERRUPTIBLE |
+                                    I915_WAIT_LOCKED);
        if (ret)
                goto err;
 
        i915_gem_retire_requests(dev_priv);
 
-       i915_gem_stop_engines(dev);
        i915_gem_context_lost(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
@@ -5008,6 +4275,22 @@ err:
        return ret;
 }
 
+void i915_gem_resume(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_restore_gtt_mappings(dev);
+
+       /* As we didn't flush the kernel context before suspend, we cannot
+        * guarantee that the context image is complete. So let's just reset
+        * it and start again.
+        */
+       dev_priv->gt.resume(dev_priv);
+
+       mutex_unlock(&dev->struct_mutex);
+}
+
 void i915_gem_init_swizzling(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -5060,53 +4343,6 @@ static void init_unused_rings(struct drm_device *dev)
        }
 }
 
-int i915_gem_init_engines(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret;
-
-       ret = intel_init_render_ring_buffer(dev);
-       if (ret)
-               return ret;
-
-       if (HAS_BSD(dev)) {
-               ret = intel_init_bsd_ring_buffer(dev);
-               if (ret)
-                       goto cleanup_render_ring;
-       }
-
-       if (HAS_BLT(dev)) {
-               ret = intel_init_blt_ring_buffer(dev);
-               if (ret)
-                       goto cleanup_bsd_ring;
-       }
-
-       if (HAS_VEBOX(dev)) {
-               ret = intel_init_vebox_ring_buffer(dev);
-               if (ret)
-                       goto cleanup_blt_ring;
-       }
-
-       if (HAS_BSD2(dev)) {
-               ret = intel_init_bsd2_ring_buffer(dev);
-               if (ret)
-                       goto cleanup_vebox_ring;
-       }
-
-       return 0;
-
-cleanup_vebox_ring:
-       intel_cleanup_engine(&dev_priv->engine[VECS]);
-cleanup_blt_ring:
-       intel_cleanup_engine(&dev_priv->engine[BCS]);
-cleanup_bsd_ring:
-       intel_cleanup_engine(&dev_priv->engine[VCS]);
-cleanup_render_ring:
-       intel_cleanup_engine(&dev_priv->engine[RCS]);
-
-       return ret;
-}
-
 int
 i915_gem_init_hw(struct drm_device *dev)
 {
@@ -5173,6 +4409,27 @@ out:
        return ret;
 }
 
+bool intel_sanitize_semaphores(struct drm_i915_private *dev_priv, int value)
+{
+       if (INTEL_INFO(dev_priv)->gen < 6)
+               return false;
+
+       /* TODO: make semaphores and Execlists play nicely together */
+       if (i915.enable_execlists)
+               return false;
+
+       if (value >= 0)
+               return value;
+
+#ifdef CONFIG_INTEL_IOMMU
+       /* Enable semaphores on SNB when IO remapping is off */
+       if (INTEL_INFO(dev_priv)->gen == 6 && intel_iommu_gfx_mapped)
+               return false;
+#endif
+
+       return true;
+}
+
 int i915_gem_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -5181,15 +4438,11 @@ int i915_gem_init(struct drm_device *dev)
        mutex_lock(&dev->struct_mutex);
 
        if (!i915.enable_execlists) {
-               dev_priv->gt.execbuf_submit = i915_gem_ringbuffer_submission;
-               dev_priv->gt.init_engines = i915_gem_init_engines;
-               dev_priv->gt.cleanup_engine = intel_cleanup_engine;
-               dev_priv->gt.stop_engine = intel_stop_engine;
+               dev_priv->gt.resume = intel_legacy_submission_resume;
+               dev_priv->gt.cleanup_engine = intel_engine_cleanup;
        } else {
-               dev_priv->gt.execbuf_submit = intel_execlists_submission;
-               dev_priv->gt.init_engines = intel_logical_rings_init;
+               dev_priv->gt.resume = intel_lr_context_resume;
                dev_priv->gt.cleanup_engine = intel_logical_ring_cleanup;
-               dev_priv->gt.stop_engine = intel_logical_ring_stop;
        }
 
        /* This is just a security blanket to placate dragons.
@@ -5201,24 +4454,27 @@ int i915_gem_init(struct drm_device *dev)
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
        i915_gem_init_userptr(dev_priv);
-       i915_gem_init_ggtt(dev);
+
+       ret = i915_gem_init_ggtt(dev_priv);
+       if (ret)
+               goto out_unlock;
 
        ret = i915_gem_context_init(dev);
        if (ret)
                goto out_unlock;
 
-       ret = dev_priv->gt.init_engines(dev);
+       ret = intel_engines_init(dev);
        if (ret)
                goto out_unlock;
 
        ret = i915_gem_init_hw(dev);
        if (ret == -EIO) {
-               /* Allow ring initialisation to fail by marking the GPU as
+               /* Allow engine initialisation to fail by marking the GPU as
                 * wedged. But we only want to do this where the GPU is angry,
                 * for all other failure, such as an allocation failure, bail.
                 */
                DRM_ERROR("Failed to initialize GPU, declaring it wedged\n");
-               atomic_or(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
+               i915_gem_set_wedged(dev_priv);
                ret = 0;
        }
 
@@ -5242,7 +4498,6 @@ i915_gem_cleanup_engines(struct drm_device *dev)
 static void
 init_engine_lists(struct intel_engine_cs *engine)
 {
-       INIT_LIST_HEAD(&engine->active_list);
        INIT_LIST_HEAD(&engine->request_list);
 }
 
@@ -5250,6 +4505,7 @@ void
 i915_gem_load_init_fences(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = &dev_priv->drm;
+       int i;
 
        if (INTEL_INFO(dev_priv)->gen >= 7 && !IS_VALLEYVIEW(dev_priv) &&
            !IS_CHERRYVIEW(dev_priv))
@@ -5265,6 +4521,13 @@ i915_gem_load_init_fences(struct drm_i915_private *dev_priv)
                                I915_READ(vgtif_reg(avail_rs.fence_num));
 
        /* Initialize fence registers to zero */
+       for (i = 0; i < dev_priv->num_fence_regs; i++) {
+               struct drm_i915_fence_reg *fence = &dev_priv->fence_regs[i];
+
+               fence->i915 = dev_priv;
+               fence->id = i;
+               list_add_tail(&fence->link, &dev_priv->mm.fence_list);
+       }
        i915_gem_restore_fences(dev);
 
        i915_gem_detect_bit_6_swizzle(dev);
@@ -5289,18 +4552,17 @@ i915_gem_load_init(struct drm_device *dev)
        dev_priv->requests =
                kmem_cache_create("i915_gem_request",
                                  sizeof(struct drm_i915_gem_request), 0,
-                                 SLAB_HWCACHE_ALIGN,
+                                 SLAB_HWCACHE_ALIGN |
+                                 SLAB_RECLAIM_ACCOUNT |
+                                 SLAB_DESTROY_BY_RCU,
                                  NULL);
 
-       INIT_LIST_HEAD(&dev_priv->vm_list);
        INIT_LIST_HEAD(&dev_priv->context_list);
        INIT_LIST_HEAD(&dev_priv->mm.unbound_list);
        INIT_LIST_HEAD(&dev_priv->mm.bound_list);
        INIT_LIST_HEAD(&dev_priv->mm.fence_list);
        for (i = 0; i < I915_NUM_ENGINES; i++)
                init_engine_lists(&dev_priv->engine[i]);
-       for (i = 0; i < I915_MAX_NUM_FENCES; i++)
-               INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
        INIT_DELAYED_WORK(&dev_priv->gt.retire_work,
                          i915_gem_retire_work_handler);
        INIT_DELAYED_WORK(&dev_priv->gt.idle_work,
@@ -5310,13 +4572,13 @@ i915_gem_load_init(struct drm_device *dev)
 
        dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL;
 
-       INIT_LIST_HEAD(&dev_priv->mm.fence_list);
-
        init_waitqueue_head(&dev_priv->pending_flip_queue);
 
        dev_priv->mm.interruptible = true;
 
-       mutex_init(&dev_priv->fb_tracking.lock);
+       atomic_set(&dev_priv->mm.bsd_engine_dispatch_index, 0);
+
+       spin_lock_init(&dev_priv->fb_tracking.lock);
 }
 
 void i915_gem_load_cleanup(struct drm_device *dev)
@@ -5326,11 +4588,32 @@ void i915_gem_load_cleanup(struct drm_device *dev)
        kmem_cache_destroy(dev_priv->requests);
        kmem_cache_destroy(dev_priv->vmas);
        kmem_cache_destroy(dev_priv->objects);
+
+       /* And ensure that our DESTROY_BY_RCU slabs are truly destroyed */
+       rcu_barrier();
+}
+
+int i915_gem_freeze(struct drm_i915_private *dev_priv)
+{
+       intel_runtime_pm_get(dev_priv);
+
+       mutex_lock(&dev_priv->drm.struct_mutex);
+       i915_gem_shrink_all(dev_priv);
+       mutex_unlock(&dev_priv->drm.struct_mutex);
+
+       intel_runtime_pm_put(dev_priv);
+
+       return 0;
 }
 
 int i915_gem_freeze_late(struct drm_i915_private *dev_priv)
 {
        struct drm_i915_gem_object *obj;
+       struct list_head *phases[] = {
+               &dev_priv->mm.unbound_list,
+               &dev_priv->mm.bound_list,
+               NULL
+       }, **p;
 
        /* Called just before we write the hibernation image.
         *
@@ -5341,17 +4624,21 @@ int i915_gem_freeze_late(struct drm_i915_private *dev_priv)
         *
         * To make sure the hibernation image contains the latest state,
         * we update that state just before writing out the image.
+        *
+        * To try and reduce the hibernation image, we manually shrink
+        * the objects as well.
         */
 
-       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
-               obj->base.read_domains = I915_GEM_DOMAIN_CPU;
-               obj->base.write_domain = I915_GEM_DOMAIN_CPU;
-       }
+       mutex_lock(&dev_priv->drm.struct_mutex);
+       i915_gem_shrink(dev_priv, -1UL, I915_SHRINK_UNBOUND);
 
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               obj->base.read_domains = I915_GEM_DOMAIN_CPU;
-               obj->base.write_domain = I915_GEM_DOMAIN_CPU;
+       for (p = phases; *p; p++) {
+               list_for_each_entry(obj, *p, global_list) {
+                       obj->base.read_domains = I915_GEM_DOMAIN_CPU;
+                       obj->base.write_domain = I915_GEM_DOMAIN_CPU;
+               }
        }
+       mutex_unlock(&dev_priv->drm.struct_mutex);
 
        return 0;
 }
@@ -5359,21 +4646,15 @@ int i915_gem_freeze_late(struct drm_i915_private *dev_priv)
 void i915_gem_release(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_i915_file_private *file_priv = file->driver_priv;
+       struct drm_i915_gem_request *request;
 
        /* Clean up our request list when the client is going away, so that
         * later retire_requests won't dereference our soon-to-be-gone
         * file_priv.
         */
        spin_lock(&file_priv->mm.lock);
-       while (!list_empty(&file_priv->mm.request_list)) {
-               struct drm_i915_gem_request *request;
-
-               request = list_first_entry(&file_priv->mm.request_list,
-                                          struct drm_i915_gem_request,
-                                          client_list);
-               list_del(&request->client_list);
+       list_for_each_entry(request, &file_priv->mm.request_list, client_list)
                request->file_priv = NULL;
-       }
        spin_unlock(&file_priv->mm.lock);
 
        if (!list_empty(&file_priv->rps.link)) {
@@ -5402,7 +4683,7 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
        spin_lock_init(&file_priv->mm.lock);
        INIT_LIST_HEAD(&file_priv->mm.request_list);
 
-       file_priv->bsd_ring = -1;
+       file_priv->bsd_engine = -1;
 
        ret = i915_gem_context_open(dev, file);
        if (ret)
@@ -5424,118 +4705,24 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
                       struct drm_i915_gem_object *new,
                       unsigned frontbuffer_bits)
 {
+       /* Control of individual bits within the mask are guarded by
+        * the owning plane->mutex, i.e. we can never see concurrent
+        * manipulation of individual bits. But since the bitfield as a whole
+        * is updated using RMW, we need to use atomics in order to update
+        * the bits.
+        */
+       BUILD_BUG_ON(INTEL_FRONTBUFFER_BITS_PER_PIPE * I915_MAX_PIPES >
+                    sizeof(atomic_t) * BITS_PER_BYTE);
+
        if (old) {
-               WARN_ON(!mutex_is_locked(&old->base.dev->struct_mutex));
-               WARN_ON(!(old->frontbuffer_bits & frontbuffer_bits));
-               old->frontbuffer_bits &= ~frontbuffer_bits;
+               WARN_ON(!(atomic_read(&old->frontbuffer_bits) & frontbuffer_bits));
+               atomic_andnot(frontbuffer_bits, &old->frontbuffer_bits);
        }
 
        if (new) {
-               WARN_ON(!mutex_is_locked(&new->base.dev->struct_mutex));
-               WARN_ON(new->frontbuffer_bits & frontbuffer_bits);
-               new->frontbuffer_bits |= frontbuffer_bits;
-       }
-}
-
-/* All the new VM stuff */
-u64 i915_gem_obj_offset(struct drm_i915_gem_object *o,
-                       struct i915_address_space *vm)
-{
-       struct drm_i915_private *dev_priv = to_i915(o->base.dev);
-       struct i915_vma *vma;
-
-       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
-
-       list_for_each_entry(vma, &o->vma_list, obj_link) {
-               if (vma->is_ggtt &&
-                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
-                       continue;
-               if (vma->vm == vm)
-                       return vma->node.start;
-       }
-
-       WARN(1, "%s vma for this object not found.\n",
-            i915_is_ggtt(vm) ? "global" : "ppgtt");
-       return -1;
-}
-
-u64 i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
-                                 const struct i915_ggtt_view *view)
-{
-       struct i915_vma *vma;
-
-       list_for_each_entry(vma, &o->vma_list, obj_link)
-               if (vma->is_ggtt && i915_ggtt_view_equal(&vma->ggtt_view, view))
-                       return vma->node.start;
-
-       WARN(1, "global vma for this object not found. (view=%u)\n", view->type);
-       return -1;
-}
-
-bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
-                       struct i915_address_space *vm)
-{
-       struct i915_vma *vma;
-
-       list_for_each_entry(vma, &o->vma_list, obj_link) {
-               if (vma->is_ggtt &&
-                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
-                       continue;
-               if (vma->vm == vm && drm_mm_node_allocated(&vma->node))
-                       return true;
+               WARN_ON(atomic_read(&new->frontbuffer_bits) & frontbuffer_bits);
+               atomic_or(frontbuffer_bits, &new->frontbuffer_bits);
        }
-
-       return false;
-}
-
-bool i915_gem_obj_ggtt_bound_view(struct drm_i915_gem_object *o,
-                                 const struct i915_ggtt_view *view)
-{
-       struct i915_vma *vma;
-
-       list_for_each_entry(vma, &o->vma_list, obj_link)
-               if (vma->is_ggtt &&
-                   i915_ggtt_view_equal(&vma->ggtt_view, view) &&
-                   drm_mm_node_allocated(&vma->node))
-                       return true;
-
-       return false;
-}
-
-bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o)
-{
-       struct i915_vma *vma;
-
-       list_for_each_entry(vma, &o->vma_list, obj_link)
-               if (drm_mm_node_allocated(&vma->node))
-                       return true;
-
-       return false;
-}
-
-unsigned long i915_gem_obj_ggtt_size(struct drm_i915_gem_object *o)
-{
-       struct i915_vma *vma;
-
-       GEM_BUG_ON(list_empty(&o->vma_list));
-
-       list_for_each_entry(vma, &o->vma_list, obj_link) {
-               if (vma->is_ggtt &&
-                   vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
-                       return vma->node.size;
-       }
-
-       return 0;
-}
-
-bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj)
-{
-       struct i915_vma *vma;
-       list_for_each_entry(vma, &obj->vma_list, obj_link)
-               if (vma->pin_count > 0)
-                       return true;
-
-       return false;
 }
 
 /* Like i915_gem_object_get_page(), but mark the returned page dirty */
@@ -5590,6 +4777,6 @@ i915_gem_object_create_from_data(struct drm_device *dev,
        return obj;
 
 fail:
-       drm_gem_object_unreference(&obj->base);
+       i915_gem_object_put(obj);
        return ERR_PTR(ret);
 }
index 3752d5d..ed98959 100644 (file)
 
 /**
  * i915_gem_batch_pool_init() - initialize a batch buffer pool
- * @dev: the drm device
+ * @engine: the associated request submission engine
  * @pool: the batch buffer pool
  */
-void i915_gem_batch_pool_init(struct drm_device *dev,
+void i915_gem_batch_pool_init(struct intel_engine_cs *engine,
                              struct i915_gem_batch_pool *pool)
 {
        int n;
 
-       pool->dev = dev;
+       pool->engine = engine;
 
        for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++)
                INIT_LIST_HEAD(&pool->cache_list[n]);
@@ -65,18 +65,17 @@ void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool)
 {
        int n;
 
-       WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
+       lockdep_assert_held(&pool->engine->i915->drm.struct_mutex);
 
        for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++) {
-               while (!list_empty(&pool->cache_list[n])) {
-                       struct drm_i915_gem_object *obj =
-                               list_first_entry(&pool->cache_list[n],
-                                                struct drm_i915_gem_object,
-                                                batch_pool_link);
-
-                       list_del(&obj->batch_pool_link);
-                       drm_gem_object_unreference(&obj->base);
-               }
+               struct drm_i915_gem_object *obj, *next;
+
+               list_for_each_entry_safe(obj, next,
+                                        &pool->cache_list[n],
+                                        batch_pool_link)
+                       i915_gem_object_put(obj);
+
+               INIT_LIST_HEAD(&pool->cache_list[n]);
        }
 }
 
@@ -102,7 +101,7 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
        struct list_head *list;
        int n;
 
-       WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
+       lockdep_assert_held(&pool->engine->i915->drm.struct_mutex);
 
        /* Compute a power-of-two bucket, but throw everything greater than
         * 16KiB into the same bucket: i.e. the the buckets hold objects of
@@ -115,13 +114,14 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
 
        list_for_each_entry_safe(tmp, next, list, batch_pool_link) {
                /* The batches are strictly LRU ordered */
-               if (tmp->active)
+               if (!i915_gem_active_is_idle(&tmp->last_read[pool->engine->id],
+                                            &tmp->base.dev->struct_mutex))
                        break;
 
                /* While we're looping, do some clean up */
                if (tmp->madv == __I915_MADV_PURGED) {
                        list_del(&tmp->batch_pool_link);
-                       drm_gem_object_unreference(&tmp->base);
+                       i915_gem_object_put(tmp);
                        continue;
                }
 
@@ -134,7 +134,7 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
        if (obj == NULL) {
                int ret;
 
-               obj = i915_gem_object_create(pool->dev, size);
+               obj = i915_gem_object_create(&pool->engine->i915->drm, size);
                if (IS_ERR(obj))
                        return obj;
 
index 848e907..10d5ac4 100644 (file)
 
 #include "i915_drv.h"
 
+struct intel_engine_cs;
+
 struct i915_gem_batch_pool {
-       struct drm_device *dev;
+       struct intel_engine_cs *engine;
        struct list_head cache_list[4];
 };
 
 /* i915_gem_batch_pool.c */
-void i915_gem_batch_pool_init(struct drm_device *dev,
+void i915_gem_batch_pool_init(struct intel_engine_cs *engine,
                              struct i915_gem_batch_pool *pool);
 void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool);
 struct drm_i915_gem_object*
index 3c97f0e..df10f4e 100644 (file)
@@ -134,21 +134,6 @@ static int get_context_size(struct drm_i915_private *dev_priv)
        return ret;
 }
 
-static void i915_gem_context_clean(struct i915_gem_context *ctx)
-{
-       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;
-       struct i915_vma *vma, *next;
-
-       if (!ppgtt)
-               return;
-
-       list_for_each_entry_safe(vma, next, &ppgtt->base.inactive_list,
-                                vm_link) {
-               if (WARN_ON(__i915_vma_unbind_no_wait(vma)))
-                       break;
-       }
-}
-
 void i915_gem_context_free(struct kref *ctx_ref)
 {
        struct i915_gem_context *ctx = container_of(ctx_ref, typeof(*ctx), ref);
@@ -156,13 +141,7 @@ void i915_gem_context_free(struct kref *ctx_ref)
 
        lockdep_assert_held(&ctx->i915->drm.struct_mutex);
        trace_i915_context_free(ctx);
-
-       /*
-        * This context is going away and we need to remove all VMAs still
-        * around. This is to handle imported shared objects for which
-        * destructor did not run when their handles were closed.
-        */
-       i915_gem_context_clean(ctx);
+       GEM_BUG_ON(!ctx->closed);
 
        i915_ppgtt_put(ctx->ppgtt);
 
@@ -173,12 +152,13 @@ void i915_gem_context_free(struct kref *ctx_ref)
                        continue;
 
                WARN_ON(ce->pin_count);
-               if (ce->ringbuf)
-                       intel_ringbuffer_free(ce->ringbuf);
+               if (ce->ring)
+                       intel_ring_free(ce->ring);
 
-               drm_gem_object_unreference(&ce->state->base);
+               i915_vma_put(ce->state);
        }
 
+       put_pid(ctx->pid);
        list_del(&ctx->link);
 
        ida_simple_remove(&ctx->i915->context_hw_ida, ctx->hw_id);
@@ -216,7 +196,7 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
                ret = i915_gem_object_set_cache_level(obj, I915_CACHE_L3_LLC);
                /* Failure shouldn't ever happen this early */
                if (WARN_ON(ret)) {
-                       drm_gem_object_unreference(&obj->base);
+                       i915_gem_object_put(obj);
                        return ERR_PTR(ret);
                }
        }
@@ -224,6 +204,37 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t 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)
+{
+       GEM_BUG_ON(ctx->closed);
+       ctx->closed = true;
+       if (ctx->ppgtt)
+               i915_ppgtt_close(&ctx->ppgtt->base);
+       ctx->file_priv = ERR_PTR(-EBADF);
+       i915_gem_context_put(ctx);
+}
+
 static int assign_hw_id(struct drm_i915_private *dev_priv, unsigned *out)
 {
        int ret;
@@ -271,13 +282,24 @@ __create_hw_context(struct drm_device *dev,
        ctx->ggtt_alignment = get_context_alignment(dev_priv);
 
        if (dev_priv->hw_context_size) {
-               struct drm_i915_gem_object *obj =
-                               i915_gem_alloc_context_obj(dev, dev_priv->hw_context_size);
+               struct drm_i915_gem_object *obj;
+               struct i915_vma *vma;
+
+               obj = i915_gem_alloc_context_obj(dev,
+                                                dev_priv->hw_context_size);
                if (IS_ERR(obj)) {
                        ret = PTR_ERR(obj);
                        goto err_out;
                }
-               ctx->engine[RCS].state = obj;
+
+               vma = i915_vma_create(obj, &dev_priv->ggtt.base, NULL);
+               if (IS_ERR(vma)) {
+                       i915_gem_object_put(obj);
+                       ret = PTR_ERR(vma);
+                       goto err_out;
+               }
+
+               ctx->engine[RCS].state = vma;
        }
 
        /* Default context will never have a file_priv */
@@ -290,6 +312,9 @@ __create_hw_context(struct drm_device *dev,
                ret = DEFAULT_CONTEXT_HANDLE;
 
        ctx->file_priv = file_priv;
+       if (file_priv)
+               ctx->pid = get_task_pid(current, PIDTYPE_PID);
+
        ctx->user_handle = ret;
        /* NB: Mark all slices as needing a remap so that when the context first
         * loads it will restore whatever remap state already exists. If there
@@ -305,7 +330,7 @@ __create_hw_context(struct drm_device *dev,
        return ctx;
 
 err_out:
-       i915_gem_context_unreference(ctx);
+       context_close(ctx);
        return ERR_PTR(ret);
 }
 
@@ -327,13 +352,14 @@ i915_gem_create_context(struct drm_device *dev,
                return ctx;
 
        if (USES_FULL_PPGTT(dev)) {
-               struct i915_hw_ppgtt *ppgtt = i915_ppgtt_create(dev, file_priv);
+               struct i915_hw_ppgtt *ppgtt =
+                       i915_ppgtt_create(to_i915(dev), file_priv);
 
                if (IS_ERR(ppgtt)) {
                        DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
                                         PTR_ERR(ppgtt));
                        idr_remove(&file_priv->context_idr, ctx->user_handle);
-                       i915_gem_context_unreference(ctx);
+                       context_close(ctx);
                        return ERR_CAST(ppgtt);
                }
 
@@ -388,28 +414,12 @@ static void i915_gem_context_unpin(struct i915_gem_context *ctx,
                struct intel_context *ce = &ctx->engine[engine->id];
 
                if (ce->state)
-                       i915_gem_object_ggtt_unpin(ce->state);
+                       i915_vma_unpin(ce->state);
 
-               i915_gem_context_unreference(ctx);
+               i915_gem_context_put(ctx);
        }
 }
 
-void i915_gem_context_reset(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       lockdep_assert_held(&dev->struct_mutex);
-
-       if (i915.enable_execlists) {
-               struct i915_gem_context *ctx;
-
-               list_for_each_entry(ctx, &dev_priv->context_list, link)
-                       intel_lr_context_reset(dev_priv, ctx);
-       }
-
-       i915_gem_context_lost(dev_priv);
-}
-
 int i915_gem_context_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -504,7 +514,7 @@ void i915_gem_context_fini(struct drm_device *dev)
 
        lockdep_assert_held(&dev->struct_mutex);
 
-       i915_gem_context_unreference(dctx);
+       context_close(dctx);
        dev_priv->kernel_context = NULL;
 
        ida_destroy(&dev_priv->context_hw_ida);
@@ -514,8 +524,7 @@ static int context_idr_cleanup(int id, void *p, void *data)
 {
        struct i915_gem_context *ctx = p;
 
-       ctx->file_priv = ERR_PTR(-EBADF);
-       i915_gem_context_unreference(ctx);
+       context_close(ctx);
        return 0;
 }
 
@@ -552,12 +561,13 @@ static inline int
 mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags)
 {
        struct drm_i915_private *dev_priv = req->i915;
+       struct intel_ring *ring = req->ring;
        struct intel_engine_cs *engine = req->engine;
        u32 flags = hw_flags | MI_MM_SPACE_GTT;
        const int num_rings =
                /* Use an extended w/a on ivb+ if signalling from other rings */
-               i915_semaphore_is_enabled(dev_priv) ?
-               hweight32(INTEL_INFO(dev_priv)->ring_mask) - 1 :
+               i915.semaphores ?
+               INTEL_INFO(dev_priv)->num_rings - 1 :
                0;
        int len, ret;
 
@@ -567,7 +577,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags)
         * itlb_before_ctx_switch.
         */
        if (IS_GEN6(dev_priv)) {
-               ret = engine->flush(req, I915_GEM_GPU_DOMAINS, 0);
+               ret = engine->emit_flush(req, EMIT_INVALIDATE);
                if (ret)
                        return ret;
        }
@@ -589,64 +599,64 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags)
 
        /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */
        if (INTEL_GEN(dev_priv) >= 7) {
-               intel_ring_emit(engine, MI_ARB_ON_OFF | MI_ARB_DISABLE);
+               intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE);
                if (num_rings) {
                        struct intel_engine_cs *signaller;
 
-                       intel_ring_emit(engine,
+                       intel_ring_emit(ring,
                                        MI_LOAD_REGISTER_IMM(num_rings));
                        for_each_engine(signaller, dev_priv) {
                                if (signaller == engine)
                                        continue;
 
-                               intel_ring_emit_reg(engine,
+                               intel_ring_emit_reg(ring,
                                                    RING_PSMI_CTL(signaller->mmio_base));
-                               intel_ring_emit(engine,
+                               intel_ring_emit(ring,
                                                _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
                        }
                }
        }
 
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_emit(engine, MI_SET_CONTEXT);
-       intel_ring_emit(engine,
-                       i915_gem_obj_ggtt_offset(req->ctx->engine[RCS].state) |
-                       flags);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(ring, MI_SET_CONTEXT);
+       intel_ring_emit(ring,
+                       i915_ggtt_offset(req->ctx->engine[RCS].state) | flags);
        /*
         * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
         * WaMiSetContext_Hang:snb,ivb,vlv
         */
-       intel_ring_emit(engine, MI_NOOP);
+       intel_ring_emit(ring, MI_NOOP);
 
        if (INTEL_GEN(dev_priv) >= 7) {
                if (num_rings) {
                        struct intel_engine_cs *signaller;
                        i915_reg_t last_reg = {}; /* keep gcc quiet */
 
-                       intel_ring_emit(engine,
+                       intel_ring_emit(ring,
                                        MI_LOAD_REGISTER_IMM(num_rings));
                        for_each_engine(signaller, dev_priv) {
                                if (signaller == engine)
                                        continue;
 
                                last_reg = RING_PSMI_CTL(signaller->mmio_base);
-                               intel_ring_emit_reg(engine, last_reg);
-                               intel_ring_emit(engine,
+                               intel_ring_emit_reg(ring, last_reg);
+                               intel_ring_emit(ring,
                                                _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
                        }
 
                        /* Insert a delay before the next switch! */
-                       intel_ring_emit(engine,
+                       intel_ring_emit(ring,
                                        MI_STORE_REGISTER_MEM |
                                        MI_SRM_LRM_GLOBAL_GTT);
-                       intel_ring_emit_reg(engine, last_reg);
-                       intel_ring_emit(engine, engine->scratch.gtt_offset);
-                       intel_ring_emit(engine, MI_NOOP);
+                       intel_ring_emit_reg(ring, last_reg);
+                       intel_ring_emit(ring,
+                                       i915_ggtt_offset(engine->scratch));
+                       intel_ring_emit(ring, MI_NOOP);
                }
-               intel_ring_emit(engine, MI_ARB_ON_OFF | MI_ARB_ENABLE);
+               intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE);
        }
 
-       intel_ring_advance(engine);
+       intel_ring_advance(ring);
 
        return ret;
 }
@@ -654,7 +664,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags)
 static int remap_l3(struct drm_i915_gem_request *req, int slice)
 {
        u32 *remap_info = req->i915->l3_parity.remap_info[slice];
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        int i, ret;
 
        if (!remap_info)
@@ -669,13 +679,13 @@ static int remap_l3(struct drm_i915_gem_request *req, int slice)
         * here because no other code should access these registers other than
         * at initialization time.
         */
-       intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(GEN7_L3LOG_SIZE/4));
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(GEN7_L3LOG_SIZE/4));
        for (i = 0; i < GEN7_L3LOG_SIZE/4; i++) {
-               intel_ring_emit_reg(engine, GEN7_L3LOG(slice, i));
-               intel_ring_emit(engine, remap_info[i]);
+               intel_ring_emit_reg(ring, GEN7_L3LOG(slice, i));
+               intel_ring_emit(ring, remap_info[i]);
        }
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -744,6 +754,7 @@ static int do_rcs_switch(struct drm_i915_gem_request *req)
        struct i915_gem_context *to = req->ctx;
        struct intel_engine_cs *engine = req->engine;
        struct i915_hw_ppgtt *ppgtt = to->ppgtt ?: req->i915->mm.aliasing_ppgtt;
+       struct i915_vma *vma = to->engine[RCS].state;
        struct i915_gem_context *from;
        u32 hw_flags;
        int ret, i;
@@ -751,10 +762,15 @@ static int do_rcs_switch(struct drm_i915_gem_request *req)
        if (skip_rcs_switch(ppgtt, engine, to))
                return 0;
 
+       /* Clear this page out of any CPU caches for coherent swap-in/out. */
+       if (!(vma->flags & I915_VMA_GLOBAL_BIND)) {
+               ret = i915_gem_object_set_to_gtt_domain(vma->obj, false);
+               if (ret)
+                       return ret;
+       }
+
        /* Trying to pin first makes error handling easier. */
-       ret = i915_gem_obj_ggtt_pin(to->engine[RCS].state,
-                                   to->ggtt_alignment,
-                                   0);
+       ret = i915_vma_pin(vma, 0, to->ggtt_alignment, PIN_GLOBAL);
        if (ret)
                return ret;
 
@@ -767,18 +783,6 @@ static int do_rcs_switch(struct drm_i915_gem_request *req)
         */
        from = engine->last_context;
 
-       /*
-        * Clear this page out of any CPU caches for coherent swap-in/out. Note
-        * that thanks to write = false in this call and us not setting any gpu
-        * write domains when putting a context object onto the active list
-        * (when switching away from it), this won't block.
-        *
-        * XXX: We need a real interface to do this instead of trickery.
-        */
-       ret = i915_gem_object_set_to_gtt_domain(to->engine[RCS].state, false);
-       if (ret)
-               goto unpin_out;
-
        if (needs_pd_load_pre(ppgtt, engine, to)) {
                /* Older GENs and non render rings still want the load first,
                 * "PP_DCLV followed by PP_DIR_BASE register through Load
@@ -787,7 +791,7 @@ static int do_rcs_switch(struct drm_i915_gem_request *req)
                trace_switch_mm(engine, to);
                ret = ppgtt->switch_mm(ppgtt, req);
                if (ret)
-                       goto unpin_out;
+                       goto err;
        }
 
        if (!to->engine[RCS].initialised || i915_gem_context_is_default(to))
@@ -804,7 +808,7 @@ static int do_rcs_switch(struct drm_i915_gem_request *req)
        if (to != from || (hw_flags & MI_FORCE_RESTORE)) {
                ret = mi_set_context(req, hw_flags);
                if (ret)
-                       goto unpin_out;
+                       goto err;
        }
 
        /* The backing object for the context is done after switching to the
@@ -814,8 +818,6 @@ static int do_rcs_switch(struct drm_i915_gem_request *req)
         * MI_SET_CONTEXT instead of when the next seqno has completed.
         */
        if (from != NULL) {
-               from->engine[RCS].state->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
-               i915_vma_move_to_active(i915_gem_obj_to_ggtt(from->engine[RCS].state), req);
                /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the
                 * whole damn pipeline, we don't need to explicitly mark the
                 * object dirty. The only exception is that the context must be
@@ -823,14 +825,12 @@ static int do_rcs_switch(struct drm_i915_gem_request *req)
                 * able to defer doing this until we know the object would be
                 * swapped, but there is no way to do that yet.
                 */
-               from->engine[RCS].state->dirty = 1;
-
-               /* obj is kept alive until the next request by its active ref */
-               i915_gem_object_ggtt_unpin(from->engine[RCS].state);
-               i915_gem_context_unreference(from);
+               i915_vma_move_to_active(from->engine[RCS].state, req, 0);
+               /* state is kept alive until the next request */
+               i915_vma_unpin(from->engine[RCS].state);
+               i915_gem_context_put(from);
        }
-       i915_gem_context_reference(to);
-       engine->last_context = to;
+       engine->last_context = i915_gem_context_get(to);
 
        /* GEN8 does *not* require an explicit reload if the PDPs have been
         * setup, and we do not wish to move them.
@@ -872,8 +872,8 @@ static int do_rcs_switch(struct drm_i915_gem_request *req)
 
        return 0;
 
-unpin_out:
-       i915_gem_object_ggtt_unpin(to->engine[RCS].state);
+err:
+       i915_vma_unpin(vma);
        return ret;
 }
 
@@ -894,8 +894,9 @@ int i915_switch_context(struct drm_i915_gem_request *req)
 {
        struct intel_engine_cs *engine = req->engine;
 
-       WARN_ON(i915.enable_execlists);
        lockdep_assert_held(&req->i915->drm.struct_mutex);
+       if (i915.enable_execlists)
+               return 0;
 
        if (!req->ctx->engine[engine->id].state) {
                struct i915_gem_context *to = req->ctx;
@@ -914,10 +915,9 @@ int i915_switch_context(struct drm_i915_gem_request *req)
                }
 
                if (to != engine->last_context) {
-                       i915_gem_context_reference(to);
                        if (engine->last_context)
-                               i915_gem_context_unreference(engine->last_context);
-                       engine->last_context = to;
+                               i915_gem_context_put(engine->last_context);
+                       engine->last_context = i915_gem_context_get(to);
                }
 
                return 0;
@@ -926,6 +926,33 @@ int i915_switch_context(struct drm_i915_gem_request *req)
        return do_rcs_switch(req);
 }
 
+int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
+{
+       struct intel_engine_cs *engine;
+
+       for_each_engine(engine, dev_priv) {
+               struct drm_i915_gem_request *req;
+               int ret;
+
+               if (engine->last_context == NULL)
+                       continue;
+
+               if (engine->last_context == dev_priv->kernel_context)
+                       continue;
+
+               req = i915_gem_request_alloc(engine, dev_priv->kernel_context);
+               if (IS_ERR(req))
+                       return PTR_ERR(req);
+
+               ret = i915_switch_context(req);
+               i915_add_request_no_flush(req);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static bool contexts_enabled(struct drm_device *dev)
 {
        return i915.enable_execlists || to_i915(dev)->hw_context_size;
@@ -985,7 +1012,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
        }
 
        idr_remove(&file_priv->context_idr, ctx->user_handle);
-       i915_gem_context_unreference(ctx);
+       context_close(ctx);
        mutex_unlock(&dev->struct_mutex);
 
        DRM_DEBUG_DRIVER("HW context %d destroyed\n", args->ctx_id);
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c
deleted file mode 100644 (file)
index a565164..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright © 2008 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.
- *
- * Authors:
- *    Keith Packard <keithp@keithp.com>
- *
- */
-
-#include <drm/drmP.h>
-#include <drm/i915_drm.h>
-#include "i915_drv.h"
-
-#if WATCH_LISTS
-int
-i915_verify_lists(struct drm_device *dev)
-{
-       static int warned;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_i915_gem_object *obj;
-       struct intel_engine_cs *engine;
-       int err = 0;
-
-       if (warned)
-               return 0;
-
-       for_each_engine(engine, dev_priv) {
-               list_for_each_entry(obj, &engine->active_list,
-                                   engine_list[engine->id]) {
-                       if (obj->base.dev != dev ||
-                           !atomic_read(&obj->base.refcount.refcount)) {
-                               DRM_ERROR("%s: freed active obj %p\n",
-                                         engine->name, obj);
-                               err++;
-                               break;
-                       } else if (!obj->active ||
-                                  obj->last_read_req[engine->id] == NULL) {
-                               DRM_ERROR("%s: invalid active obj %p\n",
-                                         engine->name, obj);
-                               err++;
-                       } else if (obj->base.write_domain) {
-                               DRM_ERROR("%s: invalid write obj %p (w %x)\n",
-                                         engine->name,
-                                         obj, obj->base.write_domain);
-                               err++;
-                       }
-               }
-       }
-
-       return warned = err;
-}
-#endif /* WATCH_LIST */
index 80bbe43..97c9d68 100644 (file)
  * Authors:
  *     Dave Airlie <airlied@redhat.com>
  */
+
+#include <linux/dma-buf.h>
+#include <linux/reservation.h>
+
 #include <drm/drmP.h>
+
 #include "i915_drv.h"
-#include <linux/dma-buf.h>
 
 static struct drm_i915_gem_object *dma_buf_to_obj(struct dma_buf *buf)
 {
@@ -115,7 +119,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
        if (ret)
                return ERR_PTR(ret);
 
-       addr = i915_gem_object_pin_map(obj);
+       addr = i915_gem_object_pin_map(obj, I915_MAP_WB);
        mutex_unlock(&dev->struct_mutex);
 
        return addr;
@@ -218,25 +222,73 @@ static const struct dma_buf_ops i915_dmabuf_ops =  {
        .end_cpu_access = i915_gem_end_cpu_access,
 };
 
+static void export_fences(struct drm_i915_gem_object *obj,
+                         struct dma_buf *dma_buf)
+{
+       struct reservation_object *resv = dma_buf->resv;
+       struct drm_i915_gem_request *req;
+       unsigned long active;
+       int idx;
+
+       active = __I915_BO_ACTIVE(obj);
+       if (!active)
+               return;
+
+       /* Serialise with execbuf to prevent concurrent fence-loops */
+       mutex_lock(&obj->base.dev->struct_mutex);
+
+       /* Mark the object for future fences before racily adding old fences */
+       obj->base.dma_buf = dma_buf;
+
+       ww_mutex_lock(&resv->lock, NULL);
+
+       for_each_active(active, idx) {
+               req = i915_gem_active_get(&obj->last_read[idx],
+                                         &obj->base.dev->struct_mutex);
+               if (!req)
+                       continue;
+
+               if (reservation_object_reserve_shared(resv) == 0)
+                       reservation_object_add_shared_fence(resv, &req->fence);
+
+               i915_gem_request_put(req);
+       }
+
+       req = i915_gem_active_get(&obj->last_write,
+                                 &obj->base.dev->struct_mutex);
+       if (req) {
+               reservation_object_add_excl_fence(resv, &req->fence);
+               i915_gem_request_put(req);
+       }
+
+       ww_mutex_unlock(&resv->lock);
+       mutex_unlock(&obj->base.dev->struct_mutex);
+}
+
 struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
                                      struct drm_gem_object *gem_obj, int flags)
 {
        struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
        DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+       struct dma_buf *dma_buf;
 
        exp_info.ops = &i915_dmabuf_ops;
        exp_info.size = gem_obj->size;
        exp_info.flags = flags;
        exp_info.priv = gem_obj;
 
-
        if (obj->ops->dmabuf_export) {
                int ret = obj->ops->dmabuf_export(obj);
                if (ret)
                        return ERR_PTR(ret);
        }
 
-       return dma_buf_export(&exp_info);
+       dma_buf = drm_gem_dmabuf_export(dev, &exp_info);
+       if (IS_ERR(dma_buf))
+               return dma_buf;
+
+       export_fences(obj, dma_buf);
+       return dma_buf;
 }
 
 static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
@@ -278,8 +330,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
                         * Importing dmabuf exported from out own gem increases
                         * refcount on gem itself instead of f_count of dmabuf.
                         */
-                       drm_gem_object_reference(&obj->base);
-                       return &obj->base;
+                       return &i915_gem_object_get(obj)->base;
                }
        }
 
@@ -300,6 +351,16 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
        i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops);
        obj->base.import_attach = attach;
 
+       /* We use GTT as shorthand for a coherent domain, one that is
+        * neither in the GPU cache nor in the CPU cache, where all
+        * writes are immediately visible in memory. (That's not strictly
+        * true, but it's close! There are internal buffers such as the
+        * write-combined buffer or a delay through the chipset for GTT
+        * writes that do require us to treat GTT as a separate cache domain.)
+        */
+       obj->base.read_domains = I915_GEM_DOMAIN_GTT;
+       obj->base.write_domain = 0;
+
        return &obj->base;
 
 fail_detach:
index 3c1280e..5b6f81c 100644 (file)
 #include "intel_drv.h"
 #include "i915_trace.h"
 
-static int switch_to_pinned_context(struct drm_i915_private *dev_priv)
+static bool
+gpu_is_idle(struct drm_i915_private *dev_priv)
 {
        struct intel_engine_cs *engine;
 
-       if (i915.enable_execlists)
-               return 0;
-
        for_each_engine(engine, dev_priv) {
-               struct drm_i915_gem_request *req;
-               int ret;
-
-               if (engine->last_context == NULL)
-                       continue;
-
-               if (engine->last_context == dev_priv->kernel_context)
-                       continue;
-
-               req = i915_gem_request_alloc(engine, dev_priv->kernel_context);
-               if (IS_ERR(req))
-                       return PTR_ERR(req);
-
-               ret = i915_switch_context(req);
-               i915_add_request_no_flush(req);
-               if (ret)
-                       return ret;
+               if (intel_engine_is_active(engine))
+                       return false;
        }
 
-       return 0;
+       return true;
 }
 
-
 static bool
-mark_free(struct i915_vma *vma, struct list_head *unwind)
+mark_free(struct i915_vma *vma, unsigned int flags, struct list_head *unwind)
 {
-       if (vma->pin_count)
+       if (i915_vma_is_pinned(vma))
                return false;
 
        if (WARN_ON(!list_empty(&vma->exec_list)))
                return false;
 
+       if (flags & PIN_NONFAULT && vma->obj->fault_mappable)
+               return false;
+
        list_add(&vma->exec_list, unwind);
        return drm_mm_scan_add_block(&vma->node);
 }
 
 /**
  * i915_gem_evict_something - Evict vmas to make room for binding a new one
- * @dev: drm_device
  * @vm: address space to evict from
  * @min_size: size of the desired free space
  * @alignment: alignment constraint of the desired free space
@@ -102,42 +86,37 @@ mark_free(struct i915_vma *vma, struct list_head *unwind)
  * memory in e.g. the shrinker.
  */
 int
-i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm,
-                        int min_size, unsigned alignment, unsigned cache_level,
-                        unsigned long start, unsigned long end,
+i915_gem_evict_something(struct i915_address_space *vm,
+                        u64 min_size, u64 alignment,
+                        unsigned cache_level,
+                        u64 start, u64 end,
                         unsigned flags)
 {
-       struct list_head eviction_list, unwind_list;
-       struct i915_vma *vma;
-       int ret = 0;
-       int pass = 0;
+       struct drm_i915_private *dev_priv = to_i915(vm->dev);
+       struct list_head eviction_list;
+       struct list_head *phases[] = {
+               &vm->inactive_list,
+               &vm->active_list,
+               NULL,
+       }, **phase;
+       struct i915_vma *vma, *next;
+       int ret;
 
-       trace_i915_gem_evict(dev, min_size, alignment, flags);
+       trace_i915_gem_evict(vm, min_size, alignment, flags);
 
        /*
         * The goal is to evict objects and amalgamate space in LRU order.
         * The oldest idle objects reside on the inactive list, which is in
-        * retirement order. The next objects to retire are those on the (per
-        * ring) active list that do not have an outstanding flush. Once the
-        * hardware reports completion (the seqno is updated after the
-        * batchbuffer has been finished) the clean buffer objects would
-        * be retired to the inactive list. Any dirty objects would be added
-        * to the tail of the flushing list. So after processing the clean
-        * active objects we need to emit a MI_FLUSH to retire the flushing
-        * list, hence the retirement order of the flushing list is in
-        * advance of the dirty objects on the active lists.
+        * retirement order. The next objects to retire are those in flight,
+        * on the active list, again in retirement order.
         *
         * The retirement sequence is thus:
         *   1. Inactive objects (already retired)
-        *   2. Clean active objects
-        *   3. Flushing list
-        *   4. Dirty active objects.
+        *   2. Active objects (will stall on unbinding)
         *
         * On each list, the oldest objects lie at the HEAD with the freshest
         * object on the TAIL.
         */
-
-       INIT_LIST_HEAD(&unwind_list);
        if (start != 0 || end != vm->total) {
                drm_mm_init_scan_with_range(&vm->mm, min_size,
                                            alignment, cache_level,
@@ -145,96 +124,86 @@ i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm,
        } else
                drm_mm_init_scan(&vm->mm, min_size, alignment, cache_level);
 
-search_again:
-       /* First see if there is a large enough contiguous idle region... */
-       list_for_each_entry(vma, &vm->inactive_list, vm_link) {
-               if (mark_free(vma, &unwind_list))
-                       goto found;
-       }
-
        if (flags & PIN_NONBLOCK)
-               goto none;
+               phases[1] = NULL;
 
-       /* Now merge in the soon-to-be-expired objects... */
-       list_for_each_entry(vma, &vm->active_list, vm_link) {
-               if (mark_free(vma, &unwind_list))
-                       goto found;
-       }
+search_again:
+       INIT_LIST_HEAD(&eviction_list);
+       phase = phases;
+       do {
+               list_for_each_entry(vma, *phase, vm_link)
+                       if (mark_free(vma, flags, &eviction_list))
+                               goto found;
+       } while (*++phase);
 
-none:
        /* Nothing found, clean up and bail out! */
-       while (!list_empty(&unwind_list)) {
-               vma = list_first_entry(&unwind_list,
-                                      struct i915_vma,
-                                      exec_list);
+       list_for_each_entry_safe(vma, next, &eviction_list, exec_list) {
                ret = drm_mm_scan_remove_block(&vma->node);
                BUG_ON(ret);
 
-               list_del_init(&vma->exec_list);
+               INIT_LIST_HEAD(&vma->exec_list);
        }
 
        /* Can we unpin some objects such as idle hw contents,
-        * or pending flips?
+        * or pending flips? But since only the GGTT has global entries
+        * such as scanouts, rinbuffers and contexts, we can skip the
+        * purge when inspecting per-process local address spaces.
         */
-       if (flags & PIN_NONBLOCK)
+       if (!i915_is_ggtt(vm) || flags & PIN_NONBLOCK)
                return -ENOSPC;
 
-       /* Only idle the GPU and repeat the search once */
-       if (pass++ == 0) {
-               struct drm_i915_private *dev_priv = to_i915(dev);
-
-               if (i915_is_ggtt(vm)) {
-                       ret = switch_to_pinned_context(dev_priv);
-                       if (ret)
-                               return ret;
-               }
-
-               ret = i915_gem_wait_for_idle(dev_priv);
-               if (ret)
-                       return ret;
-
-               i915_gem_retire_requests(dev_priv);
-               goto search_again;
+       if (gpu_is_idle(dev_priv)) {
+               /* If we still have pending pageflip completions, drop
+                * back to userspace to give our workqueues time to
+                * acquire our locks and unpin the old scanouts.
+                */
+               return intel_has_pending_fb_unpin(vm->dev) ? -EAGAIN : -ENOSPC;
        }
 
-       /* If we still have pending pageflip completions, drop
-        * back to userspace to give our workqueues time to
-        * acquire our locks and unpin the old scanouts.
+       /* Not everything in the GGTT is tracked via vma (otherwise we
+        * could evict as required with minimal stalling) so we are forced
+        * to idle the GPU and explicitly retire outstanding requests in
+        * the hopes that we can then remove contexts and the like only
+        * bound by their active reference.
         */
-       return intel_has_pending_fb_unpin(dev) ? -EAGAIN : -ENOSPC;
+       ret = i915_gem_switch_to_kernel_context(dev_priv);
+       if (ret)
+               return ret;
+
+       ret = i915_gem_wait_for_idle(dev_priv,
+                                    I915_WAIT_INTERRUPTIBLE |
+                                    I915_WAIT_LOCKED);
+       if (ret)
+               return ret;
+
+       i915_gem_retire_requests(dev_priv);
+       goto search_again;
 
 found:
        /* drm_mm doesn't allow any other other operations while
-        * scanning, therefore store to be evicted objects on a
-        * temporary list. */
-       INIT_LIST_HEAD(&eviction_list);
-       while (!list_empty(&unwind_list)) {
-               vma = list_first_entry(&unwind_list,
-                                      struct i915_vma,
-                                      exec_list);
-               if (drm_mm_scan_remove_block(&vma->node)) {
-                       list_move(&vma->exec_list, &eviction_list);
-                       drm_gem_object_reference(&vma->obj->base);
-                       continue;
-               }
-               list_del_init(&vma->exec_list);
+        * scanning, therefore store to-be-evicted objects on a
+        * temporary list and take a reference for all before
+        * calling unbind (which may remove the active reference
+        * of any of our objects, thus corrupting the list).
+        */
+       list_for_each_entry_safe(vma, next, &eviction_list, exec_list) {
+               if (drm_mm_scan_remove_block(&vma->node))
+                       __i915_vma_pin(vma);
+               else
+                       list_del_init(&vma->exec_list);
        }
 
        /* Unbinding will emit any required flushes */
        while (!list_empty(&eviction_list)) {
-               struct drm_gem_object *obj;
                vma = list_first_entry(&eviction_list,
                                       struct i915_vma,
                                       exec_list);
 
-               obj =  &vma->obj->base;
                list_del_init(&vma->exec_list);
+               __i915_vma_unpin(vma);
                if (ret == 0)
                        ret = i915_vma_unbind(vma);
-
-               drm_gem_object_unreference(obj);
        }
-
        return ret;
 }
 
@@ -256,8 +225,8 @@ i915_gem_evict_for_vma(struct i915_vma *target)
 
                vma = container_of(node, typeof(*vma), node);
 
-               if (vma->pin_count) {
-                       if (!vma->exec_entry || (vma->pin_count > 1))
+               if (i915_vma_is_pinned(vma)) {
+                       if (!vma->exec_entry || i915_vma_pin_count(vma) > 1)
                                /* Object is pinned for some other use */
                                return -EBUSY;
 
@@ -303,22 +272,23 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
                struct drm_i915_private *dev_priv = to_i915(vm->dev);
 
                if (i915_is_ggtt(vm)) {
-                       ret = switch_to_pinned_context(dev_priv);
+                       ret = i915_gem_switch_to_kernel_context(dev_priv);
                        if (ret)
                                return ret;
                }
 
-               ret = i915_gem_wait_for_idle(dev_priv);
+               ret = i915_gem_wait_for_idle(dev_priv,
+                                            I915_WAIT_INTERRUPTIBLE |
+                                            I915_WAIT_LOCKED);
                if (ret)
                        return ret;
 
                i915_gem_retire_requests(dev_priv);
-
                WARN_ON(!list_empty(&vm->active_list));
        }
 
        list_for_each_entry_safe(vma, next, &vm->inactive_list, vm_link)
-               if (vma->pin_count == 0)
+               if (!i915_vma_is_pinned(vma))
                        WARN_ON(i915_vma_unbind(vma));
 
        return 0;
index 72628ed..7adb4c7 100644 (file)
  *
  */
 
+#include <linux/dma_remapping.h>
+#include <linux/reservation.h>
+#include <linux/uaccess.h>
+
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
+
 #include "i915_drv.h"
+#include "i915_gem_dmabuf.h"
 #include "i915_trace.h"
 #include "intel_drv.h"
-#include <linux/dma_remapping.h>
-#include <linux/uaccess.h>
+#include "intel_frontbuffer.h"
 
-#define  __EXEC_OBJECT_HAS_PIN (1<<31)
-#define  __EXEC_OBJECT_HAS_FENCE (1<<30)
-#define  __EXEC_OBJECT_NEEDS_MAP (1<<29)
-#define  __EXEC_OBJECT_NEEDS_BIAS (1<<28)
+#define DBG_USE_CPU_RELOC 0 /* -1 force GTT relocs; 1 force CPU relocs */
+
+#define  __EXEC_OBJECT_HAS_PIN         (1<<31)
+#define  __EXEC_OBJECT_HAS_FENCE       (1<<30)
+#define  __EXEC_OBJECT_NEEDS_MAP       (1<<29)
+#define  __EXEC_OBJECT_NEEDS_BIAS      (1<<28)
+#define  __EXEC_OBJECT_INTERNAL_FLAGS (0xf<<28) /* all of the above */
 
 #define BATCH_OFFSET_BIAS (256*1024)
 
+struct i915_execbuffer_params {
+       struct drm_device               *dev;
+       struct drm_file                 *file;
+       struct i915_vma                 *batch;
+       u32                             dispatch_flags;
+       u32                             args_batch_start_offset;
+       struct intel_engine_cs          *engine;
+       struct i915_gem_context         *ctx;
+       struct drm_i915_gem_request     *request;
+};
+
 struct eb_vmas {
+       struct drm_i915_private *i915;
        struct list_head vmas;
        int and;
        union {
@@ -51,7 +71,8 @@ struct eb_vmas {
 };
 
 static struct eb_vmas *
-eb_create(struct drm_i915_gem_execbuffer2 *args)
+eb_create(struct drm_i915_private *i915,
+         struct drm_i915_gem_execbuffer2 *args)
 {
        struct eb_vmas *eb = NULL;
 
@@ -78,6 +99,7 @@ eb_create(struct drm_i915_gem_execbuffer2 *args)
        } else
                eb->and = -args->buffer_count;
 
+       eb->i915 = i915;
        INIT_LIST_HEAD(&eb->vmas);
        return eb;
 }
@@ -89,6 +111,26 @@ eb_reset(struct eb_vmas *eb)
                memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head));
 }
 
+static struct i915_vma *
+eb_get_batch(struct eb_vmas *eb)
+{
+       struct i915_vma *vma = list_entry(eb->vmas.prev, typeof(*vma), exec_list);
+
+       /*
+        * SNA is doing fancy tricks with compressing batch buffers, which leads
+        * to negative relocation deltas. Usually that works out ok since the
+        * relocate address is still positive, except when the batch is placed
+        * very low in the GTT. Ensure this doesn't happen.
+        *
+        * Note that actual hangs have only been observed on gen7, but for
+        * paranoia do it everywhere.
+        */
+       if ((vma->exec_entry->flags & EXEC_OBJECT_PINNED) == 0)
+               vma->exec_entry->flags |= __EXEC_OBJECT_NEEDS_BIAS;
+
+       return vma;
+}
+
 static int
 eb_lookup_vmas(struct eb_vmas *eb,
               struct drm_i915_gem_exec_object2 *exec,
@@ -122,7 +164,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
                        goto err;
                }
 
-               drm_gem_object_reference(&obj->base);
+               i915_gem_object_get(obj);
                list_add_tail(&obj->obj_exec_link, &objects);
        }
        spin_unlock(&file->table_lock);
@@ -143,8 +185,8 @@ 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);
-               if (IS_ERR(vma)) {
+               vma = i915_gem_obj_lookup_or_create_vma(obj, vm, NULL);
+               if (unlikely(IS_ERR(vma))) {
                        DRM_DEBUG("Failed to lookup VMA\n");
                        ret = PTR_ERR(vma);
                        goto err;
@@ -175,7 +217,7 @@ err:
                                       struct drm_i915_gem_object,
                                       obj_exec_link);
                list_del_init(&obj->obj_exec_link);
-               drm_gem_object_unreference(&obj->base);
+               i915_gem_object_put(obj);
        }
        /*
         * Objects already transfered to the vmas list will be unreferenced by
@@ -208,7 +250,6 @@ static void
 i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
 {
        struct drm_i915_gem_exec_object2 *entry;
-       struct drm_i915_gem_object *obj = vma->obj;
 
        if (!drm_mm_node_allocated(&vma->node))
                return;
@@ -216,10 +257,10 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
        entry = vma->exec_entry;
 
        if (entry->flags & __EXEC_OBJECT_HAS_FENCE)
-               i915_gem_object_unpin_fence(obj);
+               i915_vma_unpin_fence(vma);
 
        if (entry->flags & __EXEC_OBJECT_HAS_PIN)
-               vma->pin_count--;
+               __i915_vma_unpin(vma);
 
        entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN);
 }
@@ -234,13 +275,19 @@ static void eb_destroy(struct eb_vmas *eb)
                                       exec_list);
                list_del_init(&vma->exec_list);
                i915_gem_execbuffer_unreserve_vma(vma);
-               drm_gem_object_unreference(&vma->obj->base);
+               i915_vma_put(vma);
        }
        kfree(eb);
 }
 
 static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
 {
+       if (!i915_gem_object_has_struct_page(obj))
+               return false;
+
+       if (DBG_USE_CPU_RELOC)
+               return DBG_USE_CPU_RELOC > 0;
+
        return (HAS_LLC(obj->base.dev) ||
                obj->base.write_domain == I915_GEM_DOMAIN_CPU ||
                obj->cache_level != I915_CACHE_NONE);
@@ -265,144 +312,265 @@ static inline uint64_t gen8_noncanonical_addr(uint64_t address)
 }
 
 static inline uint64_t
-relocation_target(struct drm_i915_gem_relocation_entry *reloc,
+relocation_target(const struct drm_i915_gem_relocation_entry *reloc,
                  uint64_t target_offset)
 {
        return gen8_canonical_addr((int)reloc->delta + target_offset);
 }
 
-static int
-relocate_entry_cpu(struct drm_i915_gem_object *obj,
-                  struct drm_i915_gem_relocation_entry *reloc,
-                  uint64_t target_offset)
+struct reloc_cache {
+       struct drm_i915_private *i915;
+       struct drm_mm_node node;
+       unsigned long vaddr;
+       unsigned int page;
+       bool use_64bit_reloc;
+};
+
+static void reloc_cache_init(struct reloc_cache *cache,
+                            struct drm_i915_private *i915)
 {
-       struct drm_device *dev = obj->base.dev;
-       uint32_t page_offset = offset_in_page(reloc->offset);
-       uint64_t delta = relocation_target(reloc, target_offset);
-       char *vaddr;
-       int ret;
+       cache->page = -1;
+       cache->vaddr = 0;
+       cache->i915 = i915;
+       cache->use_64bit_reloc = INTEL_GEN(cache->i915) >= 8;
+       cache->node.allocated = false;
+}
 
-       ret = i915_gem_object_set_to_cpu_domain(obj, true);
-       if (ret)
-               return ret;
+static inline void *unmask_page(unsigned long p)
+{
+       return (void *)(uintptr_t)(p & PAGE_MASK);
+}
+
+static inline unsigned int unmask_flags(unsigned long p)
+{
+       return p & ~PAGE_MASK;
+}
+
+#define KMAP 0x4 /* after CLFLUSH_FLAGS */
+
+static void reloc_cache_fini(struct reloc_cache *cache)
+{
+       void *vaddr;
 
-       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
-                               reloc->offset >> PAGE_SHIFT));
-       *(uint32_t *)(vaddr + page_offset) = lower_32_bits(delta);
+       if (!cache->vaddr)
+               return;
 
-       if (INTEL_INFO(dev)->gen >= 8) {
-               page_offset = offset_in_page(page_offset + sizeof(uint32_t));
+       vaddr = unmask_page(cache->vaddr);
+       if (cache->vaddr & KMAP) {
+               if (cache->vaddr & CLFLUSH_AFTER)
+                       mb();
 
-               if (page_offset == 0) {
-                       kunmap_atomic(vaddr);
-                       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
-                           (reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT));
+               kunmap_atomic(vaddr);
+               i915_gem_obj_finish_shmem_access((struct drm_i915_gem_object *)cache->node.mm);
+       } else {
+               wmb();
+               io_mapping_unmap_atomic((void __iomem *)vaddr);
+               if (cache->node.allocated) {
+                       struct i915_ggtt *ggtt = &cache->i915->ggtt;
+
+                       ggtt->base.clear_range(&ggtt->base,
+                                              cache->node.start,
+                                              cache->node.size,
+                                              true);
+                       drm_mm_remove_node(&cache->node);
+               } else {
+                       i915_vma_unpin((struct i915_vma *)cache->node.mm);
                }
+       }
+}
+
+static void *reloc_kmap(struct drm_i915_gem_object *obj,
+                       struct reloc_cache *cache,
+                       int page)
+{
+       void *vaddr;
+
+       if (cache->vaddr) {
+               kunmap_atomic(unmask_page(cache->vaddr));
+       } else {
+               unsigned int flushes;
+               int ret;
+
+               ret = i915_gem_obj_prepare_shmem_write(obj, &flushes);
+               if (ret)
+                       return ERR_PTR(ret);
+
+               BUILD_BUG_ON(KMAP & CLFLUSH_FLAGS);
+               BUILD_BUG_ON((KMAP | CLFLUSH_FLAGS) & PAGE_MASK);
 
-               *(uint32_t *)(vaddr + page_offset) = upper_32_bits(delta);
+               cache->vaddr = flushes | KMAP;
+               cache->node.mm = (void *)obj;
+               if (flushes)
+                       mb();
        }
 
-       kunmap_atomic(vaddr);
+       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj, page));
+       cache->vaddr = unmask_flags(cache->vaddr) | (unsigned long)vaddr;
+       cache->page = page;
 
-       return 0;
+       return vaddr;
 }
 
-static int
-relocate_entry_gtt(struct drm_i915_gem_object *obj,
-                  struct drm_i915_gem_relocation_entry *reloc,
-                  uint64_t target_offset)
+static void *reloc_iomap(struct drm_i915_gem_object *obj,
+                        struct reloc_cache *cache,
+                        int page)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       uint64_t delta = relocation_target(reloc, target_offset);
-       uint64_t offset;
-       void __iomem *reloc_page;
-       int ret;
+       struct i915_ggtt *ggtt = &cache->i915->ggtt;
+       unsigned long offset;
+       void *vaddr;
+
+       if (cache->node.allocated) {
+               wmb();
+               ggtt->base.insert_page(&ggtt->base,
+                                      i915_gem_object_get_dma_address(obj, page),
+                                      cache->node.start, I915_CACHE_NONE, 0);
+               cache->page = page;
+               return unmask_page(cache->vaddr);
+       }
 
-       ret = i915_gem_object_set_to_gtt_domain(obj, true);
-       if (ret)
-               return ret;
+       if (cache->vaddr) {
+               io_mapping_unmap_atomic(unmask_page(cache->vaddr));
+       } else {
+               struct i915_vma *vma;
+               int ret;
 
-       ret = i915_gem_object_put_fence(obj);
-       if (ret)
-               return ret;
+               if (use_cpu_reloc(obj))
+                       return NULL;
+
+               ret = i915_gem_object_set_to_gtt_domain(obj, true);
+               if (ret)
+                       return ERR_PTR(ret);
+
+               vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
+                                              PIN_MAPPABLE | PIN_NONBLOCK);
+               if (IS_ERR(vma)) {
+                       memset(&cache->node, 0, sizeof(cache->node));
+                       ret = drm_mm_insert_node_in_range_generic
+                               (&ggtt->base.mm, &cache->node,
+                                4096, 0, 0,
+                                0, ggtt->mappable_end,
+                                DRM_MM_SEARCH_DEFAULT,
+                                DRM_MM_CREATE_DEFAULT);
+                       if (ret) /* no inactive aperture space, use cpu reloc */
+                               return NULL;
+               } else {
+                       ret = i915_vma_put_fence(vma);
+                       if (ret) {
+                               i915_vma_unpin(vma);
+                               return ERR_PTR(ret);
+                       }
 
-       /* Map the page containing the relocation we're going to perform.  */
-       offset = i915_gem_obj_ggtt_offset(obj);
-       offset += reloc->offset;
-       reloc_page = io_mapping_map_atomic_wc(ggtt->mappable,
-                                             offset & PAGE_MASK);
-       iowrite32(lower_32_bits(delta), reloc_page + offset_in_page(offset));
-
-       if (INTEL_INFO(dev)->gen >= 8) {
-               offset += sizeof(uint32_t);
-
-               if (offset_in_page(offset) == 0) {
-                       io_mapping_unmap_atomic(reloc_page);
-                       reloc_page =
-                               io_mapping_map_atomic_wc(ggtt->mappable,
-                                                        offset);
+                       cache->node.start = vma->node.start;
+                       cache->node.mm = (void *)vma;
                }
+       }
 
-               iowrite32(upper_32_bits(delta),
-                         reloc_page + offset_in_page(offset));
+       offset = cache->node.start;
+       if (cache->node.allocated) {
+               ggtt->base.insert_page(&ggtt->base,
+                                      i915_gem_object_get_dma_address(obj, page),
+                                      offset, I915_CACHE_NONE, 0);
+       } else {
+               offset += page << PAGE_SHIFT;
        }
 
-       io_mapping_unmap_atomic(reloc_page);
+       vaddr = io_mapping_map_atomic_wc(&cache->i915->ggtt.mappable, offset);
+       cache->page = page;
+       cache->vaddr = (unsigned long)vaddr;
 
-       return 0;
+       return vaddr;
 }
 
-static void
-clflush_write32(void *addr, uint32_t value)
+static void *reloc_vaddr(struct drm_i915_gem_object *obj,
+                        struct reloc_cache *cache,
+                        int page)
 {
-       /* This is not a fast path, so KISS. */
-       drm_clflush_virt_range(addr, sizeof(uint32_t));
-       *(uint32_t *)addr = value;
-       drm_clflush_virt_range(addr, sizeof(uint32_t));
+       void *vaddr;
+
+       if (cache->page == page) {
+               vaddr = unmask_page(cache->vaddr);
+       } else {
+               vaddr = NULL;
+               if ((cache->vaddr & KMAP) == 0)
+                       vaddr = reloc_iomap(obj, cache, page);
+               if (!vaddr)
+                       vaddr = reloc_kmap(obj, cache, page);
+       }
+
+       return vaddr;
 }
 
-static int
-relocate_entry_clflush(struct drm_i915_gem_object *obj,
-                      struct drm_i915_gem_relocation_entry *reloc,
-                      uint64_t target_offset)
+static void clflush_write32(u32 *addr, u32 value, unsigned int flushes)
 {
-       struct drm_device *dev = obj->base.dev;
-       uint32_t page_offset = offset_in_page(reloc->offset);
-       uint64_t delta = relocation_target(reloc, target_offset);
-       char *vaddr;
-       int ret;
+       if (unlikely(flushes & (CLFLUSH_BEFORE | CLFLUSH_AFTER))) {
+               if (flushes & CLFLUSH_BEFORE) {
+                       clflushopt(addr);
+                       mb();
+               }
 
-       ret = i915_gem_object_set_to_gtt_domain(obj, true);
-       if (ret)
-               return ret;
+               *addr = value;
+
+               /* Writes to the same cacheline are serialised by the CPU
+                * (including clflush). On the write path, we only require
+                * that it hits memory in an orderly fashion and place
+                * mb barriers at the start and end of the relocation phase
+                * to ensure ordering of clflush wrt to the system.
+                */
+               if (flushes & CLFLUSH_AFTER)
+                       clflushopt(addr);
+       } else
+               *addr = value;
+}
 
-       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
-                               reloc->offset >> PAGE_SHIFT));
-       clflush_write32(vaddr + page_offset, lower_32_bits(delta));
+static int
+relocate_entry(struct drm_i915_gem_object *obj,
+              const struct drm_i915_gem_relocation_entry *reloc,
+              struct reloc_cache *cache,
+              u64 target_offset)
+{
+       u64 offset = reloc->offset;
+       bool wide = cache->use_64bit_reloc;
+       void *vaddr;
+
+       target_offset = relocation_target(reloc, target_offset);
+repeat:
+       vaddr = reloc_vaddr(obj, cache, offset >> PAGE_SHIFT);
+       if (IS_ERR(vaddr))
+               return PTR_ERR(vaddr);
+
+       clflush_write32(vaddr + offset_in_page(offset),
+                       lower_32_bits(target_offset),
+                       cache->vaddr);
+
+       if (wide) {
+               offset += sizeof(u32);
+               target_offset >>= 32;
+               wide = false;
+               goto repeat;
+       }
 
-       if (INTEL_INFO(dev)->gen >= 8) {
-               page_offset = offset_in_page(page_offset + sizeof(uint32_t));
+       return 0;
+}
 
-               if (page_offset == 0) {
-                       kunmap_atomic(vaddr);
-                       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
-                           (reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT));
-               }
+static bool object_is_idle(struct drm_i915_gem_object *obj)
+{
+       unsigned long active = i915_gem_object_get_active(obj);
+       int idx;
 
-               clflush_write32(vaddr + page_offset, upper_32_bits(delta));
+       for_each_active(active, idx) {
+               if (!i915_gem_active_is_idle(&obj->last_read[idx],
+                                            &obj->base.dev->struct_mutex))
+                       return false;
        }
 
-       kunmap_atomic(vaddr);
-
-       return 0;
+       return true;
 }
 
 static int
 i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                                   struct eb_vmas *eb,
-                                  struct drm_i915_gem_relocation_entry *reloc)
+                                  struct drm_i915_gem_relocation_entry *reloc,
+                                  struct reloc_cache *cache)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_gem_object *target_obj;
@@ -465,7 +633,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
 
        /* Check that the relocation address is valid... */
        if (unlikely(reloc->offset >
-               obj->base.size - (INTEL_INFO(dev)->gen >= 8 ? 8 : 4))) {
+                    obj->base.size - (cache->use_64bit_reloc ? 8 : 4))) {
                DRM_DEBUG("Relocation beyond object bounds: "
                          "obj %p target %d offset %d size %d.\n",
                          obj, reloc->target_handle,
@@ -482,26 +650,15 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        }
 
        /* We can't wait for rendering with pagefaults disabled */
-       if (obj->active && pagefault_disabled())
+       if (pagefault_disabled() && !object_is_idle(obj))
                return -EFAULT;
 
-       if (use_cpu_reloc(obj))
-               ret = relocate_entry_cpu(obj, reloc, target_offset);
-       else if (obj->map_and_fenceable)
-               ret = relocate_entry_gtt(obj, reloc, target_offset);
-       else if (static_cpu_has(X86_FEATURE_CLFLUSH))
-               ret = relocate_entry_clflush(obj, reloc, target_offset);
-       else {
-               WARN_ONCE(1, "Impossible case in relocation handling\n");
-               ret = -ENODEV;
-       }
-
+       ret = relocate_entry(obj, reloc, cache, target_offset);
        if (ret)
                return ret;
 
        /* and update the user's relocation entry */
        reloc->presumed_offset = target_offset;
-
        return 0;
 }
 
@@ -513,9 +670,11 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma,
        struct drm_i915_gem_relocation_entry stack_reloc[N_RELOC(512)];
        struct drm_i915_gem_relocation_entry __user *user_relocs;
        struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
-       int remain, ret;
+       struct reloc_cache cache;
+       int remain, ret = 0;
 
        user_relocs = u64_to_user_ptr(entry->relocs_ptr);
+       reloc_cache_init(&cache, eb->i915);
 
        remain = entry->relocation_count;
        while (remain) {
@@ -525,19 +684,23 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma,
                        count = ARRAY_SIZE(stack_reloc);
                remain -= count;
 
-               if (__copy_from_user_inatomic(r, user_relocs, count*sizeof(r[0])))
-                       return -EFAULT;
+               if (__copy_from_user_inatomic(r, user_relocs, count*sizeof(r[0]))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
 
                do {
                        u64 offset = r->presumed_offset;
 
-                       ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r);
+                       ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r, &cache);
                        if (ret)
-                               return ret;
+                               goto out;
 
                        if (r->presumed_offset != offset &&
-                           __put_user(r->presumed_offset, &user_relocs->presumed_offset)) {
-                               return -EFAULT;
+                           __put_user(r->presumed_offset,
+                                      &user_relocs->presumed_offset)) {
+                               ret = -EFAULT;
+                               goto out;
                        }
 
                        user_relocs++;
@@ -545,7 +708,9 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma,
                } while (--count);
        }
 
-       return 0;
+out:
+       reloc_cache_fini(&cache);
+       return ret;
 #undef N_RELOC
 }
 
@@ -555,15 +720,18 @@ i915_gem_execbuffer_relocate_vma_slow(struct i915_vma *vma,
                                      struct drm_i915_gem_relocation_entry *relocs)
 {
        const struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
-       int i, ret;
+       struct reloc_cache cache;
+       int i, ret = 0;
 
+       reloc_cache_init(&cache, eb->i915);
        for (i = 0; i < entry->relocation_count; i++) {
-               ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i]);
+               ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i], &cache);
                if (ret)
-                       return ret;
+                       break;
        }
+       reloc_cache_fini(&cache);
 
-       return 0;
+       return ret;
 }
 
 static int
@@ -626,23 +794,27 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
                        flags |= PIN_HIGH;
        }
 
-       ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags);
-       if ((ret == -ENOSPC  || ret == -E2BIG) &&
+       ret = i915_vma_pin(vma,
+                          entry->pad_to_size,
+                          entry->alignment,
+                          flags);
+       if ((ret == -ENOSPC || ret == -E2BIG) &&
            only_mappable_for_reloc(entry->flags))
-               ret = i915_gem_object_pin(obj, vma->vm,
-                                         entry->alignment,
-                                         flags & ~PIN_MAPPABLE);
+               ret = i915_vma_pin(vma,
+                                  entry->pad_to_size,
+                                  entry->alignment,
+                                  flags & ~PIN_MAPPABLE);
        if (ret)
                return ret;
 
        entry->flags |= __EXEC_OBJECT_HAS_PIN;
 
        if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
-               ret = i915_gem_object_get_fence(obj);
+               ret = i915_vma_get_fence(vma);
                if (ret)
                        return ret;
 
-               if (i915_gem_object_pin_fence(obj))
+               if (i915_vma_pin_fence(vma))
                        entry->flags |= __EXEC_OBJECT_HAS_FENCE;
        }
 
@@ -667,7 +839,7 @@ need_reloc_mappable(struct i915_vma *vma)
        if (entry->relocation_count == 0)
                return false;
 
-       if (!vma->is_ggtt)
+       if (!i915_vma_is_ggtt(vma))
                return false;
 
        /* See also use_cpu_reloc() */
@@ -684,14 +856,17 @@ static bool
 eb_vma_misplaced(struct i915_vma *vma)
 {
        struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
-       struct drm_i915_gem_object *obj = vma->obj;
 
-       WARN_ON(entry->flags & __EXEC_OBJECT_NEEDS_MAP && !vma->is_ggtt);
+       WARN_ON(entry->flags & __EXEC_OBJECT_NEEDS_MAP &&
+               !i915_vma_is_ggtt(vma));
 
        if (entry->alignment &&
            vma->node.start & (entry->alignment - 1))
                return true;
 
+       if (vma->node.size < entry->pad_to_size)
+               return true;
+
        if (entry->flags & EXEC_OBJECT_PINNED &&
            vma->node.start != entry->offset)
                return true;
@@ -701,7 +876,8 @@ eb_vma_misplaced(struct i915_vma *vma)
                return true;
 
        /* avoid costly ping-pong once a batch bo ended up non-mappable */
-       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable)
+       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP &&
+           !i915_vma_is_map_and_fenceable(vma))
                return !only_mappable_for_reloc(entry->flags);
 
        if ((entry->flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS) == 0 &&
@@ -725,8 +901,6 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *engine,
        bool has_fenced_gpu_access = INTEL_GEN(engine->i915) < 4;
        int retry;
 
-       i915_gem_retire_requests_ring(engine);
-
        vm = list_first_entry(vmas, struct i915_vma, exec_list)->vm;
 
        INIT_LIST_HEAD(&ordered_vmas);
@@ -746,7 +920,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *engine,
                        entry->flags &= ~EXEC_OBJECT_NEEDS_FENCE;
                need_fence =
                        entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
-                       obj->tiling_mode != I915_TILING_NONE;
+                       i915_gem_object_is_tiled(obj);
                need_mappable = need_fence || need_reloc_mappable(vma);
 
                if (entry->flags & EXEC_OBJECT_PINNED)
@@ -843,7 +1017,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
                vma = list_first_entry(&eb->vmas, struct i915_vma, exec_list);
                list_del_init(&vma->exec_list);
                i915_gem_execbuffer_unreserve_vma(vma);
-               drm_gem_object_unreference(&vma->obj->base);
+               i915_vma_put(vma);
        }
 
        mutex_unlock(&dev->struct_mutex);
@@ -937,23 +1111,45 @@ err:
        return ret;
 }
 
+static unsigned int eb_other_engines(struct drm_i915_gem_request *req)
+{
+       unsigned int mask;
+
+       mask = ~intel_engine_flag(req->engine) & I915_BO_ACTIVE_MASK;
+       mask <<= I915_BO_ACTIVE_SHIFT;
+
+       return mask;
+}
+
 static int
 i915_gem_execbuffer_move_to_gpu(struct drm_i915_gem_request *req,
                                struct list_head *vmas)
 {
-       const unsigned other_rings = ~intel_engine_flag(req->engine);
+       const unsigned int other_rings = eb_other_engines(req);
        struct i915_vma *vma;
        int ret;
 
        list_for_each_entry(vma, vmas, exec_list) {
                struct drm_i915_gem_object *obj = vma->obj;
+               struct reservation_object *resv;
 
-               if (obj->active & other_rings) {
-                       ret = i915_gem_object_sync(obj, req->engine, &req);
+               if (obj->flags & other_rings) {
+                       ret = i915_gem_request_await_object
+                               (req, obj, obj->base.pending_write_domain);
                        if (ret)
                                return ret;
                }
 
+               resv = i915_gem_object_get_dmabuf_resv(obj);
+               if (resv) {
+                       ret = i915_sw_fence_await_reservation
+                               (&req->submit, resv, &i915_fence_ops,
+                                obj->base.pending_write_domain, 10*HZ,
+                                GFP_KERNEL | __GFP_NOWARN);
+                       if (ret < 0)
+                               return ret;
+               }
+
                if (obj->base.write_domain & I915_GEM_DOMAIN_CPU)
                        i915_gem_clflush_object(obj, false);
        }
@@ -961,10 +1157,8 @@ i915_gem_execbuffer_move_to_gpu(struct drm_i915_gem_request *req,
        /* Unconditionally flush any chipset caches (for streaming writes). */
        i915_gem_chipset_flush(req->engine->i915);
 
-       /* Unconditionally invalidate gpu caches and ensure that we do flush
-        * any residual writes from the previous batch.
-        */
-       return intel_ring_invalidate_all_caches(req);
+       /* Unconditionally invalidate GPU caches and TLBs. */
+       return req->engine->emit_flush(req, EMIT_INVALIDATE);
 }
 
 static bool
@@ -1000,6 +1194,9 @@ validate_exec_list(struct drm_device *dev,
        unsigned invalid_flags;
        int i;
 
+       /* INTERNAL flags must not overlap with external ones */
+       BUILD_BUG_ON(__EXEC_OBJECT_INTERNAL_FLAGS & ~__EXEC_OBJECT_UNKNOWN_FLAGS);
+
        invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS;
        if (USES_FULL_PPGTT(dev))
                invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
@@ -1029,6 +1226,14 @@ validate_exec_list(struct drm_device *dev,
                if (exec[i].alignment && !is_power_of_2(exec[i].alignment))
                        return -EINVAL;
 
+               /* pad_to_size was once a reserved field, so sanitize it */
+               if (exec[i].flags & EXEC_OBJECT_PAD_TO_SIZE) {
+                       if (offset_in_page(exec[i].pad_to_size))
+                               return -EINVAL;
+               } else {
+                       exec[i].pad_to_size = 0;
+               }
+
                /* First check for malicious input causing overflow in
                 * the worst case where we need to allocate the entire
                 * relocation tree as a single array.
@@ -1060,12 +1265,9 @@ static struct i915_gem_context *
 i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
                          struct intel_engine_cs *engine, const u32 ctx_id)
 {
-       struct i915_gem_context *ctx = NULL;
+       struct i915_gem_context *ctx;
        struct i915_ctx_hang_stats *hs;
 
-       if (engine->id != RCS && ctx_id != DEFAULT_CONTEXT_HANDLE)
-               return ERR_PTR(-EINVAL);
-
        ctx = i915_gem_context_lookup(file->driver_priv, ctx_id);
        if (IS_ERR(ctx))
                return ctx;
@@ -1079,66 +1281,99 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
        return ctx;
 }
 
-void
+void i915_vma_move_to_active(struct i915_vma *vma,
+                            struct drm_i915_gem_request *req,
+                            unsigned int flags)
+{
+       struct drm_i915_gem_object *obj = vma->obj;
+       const unsigned int idx = req->engine->id;
+
+       GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
+
+       obj->dirty = 1; /* be paranoid  */
+
+       /* Add a reference if we're newly entering the active list.
+        * The order in which we add operations to the retirement queue is
+        * vital here: mark_active adds to the start of the callback list,
+        * such that subsequent callbacks are called first. Therefore we
+        * add the active reference first and queue for it to be dropped
+        * *last*.
+        */
+       if (!i915_gem_object_is_active(obj))
+               i915_gem_object_get(obj);
+       i915_gem_object_set_active(obj, idx);
+       i915_gem_active_set(&obj->last_read[idx], req);
+
+       if (flags & EXEC_OBJECT_WRITE) {
+               i915_gem_active_set(&obj->last_write, req);
+
+               intel_fb_obj_invalidate(obj, ORIGIN_CS);
+
+               /* update for the implicit flush after a batch */
+               obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
+       }
+
+       if (flags & EXEC_OBJECT_NEEDS_FENCE)
+               i915_gem_active_set(&vma->last_fence, req);
+
+       i915_vma_set_active(vma, idx);
+       i915_gem_active_set(&vma->last_read[idx], req);
+       list_move_tail(&vma->vm_link, &vma->vm->active_list);
+}
+
+static void eb_export_fence(struct drm_i915_gem_object *obj,
+                           struct drm_i915_gem_request *req,
+                           unsigned int flags)
+{
+       struct reservation_object *resv;
+
+       resv = i915_gem_object_get_dmabuf_resv(obj);
+       if (!resv)
+               return;
+
+       /* Ignore errors from failing to allocate the new fence, we can't
+        * handle an error right now. Worst case should be missed
+        * synchronisation leading to rendering corruption.
+        */
+       ww_mutex_lock(&resv->lock, NULL);
+       if (flags & EXEC_OBJECT_WRITE)
+               reservation_object_add_excl_fence(resv, &req->fence);
+       else if (reservation_object_reserve_shared(resv) == 0)
+               reservation_object_add_shared_fence(resv, &req->fence);
+       ww_mutex_unlock(&resv->lock);
+}
+
+static void
 i915_gem_execbuffer_move_to_active(struct list_head *vmas,
                                   struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *engine = i915_gem_request_get_engine(req);
        struct i915_vma *vma;
 
        list_for_each_entry(vma, vmas, exec_list) {
-               struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
                struct drm_i915_gem_object *obj = vma->obj;
                u32 old_read = obj->base.read_domains;
                u32 old_write = obj->base.write_domain;
 
-               obj->dirty = 1; /* be paranoid  */
                obj->base.write_domain = obj->base.pending_write_domain;
-               if (obj->base.write_domain == 0)
+               if (obj->base.write_domain)
+                       vma->exec_entry->flags |= EXEC_OBJECT_WRITE;
+               else
                        obj->base.pending_read_domains |= obj->base.read_domains;
                obj->base.read_domains = obj->base.pending_read_domains;
 
-               i915_vma_move_to_active(vma, req);
-               if (obj->base.write_domain) {
-                       i915_gem_request_assign(&obj->last_write_req, req);
-
-                       intel_fb_obj_invalidate(obj, ORIGIN_CS);
-
-                       /* update for the implicit flush after a batch */
-                       obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
-               }
-               if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
-                       i915_gem_request_assign(&obj->last_fenced_req, req);
-                       if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
-                               struct drm_i915_private *dev_priv = engine->i915;
-                               list_move_tail(&dev_priv->fence_regs[obj->fence_reg].lru_list,
-                                              &dev_priv->mm.fence_list);
-                       }
-               }
-
+               i915_vma_move_to_active(vma, req, vma->exec_entry->flags);
+               eb_export_fence(obj, req, vma->exec_entry->flags);
                trace_i915_gem_object_change_domain(obj, old_read, old_write);
        }
 }
 
-static void
-i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params)
-{
-       /* Unconditionally force add_request to emit a full flush. */
-       params->engine->gpu_caches_dirty = true;
-
-       /* Add a breadcrumb for the completion of the batch buffer */
-       __i915_add_request(params->request, params->batch_obj, true);
-}
-
 static int
-i915_reset_gen7_sol_offsets(struct drm_device *dev,
-                           struct drm_i915_gem_request *req)
+i915_reset_gen7_sol_offsets(struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *engine = req->engine;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_ring *ring = req->ring;
        int ret, i;
 
-       if (!IS_GEN7(dev) || engine != &dev_priv->engine[RCS]) {
+       if (!IS_GEN7(req->i915) || req->engine->id != RCS) {
                DRM_DEBUG("sol reset is gen7/rcs only\n");
                return -EINVAL;
        }
@@ -1148,21 +1383,21 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
                return ret;
 
        for (i = 0; i < 4; i++) {
-               intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(1));
-               intel_ring_emit_reg(engine, GEN7_SO_WRITE_OFFSET(i));
-               intel_ring_emit(engine, 0);
+               intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+               intel_ring_emit_reg(ring, GEN7_SO_WRITE_OFFSET(i));
+               intel_ring_emit(ring, 0);
        }
 
-       intel_ring_advance(engine);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
-static struct drm_i915_gem_object*
+static struct i915_vma *
 i915_gem_execbuffer_parse(struct intel_engine_cs *engine,
                          struct drm_i915_gem_exec_object2 *shadow_exec_entry,
-                         struct eb_vmas *eb,
                          struct drm_i915_gem_object *batch_obj,
+                         struct eb_vmas *eb,
                          u32 batch_start_offset,
                          u32 batch_len,
                          bool is_master)
@@ -1174,51 +1409,44 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *engine,
        shadow_batch_obj = i915_gem_batch_pool_get(&engine->batch_pool,
                                                   PAGE_ALIGN(batch_len));
        if (IS_ERR(shadow_batch_obj))
-               return shadow_batch_obj;
-
-       ret = i915_parse_cmds(engine,
-                             batch_obj,
-                             shadow_batch_obj,
-                             batch_start_offset,
-                             batch_len,
-                             is_master);
-       if (ret)
-               goto err;
-
-       ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 0, 0);
-       if (ret)
-               goto err;
+               return ERR_CAST(shadow_batch_obj);
+
+       ret = intel_engine_cmd_parser(engine,
+                                     batch_obj,
+                                     shadow_batch_obj,
+                                     batch_start_offset,
+                                     batch_len,
+                                     is_master);
+       if (ret) {
+               if (ret == -EACCES) /* unhandled chained batch */
+                       vma = NULL;
+               else
+                       vma = ERR_PTR(ret);
+               goto out;
+       }
 
-       i915_gem_object_unpin_pages(shadow_batch_obj);
+       vma = i915_gem_object_ggtt_pin(shadow_batch_obj, NULL, 0, 0, 0);
+       if (IS_ERR(vma))
+               goto out;
 
        memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry));
 
-       vma = i915_gem_obj_to_ggtt(shadow_batch_obj);
        vma->exec_entry = shadow_exec_entry;
        vma->exec_entry->flags = __EXEC_OBJECT_HAS_PIN;
-       drm_gem_object_reference(&shadow_batch_obj->base);
+       i915_gem_object_get(shadow_batch_obj);
        list_add_tail(&vma->exec_list, &eb->vmas);
 
-       shadow_batch_obj->base.pending_read_domains = I915_GEM_DOMAIN_COMMAND;
-
-       return shadow_batch_obj;
-
-err:
+out:
        i915_gem_object_unpin_pages(shadow_batch_obj);
-       if (ret == -EACCES) /* unhandled chained batch */
-               return batch_obj;
-       else
-               return ERR_PTR(ret);
+       return vma;
 }
 
-int
-i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
-                              struct drm_i915_gem_execbuffer2 *args,
-                              struct list_head *vmas)
+static int
+execbuf_submit(struct i915_execbuffer_params *params,
+              struct drm_i915_gem_execbuffer2 *args,
+              struct list_head *vmas)
 {
-       struct drm_device *dev = params->dev;
-       struct intel_engine_cs *engine = params->engine;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = params->request->i915;
        u64 exec_start, exec_len;
        int instp_mode;
        u32 instp_mask;
@@ -1232,34 +1460,31 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
        if (ret)
                return ret;
 
-       WARN(params->ctx->ppgtt && params->ctx->ppgtt->pd_dirty_rings & (1<<engine->id),
-            "%s didn't clear reload\n", engine->name);
-
        instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
        instp_mask = I915_EXEC_CONSTANTS_MASK;
        switch (instp_mode) {
        case I915_EXEC_CONSTANTS_REL_GENERAL:
        case I915_EXEC_CONSTANTS_ABSOLUTE:
        case I915_EXEC_CONSTANTS_REL_SURFACE:
-               if (instp_mode != 0 && engine != &dev_priv->engine[RCS]) {
+               if (instp_mode != 0 && params->engine->id != RCS) {
                        DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
                        return -EINVAL;
                }
 
                if (instp_mode != dev_priv->relative_constants_mode) {
-                       if (INTEL_INFO(dev)->gen < 4) {
+                       if (INTEL_INFO(dev_priv)->gen < 4) {
                                DRM_DEBUG("no rel constants on pre-gen4\n");
                                return -EINVAL;
                        }
 
-                       if (INTEL_INFO(dev)->gen > 5 &&
+                       if (INTEL_INFO(dev_priv)->gen > 5 &&
                            instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
                                DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
                                return -EINVAL;
                        }
 
                        /* The HW changed the meaning on this bit on gen6 */
-                       if (INTEL_INFO(dev)->gen >= 6)
+                       if (INTEL_INFO(dev_priv)->gen >= 6)
                                instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE;
                }
                break;
@@ -1268,37 +1493,39 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
                return -EINVAL;
        }
 
-       if (engine == &dev_priv->engine[RCS] &&
+       if (params->engine->id == RCS &&
            instp_mode != dev_priv->relative_constants_mode) {
+               struct intel_ring *ring = params->request->ring;
+
                ret = intel_ring_begin(params->request, 4);
                if (ret)
                        return ret;
 
-               intel_ring_emit(engine, MI_NOOP);
-               intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(1));
-               intel_ring_emit_reg(engine, INSTPM);
-               intel_ring_emit(engine, instp_mask << 16 | instp_mode);
-               intel_ring_advance(engine);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+               intel_ring_emit_reg(ring, INSTPM);
+               intel_ring_emit(ring, instp_mask << 16 | instp_mode);
+               intel_ring_advance(ring);
 
                dev_priv->relative_constants_mode = instp_mode;
        }
 
        if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
-               ret = i915_reset_gen7_sol_offsets(dev, params->request);
+               ret = i915_reset_gen7_sol_offsets(params->request);
                if (ret)
                        return ret;
        }
 
        exec_len   = args->batch_len;
-       exec_start = params->batch_obj_vm_offset +
+       exec_start = params->batch->node.start +
                     params->args_batch_start_offset;
 
        if (exec_len == 0)
-               exec_len = params->batch_obj->base.size;
+               exec_len = params->batch->size - params->args_batch_start_offset;
 
-       ret = engine->dispatch_execbuffer(params->request,
-                                       exec_start, exec_len,
-                                       params->dispatch_flags);
+       ret = params->engine->emit_bb_start(params->request,
+                                           exec_start, exec_len,
+                                           params->dispatch_flags);
        if (ret)
                return ret;
 
@@ -1311,43 +1538,20 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
 
 /**
  * Find one BSD ring to dispatch the corresponding BSD command.
- * The ring index is returned.
+ * The engine index is returned.
  */
 static unsigned int
-gen8_dispatch_bsd_ring(struct drm_i915_private *dev_priv, struct drm_file *file)
+gen8_dispatch_bsd_engine(struct drm_i915_private *dev_priv,
+                        struct drm_file *file)
 {
        struct drm_i915_file_private *file_priv = file->driver_priv;
 
        /* Check whether the file_priv has already selected one ring. */
-       if ((int)file_priv->bsd_ring < 0) {
-               /* If not, use the ping-pong mechanism to select one. */
-               mutex_lock(&dev_priv->drm.struct_mutex);
-               file_priv->bsd_ring = dev_priv->mm.bsd_ring_dispatch_index;
-               dev_priv->mm.bsd_ring_dispatch_index ^= 1;
-               mutex_unlock(&dev_priv->drm.struct_mutex);
-       }
-
-       return file_priv->bsd_ring;
-}
-
-static struct drm_i915_gem_object *
-eb_get_batch(struct eb_vmas *eb)
-{
-       struct i915_vma *vma = list_entry(eb->vmas.prev, typeof(*vma), exec_list);
+       if ((int)file_priv->bsd_engine < 0)
+               file_priv->bsd_engine = atomic_fetch_xor(1,
+                        &dev_priv->mm.bsd_engine_dispatch_index);
 
-       /*
-        * SNA is doing fancy tricks with compressing batch buffers, which leads
-        * to negative relocation deltas. Usually that works out ok since the
-        * relocate address is still positive, except when the batch is placed
-        * very low in the GTT. Ensure this doesn't happen.
-        *
-        * Note that actual hangs have only been observed on gen7, but for
-        * paranoia do it everywhere.
-        */
-       if ((vma->exec_entry->flags & EXEC_OBJECT_PINNED) == 0)
-               vma->exec_entry->flags |= __EXEC_OBJECT_NEEDS_BIAS;
-
-       return vma->obj;
+       return file_priv->bsd_engine;
 }
 
 #define I915_USER_RINGS (4)
@@ -1360,31 +1564,31 @@ static const enum intel_engine_id user_ring_map[I915_USER_RINGS + 1] = {
        [I915_EXEC_VEBOX]       = VECS
 };
 
-static int
-eb_select_ring(struct drm_i915_private *dev_priv,
-              struct drm_file *file,
-              struct drm_i915_gem_execbuffer2 *args,
-              struct intel_engine_cs **ring)
+static struct intel_engine_cs *
+eb_select_engine(struct drm_i915_private *dev_priv,
+                struct drm_file *file,
+                struct drm_i915_gem_execbuffer2 *args)
 {
        unsigned int user_ring_id = args->flags & I915_EXEC_RING_MASK;
+       struct intel_engine_cs *engine;
 
        if (user_ring_id > I915_USER_RINGS) {
                DRM_DEBUG("execbuf with unknown ring: %u\n", user_ring_id);
-               return -EINVAL;
+               return NULL;
        }
 
        if ((user_ring_id != I915_EXEC_BSD) &&
            ((args->flags & I915_EXEC_BSD_MASK) != 0)) {
                DRM_DEBUG("execbuf with non bsd ring but with invalid "
                          "bsd dispatch flags: %d\n", (int)(args->flags));
-               return -EINVAL;
+               return NULL;
        }
 
        if (user_ring_id == I915_EXEC_BSD && HAS_BSD2(dev_priv)) {
                unsigned int bsd_idx = args->flags & I915_EXEC_BSD_MASK;
 
                if (bsd_idx == I915_EXEC_BSD_DEFAULT) {
-                       bsd_idx = gen8_dispatch_bsd_ring(dev_priv, file);
+                       bsd_idx = gen8_dispatch_bsd_engine(dev_priv, file);
                } else if (bsd_idx >= I915_EXEC_BSD_RING1 &&
                           bsd_idx <= I915_EXEC_BSD_RING2) {
                        bsd_idx >>= I915_EXEC_BSD_SHIFT;
@@ -1392,20 +1596,20 @@ eb_select_ring(struct drm_i915_private *dev_priv,
                } else {
                        DRM_DEBUG("execbuf with unknown bsd ring: %u\n",
                                  bsd_idx);
-                       return -EINVAL;
+                       return NULL;
                }
 
-               *ring = &dev_priv->engine[_VCS(bsd_idx)];
+               engine = &dev_priv->engine[_VCS(bsd_idx)];
        } else {
-               *ring = &dev_priv->engine[user_ring_map[user_ring_id]];
+               engine = &dev_priv->engine[user_ring_map[user_ring_id]];
        }
 
-       if (!intel_engine_initialized(*ring)) {
+       if (!intel_engine_initialized(engine)) {
                DRM_DEBUG("execbuf with invalid ring: %u\n", user_ring_id);
-               return -EINVAL;
+               return NULL;
        }
 
-       return 0;
+       return engine;
 }
 
 static int
@@ -1416,9 +1620,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       struct drm_i915_gem_request *req = NULL;
        struct eb_vmas *eb;
-       struct drm_i915_gem_object *batch_obj;
        struct drm_i915_gem_exec_object2 shadow_exec_entry;
        struct intel_engine_cs *engine;
        struct i915_gem_context *ctx;
@@ -1447,9 +1649,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        if (args->flags & I915_EXEC_IS_PINNED)
                dispatch_flags |= I915_DISPATCH_PINNED;
 
-       ret = eb_select_ring(dev_priv, file, args, &engine);
-       if (ret)
-               return ret;
+       engine = eb_select_engine(dev_priv, file, args);
+       if (!engine)
+               return -EINVAL;
 
        if (args->buffer_count < 1) {
                DRM_DEBUG("execbuf with %d buffers\n", args->buffer_count);
@@ -1489,7 +1691,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto pre_mutex_err;
        }
 
-       i915_gem_context_reference(ctx);
+       i915_gem_context_get(ctx);
 
        if (ctx->ppgtt)
                vm = &ctx->ppgtt->base;
@@ -1498,9 +1700,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
        memset(&params_master, 0x00, sizeof(params_master));
 
-       eb = eb_create(args);
+       eb = eb_create(dev_priv, args);
        if (eb == NULL) {
-               i915_gem_context_unreference(ctx);
+               i915_gem_context_put(ctx);
                mutex_unlock(&dev->struct_mutex);
                ret = -ENOMEM;
                goto pre_mutex_err;
@@ -1512,7 +1714,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto err;
 
        /* take note of the batch buffer before we might reorder the lists */
-       batch_obj = eb_get_batch(eb);
+       params->batch = eb_get_batch(eb);
 
        /* Move the objects en-masse into the GTT, evicting if necessary. */
        need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0;
@@ -1536,34 +1738,34 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        }
 
        /* Set the pending read domains for the batch buffer to COMMAND */
-       if (batch_obj->base.pending_write_domain) {
+       if (params->batch->obj->base.pending_write_domain) {
                DRM_DEBUG("Attempting to use self-modifying batch buffer\n");
                ret = -EINVAL;
                goto err;
        }
+       if (args->batch_start_offset > params->batch->size ||
+           args->batch_len > params->batch->size - args->batch_start_offset) {
+               DRM_DEBUG("Attempting to use out-of-bounds batch\n");
+               ret = -EINVAL;
+               goto err;
+       }
 
        params->args_batch_start_offset = args->batch_start_offset;
-       if (i915_needs_cmd_parser(engine) && args->batch_len) {
-               struct drm_i915_gem_object *parsed_batch_obj;
-
-               parsed_batch_obj = i915_gem_execbuffer_parse(engine,
-                                                            &shadow_exec_entry,
-                                                            eb,
-                                                            batch_obj,
-                                                            args->batch_start_offset,
-                                                            args->batch_len,
-                                                            drm_is_current_master(file));
-               if (IS_ERR(parsed_batch_obj)) {
-                       ret = PTR_ERR(parsed_batch_obj);
+       if (intel_engine_needs_cmd_parser(engine) && args->batch_len) {
+               struct i915_vma *vma;
+
+               vma = i915_gem_execbuffer_parse(engine, &shadow_exec_entry,
+                                               params->batch->obj,
+                                               eb,
+                                               args->batch_start_offset,
+                                               args->batch_len,
+                                               drm_is_current_master(file));
+               if (IS_ERR(vma)) {
+                       ret = PTR_ERR(vma);
                        goto err;
                }
 
-               /*
-                * parsed_batch_obj == batch_obj means batch not fully parsed:
-                * Accept, but don't promote to secure.
-                */
-
-               if (parsed_batch_obj != batch_obj) {
+               if (vma) {
                        /*
                         * Batch parsed and accepted:
                         *
@@ -1575,16 +1777,19 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                         */
                        dispatch_flags |= I915_DISPATCH_SECURE;
                        params->args_batch_start_offset = 0;
-                       batch_obj = parsed_batch_obj;
+                       params->batch = vma;
                }
        }
 
-       batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
+       params->batch->obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
 
        /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
         * batch" bit. Hence we need to pin secure batches into the global gtt.
         * hsw should have this fixed, but bdw mucks it up again. */
        if (dispatch_flags & I915_DISPATCH_SECURE) {
+               struct drm_i915_gem_object *obj = params->batch->obj;
+               struct i915_vma *vma;
+
                /*
                 * So on first glance it looks freaky that we pin the batch here
                 * outside of the reservation loop. But:
@@ -1595,22 +1800,31 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                 *   fitting due to fragmentation.
                 * So this is actually safe.
                 */
-               ret = i915_gem_obj_ggtt_pin(batch_obj, 0, 0);
-               if (ret)
+               vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
+               if (IS_ERR(vma)) {
+                       ret = PTR_ERR(vma);
                        goto err;
+               }
 
-               params->batch_obj_vm_offset = i915_gem_obj_ggtt_offset(batch_obj);
-       } else
-               params->batch_obj_vm_offset = i915_gem_obj_offset(batch_obj, vm);
+               params->batch = vma;
+       }
 
        /* Allocate a request for this batch buffer nice and early. */
-       req = i915_gem_request_alloc(engine, ctx);
-       if (IS_ERR(req)) {
-               ret = PTR_ERR(req);
+       params->request = i915_gem_request_alloc(engine, ctx);
+       if (IS_ERR(params->request)) {
+               ret = PTR_ERR(params->request);
                goto err_batch_unpin;
        }
 
-       ret = i915_gem_request_add_to_client(req, file);
+       /* Whilst this request exists, batch_obj will be on the
+        * active_list, and so will hold the active reference. Only when this
+        * request is retired will the the batch_obj be moved onto the
+        * inactive_list and lose its active reference. Hence we do not need
+        * to explicitly hold another reference here.
+        */
+       params->request->batch = params->batch;
+
+       ret = i915_gem_request_add_to_client(params->request, file);
        if (ret)
                goto err_request;
 
@@ -1624,13 +1838,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        params->file                    = file;
        params->engine                    = engine;
        params->dispatch_flags          = dispatch_flags;
-       params->batch_obj               = batch_obj;
        params->ctx                     = ctx;
-       params->request                 = req;
 
-       ret = dev_priv->gt.execbuf_submit(params, args, &eb->vmas);
+       ret = execbuf_submit(params, args, &eb->vmas);
 err_request:
-       i915_gem_execbuffer_retire_commands(params);
+       __i915_add_request(params->request, ret == 0);
 
 err_batch_unpin:
        /*
@@ -1640,11 +1852,10 @@ err_batch_unpin:
         * active.
         */
        if (dispatch_flags & I915_DISPATCH_SECURE)
-               i915_gem_object_ggtt_unpin(batch_obj);
-
+               i915_vma_unpin(params->batch);
 err:
        /* the request owns the ref now */
-       i915_gem_context_unreference(ctx);
+       i915_gem_context_put(ctx);
        eb_destroy(eb);
 
        mutex_unlock(&dev->struct_mutex);
index 251d7a9..8df1fa7 100644 (file)
  * CPU ptes into GTT mmaps (not the GTT ptes themselves) as needed.
  */
 
-static void i965_write_fence_reg(struct drm_device *dev, int reg,
-                                struct drm_i915_gem_object *obj)
+#define pipelined 0
+
+static void i965_write_fence_reg(struct drm_i915_fence_reg *fence,
+                                struct i915_vma *vma)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        i915_reg_t fence_reg_lo, fence_reg_hi;
        int fence_pitch_shift;
+       u64 val;
 
-       if (INTEL_INFO(dev)->gen >= 6) {
-               fence_reg_lo = FENCE_REG_GEN6_LO(reg);
-               fence_reg_hi = FENCE_REG_GEN6_HI(reg);
+       if (INTEL_INFO(fence->i915)->gen >= 6) {
+               fence_reg_lo = FENCE_REG_GEN6_LO(fence->id);
+               fence_reg_hi = FENCE_REG_GEN6_HI(fence->id);
                fence_pitch_shift = GEN6_FENCE_PITCH_SHIFT;
+
        } else {
-               fence_reg_lo = FENCE_REG_965_LO(reg);
-               fence_reg_hi = FENCE_REG_965_HI(reg);
+               fence_reg_lo = FENCE_REG_965_LO(fence->id);
+               fence_reg_hi = FENCE_REG_965_HI(fence->id);
                fence_pitch_shift = I965_FENCE_PITCH_SHIFT;
        }
 
-       /* To w/a incoherency with non-atomic 64-bit register updates,
-        * we split the 64-bit update into two 32-bit writes. In order
-        * for a partial fence not to be evaluated between writes, we
-        * precede the update with write to turn off the fence register,
-        * and only enable the fence as the last step.
-        *
-        * For extra levels of paranoia, we make sure each step lands
-        * before applying the next step.
-        */
-       I915_WRITE(fence_reg_lo, 0);
-       POSTING_READ(fence_reg_lo);
-
-       if (obj) {
-               u32 size = i915_gem_obj_ggtt_size(obj);
-               uint64_t val;
-
-               /* Adjust fence size to match tiled area */
-               if (obj->tiling_mode != I915_TILING_NONE) {
-                       uint32_t row_size = obj->stride *
-                               (obj->tiling_mode == I915_TILING_Y ? 32 : 8);
-                       size = (size / row_size) * row_size;
-               }
-
-               val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) &
-                                0xfffff000) << 32;
-               val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000;
-               val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift;
-               if (obj->tiling_mode == I915_TILING_Y)
-                       val |= 1 << I965_FENCE_TILING_Y_SHIFT;
+       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;
+               val |= (u64)((stride / 128) - 1) << fence_pitch_shift;
+               if (is_y_tiled)
+                       val |= BIT(I965_FENCE_TILING_Y_SHIFT);
                val |= I965_FENCE_REG_VALID;
+       }
 
-               I915_WRITE(fence_reg_hi, val >> 32);
-               POSTING_READ(fence_reg_hi);
+       if (!pipelined) {
+               struct drm_i915_private *dev_priv = fence->i915;
 
-               I915_WRITE(fence_reg_lo, val);
+               /* To w/a incoherency with non-atomic 64-bit register updates,
+                * we split the 64-bit update into two 32-bit writes. In order
+                * for a partial fence not to be evaluated between writes, we
+                * precede the update with write to turn off the fence register,
+                * and only enable the fence as the last step.
+                *
+                * For extra levels of paranoia, we make sure each step lands
+                * before applying the next step.
+                */
+               I915_WRITE(fence_reg_lo, 0);
+               POSTING_READ(fence_reg_lo);
+
+               I915_WRITE(fence_reg_hi, upper_32_bits(val));
+               I915_WRITE(fence_reg_lo, lower_32_bits(val));
                POSTING_READ(fence_reg_lo);
-       } else {
-               I915_WRITE(fence_reg_hi, 0);
-               POSTING_READ(fence_reg_hi);
        }
 }
 
-static void i915_write_fence_reg(struct drm_device *dev, int reg,
-                                struct drm_i915_gem_object *obj)
+static void i915_write_fence_reg(struct drm_i915_fence_reg *fence,
+                                struct i915_vma *vma)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u32 val;
 
-       if (obj) {
-               u32 size = i915_gem_obj_ggtt_size(obj);
+       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);
                int pitch_val;
                int tile_width;
 
-               WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) ||
-                    (size & -size) != size ||
-                    (i915_gem_obj_ggtt_offset(obj) & (size - 1)),
-                    "object 0x%08llx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
-                    i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size);
+               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);
 
-               if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
+               if (is_y_tiled && HAS_128_BYTE_Y_TILING(fence->i915))
                        tile_width = 128;
                else
                        tile_width = 512;
 
                /* Note: pitch better be a power of two tile widths */
-               pitch_val = obj->stride / tile_width;
+               pitch_val = stride / tile_width;
                pitch_val = ffs(pitch_val) - 1;
 
-               val = i915_gem_obj_ggtt_offset(obj);
-               if (obj->tiling_mode == I915_TILING_Y)
-                       val |= 1 << I830_FENCE_TILING_Y_SHIFT;
-               val |= I915_FENCE_SIZE_BITS(size);
+               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 |= I830_FENCE_REG_VALID;
-       } else
-               val = 0;
+       }
+
+       if (!pipelined) {
+               struct drm_i915_private *dev_priv = fence->i915;
+               i915_reg_t reg = FENCE_REG(fence->id);
 
-       I915_WRITE(FENCE_REG(reg), val);
-       POSTING_READ(FENCE_REG(reg));
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+       }
 }
 
-static void i830_write_fence_reg(struct drm_device *dev, int reg,
-                               struct drm_i915_gem_object *obj)
+static void i830_write_fence_reg(struct drm_i915_fence_reg *fence,
+                                struct i915_vma *vma)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       uint32_t val;
+       u32 val;
 
-       if (obj) {
-               u32 size = i915_gem_obj_ggtt_size(obj);
-               uint32_t pitch_val;
+       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((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) ||
-                    (size & -size) != size ||
-                    (i915_gem_obj_ggtt_offset(obj) & (size - 1)),
-                    "object 0x%08llx not 512K or pot-size 0x%08x aligned\n",
-                    i915_gem_obj_ggtt_offset(obj), size);
+               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 = obj->stride / 128;
+               pitch_val = stride / 128;
                pitch_val = ffs(pitch_val) - 1;
 
-               val = i915_gem_obj_ggtt_offset(obj);
-               if (obj->tiling_mode == I915_TILING_Y)
-                       val |= 1 << I830_FENCE_TILING_Y_SHIFT;
-               val |= I830_FENCE_SIZE_BITS(size);
+               val = vma->node.start;
+               if (is_y_tiled)
+                       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_REG_VALID;
-       } else
-               val = 0;
+       }
 
-       I915_WRITE(FENCE_REG(reg), val);
-       POSTING_READ(FENCE_REG(reg));
-}
+       if (!pipelined) {
+               struct drm_i915_private *dev_priv = fence->i915;
+               i915_reg_t reg = FENCE_REG(fence->id);
 
-inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj)
-{
-       return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT;
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+       }
 }
 
-static void i915_gem_write_fence(struct drm_device *dev, int reg,
-                                struct drm_i915_gem_object *obj)
+static void fence_write(struct drm_i915_fence_reg *fence,
+                       struct i915_vma *vma)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       /* Ensure that all CPU reads are completed before installing a fence
-        * and all writes before removing the fence.
+       /* Previous access through the fence register is marshalled by
+        * the mb() inside the fault handlers (i915_gem_release_mmaps)
+        * and explicitly managed for internal users.
         */
-       if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj))
-               mb();
-
-       WARN(obj && (!obj->stride || !obj->tiling_mode),
-            "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
-            obj->stride, obj->tiling_mode);
-
-       if (IS_GEN2(dev))
-               i830_write_fence_reg(dev, reg, obj);
-       else if (IS_GEN3(dev))
-               i915_write_fence_reg(dev, reg, obj);
-       else if (INTEL_INFO(dev)->gen >= 4)
-               i965_write_fence_reg(dev, reg, obj);
-
-       /* And similarly be paranoid that no direct access to this region
-        * is reordered to before the fence is installed.
+
+       if (IS_GEN2(fence->i915))
+               i830_write_fence_reg(fence, vma);
+       else if (IS_GEN3(fence->i915))
+               i915_write_fence_reg(fence, vma);
+       else
+               i965_write_fence_reg(fence, vma);
+
+       /* Access through the fenced region afterwards is
+        * ordered by the posting reads whilst writing the registers.
         */
-       if (i915_gem_object_needs_mb(obj))
-               mb();
-}
 
-static inline int fence_number(struct drm_i915_private *dev_priv,
-                              struct drm_i915_fence_reg *fence)
-{
-       return fence - dev_priv->fence_regs;
+       fence->dirty = false;
 }
 
-static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
-                                        struct drm_i915_fence_reg *fence,
-                                        bool enable)
+static int fence_update(struct drm_i915_fence_reg *fence,
+                       struct i915_vma *vma)
 {
-       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
-       int reg = fence_number(dev_priv, fence);
-
-       i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL);
+       int ret;
 
-       if (enable) {
-               obj->fence_reg = reg;
-               fence->obj = obj;
-               list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
-       } else {
-               obj->fence_reg = I915_FENCE_REG_NONE;
-               fence->obj = NULL;
-               list_del_init(&fence->lru_list);
-       }
-       obj->fence_dirty = false;
-}
+       if (vma) {
+               if (!i915_vma_is_map_and_fenceable(vma))
+                       return -EINVAL;
 
-static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
-{
-       if (obj->tiling_mode)
-               i915_gem_release_mmap(obj);
+               if (WARN(!i915_gem_object_get_stride(vma->obj) ||
+                        !i915_gem_object_get_tiling(vma->obj),
+                        "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
+                        i915_gem_object_get_stride(vma->obj),
+                        i915_gem_object_get_tiling(vma->obj)))
+                       return -EINVAL;
 
-       /* As we do not have an associated fence register, we will force
-        * a tiling change if we ever need to acquire one.
-        */
-       obj->fence_dirty = false;
-       obj->fence_reg = I915_FENCE_REG_NONE;
-}
+               ret = i915_gem_active_retire(&vma->last_fence,
+                                            &vma->obj->base.dev->struct_mutex);
+               if (ret)
+                       return ret;
+       }
 
-static int
-i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
-{
-       if (obj->last_fenced_req) {
-               int ret = i915_wait_request(obj->last_fenced_req);
+       if (fence->vma) {
+               ret = i915_gem_active_retire(&fence->vma->last_fence,
+                                     &fence->vma->obj->base.dev->struct_mutex);
                if (ret)
                        return ret;
+       }
+
+       if (fence->vma && fence->vma != vma) {
+               /* Ensure that all userspace CPU access is completed before
+                * stealing the fence.
+                */
+               i915_gem_release_mmap(fence->vma->obj);
+
+               fence->vma->fence = NULL;
+               fence->vma = NULL;
+
+               list_move(&fence->link, &fence->i915->mm.fence_list);
+       }
+
+       fence_write(fence, vma);
+
+       if (vma) {
+               if (fence->vma != vma) {
+                       vma->fence = fence;
+                       fence->vma = vma;
+               }
 
-               i915_gem_request_assign(&obj->last_fenced_req, NULL);
+               list_move_tail(&fence->link, &fence->i915->mm.fence_list);
        }
 
        return 0;
 }
 
 /**
- * i915_gem_object_put_fence - force-remove fence for an object
- * @obj: object to map through a fence reg
+ * i915_vma_put_fence - force-remove fence for a VMA
+ * @vma: vma to map linearly (not through a fence reg)
  *
  * This function force-removes any fence from the given object, which is useful
  * if the kernel wants to do untiled GTT access.
@@ -284,70 +286,40 @@ i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
  * 0 on success, negative error code on failure.
  */
 int
-i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
+i915_vma_put_fence(struct i915_vma *vma)
 {
-       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
-       struct drm_i915_fence_reg *fence;
-       int ret;
+       struct drm_i915_fence_reg *fence = vma->fence;
 
-       ret = i915_gem_object_wait_fence(obj);
-       if (ret)
-               return ret;
-
-       if (obj->fence_reg == I915_FENCE_REG_NONE)
+       if (!fence)
                return 0;
 
-       fence = &dev_priv->fence_regs[obj->fence_reg];
-
-       if (WARN_ON(fence->pin_count))
+       if (fence->pin_count)
                return -EBUSY;
 
-       i915_gem_object_fence_lost(obj);
-       i915_gem_object_update_fence(obj, fence, false);
-
-       return 0;
+       return fence_update(fence, NULL);
 }
 
-static struct drm_i915_fence_reg *
-i915_find_fence_reg(struct drm_device *dev)
+static struct drm_i915_fence_reg *fence_find(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_i915_fence_reg *reg, *avail;
-       int i;
-
-       /* First try to find a free reg */
-       avail = NULL;
-       for (i = 0; i < dev_priv->num_fence_regs; i++) {
-               reg = &dev_priv->fence_regs[i];
-               if (!reg->obj)
-                       return reg;
-
-               if (!reg->pin_count)
-                       avail = reg;
-       }
-
-       if (avail == NULL)
-               goto deadlock;
+       struct drm_i915_fence_reg *fence;
 
-       /* None available, try to steal one or wait for a user to finish */
-       list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) {
-               if (reg->pin_count)
+       list_for_each_entry(fence, &dev_priv->mm.fence_list, link) {
+               if (fence->pin_count)
                        continue;
 
-               return reg;
+               return fence;
        }
 
-deadlock:
        /* Wait for completion of pending flips which consume fences */
-       if (intel_has_pending_fb_unpin(dev))
+       if (intel_has_pending_fb_unpin(&dev_priv->drm))
                return ERR_PTR(-EAGAIN);
 
        return ERR_PTR(-EDEADLK);
 }
 
 /**
- * i915_gem_object_get_fence - set up fencing for an object
- * @obj: object to map through a fence reg
+ * i915_vma_get_fence - set up fencing for a vma
+ * @vma: vma to map through a fence reg
  *
  * When mapping objects through the GTT, userspace wants to be able to write
  * to them without having to worry about swizzling if the object is tiled.
@@ -364,103 +336,27 @@ deadlock:
  * 0 on success, negative error code on failure.
  */
 int
-i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
+i915_vma_get_fence(struct i915_vma *vma)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       bool enable = obj->tiling_mode != I915_TILING_NONE;
-       struct drm_i915_fence_reg *reg;
-       int ret;
-
-       /* Have we updated the tiling parameters upon the object and so
-        * will need to serialise the write to the associated fence register?
-        */
-       if (obj->fence_dirty) {
-               ret = i915_gem_object_wait_fence(obj);
-               if (ret)
-                       return ret;
-       }
+       struct drm_i915_fence_reg *fence;
+       struct i915_vma *set = i915_gem_object_is_tiled(vma->obj) ? vma : NULL;
 
        /* Just update our place in the LRU if our fence is getting reused. */
-       if (obj->fence_reg != I915_FENCE_REG_NONE) {
-               reg = &dev_priv->fence_regs[obj->fence_reg];
-               if (!obj->fence_dirty) {
-                       list_move_tail(&reg->lru_list,
-                                      &dev_priv->mm.fence_list);
+       if (vma->fence) {
+               fence = vma->fence;
+               if (!fence->dirty) {
+                       list_move_tail(&fence->link,
+                                      &fence->i915->mm.fence_list);
                        return 0;
                }
-       } else if (enable) {
-               if (WARN_ON(!obj->map_and_fenceable))
-                       return -EINVAL;
-
-               reg = i915_find_fence_reg(dev);
-               if (IS_ERR(reg))
-                       return PTR_ERR(reg);
-
-               if (reg->obj) {
-                       struct drm_i915_gem_object *old = reg->obj;
-
-                       ret = i915_gem_object_wait_fence(old);
-                       if (ret)
-                               return ret;
-
-                       i915_gem_object_fence_lost(old);
-               }
+       } else if (set) {
+               fence = fence_find(to_i915(vma->vm->dev));
+               if (IS_ERR(fence))
+                       return PTR_ERR(fence);
        } else
                return 0;
 
-       i915_gem_object_update_fence(obj, reg, enable);
-
-       return 0;
-}
-
-/**
- * i915_gem_object_pin_fence - pin fencing state
- * @obj: object to pin fencing for
- *
- * This pins the fencing state (whether tiled or untiled) to make sure the
- * object is ready to be used as a scanout target. Fencing status must be
- * synchronize first by calling i915_gem_object_get_fence():
- *
- * The resulting fence pin reference must be released again with
- * i915_gem_object_unpin_fence().
- *
- * Returns:
- *
- * True if the object has a fence, false otherwise.
- */
-bool
-i915_gem_object_pin_fence(struct drm_i915_gem_object *obj)
-{
-       if (obj->fence_reg != I915_FENCE_REG_NONE) {
-               struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
-               struct i915_vma *ggtt_vma = i915_gem_obj_to_ggtt(obj);
-
-               WARN_ON(!ggtt_vma ||
-                       dev_priv->fence_regs[obj->fence_reg].pin_count >
-                       ggtt_vma->pin_count);
-               dev_priv->fence_regs[obj->fence_reg].pin_count++;
-               return true;
-       } else
-               return false;
-}
-
-/**
- * i915_gem_object_unpin_fence - unpin fencing state
- * @obj: object to unpin fencing for
- *
- * This releases the fence pin reference acquired through
- * i915_gem_object_pin_fence. It will handle both objects with and without an
- * attached fence correctly, callers do not need to distinguish this.
- */
-void
-i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
-{
-       if (obj->fence_reg != I915_FENCE_REG_NONE) {
-               struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
-               WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0);
-               dev_priv->fence_regs[obj->fence_reg].pin_count--;
-       }
+       return fence_update(fence, set);
 }
 
 /**
@@ -477,17 +373,16 @@ void i915_gem_restore_fences(struct drm_device *dev)
 
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
+               struct i915_vma *vma = reg->vma;
 
                /*
                 * Commit delayed tiling changes if we have an object still
                 * attached to the fence, otherwise just clear the fence.
                 */
-               if (reg->obj) {
-                       i915_gem_object_update_fence(reg->obj, reg,
-                                                    reg->obj->tiling_mode);
-               } else {
-                       i915_gem_write_fence(dev, i, NULL);
-               }
+               if (vma && !i915_gem_object_is_tiled(vma->obj))
+                       vma = NULL;
+
+               fence_update(reg, vma);
        }
 }
 
index f38ceff..0bb4232 100644 (file)
@@ -32,6 +32,8 @@
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+#define I915_GFP_DMA (GFP_KERNEL | __GFP_HIGHMEM)
+
 /**
  * DOC: Global GTT views
  *
@@ -173,11 +175,13 @@ static int ppgtt_bind_vma(struct i915_vma *vma,
 {
        u32 pte_flags = 0;
 
+       vma->pages = vma->obj->pages;
+
        /* Currently applicable only to VLV */
        if (vma->obj->gt_ro)
                pte_flags |= PTE_READ_ONLY;
 
-       vma->vm->insert_entries(vma->vm, vma->obj->pages, vma->node.start,
+       vma->vm->insert_entries(vma->vm, vma->pages, vma->node.start,
                                cache_level, pte_flags);
 
        return 0;
@@ -187,7 +191,7 @@ static void ppgtt_unbind_vma(struct i915_vma *vma)
 {
        vma->vm->clear_range(vma->vm,
                             vma->node.start,
-                            vma->obj->base.size,
+                            vma->size,
                             true);
 }
 
@@ -327,16 +331,16 @@ static gen6_pte_t iris_pte_encode(dma_addr_t addr,
 static int __setup_page_dma(struct drm_device *dev,
                            struct i915_page_dma *p, gfp_t flags)
 {
-       struct device *device = &dev->pdev->dev;
+       struct device *kdev = &dev->pdev->dev;
 
        p->page = alloc_page(flags);
        if (!p->page)
                return -ENOMEM;
 
-       p->daddr = dma_map_page(device,
+       p->daddr = dma_map_page(kdev,
                                p->page, 0, 4096, PCI_DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(device, p->daddr)) {
+       if (dma_mapping_error(kdev, p->daddr)) {
                __free_page(p->page);
                return -EINVAL;
        }
@@ -346,15 +350,17 @@ static int __setup_page_dma(struct drm_device *dev,
 
 static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p)
 {
-       return __setup_page_dma(dev, p, GFP_KERNEL);
+       return __setup_page_dma(dev, p, I915_GFP_DMA);
 }
 
 static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p)
 {
+       struct pci_dev *pdev = dev->pdev;
+
        if (WARN_ON(!p->page))
                return;
 
-       dma_unmap_page(&dev->pdev->dev, p->daddr, 4096, PCI_DMA_BIDIRECTIONAL);
+       dma_unmap_page(&pdev->dev, p->daddr, 4096, PCI_DMA_BIDIRECTIONAL);
        __free_page(p->page);
        memset(p, 0, sizeof(*p));
 }
@@ -408,33 +414,18 @@ static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p,
        fill_page_dma(dev, p, v);
 }
 
-static struct i915_page_scratch *alloc_scratch_page(struct drm_device *dev)
+static int
+setup_scratch_page(struct drm_device *dev,
+                  struct i915_page_dma *scratch,
+                  gfp_t gfp)
 {
-       struct i915_page_scratch *sp;
-       int ret;
-
-       sp = kzalloc(sizeof(*sp), GFP_KERNEL);
-       if (sp == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       ret = __setup_page_dma(dev, px_base(sp), GFP_DMA32 | __GFP_ZERO);
-       if (ret) {
-               kfree(sp);
-               return ERR_PTR(ret);
-       }
-
-       set_pages_uc(px_page(sp), 1);
-
-       return sp;
+       return __setup_page_dma(dev, scratch, gfp | __GFP_ZERO);
 }
 
-static void free_scratch_page(struct drm_device *dev,
-                             struct i915_page_scratch *sp)
+static void cleanup_scratch_page(struct drm_device *dev,
+                                struct i915_page_dma *scratch)
 {
-       set_pages_wb(px_page(sp), 1);
-
-       cleanup_px(dev, sp);
-       kfree(sp);
+       cleanup_page_dma(dev, scratch);
 }
 
 static struct i915_page_table *alloc_pt(struct drm_device *dev)
@@ -480,7 +471,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm,
 {
        gen8_pte_t scratch_pte;
 
-       scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
+       scratch_pte = gen8_pte_encode(vm->scratch_page.daddr,
                                      I915_CACHE_LLC, true);
 
        fill_px(vm->dev, pt, scratch_pte);
@@ -491,9 +482,9 @@ static void gen6_initialize_pt(struct i915_address_space *vm,
 {
        gen6_pte_t scratch_pte;
 
-       WARN_ON(px_dma(vm->scratch_page) == 0);
+       WARN_ON(vm->scratch_page.daddr == 0);
 
-       scratch_pte = vm->pte_encode(px_dma(vm->scratch_page),
+       scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
                                     I915_CACHE_LLC, true, 0);
 
        fill32_px(vm->dev, pt, scratch_pte);
@@ -672,6 +663,7 @@ static int gen8_write_pdp(struct drm_i915_gem_request *req,
                          unsigned entry,
                          dma_addr_t addr)
 {
+       struct intel_ring *ring = req->ring;
        struct intel_engine_cs *engine = req->engine;
        int ret;
 
@@ -681,13 +673,13 @@ static int gen8_write_pdp(struct drm_i915_gem_request *req,
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(1));
-       intel_ring_emit_reg(engine, GEN8_RING_PDP_UDW(engine, entry));
-       intel_ring_emit(engine, upper_32_bits(addr));
-       intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(1));
-       intel_ring_emit_reg(engine, GEN8_RING_PDP_LDW(engine, entry));
-       intel_ring_emit(engine, lower_32_bits(addr));
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+       intel_ring_emit_reg(ring, GEN8_RING_PDP_UDW(engine, entry));
+       intel_ring_emit(ring, upper_32_bits(addr));
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+       intel_ring_emit_reg(ring, GEN8_RING_PDP_LDW(engine, entry));
+       intel_ring_emit(ring, lower_32_bits(addr));
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -776,7 +768,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
                                   bool use_scratch)
 {
        struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
-       gen8_pte_t scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
+       gen8_pte_t scratch_pte = gen8_pte_encode(vm->scratch_page.daddr,
                                                 I915_CACHE_LLC, use_scratch);
 
        if (!USES_FULL_48BIT_PPGTT(vm->dev)) {
@@ -882,9 +874,9 @@ static int gen8_init_scratch(struct i915_address_space *vm)
        struct drm_device *dev = vm->dev;
        int ret;
 
-       vm->scratch_page = alloc_scratch_page(dev);
-       if (IS_ERR(vm->scratch_page))
-               return PTR_ERR(vm->scratch_page);
+       ret = setup_scratch_page(dev, &vm->scratch_page, I915_GFP_DMA);
+       if (ret)
+               return ret;
 
        vm->scratch_pt = alloc_pt(dev);
        if (IS_ERR(vm->scratch_pt)) {
@@ -918,7 +910,7 @@ free_pd:
 free_pt:
        free_pt(dev, vm->scratch_pt);
 free_scratch_page:
-       free_scratch_page(dev, vm->scratch_page);
+       cleanup_scratch_page(dev, &vm->scratch_page);
 
        return ret;
 }
@@ -962,7 +954,7 @@ static void gen8_free_scratch(struct i915_address_space *vm)
                free_pdp(dev, vm->scratch_pdp);
        free_pd(dev, vm->scratch_pd);
        free_pt(dev, vm->scratch_pt);
-       free_scratch_page(dev, vm->scratch_page);
+       cleanup_scratch_page(dev, &vm->scratch_page);
 }
 
 static void gen8_ppgtt_cleanup_3lvl(struct drm_device *dev,
@@ -1459,7 +1451,7 @@ static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
        struct i915_address_space *vm = &ppgtt->base;
        uint64_t start = ppgtt->base.start;
        uint64_t length = ppgtt->base.total;
-       gen8_pte_t scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
+       gen8_pte_t scratch_pte = gen8_pte_encode(vm->scratch_page.daddr,
                                                 I915_CACHE_LLC, true);
 
        if (!USES_FULL_48BIT_PPGTT(vm->dev)) {
@@ -1576,7 +1568,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
        uint32_t  pte, pde;
        uint32_t start = ppgtt->base.start, length = ppgtt->base.total;
 
-       scratch_pte = vm->pte_encode(px_dma(vm->scratch_page),
+       scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
                                     I915_CACHE_LLC, true, 0);
 
        gen6_for_each_pde(unused, &ppgtt->pd, start, length, pde) {
@@ -1663,11 +1655,12 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt)
 static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
                         struct drm_i915_gem_request *req)
 {
+       struct intel_ring *ring = req->ring;
        struct intel_engine_cs *engine = req->engine;
        int ret;
 
        /* NB: TLBs must be flushed and invalidated before a switch */
-       ret = engine->flush(req, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+       ret = engine->emit_flush(req, EMIT_INVALIDATE | EMIT_FLUSH);
        if (ret)
                return ret;
 
@@ -1675,13 +1668,13 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(2));
-       intel_ring_emit_reg(engine, RING_PP_DIR_DCLV(engine));
-       intel_ring_emit(engine, PP_DIR_DCLV_2G);
-       intel_ring_emit_reg(engine, RING_PP_DIR_BASE(engine));
-       intel_ring_emit(engine, get_pd_offset(ppgtt));
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
+       intel_ring_emit_reg(ring, RING_PP_DIR_DCLV(engine));
+       intel_ring_emit(ring, PP_DIR_DCLV_2G);
+       intel_ring_emit_reg(ring, RING_PP_DIR_BASE(engine));
+       intel_ring_emit(ring, get_pd_offset(ppgtt));
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -1689,11 +1682,12 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
 static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
                          struct drm_i915_gem_request *req)
 {
+       struct intel_ring *ring = req->ring;
        struct intel_engine_cs *engine = req->engine;
        int ret;
 
        /* NB: TLBs must be flushed and invalidated before a switch */
-       ret = engine->flush(req, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+       ret = engine->emit_flush(req, EMIT_INVALIDATE | EMIT_FLUSH);
        if (ret)
                return ret;
 
@@ -1701,17 +1695,17 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(2));
-       intel_ring_emit_reg(engine, RING_PP_DIR_DCLV(engine));
-       intel_ring_emit(engine, PP_DIR_DCLV_2G);
-       intel_ring_emit_reg(engine, RING_PP_DIR_BASE(engine));
-       intel_ring_emit(engine, get_pd_offset(ppgtt));
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
+       intel_ring_emit_reg(ring, RING_PP_DIR_DCLV(engine));
+       intel_ring_emit(ring, PP_DIR_DCLV_2G);
+       intel_ring_emit_reg(ring, RING_PP_DIR_BASE(engine));
+       intel_ring_emit(ring, get_pd_offset(ppgtt));
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        /* XXX: RCS is the only one to auto invalidate the TLBs? */
        if (engine->id != RCS) {
-               ret = engine->flush(req, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+               ret = engine->emit_flush(req, EMIT_INVALIDATE | EMIT_FLUSH);
                if (ret)
                        return ret;
        }
@@ -1799,7 +1793,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
        unsigned first_pte = first_entry % GEN6_PTES;
        unsigned last_pte, i;
 
-       scratch_pte = vm->pte_encode(px_dma(vm->scratch_page),
+       scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
                                     I915_CACHE_LLC, true, 0);
 
        while (num_entries) {
@@ -1945,14 +1939,15 @@ unwind_out:
 static int gen6_init_scratch(struct i915_address_space *vm)
 {
        struct drm_device *dev = vm->dev;
+       int ret;
 
-       vm->scratch_page = alloc_scratch_page(dev);
-       if (IS_ERR(vm->scratch_page))
-               return PTR_ERR(vm->scratch_page);
+       ret = setup_scratch_page(dev, &vm->scratch_page, I915_GFP_DMA);
+       if (ret)
+               return ret;
 
        vm->scratch_pt = alloc_pt(dev);
        if (IS_ERR(vm->scratch_pt)) {
-               free_scratch_page(dev, vm->scratch_page);
+               cleanup_scratch_page(dev, &vm->scratch_page);
                return PTR_ERR(vm->scratch_pt);
        }
 
@@ -1966,7 +1961,7 @@ static void gen6_free_scratch(struct i915_address_space *vm)
        struct drm_device *dev = vm->dev;
 
        free_pt(dev, vm->scratch_pt);
-       free_scratch_page(dev, vm->scratch_page);
+       cleanup_scratch_page(dev, &vm->scratch_page);
 }
 
 static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
@@ -2012,7 +2007,7 @@ alloc:
                                                  0, ggtt->base.total,
                                                  DRM_MM_TOPDOWN);
        if (ret == -ENOSPC && !retried) {
-               ret = i915_gem_evict_something(dev, &ggtt->base,
+               ret = i915_gem_evict_something(&ggtt->base,
                                               GEN6_PD_SIZE, GEN6_PD_ALIGN,
                                               I915_CACHE_NONE,
                                               0, ggtt->base.total,
@@ -2104,11 +2099,12 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        return 0;
 }
 
-static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+static int __hw_ppgtt_init(struct i915_hw_ppgtt *ppgtt,
+                          struct drm_i915_private *dev_priv)
 {
-       ppgtt->base.dev = dev;
+       ppgtt->base.dev = &dev_priv->drm;
 
-       if (INTEL_INFO(dev)->gen < 8)
+       if (INTEL_INFO(dev_priv)->gen < 8)
                return gen6_ppgtt_init(ppgtt);
        else
                return gen8_ppgtt_init(ppgtt);
@@ -2118,9 +2114,9 @@ static void i915_address_space_init(struct i915_address_space *vm,
                                    struct drm_i915_private *dev_priv)
 {
        drm_mm_init(&vm->mm, vm->start, vm->total);
-       vm->dev = &dev_priv->drm;
        INIT_LIST_HEAD(&vm->active_list);
        INIT_LIST_HEAD(&vm->inactive_list);
+       INIT_LIST_HEAD(&vm->unbound_list);
        list_add_tail(&vm->global_link, &dev_priv->vm_list);
 }
 
@@ -2143,15 +2139,17 @@ static void gtt_write_workarounds(struct drm_device *dev)
                I915_WRITE(GEN8_L3_LRA_1_GPGPU, GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_BXT);
 }
 
-static int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+static int i915_ppgtt_init(struct i915_hw_ppgtt *ppgtt,
+                          struct drm_i915_private *dev_priv,
+                          struct drm_i915_file_private *file_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret = 0;
+       int ret;
 
-       ret = __hw_ppgtt_init(dev, ppgtt);
+       ret = __hw_ppgtt_init(ppgtt, dev_priv);
        if (ret == 0) {
                kref_init(&ppgtt->ref);
                i915_address_space_init(&ppgtt->base, dev_priv);
+               ppgtt->base.file = file_priv;
        }
 
        return ret;
@@ -2183,7 +2181,8 @@ int i915_ppgtt_init_hw(struct drm_device *dev)
 }
 
 struct i915_hw_ppgtt *
-i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv)
+i915_ppgtt_create(struct drm_i915_private *dev_priv,
+                 struct drm_i915_file_private *fpriv)
 {
        struct i915_hw_ppgtt *ppgtt;
        int ret;
@@ -2192,14 +2191,12 @@ i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv)
        if (!ppgtt)
                return ERR_PTR(-ENOMEM);
 
-       ret = i915_ppgtt_init(dev, ppgtt);
+       ret = i915_ppgtt_init(ppgtt, dev_priv, fpriv);
        if (ret) {
                kfree(ppgtt);
                return ERR_PTR(ret);
        }
 
-       ppgtt->file_priv = fpriv;
-
        trace_i915_ppgtt_create(&ppgtt->base);
 
        return ppgtt;
@@ -2212,9 +2209,10 @@ void  i915_ppgtt_release(struct kref *kref)
 
        trace_i915_ppgtt_release(&ppgtt->base);
 
-       /* vmas should already be unbound */
+       /* vmas should already be unbound and destroyed */
        WARN_ON(!list_empty(&ppgtt->base.active_list));
        WARN_ON(!list_empty(&ppgtt->base.inactive_list));
+       WARN_ON(!list_empty(&ppgtt->base.unbound_list));
 
        list_del(&ppgtt->base.global_link);
        drm_mm_takedown(&ppgtt->base.mm);
@@ -2223,47 +2221,21 @@ void  i915_ppgtt_release(struct kref *kref)
        kfree(ppgtt);
 }
 
-extern int intel_iommu_gfx_mapped;
 /* Certain Gen5 chipsets require require idling the GPU before
  * unmapping anything from the GTT when VT-d is enabled.
  */
-static bool needs_idle_maps(struct drm_device *dev)
+static bool needs_idle_maps(struct drm_i915_private *dev_priv)
 {
 #ifdef CONFIG_INTEL_IOMMU
        /* Query intel_iommu to see if we need the workaround. Presumably that
         * was loaded first.
         */
-       if (IS_GEN5(dev) && IS_MOBILE(dev) && intel_iommu_gfx_mapped)
+       if (IS_GEN5(dev_priv) && IS_MOBILE(dev_priv) && intel_iommu_gfx_mapped)
                return true;
 #endif
        return false;
 }
 
-static bool do_idling(struct drm_i915_private *dev_priv)
-{
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       bool ret = dev_priv->mm.interruptible;
-
-       if (unlikely(ggtt->do_idle_maps)) {
-               dev_priv->mm.interruptible = false;
-               if (i915_gem_wait_for_idle(dev_priv)) {
-                       DRM_ERROR("Failed to wait for idle; VT'd may hang.\n");
-                       /* Wait a bit, in hopes it avoids the hang */
-                       udelay(10);
-               }
-       }
-
-       return ret;
-}
-
-static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible)
-{
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-
-       if (unlikely(ggtt->do_idle_maps))
-               dev_priv->mm.interruptible = interruptible;
-}
-
 void i915_check_and_clear_faults(struct drm_i915_private *dev_priv)
 {
        struct intel_engine_cs *engine;
@@ -2332,12 +2304,7 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
 
 static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte)
 {
-#ifdef writeq
        writeq(pte, addr);
-#else
-       iowrite32((u32)pte, addr);
-       iowrite32(pte >> 32, addr + 4);
-#endif
 }
 
 static void gen8_ggtt_insert_page(struct i915_address_space *vm,
@@ -2530,7 +2497,7 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm,
                 first_entry, num_entries, max_entries))
                num_entries = max_entries;
 
-       scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
+       scratch_pte = gen8_pte_encode(vm->scratch_page.daddr,
                                      I915_CACHE_LLC,
                                      use_scratch);
        for (i = 0; i < num_entries; i++)
@@ -2562,7 +2529,7 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                 first_entry, num_entries, max_entries))
                num_entries = max_entries;
 
-       scratch_pte = vm->pte_encode(px_dma(vm->scratch_page),
+       scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
                                     I915_CACHE_LLC, use_scratch, 0);
 
        for (i = 0; i < num_entries; i++)
@@ -2641,8 +2608,7 @@ static int ggtt_bind_vma(struct i915_vma *vma,
        if (obj->gt_ro)
                pte_flags |= PTE_READ_ONLY;
 
-       vma->vm->insert_entries(vma->vm, vma->ggtt_view.pages,
-                               vma->node.start,
+       vma->vm->insert_entries(vma->vm, vma->pages, vma->node.start,
                                cache_level, pte_flags);
 
        /*
@@ -2650,7 +2616,7 @@ static int ggtt_bind_vma(struct i915_vma *vma,
         * GLOBAL/LOCAL_BIND, it's all the same ptes. Hence unconditionally
         * upgrade to both bound if we bind either to avoid double-binding.
         */
-       vma->bound |= GLOBAL_BIND | LOCAL_BIND;
+       vma->flags |= I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND;
 
        return 0;
 }
@@ -2672,19 +2638,17 @@ static int aliasing_gtt_bind_vma(struct i915_vma *vma,
                pte_flags |= PTE_READ_ONLY;
 
 
-       if (flags & GLOBAL_BIND) {
+       if (flags & I915_VMA_GLOBAL_BIND) {
                vma->vm->insert_entries(vma->vm,
-                                       vma->ggtt_view.pages,
-                                       vma->node.start,
+                                       vma->pages, vma->node.start,
                                        cache_level, pte_flags);
        }
 
-       if (flags & LOCAL_BIND) {
+       if (flags & I915_VMA_LOCAL_BIND) {
                struct i915_hw_ppgtt *appgtt =
                        to_i915(vma->vm->dev)->mm.aliasing_ppgtt;
                appgtt->base.insert_entries(&appgtt->base,
-                                           vma->ggtt_view.pages,
-                                           vma->node.start,
+                                           vma->pages, vma->node.start,
                                            cache_level, pte_flags);
        }
 
@@ -2693,42 +2657,36 @@ static int aliasing_gtt_bind_vma(struct i915_vma *vma,
 
 static void ggtt_unbind_vma(struct i915_vma *vma)
 {
-       struct drm_device *dev = vma->vm->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_i915_gem_object *obj = vma->obj;
-       const uint64_t size = min_t(uint64_t,
-                                   obj->base.size,
-                                   vma->node.size);
+       struct i915_hw_ppgtt *appgtt = to_i915(vma->vm->dev)->mm.aliasing_ppgtt;
+       const u64 size = min(vma->size, vma->node.size);
 
-       if (vma->bound & GLOBAL_BIND) {
+       if (vma->flags & I915_VMA_GLOBAL_BIND)
                vma->vm->clear_range(vma->vm,
-                                    vma->node.start,
-                                    size,
+                                    vma->node.start, size,
                                     true);
-       }
-
-       if (dev_priv->mm.aliasing_ppgtt && vma->bound & LOCAL_BIND) {
-               struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
 
+       if (vma->flags & I915_VMA_LOCAL_BIND && appgtt)
                appgtt->base.clear_range(&appgtt->base,
-                                        vma->node.start,
-                                        size,
+                                        vma->node.start, size,
                                         true);
-       }
 }
 
 void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       bool interruptible;
+       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
+       struct device *kdev = &dev_priv->drm.pdev->dev;
+       struct i915_ggtt *ggtt = &dev_priv->ggtt;
 
-       interruptible = do_idling(dev_priv);
+       if (unlikely(ggtt->do_idle_maps)) {
+               if (i915_gem_wait_for_idle(dev_priv, I915_WAIT_LOCKED)) {
+                       DRM_ERROR("Failed to wait for idle; VT'd may hang.\n");
+                       /* Wait a bit, in hopes it avoids the hang */
+                       udelay(10);
+               }
+       }
 
-       dma_unmap_sg(&dev->pdev->dev, obj->pages->sgl, obj->pages->nents,
+       dma_unmap_sg(kdev, obj->pages->sgl, obj->pages->nents,
                     PCI_DMA_BIDIRECTIONAL);
-
-       undo_idling(dev_priv, interruptible);
 }
 
 static void i915_gtt_color_adjust(struct drm_mm_node *node,
@@ -2739,19 +2697,14 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node,
        if (node->color != color)
                *start += 4096;
 
-       if (!list_empty(&node->node_list)) {
-               node = list_entry(node->node_list.next,
-                                 struct drm_mm_node,
-                                 node_list);
-               if (node->allocated && node->color != color)
-                       *end -= 4096;
-       }
+       node = list_first_entry_or_null(&node->node_list,
+                                       struct drm_mm_node,
+                                       node_list);
+       if (node && node->allocated && node->color != color)
+               *end -= 4096;
 }
 
-static int i915_gem_setup_global_gtt(struct drm_device *dev,
-                                    u64 start,
-                                    u64 mappable_end,
-                                    u64 end)
+int i915_gem_init_ggtt(struct drm_i915_private *dev_priv)
 {
        /* Let GEM Manage all of the aperture.
         *
@@ -2762,48 +2715,15 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
         * aperture.  One page should be enough to keep any prefetching inside
         * of the aperture.
         */
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       struct drm_mm_node *entry;
-       struct drm_i915_gem_object *obj;
        unsigned long hole_start, hole_end;
+       struct drm_mm_node *entry;
        int ret;
 
-       BUG_ON(mappable_end > end);
-
-       ggtt->base.start = start;
-
-       /* Subtract the guard page before address space initialization to
-        * shrink the range used by drm_mm */
-       ggtt->base.total = end - start - PAGE_SIZE;
-       i915_address_space_init(&ggtt->base, dev_priv);
-       ggtt->base.total += PAGE_SIZE;
-
        ret = intel_vgt_balloon(dev_priv);
        if (ret)
                return ret;
 
-       if (!HAS_LLC(dev))
-               ggtt->base.mm.color_adjust = i915_gtt_color_adjust;
-
-       /* Mark any preallocated objects as occupied */
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               struct i915_vma *vma = i915_gem_obj_to_vma(obj, &ggtt->base);
-
-               DRM_DEBUG_KMS("reserving preallocated space: %llx + %zx\n",
-                             i915_gem_obj_ggtt_offset(obj), obj->base.size);
-
-               WARN_ON(i915_gem_obj_ggtt_bound(obj));
-               ret = drm_mm_reserve_node(&ggtt->base.mm, &vma->node);
-               if (ret) {
-                       DRM_DEBUG_KMS("Reservation failed: %i\n", ret);
-                       return ret;
-               }
-               vma->bound |= GLOBAL_BIND;
-               __i915_vma_set_map_and_fenceable(vma);
-               list_add_tail(&vma->vm_link, &ggtt->base.inactive_list);
-       }
-
        /* Clear any non-preallocated blocks */
        drm_mm_for_each_hole(entry, &ggtt->base.mm, hole_start, hole_end) {
                DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
@@ -2813,18 +2733,19 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
        }
 
        /* And finally clear the reserved guard page */
-       ggtt->base.clear_range(&ggtt->base, end - PAGE_SIZE, PAGE_SIZE, true);
+       ggtt->base.clear_range(&ggtt->base,
+                              ggtt->base.total - PAGE_SIZE, PAGE_SIZE,
+                              true);
 
-       if (USES_PPGTT(dev) && !USES_FULL_PPGTT(dev)) {
+       if (USES_PPGTT(dev_priv) && !USES_FULL_PPGTT(dev_priv)) {
                struct i915_hw_ppgtt *ppgtt;
 
                ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
                if (!ppgtt)
                        return -ENOMEM;
 
-               ret = __hw_ppgtt_init(dev, ppgtt);
+               ret = __hw_ppgtt_init(ppgtt, dev_priv);
                if (ret) {
-                       ppgtt->base.cleanup(&ppgtt->base);
                        kfree(ppgtt);
                        return ret;
                }
@@ -2851,35 +2772,21 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
        return 0;
 }
 
-/**
- * i915_gem_init_ggtt - Initialize GEM for Global GTT
- * @dev: DRM device
- */
-void i915_gem_init_ggtt(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-
-       i915_gem_setup_global_gtt(dev, 0, ggtt->mappable_end, ggtt->base.total);
-}
-
 /**
  * i915_ggtt_cleanup_hw - Clean up GGTT hardware initialization
- * @dev: DRM device
+ * @dev_priv: i915 device
  */
-void i915_ggtt_cleanup_hw(struct drm_device *dev)
+void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
 
        if (dev_priv->mm.aliasing_ppgtt) {
                struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-
                ppgtt->base.cleanup(&ppgtt->base);
                kfree(ppgtt);
        }
 
-       i915_gem_cleanup_stolen(dev);
+       i915_gem_cleanup_stolen(&dev_priv->drm);
 
        if (drm_mm_initialized(&ggtt->base.mm)) {
                intel_vgt_deballoon(dev_priv);
@@ -2889,6 +2796,9 @@ void i915_ggtt_cleanup_hw(struct drm_device *dev)
        }
 
        ggtt->base.cleanup(&ggtt->base);
+
+       arch_phys_wc_del(ggtt->mtrr);
+       io_mapping_fini(&ggtt->mappable);
 }
 
 static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
@@ -2969,17 +2879,14 @@ static size_t gen9_get_stolen_size(u16 gen9_gmch_ctl)
                return (gen9_gmch_ctl - 0xf0 + 1) << 22;
 }
 
-static int ggtt_probe_common(struct drm_device *dev,
-                            size_t gtt_size)
+static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       struct i915_page_scratch *scratch_page;
-       phys_addr_t ggtt_phys_addr;
+       struct pci_dev *pdev = ggtt->base.dev->pdev;
+       phys_addr_t phys_addr;
+       int ret;
 
        /* For Modern GENs the PTEs and register space are split in the BAR */
-       ggtt_phys_addr = pci_resource_start(dev->pdev, 0) +
-                        (pci_resource_len(dev->pdev, 0) / 2);
+       phys_addr = pci_resource_start(pdev, 0) + pci_resource_len(pdev, 0) / 2;
 
        /*
         * On BXT writes larger than 64 bit to the GTT pagetable range will be
@@ -2988,25 +2895,25 @@ static int ggtt_probe_common(struct drm_device *dev,
         * resort to an uncached mapping. The WC issue is easily caught by the
         * readback check when writing GTT PTE entries.
         */
-       if (IS_BROXTON(dev))
-               ggtt->gsm = ioremap_nocache(ggtt_phys_addr, gtt_size);
+       if (IS_BROXTON(ggtt->base.dev))
+               ggtt->gsm = ioremap_nocache(phys_addr, size);
        else
-               ggtt->gsm = ioremap_wc(ggtt_phys_addr, gtt_size);
+               ggtt->gsm = ioremap_wc(phys_addr, size);
        if (!ggtt->gsm) {
-               DRM_ERROR("Failed to map the gtt page table\n");
+               DRM_ERROR("Failed to map the ggtt page table\n");
                return -ENOMEM;
        }
 
-       scratch_page = alloc_scratch_page(dev);
-       if (IS_ERR(scratch_page)) {
+       ret = setup_scratch_page(ggtt->base.dev,
+                                &ggtt->base.scratch_page,
+                                GFP_DMA32);
+       if (ret) {
                DRM_ERROR("Scratch setup failed\n");
                /* iounmap will also get called at remove, but meh */
                iounmap(ggtt->gsm);
-               return PTR_ERR(scratch_page);
+               return ret;
        }
 
-       ggtt->base.scratch_page = scratch_page;
-
        return 0;
 }
 
@@ -3083,42 +2990,49 @@ static void chv_setup_private_ppat(struct drm_i915_private *dev_priv)
        I915_WRITE(GEN8_PRIVATE_PAT_HI, pat >> 32);
 }
 
+static void gen6_gmch_remove(struct i915_address_space *vm)
+{
+       struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
+
+       iounmap(ggtt->gsm);
+       cleanup_scratch_page(vm->dev, &vm->scratch_page);
+}
+
 static int gen8_gmch_probe(struct i915_ggtt *ggtt)
 {
-       struct drm_device *dev = ggtt->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(ggtt->base.dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
+       unsigned int size;
        u16 snb_gmch_ctl;
-       int ret;
 
        /* TODO: We're not aware of mappable constraints on gen8 yet */
-       ggtt->mappable_base = pci_resource_start(dev->pdev, 2);
-       ggtt->mappable_end = pci_resource_len(dev->pdev, 2);
+       ggtt->mappable_base = pci_resource_start(pdev, 2);
+       ggtt->mappable_end = pci_resource_len(pdev, 2);
 
-       if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(39)))
-               pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(39));
+       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(39)))
+               pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(39));
 
-       pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+       pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
 
-       if (INTEL_INFO(dev)->gen >= 9) {
+       if (INTEL_GEN(dev_priv) >= 9) {
                ggtt->stolen_size = gen9_get_stolen_size(snb_gmch_ctl);
-               ggtt->size = gen8_get_total_gtt_size(snb_gmch_ctl);
-       } else if (IS_CHERRYVIEW(dev)) {
+               size = gen8_get_total_gtt_size(snb_gmch_ctl);
+       } else if (IS_CHERRYVIEW(dev_priv)) {
                ggtt->stolen_size = chv_get_stolen_size(snb_gmch_ctl);
-               ggtt->size = chv_get_total_gtt_size(snb_gmch_ctl);
+               size = chv_get_total_gtt_size(snb_gmch_ctl);
        } else {
                ggtt->stolen_size = gen8_get_stolen_size(snb_gmch_ctl);
-               ggtt->size = gen8_get_total_gtt_size(snb_gmch_ctl);
+               size = gen8_get_total_gtt_size(snb_gmch_ctl);
        }
 
-       ggtt->base.total = (ggtt->size / sizeof(gen8_pte_t)) << PAGE_SHIFT;
+       ggtt->base.total = (size / sizeof(gen8_pte_t)) << PAGE_SHIFT;
 
-       if (IS_CHERRYVIEW(dev) || IS_BROXTON(dev))
+       if (IS_CHERRYVIEW(dev_priv) || IS_BROXTON(dev_priv))
                chv_setup_private_ppat(dev_priv);
        else
                bdw_setup_private_ppat(dev_priv);
 
-       ret = ggtt_probe_common(dev, ggtt->size);
-
+       ggtt->base.cleanup = gen6_gmch_remove;
        ggtt->base.bind_vma = ggtt_bind_vma;
        ggtt->base.unbind_vma = ggtt_unbind_vma;
        ggtt->base.insert_page = gen8_ggtt_insert_page;
@@ -3130,57 +3044,65 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
        if (IS_CHERRYVIEW(dev_priv))
                ggtt->base.insert_entries = gen8_ggtt_insert_entries__BKL;
 
-       return ret;
+       return ggtt_probe_common(ggtt, size);
 }
 
 static int gen6_gmch_probe(struct i915_ggtt *ggtt)
 {
-       struct drm_device *dev = ggtt->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(ggtt->base.dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
+       unsigned int size;
        u16 snb_gmch_ctl;
-       int ret;
 
-       ggtt->mappable_base = pci_resource_start(dev->pdev, 2);
-       ggtt->mappable_end = pci_resource_len(dev->pdev, 2);
+       ggtt->mappable_base = pci_resource_start(pdev, 2);
+       ggtt->mappable_end = pci_resource_len(pdev, 2);
 
        /* 64/512MB is the current min/max we actually know of, but this is just
         * a coarse sanity check.
         */
-       if ((ggtt->mappable_end < (64<<20) || (ggtt->mappable_end > (512<<20)))) {
+       if (ggtt->mappable_end < (64<<20) || ggtt->mappable_end > (512<<20)) {
                DRM_ERROR("Unknown GMADR size (%llx)\n", ggtt->mappable_end);
                return -ENXIO;
        }
 
-       if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(40)))
-               pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(40));
-       pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(40)))
+               pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40));
+       pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
 
        ggtt->stolen_size = gen6_get_stolen_size(snb_gmch_ctl);
-       ggtt->size = gen6_get_total_gtt_size(snb_gmch_ctl);
-       ggtt->base.total = (ggtt->size / sizeof(gen6_pte_t)) << PAGE_SHIFT;
 
-       ret = ggtt_probe_common(dev, ggtt->size);
+       size = gen6_get_total_gtt_size(snb_gmch_ctl);
+       ggtt->base.total = (size / sizeof(gen6_pte_t)) << PAGE_SHIFT;
 
        ggtt->base.clear_range = gen6_ggtt_clear_range;
        ggtt->base.insert_page = gen6_ggtt_insert_page;
        ggtt->base.insert_entries = gen6_ggtt_insert_entries;
        ggtt->base.bind_vma = ggtt_bind_vma;
        ggtt->base.unbind_vma = ggtt_unbind_vma;
+       ggtt->base.cleanup = gen6_gmch_remove;
+
+       if (HAS_EDRAM(dev_priv))
+               ggtt->base.pte_encode = iris_pte_encode;
+       else if (IS_HASWELL(dev_priv))
+               ggtt->base.pte_encode = hsw_pte_encode;
+       else if (IS_VALLEYVIEW(dev_priv))
+               ggtt->base.pte_encode = byt_pte_encode;
+       else if (INTEL_GEN(dev_priv) >= 7)
+               ggtt->base.pte_encode = ivb_pte_encode;
+       else
+               ggtt->base.pte_encode = snb_pte_encode;
 
-       return ret;
+       return ggtt_probe_common(ggtt, size);
 }
 
-static void gen6_gmch_remove(struct i915_address_space *vm)
+static void i915_gmch_remove(struct i915_address_space *vm)
 {
-       struct i915_ggtt *ggtt = container_of(vm, struct i915_ggtt, base);
-
-       iounmap(ggtt->gsm);
-       free_scratch_page(vm->dev, vm->scratch_page);
+       intel_gmch_remove();
 }
 
 static int i915_gmch_probe(struct i915_ggtt *ggtt)
 {
-       struct drm_device *dev = ggtt->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(ggtt->base.dev);
        int ret;
 
        ret = intel_gmch_probe(dev_priv->bridge_dev, dev_priv->drm.pdev, NULL);
@@ -3192,12 +3114,13 @@ static int i915_gmch_probe(struct i915_ggtt *ggtt)
        intel_gtt_get(&ggtt->base.total, &ggtt->stolen_size,
                      &ggtt->mappable_base, &ggtt->mappable_end);
 
-       ggtt->do_idle_maps = needs_idle_maps(&dev_priv->drm);
+       ggtt->do_idle_maps = needs_idle_maps(dev_priv);
        ggtt->base.insert_page = i915_ggtt_insert_page;
        ggtt->base.insert_entries = i915_ggtt_insert_entries;
        ggtt->base.clear_range = i915_ggtt_clear_range;
        ggtt->base.bind_vma = ggtt_bind_vma;
        ggtt->base.unbind_vma = ggtt_unbind_vma;
+       ggtt->base.cleanup = i915_gmch_remove;
 
        if (unlikely(ggtt->do_idle_maps))
                DRM_INFO("applying Ironlake quirks for intel_iommu\n");
@@ -3205,65 +3128,40 @@ static int i915_gmch_probe(struct i915_ggtt *ggtt)
        return 0;
 }
 
-static void i915_gmch_remove(struct i915_address_space *vm)
-{
-       intel_gmch_remove();
-}
-
 /**
- * i915_ggtt_init_hw - Initialize GGTT hardware
- * @dev: DRM device
+ * i915_ggtt_probe_hw - Probe GGTT hardware location
+ * @dev_priv: i915 device
  */
-int i915_ggtt_init_hw(struct drm_device *dev)
+int i915_ggtt_probe_hw(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
        int ret;
 
-       if (INTEL_INFO(dev)->gen <= 5) {
-               ggtt->probe = i915_gmch_probe;
-               ggtt->base.cleanup = i915_gmch_remove;
-       } else if (INTEL_INFO(dev)->gen < 8) {
-               ggtt->probe = gen6_gmch_probe;
-               ggtt->base.cleanup = gen6_gmch_remove;
-
-               if (HAS_EDRAM(dev))
-                       ggtt->base.pte_encode = iris_pte_encode;
-               else if (IS_HASWELL(dev))
-                       ggtt->base.pte_encode = hsw_pte_encode;
-               else if (IS_VALLEYVIEW(dev))
-                       ggtt->base.pte_encode = byt_pte_encode;
-               else if (INTEL_INFO(dev)->gen >= 7)
-                       ggtt->base.pte_encode = ivb_pte_encode;
-               else
-                       ggtt->base.pte_encode = snb_pte_encode;
-       } else {
-               ggtt->probe = gen8_gmch_probe;
-               ggtt->base.cleanup = gen6_gmch_remove;
-       }
-
-       ggtt->base.dev = dev;
-       ggtt->base.is_ggtt = true;
+       ggtt->base.dev = &dev_priv->drm;
 
-       ret = ggtt->probe(ggtt);
+       if (INTEL_GEN(dev_priv) <= 5)
+               ret = i915_gmch_probe(ggtt);
+       else if (INTEL_GEN(dev_priv) < 8)
+               ret = gen6_gmch_probe(ggtt);
+       else
+               ret = gen8_gmch_probe(ggtt);
        if (ret)
                return ret;
 
        if ((ggtt->base.total - 1) >> 32) {
                DRM_ERROR("We never expected a Global GTT with more than 32bits"
-                         "of address space! Found %lldM!\n",
+                         " of address space! Found %lldM!\n",
                          ggtt->base.total >> 20);
                ggtt->base.total = 1ULL << 32;
                ggtt->mappable_end = min(ggtt->mappable_end, ggtt->base.total);
        }
 
-       /*
-        * Initialise stolen early so that we may reserve preallocated
-        * objects for the BIOS to KMS transition.
-        */
-       ret = i915_gem_init_stolen(dev);
-       if (ret)
-               goto out_gtt_cleanup;
+       if (ggtt->mappable_end > ggtt->base.total) {
+               DRM_ERROR("mappable aperture extends past end of GGTT,"
+                         " aperture=%llx, total=%llx\n",
+                         ggtt->mappable_end, ggtt->base.total);
+               ggtt->mappable_end = ggtt->base.total;
+       }
 
        /* GMADR is the PCI mmio aperture into the global GTT. */
        DRM_INFO("Memory usable by graphics device = %lluM\n",
@@ -3276,16 +3174,55 @@ int i915_ggtt_init_hw(struct drm_device *dev)
 #endif
 
        return 0;
+}
+
+/**
+ * i915_ggtt_init_hw - Initialize GGTT hardware
+ * @dev_priv: i915 device
+ */
+int i915_ggtt_init_hw(struct drm_i915_private *dev_priv)
+{
+       struct i915_ggtt *ggtt = &dev_priv->ggtt;
+       int ret;
+
+       INIT_LIST_HEAD(&dev_priv->vm_list);
+
+       /* Subtract the guard page before address space initialization to
+        * shrink the range used by drm_mm.
+        */
+       ggtt->base.total -= PAGE_SIZE;
+       i915_address_space_init(&ggtt->base, dev_priv);
+       ggtt->base.total += PAGE_SIZE;
+       if (!HAS_LLC(dev_priv))
+               ggtt->base.mm.color_adjust = i915_gtt_color_adjust;
+
+       if (!io_mapping_init_wc(&dev_priv->ggtt.mappable,
+                               dev_priv->ggtt.mappable_base,
+                               dev_priv->ggtt.mappable_end)) {
+               ret = -EIO;
+               goto out_gtt_cleanup;
+       }
+
+       ggtt->mtrr = arch_phys_wc_add(ggtt->mappable_base, ggtt->mappable_end);
+
+       /*
+        * Initialise stolen early so that we may reserve preallocated
+        * objects for the BIOS to KMS transition.
+        */
+       ret = i915_gem_init_stolen(&dev_priv->drm);
+       if (ret)
+               goto out_gtt_cleanup;
+
+       return 0;
 
 out_gtt_cleanup:
        ggtt->base.cleanup(&ggtt->base);
-
        return ret;
 }
 
-int i915_ggtt_enable_hw(struct drm_device *dev)
+int i915_ggtt_enable_hw(struct drm_i915_private *dev_priv)
 {
-       if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
+       if (INTEL_GEN(dev_priv) < 6 && !intel_enable_gtt())
                return -EIO;
 
        return 0;
@@ -3295,8 +3232,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       struct drm_i915_gem_object *obj;
-       struct i915_vma *vma;
+       struct drm_i915_gem_object *obj, *on;
 
        i915_check_and_clear_faults(dev_priv);
 
@@ -3304,20 +3240,32 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
        ggtt->base.clear_range(&ggtt->base, ggtt->base.start, ggtt->base.total,
                               true);
 
-       /* Cache flush objects bound into GGTT and rebind them. */
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
+       ggtt->base.closed = true; /* skip rewriting PTE on VMA unbind */
+
+       /* clflush objects bound into the GGTT and rebind them. */
+       list_for_each_entry_safe(obj, on,
+                                &dev_priv->mm.bound_list, global_list) {
+               bool ggtt_bound = false;
+               struct i915_vma *vma;
+
                list_for_each_entry(vma, &obj->vma_list, obj_link) {
                        if (vma->vm != &ggtt->base)
                                continue;
 
+                       if (!i915_vma_unbind(vma))
+                               continue;
+
                        WARN_ON(i915_vma_bind(vma, obj->cache_level,
                                              PIN_UPDATE));
+                       ggtt_bound = true;
                }
 
-               if (obj->pin_display)
+               if (ggtt_bound)
                        WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false));
        }
 
+       ggtt->base.closed = false;
+
        if (INTEL_INFO(dev)->gen >= 8) {
                if (IS_CHERRYVIEW(dev) || IS_BROXTON(dev))
                        chv_setup_private_ppat(dev_priv);
@@ -3335,7 +3283,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 
                        struct i915_hw_ppgtt *ppgtt;
 
-                       if (vm->is_ggtt)
+                       if (i915_is_ggtt(vm))
                                ppgtt = dev_priv->mm.aliasing_ppgtt;
                        else
                                ppgtt = i915_vm_to_ppgtt(vm);
@@ -3348,65 +3296,155 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
        i915_ggtt_flush(dev_priv);
 }
 
+static void
+i915_vma_retire(struct i915_gem_active *active,
+               struct drm_i915_gem_request *rq)
+{
+       const unsigned int idx = rq->engine->id;
+       struct i915_vma *vma =
+               container_of(active, struct i915_vma, last_read[idx]);
+
+       GEM_BUG_ON(!i915_vma_has_active_engine(vma, idx));
+
+       i915_vma_clear_active(vma, idx);
+       if (i915_vma_is_active(vma))
+               return;
+
+       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));
+}
+
+void i915_vma_destroy(struct i915_vma *vma)
+{
+       GEM_BUG_ON(vma->node.allocated);
+       GEM_BUG_ON(i915_vma_is_active(vma));
+       GEM_BUG_ON(!i915_vma_is_closed(vma));
+       GEM_BUG_ON(vma->fence);
+
+       list_del(&vma->vm_link);
+       if (!i915_vma_is_ggtt(vma))
+               i915_ppgtt_put(i915_vm_to_ppgtt(vma->vm));
+
+       kmem_cache_free(to_i915(vma->obj->base.dev)->vmas, vma);
+}
+
+void i915_vma_close(struct i915_vma *vma)
+{
+       GEM_BUG_ON(i915_vma_is_closed(vma));
+       vma->flags |= I915_VMA_CLOSED;
+
+       list_del_init(&vma->obj_link);
+       if (!i915_vma_is_active(vma) && !i915_vma_is_pinned(vma))
+               WARN_ON(i915_vma_unbind(vma));
+}
+
 static struct i915_vma *
-__i915_gem_vma_create(struct drm_i915_gem_object *obj,
-                     struct i915_address_space *vm,
-                     const struct i915_ggtt_view *ggtt_view)
+__i915_vma_create(struct drm_i915_gem_object *obj,
+                 struct i915_address_space *vm,
+                 const struct i915_ggtt_view *view)
 {
        struct i915_vma *vma;
+       int i;
 
-       if (WARN_ON(i915_is_ggtt(vm) != !!ggtt_view))
-               return ERR_PTR(-EINVAL);
+       GEM_BUG_ON(vm->closed);
 
        vma = kmem_cache_zalloc(to_i915(obj->base.dev)->vmas, GFP_KERNEL);
        if (vma == NULL)
                return ERR_PTR(-ENOMEM);
 
-       INIT_LIST_HEAD(&vma->vm_link);
-       INIT_LIST_HEAD(&vma->obj_link);
        INIT_LIST_HEAD(&vma->exec_list);
+       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->is_ggtt = i915_is_ggtt(vm);
+       vma->size = obj->base.size;
+
+       if (view) {
+               vma->ggtt_view = *view;
+               if (view->type == I915_GGTT_VIEW_PARTIAL) {
+                       vma->size = view->params.partial.size;
+                       vma->size <<= PAGE_SHIFT;
+               } else if (view->type == I915_GGTT_VIEW_ROTATED) {
+                       vma->size =
+                               intel_rotation_info_size(&view->params.rotated);
+                       vma->size <<= PAGE_SHIFT;
+               }
+       }
 
-       if (i915_is_ggtt(vm))
-               vma->ggtt_view = *ggtt_view;
-       else
+       if (i915_is_ggtt(vm)) {
+               vma->flags |= I915_VMA_GGTT;
+       } else {
                i915_ppgtt_get(i915_vm_to_ppgtt(vm));
+       }
 
        list_add_tail(&vma->obj_link, &obj->vma_list);
-
        return vma;
 }
 
+static inline bool vma_matches(struct i915_vma *vma,
+                              struct i915_address_space *vm,
+                              const struct i915_ggtt_view *view)
+{
+       if (vma->vm != vm)
+               return false;
+
+       if (!i915_vma_is_ggtt(vma))
+               return true;
+
+       if (!view)
+               return vma->ggtt_view.type == 0;
+
+       if (vma->ggtt_view.type != view->type)
+               return false;
+
+       return memcmp(&vma->ggtt_view.params,
+                     &view->params,
+                     sizeof(view->params)) == 0;
+}
+
 struct i915_vma *
-i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
-                                 struct i915_address_space *vm)
+i915_vma_create(struct drm_i915_gem_object *obj,
+               struct i915_address_space *vm,
+               const struct i915_ggtt_view *view)
+{
+       GEM_BUG_ON(view && !i915_is_ggtt(vm));
+       GEM_BUG_ON(i915_gem_obj_to_vma(obj, vm, view));
+
+       return __i915_vma_create(obj, vm, view);
+}
+
+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 *vma;
 
-       vma = i915_gem_obj_to_vma(obj, vm);
-       if (!vma)
-               vma = __i915_gem_vma_create(obj, vm,
-                                           i915_is_ggtt(vm) ? &i915_ggtt_view_normal : NULL);
+       list_for_each_entry_reverse(vma, &obj->vma_list, obj_link)
+               if (vma_matches(vma, vm, view))
+                       return vma;
 
-       return vma;
+       return NULL;
 }
 
 struct i915_vma *
-i915_gem_obj_lookup_or_create_ggtt_vma(struct drm_i915_gem_object *obj,
-                                      const struct i915_ggtt_view *view)
+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 drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       struct i915_vma *vma = i915_gem_obj_to_ggtt_view(obj, view);
+       struct i915_vma *vma;
+
+       GEM_BUG_ON(view && !i915_is_ggtt(vm));
 
+       vma = i915_gem_obj_to_vma(obj, vm, view);
        if (!vma)
-               vma = __i915_gem_vma_create(obj, &ggtt->base, view);
+               vma = __i915_vma_create(obj, vm, view);
 
+       GEM_BUG_ON(i915_vma_is_closed(vma));
        return vma;
-
 }
 
 static struct scatterlist *
@@ -3438,18 +3476,16 @@ rotate_pages(const dma_addr_t *in, unsigned int offset,
 }
 
 static struct sg_table *
-intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
+intel_rotate_fb_obj_pages(const struct intel_rotation_info *rot_info,
                          struct drm_i915_gem_object *obj)
 {
        const size_t n_pages = obj->base.size / PAGE_SIZE;
-       unsigned int size_pages = rot_info->plane[0].width * rot_info->plane[0].height;
-       unsigned int size_pages_uv;
+       unsigned int size = intel_rotation_info_size(rot_info);
        struct sgt_iter sgt_iter;
        dma_addr_t dma_addr;
        unsigned long i;
        dma_addr_t *page_addr_list;
        struct sg_table *st;
-       unsigned int uv_start_page;
        struct scatterlist *sg;
        int ret = -ENOMEM;
 
@@ -3460,18 +3496,12 @@ intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
        if (!page_addr_list)
                return ERR_PTR(ret);
 
-       /* Account for UV plane with NV12. */
-       if (rot_info->pixel_format == DRM_FORMAT_NV12)
-               size_pages_uv = rot_info->plane[1].width * rot_info->plane[1].height;
-       else
-               size_pages_uv = 0;
-
        /* Allocate target SG list. */
        st = kmalloc(sizeof(*st), GFP_KERNEL);
        if (!st)
                goto err_st_alloc;
 
-       ret = sg_alloc_table(st, size_pages + size_pages_uv, GFP_KERNEL);
+       ret = sg_alloc_table(st, size, GFP_KERNEL);
        if (ret)
                goto err_sg_alloc;
 
@@ -3484,32 +3514,14 @@ intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
        st->nents = 0;
        sg = st->sgl;
 
-       /* Rotate the pages. */
-       sg = rotate_pages(page_addr_list, 0,
-                         rot_info->plane[0].width, rot_info->plane[0].height,
-                         rot_info->plane[0].width,
-                         st, sg);
-
-       /* Append the UV plane if NV12. */
-       if (rot_info->pixel_format == DRM_FORMAT_NV12) {
-               uv_start_page = size_pages;
-
-               /* Check for tile-row un-alignment. */
-               if (offset_in_page(rot_info->uv_offset))
-                       uv_start_page--;
-
-               rot_info->uv_start_page = uv_start_page;
-
-               sg = rotate_pages(page_addr_list, rot_info->uv_start_page,
-                                 rot_info->plane[1].width, rot_info->plane[1].height,
-                                 rot_info->plane[1].width,
-                                 st, sg);
+       for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++) {
+               sg = rotate_pages(page_addr_list, rot_info->plane[i].offset,
+                                 rot_info->plane[i].width, rot_info->plane[i].height,
+                                 rot_info->plane[i].stride, st, sg);
        }
 
-       DRM_DEBUG_KMS("Created rotated page mapping for object size %zu (%ux%u tiles, %u pages (%u plane 0)).\n",
-                     obj->base.size, rot_info->plane[0].width,
-                     rot_info->plane[0].height, size_pages + size_pages_uv,
-                     size_pages);
+       DRM_DEBUG_KMS("Created rotated page mapping for object size %zu (%ux%u tiles, %u pages)\n",
+                     obj->base.size, rot_info->plane[0].width, rot_info->plane[0].height, size);
 
        drm_free_large(page_addr_list);
 
@@ -3520,10 +3532,9 @@ err_sg_alloc:
 err_st_alloc:
        drm_free_large(page_addr_list);
 
-       DRM_DEBUG_KMS("Failed to create rotated mapping for object size %zu! (%d) (%ux%u tiles, %u pages (%u plane 0))\n",
-                     obj->base.size, ret, rot_info->plane[0].width,
-                     rot_info->plane[0].height, size_pages + size_pages_uv,
-                     size_pages);
+       DRM_DEBUG_KMS("Failed to create rotated mapping for object size %zu! (%ux%u tiles, %u pages)\n",
+                     obj->base.size, rot_info->plane[0].width, rot_info->plane[0].height, size);
+
        return ERR_PTR(ret);
 }
 
@@ -3573,28 +3584,27 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
 {
        int ret = 0;
 
-       if (vma->ggtt_view.pages)
+       if (vma->pages)
                return 0;
 
        if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
-               vma->ggtt_view.pages = vma->obj->pages;
+               vma->pages = vma->obj->pages;
        else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
-               vma->ggtt_view.pages =
+               vma->pages =
                        intel_rotate_fb_obj_pages(&vma->ggtt_view.params.rotated, vma->obj);
        else if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL)
-               vma->ggtt_view.pages =
-                       intel_partial_pages(&vma->ggtt_view, vma->obj);
+               vma->pages = intel_partial_pages(&vma->ggtt_view, vma->obj);
        else
                WARN_ONCE(1, "GGTT view %u not implemented!\n",
                          vma->ggtt_view.type);
 
-       if (!vma->ggtt_view.pages) {
+       if (!vma->pages) {
                DRM_ERROR("Failed to get pages for GGTT view type %u!\n",
                          vma->ggtt_view.type);
                ret = -EINVAL;
-       } else if (IS_ERR(vma->ggtt_view.pages)) {
-               ret = PTR_ERR(vma->ggtt_view.pages);
-               vma->ggtt_view.pages = NULL;
+       } else if (IS_ERR(vma->pages)) {
+               ret = PTR_ERR(vma->pages);
+               vma->pages = NULL;
                DRM_ERROR("Failed to get pages for VMA view type %u (%d)!\n",
                          vma->ggtt_view.type, ret);
        }
@@ -3615,34 +3625,32 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
 int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
                  u32 flags)
 {
-       int ret;
        u32 bind_flags;
+       u32 vma_flags;
+       int ret;
 
        if (WARN_ON(flags == 0))
                return -EINVAL;
 
        bind_flags = 0;
        if (flags & PIN_GLOBAL)
-               bind_flags |= GLOBAL_BIND;
+               bind_flags |= I915_VMA_GLOBAL_BIND;
        if (flags & PIN_USER)
-               bind_flags |= LOCAL_BIND;
+               bind_flags |= I915_VMA_LOCAL_BIND;
 
+       vma_flags = vma->flags & (I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND);
        if (flags & PIN_UPDATE)
-               bind_flags |= vma->bound;
+               bind_flags |= vma_flags;
        else
-               bind_flags &= ~vma->bound;
-
+               bind_flags &= ~vma_flags;
        if (bind_flags == 0)
                return 0;
 
-       if (vma->bound == 0 && vma->vm->allocate_va_range) {
-               /* XXX: i915_vma_pin() will fix this +- hack */
-               vma->pin_count++;
+       if (vma_flags == 0 && vma->vm->allocate_va_range) {
                trace_i915_va_alloc(vma);
                ret = vma->vm->allocate_va_range(vma->vm,
                                                 vma->node.start,
                                                 vma->node.size);
-               vma->pin_count--;
                if (ret)
                        return ret;
        }
@@ -3651,56 +3659,47 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
        if (ret)
                return ret;
 
-       vma->bound |= bind_flags;
-
+       vma->flags |= bind_flags;
        return 0;
 }
 
-/**
- * i915_ggtt_view_size - Get the size of a GGTT view.
- * @obj: Object the view is of.
- * @view: The view in question.
- *
- * @return The size of the GGTT view in bytes.
- */
-size_t
-i915_ggtt_view_size(struct drm_i915_gem_object *obj,
-                   const struct i915_ggtt_view *view)
-{
-       if (view->type == I915_GGTT_VIEW_NORMAL) {
-               return obj->base.size;
-       } else if (view->type == I915_GGTT_VIEW_ROTATED) {
-               return intel_rotation_info_size(&view->params.rotated) << PAGE_SHIFT;
-       } else if (view->type == I915_GGTT_VIEW_PARTIAL) {
-               return view->params.partial.size << PAGE_SHIFT;
-       } else {
-               WARN_ONCE(1, "GGTT view %u not implemented!\n", view->type);
-               return obj->base.size;
-       }
-}
-
 void __iomem *i915_vma_pin_iomap(struct i915_vma *vma)
 {
        void __iomem *ptr;
 
+       /* Access through the GTT requires the device to be awake. */
+       assert_rpm_wakelock_held(to_i915(vma->vm->dev));
+
        lockdep_assert_held(&vma->vm->dev->struct_mutex);
-       if (WARN_ON(!vma->obj->map_and_fenceable))
-               return ERR_PTR(-ENODEV);
+       if (WARN_ON(!i915_vma_is_map_and_fenceable(vma)))
+               return IO_ERR_PTR(-ENODEV);
 
-       GEM_BUG_ON(!vma->is_ggtt);
-       GEM_BUG_ON((vma->bound & GLOBAL_BIND) == 0);
+       GEM_BUG_ON(!i915_vma_is_ggtt(vma));
+       GEM_BUG_ON((vma->flags & I915_VMA_GLOBAL_BIND) == 0);
 
        ptr = vma->iomap;
        if (ptr == NULL) {
-               ptr = io_mapping_map_wc(i915_vm_to_ggtt(vma->vm)->mappable,
+               ptr = io_mapping_map_wc(&i915_vm_to_ggtt(vma->vm)->mappable,
                                        vma->node.start,
                                        vma->node.size);
                if (ptr == NULL)
-                       return ERR_PTR(-ENOMEM);
+                       return IO_ERR_PTR(-ENOMEM);
 
                vma->iomap = ptr;
        }
 
-       vma->pin_count++;
+       __i915_vma_pin(vma);
        return ptr;
 }
+
+void i915_vma_unpin_and_release(struct i915_vma **p_vma)
+{
+       struct i915_vma *vma;
+
+       vma = fetch_and_zero(p_vma);
+       if (!vma)
+               return;
+
+       i915_vma_unpin(vma);
+       i915_vma_put(vma);
+}
index aa5f31d..ec78be2 100644 (file)
 
 #include <linux/io-mapping.h>
 
+#include "i915_gem_request.h"
+
+#define I915_FENCE_REG_NONE -1
+#define I915_MAX_NUM_FENCES 32
+/* 32 fences + sign bit for FENCE_REG_NONE */
+#define I915_MAX_NUM_FENCE_BITS 6
+
 struct drm_i915_file_private;
+struct drm_i915_fence_reg;
 
 typedef uint32_t gen6_pte_t;
 typedef uint64_t gen8_pte_t;
@@ -137,12 +145,9 @@ enum i915_ggtt_view_type {
 };
 
 struct intel_rotation_info {
-       unsigned int uv_offset;
-       uint32_t pixel_format;
-       unsigned int uv_start_page;
        struct {
                /* tiles */
-               unsigned int width, height;
+               unsigned int width, height, stride, offset;
        } plane[2];
 };
 
@@ -156,8 +161,6 @@ struct i915_ggtt_view {
                } partial;
                struct intel_rotation_info rotated;
        } params;
-
-       struct sg_table *pages;
 };
 
 extern const struct i915_ggtt_view i915_ggtt_view_normal;
@@ -177,13 +180,38 @@ struct i915_vma {
        struct drm_mm_node node;
        struct drm_i915_gem_object *obj;
        struct i915_address_space *vm;
+       struct drm_i915_fence_reg *fence;
+       struct sg_table *pages;
        void __iomem *iomap;
+       u64 size;
+       u64 display_alignment;
+
+       unsigned int flags;
+       /**
+        * How many users have pinned this object in GTT space. The following
+        * users can each hold at most one reference: pwrite/pread, execbuffer
+        * (objects are not allowed multiple times for the same batchbuffer),
+        * and the framebuffer code. When switching/pageflipping, the
+        * framebuffer code has at most two buffers pinned per crtc.
+        *
+        * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
+        * bits with absolutely no headroom. So use 4 bits.
+        */
+#define I915_VMA_PIN_MASK 0xf
+#define I915_VMA_PIN_OVERFLOW  BIT(5)
 
        /** Flags and address space this VMA is bound to */
-#define GLOBAL_BIND    (1<<0)
-#define LOCAL_BIND     (1<<1)
-       unsigned int bound : 4;
-       bool is_ggtt : 1;
+#define I915_VMA_GLOBAL_BIND   BIT(6)
+#define I915_VMA_LOCAL_BIND    BIT(7)
+#define I915_VMA_BIND_MASK (I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND | I915_VMA_PIN_OVERFLOW)
+
+#define I915_VMA_GGTT          BIT(8)
+#define I915_VMA_CAN_FENCE     BIT(9)
+#define I915_VMA_CLOSED                BIT(10)
+
+       unsigned int active;
+       struct i915_gem_active last_read[I915_NUM_ENGINES];
+       struct i915_gem_active last_fence;
 
        /**
         * Support different GGTT views into the same object.
@@ -208,20 +236,66 @@ struct i915_vma {
        struct hlist_node exec_node;
        unsigned long exec_handle;
        struct drm_i915_gem_exec_object2 *exec_entry;
-
-       /**
-        * How many users have pinned this object in GTT space. The following
-        * users can each hold at most one reference: pwrite/pread, execbuffer
-        * (objects are not allowed multiple times for the same batchbuffer),
-        * and the framebuffer code. When switching/pageflipping, the
-        * framebuffer code has at most two buffers pinned per crtc.
-        *
-        * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
-        * bits with absolutely no headroom. So use 4 bits. */
-       unsigned int pin_count:4;
-#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
 };
 
+struct i915_vma *
+i915_vma_create(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);
+
+static inline bool i915_vma_is_ggtt(const struct i915_vma *vma)
+{
+       return vma->flags & I915_VMA_GGTT;
+}
+
+static inline bool i915_vma_is_map_and_fenceable(const struct i915_vma *vma)
+{
+       return vma->flags & I915_VMA_CAN_FENCE;
+}
+
+static inline bool i915_vma_is_closed(const struct i915_vma *vma)
+{
+       return vma->flags & I915_VMA_CLOSED;
+}
+
+static inline unsigned int i915_vma_get_active(const struct i915_vma *vma)
+{
+       return vma->active;
+}
+
+static inline bool i915_vma_is_active(const struct i915_vma *vma)
+{
+       return i915_vma_get_active(vma);
+}
+
+static inline void i915_vma_set_active(struct i915_vma *vma,
+                                      unsigned int engine)
+{
+       vma->active |= BIT(engine);
+}
+
+static inline void i915_vma_clear_active(struct i915_vma *vma,
+                                        unsigned int engine)
+{
+       vma->active &= ~BIT(engine);
+}
+
+static inline bool i915_vma_has_active_engine(const struct i915_vma *vma,
+                                             unsigned int engine)
+{
+       return vma->active & BIT(engine);
+}
+
+static inline u32 i915_ggtt_offset(const struct i915_vma *vma)
+{
+       GEM_BUG_ON(!i915_vma_is_ggtt(vma));
+       GEM_BUG_ON(!vma->node.allocated);
+       GEM_BUG_ON(upper_32_bits(vma->node.start));
+       GEM_BUG_ON(upper_32_bits(vma->node.start + vma->node.size - 1));
+       return lower_32_bits(vma->node.start);
+}
+
 struct i915_page_dma {
        struct page *page;
        union {
@@ -238,10 +312,6 @@ struct i915_page_dma {
 #define px_page(px) (px_base(px)->page)
 #define px_dma(px) (px_base(px)->daddr)
 
-struct i915_page_scratch {
-       struct i915_page_dma base;
-};
-
 struct i915_page_table {
        struct i915_page_dma base;
 
@@ -272,13 +342,22 @@ struct i915_pml4 {
 struct i915_address_space {
        struct drm_mm mm;
        struct drm_device *dev;
+       /* Every address space belongs to a struct file - except for the global
+        * GTT that is owned by the driver (and so @file is set to NULL). In
+        * principle, no information should leak from one context to another
+        * (or between files/processes etc) unless explicitly shared by the
+        * owner. Tracking the owner is important in order to free up per-file
+        * objects along with the file, to aide resource tracking, and to
+        * assign blame.
+        */
+       struct drm_i915_file_private *file;
        struct list_head global_link;
        u64 start;              /* Start offset always 0 for dri2 */
        u64 total;              /* size addr space maps (ex. 2GB for ggtt) */
 
-       bool is_ggtt;
+       bool closed;
 
-       struct i915_page_scratch *scratch_page;
+       struct i915_page_dma scratch_page;
        struct i915_page_table *scratch_pt;
        struct i915_page_directory *scratch_pd;
        struct i915_page_directory_pointer *scratch_pdp; /* GEN8+ & 48b PPGTT */
@@ -306,6 +385,13 @@ struct i915_address_space {
         */
        struct list_head inactive_list;
 
+       /**
+        * List of vma that have been unbound.
+        *
+        * A reference is not held on the buffer while on this list.
+        */
+       struct list_head unbound_list;
+
        /* FIXME: Need a more generic return type */
        gen6_pte_t (*pte_encode)(dma_addr_t addr,
                                 enum i915_cache_level level,
@@ -338,7 +424,7 @@ struct i915_address_space {
                        u32 flags);
 };
 
-#define i915_is_ggtt(V) ((V)->is_ggtt)
+#define i915_is_ggtt(V) (!(V)->file)
 
 /* The Graphics Translation Table is the way in which GEN hardware translates a
  * Graphics Virtual Address into a Physical Address. In addition to the normal
@@ -349,14 +435,13 @@ struct i915_address_space {
  */
 struct i915_ggtt {
        struct i915_address_space base;
+       struct io_mapping mappable;     /* Mapping to our CPU mappable region */
 
        size_t stolen_size;             /* Total size of stolen memory */
        size_t stolen_usable_size;      /* Total size minus BIOS reserved */
        size_t stolen_reserved_base;
        size_t stolen_reserved_size;
-       size_t size;                    /* Total size of Global GTT */
        u64 mappable_end;               /* End offset that we can CPU map */
-       struct io_mapping *mappable;    /* Mapping to our CPU mappable region */
        phys_addr_t mappable_base;      /* PA of our GMADR */
 
        /** "Graphics Stolen Memory" holds the global PTEs */
@@ -365,8 +450,6 @@ struct i915_ggtt {
        bool do_idle_maps;
 
        int mtrr;
-
-       int (*probe)(struct i915_ggtt *ggtt);
 };
 
 struct i915_hw_ppgtt {
@@ -380,8 +463,6 @@ struct i915_hw_ppgtt {
                struct i915_page_directory pd;          /* GEN6-7 */
        };
 
-       struct drm_i915_file_private *file_priv;
-
        gen6_pte_t __iomem *pd_addr;
 
        int (*enable)(struct i915_hw_ppgtt *ppgtt);
@@ -521,14 +602,15 @@ i915_page_dir_dma_addr(const struct i915_hw_ppgtt *ppgtt, const unsigned n)
                px_dma(ppgtt->base.scratch_pd);
 }
 
-int i915_ggtt_init_hw(struct drm_device *dev);
-int i915_ggtt_enable_hw(struct drm_device *dev);
-void i915_gem_init_ggtt(struct drm_device *dev);
-void i915_ggtt_cleanup_hw(struct drm_device *dev);
+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);
+int i915_gem_init_ggtt(struct drm_i915_private *dev_priv);
+void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv);
 
 int i915_ppgtt_init_hw(struct drm_device *dev);
 void i915_ppgtt_release(struct kref *kref);
-struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_device *dev,
+struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_i915_private *dev_priv,
                                        struct drm_i915_file_private *fpriv);
 static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt)
 {
@@ -548,23 +630,67 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev);
 int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
 void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj);
 
-static inline bool
-i915_ggtt_view_equal(const struct i915_ggtt_view *a,
-                     const struct i915_ggtt_view *b)
+/* Flags used by pin/bind&friends. */
+#define PIN_NONBLOCK           BIT(0)
+#define PIN_MAPPABLE           BIT(1)
+#define PIN_ZONE_4G            BIT(2)
+#define PIN_NONFAULT           BIT(3)
+
+#define PIN_MBZ                        BIT(5) /* I915_VMA_PIN_OVERFLOW */
+#define PIN_GLOBAL             BIT(6) /* I915_VMA_GLOBAL_BIND */
+#define PIN_USER               BIT(7) /* I915_VMA_LOCAL_BIND */
+#define PIN_UPDATE             BIT(8)
+
+#define PIN_HIGH               BIT(9)
+#define PIN_OFFSET_BIAS                BIT(10)
+#define PIN_OFFSET_FIXED       BIT(11)
+#define PIN_OFFSET_MASK                (~4095)
+
+int __i915_vma_do_pin(struct i915_vma *vma,
+                     u64 size, u64 alignment, u64 flags);
+static inline int __must_check
+i915_vma_pin(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
 {
-       if (WARN_ON(!a || !b))
-               return false;
-
-       if (a->type != b->type)
-               return false;
-       if (a->type != I915_GGTT_VIEW_NORMAL)
-               return !memcmp(&a->params, &b->params, sizeof(a->params));
-       return true;
+       BUILD_BUG_ON(PIN_MBZ != I915_VMA_PIN_OVERFLOW);
+       BUILD_BUG_ON(PIN_GLOBAL != I915_VMA_GLOBAL_BIND);
+       BUILD_BUG_ON(PIN_USER != I915_VMA_LOCAL_BIND);
+
+       /* 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))
+               return 0;
+
+       return __i915_vma_do_pin(vma, size, alignment, flags);
 }
 
-size_t
-i915_ggtt_view_size(struct drm_i915_gem_object *obj,
-                   const struct i915_ggtt_view *view);
+static inline int i915_vma_pin_count(const struct i915_vma *vma)
+{
+       return vma->flags & I915_VMA_PIN_MASK;
+}
+
+static inline bool i915_vma_is_pinned(const struct i915_vma *vma)
+{
+       return i915_vma_pin_count(vma);
+}
+
+static inline void __i915_vma_pin(struct i915_vma *vma)
+{
+       vma->flags++;
+       GEM_BUG_ON(vma->flags & I915_VMA_PIN_OVERFLOW);
+}
+
+static inline void __i915_vma_unpin(struct i915_vma *vma)
+{
+       GEM_BUG_ON(!i915_vma_is_pinned(vma));
+       vma->flags--;
+}
+
+static inline void i915_vma_unpin(struct i915_vma *vma)
+{
+       GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
+       __i915_vma_unpin(vma);
+}
 
 /**
  * i915_vma_pin_iomap - calls ioremap_wc to map the GGTT VMA via the aperture
@@ -580,6 +706,7 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj,
  * Returns a valid iomapped pointer or ERR_PTR.
  */
 void __iomem *i915_vma_pin_iomap(struct i915_vma *vma);
+#define IO_ERR_PTR(x) ((void __iomem *)ERR_PTR(x))
 
 /**
  * i915_vma_unpin_iomap - unpins the mapping returned from i915_vma_iomap
@@ -593,9 +720,14 @@ void __iomem *i915_vma_pin_iomap(struct i915_vma *vma);
 static inline void i915_vma_unpin_iomap(struct i915_vma *vma)
 {
        lockdep_assert_held(&vma->vm->dev->struct_mutex);
-       GEM_BUG_ON(vma->pin_count == 0);
        GEM_BUG_ON(vma->iomap == NULL);
-       vma->pin_count--;
+       i915_vma_unpin(vma);
+}
+
+static inline struct page *i915_vma_first_page(struct i915_vma *vma)
+{
+       GEM_BUG_ON(!vma->pages);
+       return sg_page(vma->pages->sgl);
 }
 
 #endif
index f75bbd6..95b7e9a 100644 (file)
 #include "i915_drv.h"
 #include "intel_renderstate.h"
 
+struct render_state {
+       const struct intel_renderstate_rodata *rodata;
+       struct i915_vma *vma;
+       u32 aux_batch_size;
+       u32 aux_batch_offset;
+};
+
 static const struct intel_renderstate_rodata *
-render_state_get_rodata(const int gen)
+render_state_get_rodata(const struct drm_i915_gem_request *req)
 {
-       switch (gen) {
+       switch (INTEL_GEN(req->i915)) {
        case 6:
                return &gen6_null_state;
        case 7:
@@ -45,35 +52,6 @@ render_state_get_rodata(const int gen)
        return NULL;
 }
 
-static int render_state_init(struct render_state *so,
-                            struct drm_i915_private *dev_priv)
-{
-       int ret;
-
-       so->gen = INTEL_GEN(dev_priv);
-       so->rodata = render_state_get_rodata(so->gen);
-       if (so->rodata == NULL)
-               return 0;
-
-       if (so->rodata->batch_items * 4 > 4096)
-               return -EINVAL;
-
-       so->obj = i915_gem_object_create(&dev_priv->drm, 4096);
-       if (IS_ERR(so->obj))
-               return PTR_ERR(so->obj);
-
-       ret = i915_gem_obj_ggtt_pin(so->obj, 4096, 0);
-       if (ret)
-               goto free_gem;
-
-       so->ggtt_offset = i915_gem_obj_ggtt_offset(so->obj);
-       return 0;
-
-free_gem:
-       drm_gem_object_unreference(&so->obj->base);
-       return ret;
-}
-
 /*
  * Macro to add commands to auxiliary batch.
  * This macro only checks for page overflow before inserting the commands,
@@ -94,27 +72,28 @@ free_gem:
 
 static int render_state_setup(struct render_state *so)
 {
-       struct drm_device *dev = so->obj->base.dev;
+       struct drm_device *dev = so->vma->vm->dev;
        const struct intel_renderstate_rodata *rodata = so->rodata;
+       const bool has_64bit_reloc = INTEL_GEN(dev) >= 8;
        unsigned int i = 0, reloc_index = 0;
        struct page *page;
        u32 *d;
        int ret;
 
-       ret = i915_gem_object_set_to_cpu_domain(so->obj, true);
+       ret = i915_gem_object_set_to_cpu_domain(so->vma->obj, true);
        if (ret)
                return ret;
 
-       page = i915_gem_object_get_dirty_page(so->obj, 0);
+       page = i915_gem_object_get_dirty_page(so->vma->obj, 0);
        d = kmap(page);
 
        while (i < rodata->batch_items) {
                u32 s = rodata->batch[i];
 
                if (i * 4  == rodata->reloc[reloc_index]) {
-                       u64 r = s + so->ggtt_offset;
+                       u64 r = s + so->vma->node.start;
                        s = lower_32_bits(r);
-                       if (so->gen >= 8) {
+                       if (has_64bit_reloc) {
                                if (i + 1 >= rodata->batch_items ||
                                    rodata->batch[i + 1] != 0) {
                                        ret = -EINVAL;
@@ -174,7 +153,7 @@ static int render_state_setup(struct render_state *so)
 
        kunmap(page);
 
-       ret = i915_gem_object_set_to_gtt_domain(so->obj, false);
+       ret = i915_gem_object_set_to_gtt_domain(so->vma->obj, false);
        if (ret)
                return ret;
 
@@ -192,67 +171,60 @@ err_out:
 
 #undef OUT_BATCH
 
-void i915_gem_render_state_fini(struct render_state *so)
-{
-       i915_gem_object_ggtt_unpin(so->obj);
-       drm_gem_object_unreference(&so->obj->base);
-}
-
-int i915_gem_render_state_prepare(struct intel_engine_cs *engine,
-                                 struct render_state *so)
+int i915_gem_render_state_init(struct drm_i915_gem_request *req)
 {
+       struct render_state so;
+       struct drm_i915_gem_object *obj;
        int ret;
 
-       if (WARN_ON(engine->id != RCS))
+       if (WARN_ON(req->engine->id != RCS))
                return -ENOENT;
 
-       ret = render_state_init(so, engine->i915);
-       if (ret)
-               return ret;
-
-       if (so->rodata == NULL)
+       so.rodata = render_state_get_rodata(req);
+       if (!so.rodata)
                return 0;
 
-       ret = render_state_setup(so);
-       if (ret) {
-               i915_gem_render_state_fini(so);
-               return ret;
-       }
+       if (so.rodata->batch_items * 4 > 4096)
+               return -EINVAL;
 
-       return 0;
-}
+       obj = i915_gem_object_create(&req->i915->drm, 4096);
+       if (IS_ERR(obj))
+               return PTR_ERR(obj);
 
-int i915_gem_render_state_init(struct drm_i915_gem_request *req)
-{
-       struct render_state so;
-       int ret;
+       so.vma = i915_vma_create(obj, &req->i915->ggtt.base, NULL);
+       if (IS_ERR(so.vma)) {
+               ret = PTR_ERR(so.vma);
+               goto err_obj;
+       }
 
-       ret = i915_gem_render_state_prepare(req->engine, &so);
+       ret = i915_vma_pin(so.vma, 0, 0, PIN_GLOBAL);
        if (ret)
-               return ret;
+               goto err_obj;
 
-       if (so.rodata == NULL)
-               return 0;
+       ret = render_state_setup(&so);
+       if (ret)
+               goto err_unpin;
 
-       ret = req->engine->dispatch_execbuffer(req, so.ggtt_offset,
-                                            so.rodata->batch_items * 4,
-                                            I915_DISPATCH_SECURE);
+       ret = req->engine->emit_bb_start(req, so.vma->node.start,
+                                        so.rodata->batch_items * 4,
+                                        I915_DISPATCH_SECURE);
        if (ret)
-               goto out;
+               goto err_unpin;
 
        if (so.aux_batch_size > 8) {
-               ret = req->engine->dispatch_execbuffer(req,
-                                                    (so.ggtt_offset +
-                                                     so.aux_batch_offset),
-                                                    so.aux_batch_size,
-                                                    I915_DISPATCH_SECURE);
+               ret = req->engine->emit_bb_start(req,
+                                                (so.vma->node.start +
+                                                 so.aux_batch_offset),
+                                                so.aux_batch_size,
+                                                I915_DISPATCH_SECURE);
                if (ret)
-                       goto out;
+                       goto err_unpin;
        }
 
-       i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req);
-
-out:
-       i915_gem_render_state_fini(&so);
+       i915_vma_move_to_active(so.vma, req, 0);
+err_unpin:
+       i915_vma_unpin(so.vma);
+err_obj:
+       i915_gem_object_put(obj);
        return ret;
 }
index 6aaa3a1..18cce3f 100644 (file)
 #ifndef _I915_GEM_RENDER_STATE_H_
 #define _I915_GEM_RENDER_STATE_H_
 
-#include <linux/types.h>
-
-struct intel_renderstate_rodata {
-       const u32 *reloc;
-       const u32 *batch;
-       const u32 batch_items;
-};
-
-struct render_state {
-       const struct intel_renderstate_rodata *rodata;
-       struct drm_i915_gem_object *obj;
-       u64 ggtt_offset;
-       int gen;
-       u32 aux_batch_size;
-       u32 aux_batch_offset;
-};
+struct drm_i915_gem_request;
 
 int i915_gem_render_state_init(struct drm_i915_gem_request *req);
-void i915_gem_render_state_fini(struct render_state *so);
-int i915_gem_render_state_prepare(struct intel_engine_cs *engine,
-                                 struct render_state *so);
 
 #endif /* _I915_GEM_RENDER_STATE_H_ */
diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c
new file mode 100644 (file)
index 0000000..8832f8e
--- /dev/null
@@ -0,0 +1,947 @@
+/*
+ * Copyright © 2008-2015 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/prefetch.h>
+
+#include "i915_drv.h"
+
+static const char *i915_fence_get_driver_name(struct fence *fence)
+{
+       return "i915";
+}
+
+static const char *i915_fence_get_timeline_name(struct fence *fence)
+{
+       /* Timelines are bound by eviction to a VM. However, since
+        * we only have a global seqno at the moment, we only have
+        * a single timeline. Note that each timeline will have
+        * multiple execution contexts (fence contexts) as we allow
+        * engines within a single timeline to execute in parallel.
+        */
+       return "global";
+}
+
+static bool i915_fence_signaled(struct fence *fence)
+{
+       return i915_gem_request_completed(to_request(fence));
+}
+
+static bool i915_fence_enable_signaling(struct fence *fence)
+{
+       if (i915_fence_signaled(fence))
+               return false;
+
+       intel_engine_enable_signaling(to_request(fence));
+       return true;
+}
+
+static signed long i915_fence_wait(struct fence *fence,
+                                  bool interruptible,
+                                  signed long timeout_jiffies)
+{
+       s64 timeout_ns, *timeout;
+       int ret;
+
+       if (timeout_jiffies != MAX_SCHEDULE_TIMEOUT) {
+               timeout_ns = jiffies_to_nsecs(timeout_jiffies);
+               timeout = &timeout_ns;
+       } else {
+               timeout = NULL;
+       }
+
+       ret = i915_wait_request(to_request(fence),
+                               interruptible, timeout,
+                               NO_WAITBOOST);
+       if (ret == -ETIME)
+               return 0;
+
+       if (ret < 0)
+               return ret;
+
+       if (timeout_jiffies != MAX_SCHEDULE_TIMEOUT)
+               timeout_jiffies = nsecs_to_jiffies(timeout_ns);
+
+       return timeout_jiffies;
+}
+
+static void i915_fence_value_str(struct fence *fence, char *str, int size)
+{
+       snprintf(str, size, "%u", fence->seqno);
+}
+
+static void i915_fence_timeline_value_str(struct fence *fence, char *str,
+                                         int size)
+{
+       snprintf(str, size, "%u",
+                intel_engine_get_seqno(to_request(fence)->engine));
+}
+
+static void i915_fence_release(struct fence *fence)
+{
+       struct drm_i915_gem_request *req = to_request(fence);
+
+       kmem_cache_free(req->i915->requests, req);
+}
+
+const struct fence_ops i915_fence_ops = {
+       .get_driver_name = i915_fence_get_driver_name,
+       .get_timeline_name = i915_fence_get_timeline_name,
+       .enable_signaling = i915_fence_enable_signaling,
+       .signaled = i915_fence_signaled,
+       .wait = i915_fence_wait,
+       .release = i915_fence_release,
+       .fence_value_str = i915_fence_value_str,
+       .timeline_value_str = i915_fence_timeline_value_str,
+};
+
+int i915_gem_request_add_to_client(struct drm_i915_gem_request *req,
+                                  struct drm_file *file)
+{
+       struct drm_i915_private *dev_private;
+       struct drm_i915_file_private *file_priv;
+
+       WARN_ON(!req || !file || req->file_priv);
+
+       if (!req || !file)
+               return -EINVAL;
+
+       if (req->file_priv)
+               return -EINVAL;
+
+       dev_private = req->i915;
+       file_priv = file->driver_priv;
+
+       spin_lock(&file_priv->mm.lock);
+       req->file_priv = file_priv;
+       list_add_tail(&req->client_list, &file_priv->mm.request_list);
+       spin_unlock(&file_priv->mm.lock);
+
+       return 0;
+}
+
+static inline void
+i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
+{
+       struct drm_i915_file_private *file_priv = request->file_priv;
+
+       if (!file_priv)
+               return;
+
+       spin_lock(&file_priv->mm.lock);
+       list_del(&request->client_list);
+       request->file_priv = NULL;
+       spin_unlock(&file_priv->mm.lock);
+}
+
+void i915_gem_retire_noop(struct i915_gem_active *active,
+                         struct drm_i915_gem_request *request)
+{
+       /* Space left intentionally blank */
+}
+
+static void i915_gem_request_retire(struct drm_i915_gem_request *request)
+{
+       struct i915_gem_active *active, *next;
+
+       trace_i915_gem_request_retire(request);
+       list_del(&request->link);
+
+       /* We know the GPU must have read the request to have
+        * sent us the seqno + interrupt, so use the position
+        * of tail of the request to update the last known position
+        * of the GPU head.
+        *
+        * Note this requires that we are always called in request
+        * completion order.
+        */
+       list_del(&request->ring_link);
+       request->ring->last_retired_head = request->postfix;
+
+       /* Walk through the active list, calling retire on each. This allows
+        * objects to track their GPU activity and mark themselves as idle
+        * when their *last* active request is completed (updating state
+        * tracking lists for eviction, active references for GEM, etc).
+        *
+        * As the ->retire() may free the node, we decouple it first and
+        * pass along the auxiliary information (to avoid dereferencing
+        * the node after the callback).
+        */
+       list_for_each_entry_safe(active, next, &request->active_list, link) {
+               /* In microbenchmarks or focusing upon time inside the kernel,
+                * we may spend an inordinate amount of time simply handling
+                * the retirement of requests and processing their callbacks.
+                * Of which, this loop itself is particularly hot due to the
+                * cache misses when jumping around the list of i915_gem_active.
+                * So we try to keep this loop as streamlined as possible and
+                * also prefetch the next i915_gem_active to try and hide
+                * the likely cache miss.
+                */
+               prefetchw(next);
+
+               INIT_LIST_HEAD(&active->link);
+               RCU_INIT_POINTER(active->request, NULL);
+
+               active->retire(active, request);
+       }
+
+       i915_gem_request_remove_from_client(request);
+
+       if (request->previous_context) {
+               if (i915.enable_execlists)
+                       intel_lr_context_unpin(request->previous_context,
+                                              request->engine);
+       }
+
+       i915_gem_context_put(request->ctx);
+       i915_gem_request_put(request);
+}
+
+void i915_gem_request_retire_upto(struct drm_i915_gem_request *req)
+{
+       struct intel_engine_cs *engine = req->engine;
+       struct drm_i915_gem_request *tmp;
+
+       lockdep_assert_held(&req->i915->drm.struct_mutex);
+       GEM_BUG_ON(list_empty(&req->link));
+
+       do {
+               tmp = list_first_entry(&engine->request_list,
+                                      typeof(*tmp), link);
+
+               i915_gem_request_retire(tmp);
+       } 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_seqno(struct drm_i915_private *dev_priv, u32 seqno)
+{
+       struct intel_engine_cs *engine;
+       int ret;
+
+       /* Carefully retire all requests without writing to the rings */
+       for_each_engine(engine, dev_priv) {
+               ret = intel_engine_idle(engine,
+                                       I915_WAIT_INTERRUPTIBLE |
+                                       I915_WAIT_LOCKED);
+               if (ret)
+                       return ret;
+       }
+       i915_gem_retire_requests(dev_priv);
+
+       /* If the seqno wraps around, we need to clear the breadcrumb rbtree */
+       if (!i915_seqno_passed(seqno, dev_priv->next_seqno)) {
+               while (intel_kick_waiters(dev_priv) ||
+                      intel_kick_signalers(dev_priv))
+                       yield();
+       }
+
+       /* Finally reset hw state */
+       for_each_engine(engine, dev_priv)
+               intel_engine_init_seqno(engine, seqno);
+
+       return 0;
+}
+
+int i915_gem_set_seqno(struct drm_device *dev, u32 seqno)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       int ret;
+
+       if (seqno == 0)
+               return -EINVAL;
+
+       /* HWS page needs to be set less than what we
+        * will inject to ring
+        */
+       ret = i915_gem_init_seqno(dev_priv, seqno - 1);
+       if (ret)
+               return ret;
+
+       dev_priv->next_seqno = seqno;
+       return 0;
+}
+
+static int i915_gem_get_seqno(struct drm_i915_private *dev_priv, u32 *seqno)
+{
+       /* reserve 0 for non-seqno */
+       if (unlikely(dev_priv->next_seqno == 0)) {
+               int ret;
+
+               ret = i915_gem_init_seqno(dev_priv, 0);
+               if (ret)
+                       return ret;
+
+               dev_priv->next_seqno = 1;
+       }
+
+       *seqno = dev_priv->next_seqno++;
+       return 0;
+}
+
+static int __i915_sw_fence_call
+submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
+{
+       struct drm_i915_gem_request *request =
+               container_of(fence, typeof(*request), submit);
+
+       /* Will be called from irq-context when using foreign DMA fences */
+
+       switch (state) {
+       case FENCE_COMPLETE:
+               request->engine->last_submitted_seqno = request->fence.seqno;
+               request->engine->submit_request(request);
+               break;
+
+       case FENCE_FREE:
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+/**
+ * i915_gem_request_alloc - allocate a request structure
+ *
+ * @engine: engine that we wish to issue the request on.
+ * @ctx: context that the request will be associated with.
+ *       This can be NULL if the request is not directly related to
+ *       any specific user context, in which case this function will
+ *       choose an appropriate context to use.
+ *
+ * Returns a pointer to the allocated request if successful,
+ * or an error code if not.
+ */
+struct drm_i915_gem_request *
+i915_gem_request_alloc(struct intel_engine_cs *engine,
+                      struct i915_gem_context *ctx)
+{
+       struct drm_i915_private *dev_priv = engine->i915;
+       struct drm_i915_gem_request *req;
+       u32 seqno;
+       int ret;
+
+       /* 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.
+        */
+       ret = i915_gem_check_wedge(dev_priv);
+       if (ret)
+               return ERR_PTR(ret);
+
+       /* Move the oldest request to the slab-cache (if not in use!) */
+       req = list_first_entry_or_null(&engine->request_list,
+                                      typeof(*req), link);
+       if (req && i915_gem_request_completed(req))
+               i915_gem_request_retire(req);
+
+       /* Beware: Dragons be flying overhead.
+        *
+        * We use RCU to look up requests in flight. The lookups may
+        * race with the request being allocated from the slab freelist.
+        * That is the request we are writing to here, may be in the process
+        * of being read by __i915_gem_active_get_rcu(). As such,
+        * we have to be very careful when overwriting the contents. During
+        * the RCU lookup, we change chase the request->engine pointer,
+        * read the request->fence.seqno and increment the reference count.
+        *
+        * The reference count is incremented atomically. If it is zero,
+        * the lookup knows the request is unallocated and complete. Otherwise,
+        * it is either still in use, or has been reallocated and reset
+        * with fence_init(). This increment is safe for release as we check
+        * that the request we have a reference to and matches the active
+        * request.
+        *
+        * Before we increment the refcount, we chase the request->engine
+        * pointer. We must not call kmem_cache_zalloc() or else we set
+        * that pointer to NULL and cause a crash during the lookup. If
+        * we see the request is completed (based on the value of the
+        * old engine and seqno), the lookup is complete and reports NULL.
+        * If we decide the request is not completed (new engine or seqno),
+        * then we grab a reference and double check that it is still the
+        * active request - which it won't be and restart the lookup.
+        *
+        * Do not use kmem_cache_zalloc() here!
+        */
+       req = kmem_cache_alloc(dev_priv->requests, GFP_KERNEL);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       ret = i915_gem_get_seqno(dev_priv, &seqno);
+       if (ret)
+               goto err;
+
+       spin_lock_init(&req->lock);
+       fence_init(&req->fence,
+                  &i915_fence_ops,
+                  &req->lock,
+                  engine->fence_context,
+                  seqno);
+
+       i915_sw_fence_init(&req->submit, submit_notify);
+
+       INIT_LIST_HEAD(&req->active_list);
+       req->i915 = dev_priv;
+       req->engine = engine;
+       req->ctx = i915_gem_context_get(ctx);
+
+       /* No zalloc, must clear what we need by hand */
+       req->previous_context = NULL;
+       req->file_priv = NULL;
+       req->batch = NULL;
+
+       /*
+        * Reserve space in the ring buffer for all the commands required to
+        * eventually emit this request. This is to guarantee that the
+        * i915_add_request() call can't fail. Note that the reserve may need
+        * to be redone if the request is not actually submitted straight
+        * away, e.g. because a GPU scheduler has deferred it.
+        */
+       req->reserved_space = MIN_SPACE_FOR_ADD_REQUEST;
+
+       if (i915.enable_execlists)
+               ret = intel_logical_ring_alloc_request_extras(req);
+       else
+               ret = intel_ring_alloc_request_extras(req);
+       if (ret)
+               goto err_ctx;
+
+       /* Record the position of the start of the request so that
+        * should we detect the updated seqno part-way through the
+        * GPU processing the request, we never over-estimate the
+        * position of the head.
+        */
+       req->head = req->ring->tail;
+
+       return req;
+
+err_ctx:
+       i915_gem_context_put(ctx);
+err:
+       kmem_cache_free(dev_priv->requests, req);
+       return ERR_PTR(ret);
+}
+
+static int
+i915_gem_request_await_request(struct drm_i915_gem_request *to,
+                              struct drm_i915_gem_request *from)
+{
+       int idx, ret;
+
+       GEM_BUG_ON(to == from);
+
+       if (to->engine == from->engine)
+               return 0;
+
+       idx = intel_engine_sync_index(from->engine, to->engine);
+       if (from->fence.seqno <= from->engine->semaphore.sync_seqno[idx])
+               return 0;
+
+       trace_i915_gem_ring_sync_to(to, from);
+       if (!i915.semaphores) {
+               if (!i915_spin_request(from, TASK_INTERRUPTIBLE, 2)) {
+                       ret = i915_sw_fence_await_dma_fence(&to->submit,
+                                                           &from->fence, 0,
+                                                           GFP_KERNEL);
+                       if (ret < 0)
+                               return ret;
+               }
+       } else {
+               ret = to->engine->semaphore.sync_to(to, from);
+               if (ret)
+                       return ret;
+       }
+
+       from->engine->semaphore.sync_seqno[idx] = from->fence.seqno;
+       return 0;
+}
+
+/**
+ * i915_gem_request_await_object - set this request to (async) wait upon a bo
+ *
+ * @to: request we are wishing to use
+ * @obj: object which may be in use on another ring.
+ *
+ * This code is meant to abstract object synchronization with the GPU.
+ * Conceptually we serialise writes between engines inside the GPU.
+ * We only allow one engine to write into a buffer at any time, but
+ * multiple readers. To ensure each has a coherent view of memory, we must:
+ *
+ * - If there is an outstanding write request to the object, the new
+ *   request must wait for it to complete (either CPU or in hw, requests
+ *   on the same ring will be naturally ordered).
+ *
+ * - If we are a write request (pending_write_domain is set), the new
+ *   request must wait for outstanding read requests to complete.
+ *
+ * Returns 0 if successful, else propagates up the lower layer error.
+ */
+int
+i915_gem_request_await_object(struct drm_i915_gem_request *to,
+                             struct drm_i915_gem_object *obj,
+                             bool write)
+{
+       struct i915_gem_active *active;
+       unsigned long active_mask;
+       int idx;
+
+       if (write) {
+               active_mask = i915_gem_object_get_active(obj);
+               active = obj->last_read;
+       } else {
+               active_mask = 1;
+               active = &obj->last_write;
+       }
+
+       for_each_active(active_mask, idx) {
+               struct drm_i915_gem_request *request;
+               int ret;
+
+               request = i915_gem_active_peek(&active[idx],
+                                              &obj->base.dev->struct_mutex);
+               if (!request)
+                       continue;
+
+               ret = i915_gem_request_await_request(to, request);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void i915_gem_mark_busy(const struct intel_engine_cs *engine)
+{
+       struct drm_i915_private *dev_priv = engine->i915;
+
+       dev_priv->gt.active_engines |= intel_engine_flag(engine);
+       if (dev_priv->gt.awake)
+               return;
+
+       intel_runtime_pm_get_noresume(dev_priv);
+       dev_priv->gt.awake = true;
+
+       intel_enable_gt_powersave(dev_priv);
+       i915_update_gfx_val(dev_priv);
+       if (INTEL_GEN(dev_priv) >= 6)
+               gen6_rps_busy(dev_priv);
+
+       queue_delayed_work(dev_priv->wq,
+                          &dev_priv->gt.retire_work,
+                          round_jiffies_up_relative(HZ));
+}
+
+/*
+ * NB: This function is not allowed to fail. Doing so would mean the the
+ * request is not being tracked for completion but the work itself is
+ * going to happen on the hardware. This would be a Bad Thing(tm).
+ */
+void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
+{
+       struct intel_engine_cs *engine = request->engine;
+       struct intel_ring *ring = request->ring;
+       struct drm_i915_gem_request *prev;
+       u32 request_start;
+       u32 reserved_tail;
+       int ret;
+
+       trace_i915_gem_request_add(request);
+
+       /*
+        * To ensure that this call will not fail, space for its emissions
+        * should already have been reserved in the ring buffer. Let the ring
+        * know that it is time to use that space up.
+        */
+       request_start = ring->tail;
+       reserved_tail = request->reserved_space;
+       request->reserved_space = 0;
+
+       /*
+        * Emit any outstanding flushes - execbuf can fail to emit the flush
+        * after having emitted the batchbuffer command. Hence we need to fix
+        * things up similar to emitting the lazy request. The difference here
+        * is that the flush _must_ happen before the next request, no matter
+        * what.
+        */
+       if (flush_caches) {
+               ret = engine->emit_flush(request, EMIT_FLUSH);
+
+               /* Not allowed to fail! */
+               WARN(ret, "engine->emit_flush() failed: %d!\n", ret);
+       }
+
+       /* Record the position of the start of the breadcrumb so that
+        * should we detect the updated seqno part-way through the
+        * GPU processing the request, we never over-estimate the
+        * position of the ring's HEAD.
+        */
+       request->postfix = ring->tail;
+
+       /* Not allowed to fail! */
+       ret = engine->emit_request(request);
+       WARN(ret, "(%s)->emit_request failed: %d!\n", engine->name, ret);
+
+       /* Sanity check that the reserved size was large enough. */
+       ret = ring->tail - request_start;
+       if (ret < 0)
+               ret += ring->size;
+       WARN_ONCE(ret > reserved_tail,
+                 "Not enough space reserved (%d bytes) "
+                 "for adding the request (%d bytes)\n",
+                 reserved_tail, ret);
+
+       /* Seal the request and mark it as pending execution. Note that
+        * we may inspect this state, without holding any locks, during
+        * hangcheck. Hence we apply the barrier to ensure that we do not
+        * see a more recent value in the hws than we are tracking.
+        */
+
+       prev = i915_gem_active_raw(&engine->last_request,
+                                  &request->i915->drm.struct_mutex);
+       if (prev)
+               i915_sw_fence_await_sw_fence(&request->submit, &prev->submit,
+                                            &request->submitq);
+
+       request->emitted_jiffies = jiffies;
+       request->previous_seqno = engine->last_pending_seqno;
+       engine->last_pending_seqno = request->fence.seqno;
+       i915_gem_active_set(&engine->last_request, request);
+       list_add_tail(&request->link, &engine->request_list);
+       list_add_tail(&request->ring_link, &ring->request_list);
+
+       i915_gem_mark_busy(engine);
+
+       local_bh_disable();
+       i915_sw_fence_commit(&request->submit);
+       local_bh_enable(); /* Kick the execlists tasklet if just scheduled */
+}
+
+static void reset_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&q->lock, flags);
+       if (list_empty(&wait->task_list))
+               __add_wait_queue(q, wait);
+       spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static unsigned long local_clock_us(unsigned int *cpu)
+{
+       unsigned long t;
+
+       /* Cheaply and approximately convert from nanoseconds to microseconds.
+        * The result and subsequent calculations are also defined in the same
+        * approximate microseconds units. The principal source of timing
+        * error here is from the simple truncation.
+        *
+        * Note that local_clock() is only defined wrt to the current CPU;
+        * the comparisons are no longer valid if we switch CPUs. Instead of
+        * blocking preemption for the entire busywait, we can detect the CPU
+        * switch and use that as indicator of system load and a reason to
+        * stop busywaiting, see busywait_stop().
+        */
+       *cpu = get_cpu();
+       t = local_clock() >> 10;
+       put_cpu();
+
+       return t;
+}
+
+static bool busywait_stop(unsigned long timeout, unsigned int cpu)
+{
+       unsigned int this_cpu;
+
+       if (time_after(local_clock_us(&this_cpu), timeout))
+               return true;
+
+       return this_cpu != cpu;
+}
+
+bool __i915_spin_request(const struct drm_i915_gem_request *req,
+                        int state, unsigned long timeout_us)
+{
+       unsigned int cpu;
+
+       /* When waiting for high frequency requests, e.g. during synchronous
+        * rendering split between the CPU and GPU, the finite amount of time
+        * required to set up the irq and wait upon it limits the response
+        * rate. By busywaiting on the request completion for a short while we
+        * can service the high frequency waits as quick as possible. However,
+        * if it is a slow request, we want to sleep as quickly as possible.
+        * The tradeoff between waiting and sleeping is roughly the time it
+        * takes to sleep on a request, on the order of a microsecond.
+        */
+
+       timeout_us += local_clock_us(&cpu);
+       do {
+               if (i915_gem_request_completed(req))
+                       return true;
+
+               if (signal_pending_state(state, current))
+                       break;
+
+               if (busywait_stop(timeout_us, cpu))
+                       break;
+
+               cpu_relax_lowlatency();
+       } while (!need_resched());
+
+       return false;
+}
+
+/**
+ * i915_wait_request - wait until execution of request has finished
+ * @req: duh!
+ * @flags: how to wait
+ * @timeout: in - how long to wait (NULL forever); out - how much time remaining
+ * @rps: client to charge for RPS boosting
+ *
+ * Note: It is of utmost importance that the passed in seqno and reset_counter
+ * values have been read by the caller in an smp safe manner. Where read-side
+ * locks are involved, it is sufficient to read the reset_counter before
+ * unlocking the lock that protects the seqno. For lockless tricks, the
+ * reset_counter _must_ be read before, and an appropriate smp_rmb must be
+ * inserted.
+ *
+ * Returns 0 if the request was found within the alloted time. Else returns the
+ * errno with remaining time filled in timeout argument.
+ */
+int i915_wait_request(struct drm_i915_gem_request *req,
+                     unsigned int flags,
+                     s64 *timeout,
+                     struct intel_rps_client *rps)
+{
+       const int state = flags & I915_WAIT_INTERRUPTIBLE ?
+               TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
+       DEFINE_WAIT(reset);
+       struct intel_wait wait;
+       unsigned long timeout_remain;
+       int ret = 0;
+
+       might_sleep();
+#if IS_ENABLED(CONFIG_LOCKDEP)
+       GEM_BUG_ON(!!lockdep_is_held(&req->i915->drm.struct_mutex) !=
+                  !!(flags & I915_WAIT_LOCKED));
+#endif
+
+       if (i915_gem_request_completed(req))
+               return 0;
+
+       timeout_remain = MAX_SCHEDULE_TIMEOUT;
+       if (timeout) {
+               if (WARN_ON(*timeout < 0))
+                       return -EINVAL;
+
+               if (*timeout == 0)
+                       return -ETIME;
+
+               /* Record current time in case interrupted, or wedged */
+               timeout_remain = nsecs_to_jiffies_timeout(*timeout);
+               *timeout += ktime_get_raw_ns();
+       }
+
+       trace_i915_gem_request_wait_begin(req);
+
+       /* This client is about to stall waiting for the GPU. In many cases
+        * this is undesirable and limits the throughput of the system, as
+        * many clients cannot continue processing user input/output whilst
+        * blocked. RPS autotuning may take tens of milliseconds to respond
+        * to the GPU load and thus incurs additional latency for the client.
+        * We can circumvent that by promoting the GPU frequency to maximum
+        * before we wait. This makes the GPU throttle up much more quickly
+        * (good for benchmarks and user experience, e.g. window animations),
+        * but at a cost of spending more power processing the workload
+        * (bad for battery). Not all clients even want their results
+        * immediately and for them we should just let the GPU select its own
+        * frequency to maximise efficiency. To prevent a single client from
+        * forcing the clocks too high for the whole system, we only allow
+        * each client to waitboost once in a busy period.
+        */
+       if (IS_RPS_CLIENT(rps) && INTEL_GEN(req->i915) >= 6)
+               gen6_rps_boost(req->i915, rps, req->emitted_jiffies);
+
+       /* Optimistic short spin before touching IRQs */
+       if (i915_spin_request(req, state, 5))
+               goto complete;
+
+       set_current_state(state);
+       if (flags & I915_WAIT_LOCKED)
+               add_wait_queue(&req->i915->gpu_error.wait_queue, &reset);
+
+       intel_wait_init(&wait, req->fence.seqno);
+       if (intel_engine_add_wait(req->engine, &wait))
+               /* In order to check that we haven't missed the interrupt
+                * as we enabled it, we need to kick ourselves to do a
+                * coherent check on the seqno before we sleep.
+                */
+               goto wakeup;
+
+       for (;;) {
+               if (signal_pending_state(state, current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               timeout_remain = io_schedule_timeout(timeout_remain);
+               if (timeout_remain == 0) {
+                       ret = -ETIME;
+                       break;
+               }
+
+               if (intel_wait_complete(&wait))
+                       break;
+
+               set_current_state(state);
+
+wakeup:
+               /* Carefully check if the request is complete, giving time
+                * for the seqno to be visible following the interrupt.
+                * We also have to check in case we are kicked by the GPU
+                * reset in order to drop the struct_mutex.
+                */
+               if (__i915_request_irq_complete(req))
+                       break;
+
+               /* If the GPU is hung, and we hold the lock, reset the GPU
+                * and then check for completion. On a full reset, the engine's
+                * HW seqno will be advanced passed us and we are complete.
+                * If we do a partial reset, we have to wait for the GPU to
+                * resume and update the breadcrumb.
+                *
+                * If we don't hold the mutex, we can just wait for the worker
+                * to come along and update the breadcrumb (either directly
+                * itself, or indirectly by recovering the GPU).
+                */
+               if (flags & I915_WAIT_LOCKED &&
+                   i915_reset_in_progress(&req->i915->gpu_error)) {
+                       __set_current_state(TASK_RUNNING);
+                       i915_reset(req->i915);
+                       reset_wait_queue(&req->i915->gpu_error.wait_queue,
+                                        &reset);
+                       continue;
+               }
+
+               /* Only spin if we know the GPU is processing this request */
+               if (i915_spin_request(req, state, 2))
+                       break;
+       }
+
+       intel_engine_remove_wait(req->engine, &wait);
+       if (flags & I915_WAIT_LOCKED)
+               remove_wait_queue(&req->i915->gpu_error.wait_queue, &reset);
+       __set_current_state(TASK_RUNNING);
+
+complete:
+       trace_i915_gem_request_wait_end(req);
+
+       if (timeout) {
+               *timeout -= ktime_get_raw_ns();
+               if (*timeout < 0)
+                       *timeout = 0;
+
+               /*
+                * Apparently ktime isn't accurate enough and occasionally has a
+                * bit of mismatch in the jiffies<->nsecs<->ktime loop. So patch
+                * things up to make the test happy. We allow up to 1 jiffy.
+                *
+                * This is a regrssion from the timespec->ktime conversion.
+                */
+               if (ret == -ETIME && *timeout < jiffies_to_usecs(1)*1000)
+                       *timeout = 0;
+       }
+
+       if (IS_RPS_USER(rps) &&
+           req->fence.seqno == req->engine->last_submitted_seqno) {
+               /* The GPU is now idle and this client has stalled.
+                * Since no other client has submitted a request in the
+                * meantime, assume that this client is the only one
+                * supplying work to the GPU but is unable to keep that
+                * work supplied because it is waiting. Since the GPU is
+                * then never kept fully busy, RPS autoclocking will
+                * keep the clocks relatively low, causing further delays.
+                * Compensate by giving the synchronous client credit for
+                * a waitboost next time.
+                */
+               spin_lock(&req->i915->rps.client_lock);
+               list_del_init(&rps->link);
+               spin_unlock(&req->i915->rps.client_lock);
+       }
+
+       return ret;
+}
+
+static bool engine_retire_requests(struct intel_engine_cs *engine)
+{
+       struct drm_i915_gem_request *request, *next;
+
+       list_for_each_entry_safe(request, next, &engine->request_list, link) {
+               if (!i915_gem_request_completed(request))
+                       return false;
+
+               i915_gem_request_retire(request);
+       }
+
+       return true;
+}
+
+void i915_gem_retire_requests(struct drm_i915_private *dev_priv)
+{
+       struct intel_engine_cs *engine;
+       unsigned int tmp;
+
+       lockdep_assert_held(&dev_priv->drm.struct_mutex);
+
+       if (dev_priv->gt.active_engines == 0)
+               return;
+
+       GEM_BUG_ON(!dev_priv->gt.awake);
+
+       for_each_engine_masked(engine, dev_priv, dev_priv->gt.active_engines, tmp)
+               if (engine_retire_requests(engine))
+                       dev_priv->gt.active_engines &= ~intel_engine_flag(engine);
+
+       if (dev_priv->gt.active_engines == 0)
+               queue_delayed_work(dev_priv->wq,
+                                  &dev_priv->gt.idle_work,
+                                  msecs_to_jiffies(100));
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_request.h b/drivers/gpu/drm/i915/i915_gem_request.h
new file mode 100644 (file)
index 0000000..974bd7b
--- /dev/null
@@ -0,0 +1,689 @@
+/*
+ * Copyright © 2008-2015 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.
+ *
+ */
+
+#ifndef I915_GEM_REQUEST_H
+#define I915_GEM_REQUEST_H
+
+#include <linux/fence.h>
+
+#include "i915_gem.h"
+#include "i915_sw_fence.h"
+
+struct intel_wait {
+       struct rb_node node;
+       struct task_struct *tsk;
+       u32 seqno;
+};
+
+struct intel_signal_node {
+       struct rb_node node;
+       struct intel_wait wait;
+};
+
+/**
+ * Request queue structure.
+ *
+ * The request queue allows us to note sequence numbers that have been emitted
+ * and may be associated with active buffers to be retired.
+ *
+ * By keeping this list, we can avoid having to do questionable sequence
+ * number comparisons on buffer last_read|write_seqno. It also allows an
+ * emission time to be associated with the request for tracking how far ahead
+ * of the GPU the submission is.
+ *
+ * When modifying this structure be very aware that we perform a lockless
+ * RCU lookup of it that may race against reallocation of the struct
+ * from the slab freelist. We intentionally do not zero the structure on
+ * allocation so that the lookup can use the dangling pointers (and is
+ * cogniscent that those pointers may be wrong). Instead, everything that
+ * needs to be initialised must be done so explicitly.
+ *
+ * The requests are reference counted.
+ */
+struct drm_i915_gem_request {
+       struct fence fence;
+       spinlock_t lock;
+
+       /** On Which ring this request was generated */
+       struct drm_i915_private *i915;
+
+       /**
+        * Context and ring buffer related to this request
+        * Contexts are refcounted, so when this request is associated with a
+        * context, we must increment the context's refcount, to guarantee that
+        * it persists while any request is linked to it. Requests themselves
+        * are also refcounted, so the request will only be freed when the last
+        * reference to it is dismissed, and the code in
+        * i915_gem_request_free() will then decrement the refcount on the
+        * context.
+        */
+       struct i915_gem_context *ctx;
+       struct intel_engine_cs *engine;
+       struct intel_ring *ring;
+       struct intel_signal_node signaling;
+
+       struct i915_sw_fence submit;
+       wait_queue_t submitq;
+
+       /** GEM sequence number associated with the previous request,
+        * when the HWS breadcrumb is equal to this the GPU is processing
+        * this request.
+        */
+       u32 previous_seqno;
+
+       /** Position in the ring of the start of the request */
+       u32 head;
+
+       /**
+        * Position in the ring of the start of the postfix.
+        * This is required to calculate the maximum available ring space
+        * without overwriting the postfix.
+        */
+       u32 postfix;
+
+       /** Position in the ring of the end of the whole request */
+       u32 tail;
+
+       /** Position in the ring of the end of any workarounds after the tail */
+       u32 wa_tail;
+
+       /** Preallocate space in the ring for the emitting the request */
+       u32 reserved_space;
+
+       /**
+        * Context related to the previous request.
+        * As the contexts are accessed by the hardware until the switch is
+        * completed to a new context, the hardware may still be writing
+        * to the context object after the breadcrumb is visible. We must
+        * not unpin/unbind/prune that object whilst still active and so
+        * we keep the previous context pinned until the following (this)
+        * request is retired.
+        */
+       struct i915_gem_context *previous_context;
+
+       /** Batch buffer related to this request if any (used for
+        * error state dump only).
+        */
+       struct i915_vma *batch;
+       struct list_head active_list;
+
+       /** Time at which this request was emitted, in jiffies. */
+       unsigned long emitted_jiffies;
+
+       /** engine->request_list entry for this request */
+       struct list_head link;
+
+       /** ring->request_list entry for this request */
+       struct list_head ring_link;
+
+       struct drm_i915_file_private *file_priv;
+       /** file_priv list entry for this request */
+       struct list_head client_list;
+
+       /** Link in the execlist submission queue, guarded by execlist_lock. */
+       struct list_head execlist_link;
+};
+
+extern const struct fence_ops i915_fence_ops;
+
+static inline bool fence_is_i915(struct fence *fence)
+{
+       return fence->ops == &i915_fence_ops;
+}
+
+struct drm_i915_gem_request * __must_check
+i915_gem_request_alloc(struct intel_engine_cs *engine,
+                      struct i915_gem_context *ctx);
+int i915_gem_request_add_to_client(struct drm_i915_gem_request *req,
+                                  struct drm_file *file);
+void i915_gem_request_retire_upto(struct drm_i915_gem_request *req);
+
+static inline u32
+i915_gem_request_get_seqno(struct drm_i915_gem_request *req)
+{
+       return req ? req->fence.seqno : 0;
+}
+
+static inline struct intel_engine_cs *
+i915_gem_request_get_engine(struct drm_i915_gem_request *req)
+{
+       return req ? req->engine : NULL;
+}
+
+static inline struct drm_i915_gem_request *
+to_request(struct fence *fence)
+{
+       /* We assume that NULL fence/request are interoperable */
+       BUILD_BUG_ON(offsetof(struct drm_i915_gem_request, fence) != 0);
+       GEM_BUG_ON(fence && !fence_is_i915(fence));
+       return container_of(fence, struct drm_i915_gem_request, fence);
+}
+
+static inline struct drm_i915_gem_request *
+i915_gem_request_get(struct drm_i915_gem_request *req)
+{
+       return to_request(fence_get(&req->fence));
+}
+
+static inline struct drm_i915_gem_request *
+i915_gem_request_get_rcu(struct drm_i915_gem_request *req)
+{
+       return to_request(fence_get_rcu(&req->fence));
+}
+
+static inline void
+i915_gem_request_put(struct drm_i915_gem_request *req)
+{
+       fence_put(&req->fence);
+}
+
+static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
+                                          struct drm_i915_gem_request *src)
+{
+       if (src)
+               i915_gem_request_get(src);
+
+       if (*pdst)
+               i915_gem_request_put(*pdst);
+
+       *pdst = src;
+}
+
+int
+i915_gem_request_await_object(struct drm_i915_gem_request *to,
+                             struct drm_i915_gem_object *obj,
+                             bool write);
+
+void __i915_add_request(struct drm_i915_gem_request *req, bool flush_caches);
+#define i915_add_request(req) \
+       __i915_add_request(req, true)
+#define i915_add_request_no_flush(req) \
+       __i915_add_request(req, false)
+
+struct intel_rps_client;
+#define NO_WAITBOOST ERR_PTR(-1)
+#define IS_RPS_CLIENT(p) (!IS_ERR(p))
+#define IS_RPS_USER(p) (!IS_ERR_OR_NULL(p))
+
+int i915_wait_request(struct drm_i915_gem_request *req,
+                     unsigned int flags,
+                     s64 *timeout,
+                     struct intel_rps_client *rps)
+       __attribute__((nonnull(1)));
+#define I915_WAIT_INTERRUPTIBLE        BIT(0)
+#define I915_WAIT_LOCKED       BIT(1) /* struct_mutex held, handle GPU reset */
+
+static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine);
+
+/**
+ * Returns true if seq1 is later than seq2.
+ */
+static inline bool i915_seqno_passed(u32 seq1, u32 seq2)
+{
+       return (s32)(seq1 - seq2) >= 0;
+}
+
+static inline bool
+i915_gem_request_started(const struct drm_i915_gem_request *req)
+{
+       return i915_seqno_passed(intel_engine_get_seqno(req->engine),
+                                req->previous_seqno);
+}
+
+static inline bool
+i915_gem_request_completed(const struct drm_i915_gem_request *req)
+{
+       return i915_seqno_passed(intel_engine_get_seqno(req->engine),
+                                req->fence.seqno);
+}
+
+bool __i915_spin_request(const struct drm_i915_gem_request *request,
+                        int state, unsigned long timeout_us);
+static inline bool i915_spin_request(const struct drm_i915_gem_request *request,
+                                    int state, unsigned long timeout_us)
+{
+       return (i915_gem_request_started(request) &&
+               __i915_spin_request(request, state, timeout_us));
+}
+
+/* We treat requests as fences. This is not be to confused with our
+ * "fence registers" but pipeline synchronisation objects ala GL_ARB_sync.
+ * We use the fences to synchronize access from the CPU with activity on the
+ * GPU, for example, we should not rewrite an object's PTE whilst the GPU
+ * is reading them. We also track fences at a higher level to provide
+ * implicit synchronisation around GEM objects, e.g. set-domain will wait
+ * for outstanding GPU rendering before marking the object ready for CPU
+ * access, or a pageflip will wait until the GPU is complete before showing
+ * the frame on the scanout.
+ *
+ * In order to use a fence, the object must track the fence it needs to
+ * serialise with. For example, GEM objects want to track both read and
+ * write access so that we can perform concurrent read operations between
+ * the CPU and GPU engines, as well as waiting for all rendering to
+ * complete, or waiting for the last GPU user of a "fence register". The
+ * object then embeds a #i915_gem_active to track the most recent (in
+ * retirement order) request relevant for the desired mode of access.
+ * The #i915_gem_active is updated with i915_gem_active_set() to track the
+ * most recent fence request, typically this is done as part of
+ * i915_vma_move_to_active().
+ *
+ * When the #i915_gem_active completes (is retired), it will
+ * signal its completion to the owner through a callback as well as mark
+ * itself as idle (i915_gem_active.request == NULL). The owner
+ * can then perform any action, such as delayed freeing of an active
+ * resource including itself.
+ */
+struct i915_gem_active;
+
+typedef void (*i915_gem_retire_fn)(struct i915_gem_active *,
+                                  struct drm_i915_gem_request *);
+
+struct i915_gem_active {
+       struct drm_i915_gem_request __rcu *request;
+       struct list_head link;
+       i915_gem_retire_fn retire;
+};
+
+void i915_gem_retire_noop(struct i915_gem_active *,
+                         struct drm_i915_gem_request *request);
+
+/**
+ * init_request_active - prepares the activity tracker for use
+ * @active - the active tracker
+ * @func - a callback when then the tracker is retired (becomes idle),
+ *         can be NULL
+ *
+ * init_request_active() prepares the embedded @active struct for use as
+ * an activity tracker, that is for tracking the last known active request
+ * associated with it. When the last request becomes idle, when it is retired
+ * after completion, the optional callback @func is invoked.
+ */
+static inline void
+init_request_active(struct i915_gem_active *active,
+                   i915_gem_retire_fn retire)
+{
+       INIT_LIST_HEAD(&active->link);
+       active->retire = retire ?: i915_gem_retire_noop;
+}
+
+/**
+ * i915_gem_active_set - updates the tracker to watch the current request
+ * @active - the active tracker
+ * @request - the request to watch
+ *
+ * i915_gem_active_set() watches the given @request for completion. Whilst
+ * that @request is busy, the @active reports busy. When that @request is
+ * retired, the @active tracker is updated to report idle.
+ */
+static inline void
+i915_gem_active_set(struct i915_gem_active *active,
+                   struct drm_i915_gem_request *request)
+{
+       list_move(&active->link, &request->active_list);
+       rcu_assign_pointer(active->request, request);
+}
+
+static inline struct drm_i915_gem_request *
+__i915_gem_active_peek(const struct i915_gem_active *active)
+{
+       /* Inside the error capture (running with the driver in an unknown
+        * state), we want to bend the rules slightly (a lot).
+        *
+        * Work is in progress to make it safer, in the meantime this keeps
+        * the known issue from spamming the logs.
+        */
+       return rcu_dereference_protected(active->request, 1);
+}
+
+/**
+ * i915_gem_active_raw - return the active request
+ * @active - the active tracker
+ *
+ * i915_gem_active_raw() returns the current request being tracked, or NULL.
+ * It does not obtain a reference on the request for the caller, so the caller
+ * must hold struct_mutex.
+ */
+static inline struct drm_i915_gem_request *
+i915_gem_active_raw(const struct i915_gem_active *active, struct mutex *mutex)
+{
+       return rcu_dereference_protected(active->request,
+                                        lockdep_is_held(mutex));
+}
+
+/**
+ * i915_gem_active_peek - report the active request being monitored
+ * @active - the active tracker
+ *
+ * i915_gem_active_peek() returns the current request being tracked if
+ * still active, or NULL. It does not obtain a reference on the request
+ * for the caller, so the caller must hold struct_mutex.
+ */
+static inline struct drm_i915_gem_request *
+i915_gem_active_peek(const struct i915_gem_active *active, struct mutex *mutex)
+{
+       struct drm_i915_gem_request *request;
+
+       request = i915_gem_active_raw(active, mutex);
+       if (!request || i915_gem_request_completed(request))
+               return NULL;
+
+       return request;
+}
+
+/**
+ * i915_gem_active_get - return a reference to the active request
+ * @active - the active tracker
+ *
+ * i915_gem_active_get() returns a reference to the active request, or NULL
+ * if the active tracker is idle. The caller must hold struct_mutex.
+ */
+static inline struct drm_i915_gem_request *
+i915_gem_active_get(const struct i915_gem_active *active, struct mutex *mutex)
+{
+       return i915_gem_request_get(i915_gem_active_peek(active, mutex));
+}
+
+/**
+ * __i915_gem_active_get_rcu - return a reference to the active request
+ * @active - the active tracker
+ *
+ * __i915_gem_active_get() returns a reference to the active request, or NULL
+ * if the active tracker is idle. The caller must hold the RCU read lock, but
+ * the returned pointer is safe to use outside of RCU.
+ */
+static inline struct drm_i915_gem_request *
+__i915_gem_active_get_rcu(const struct i915_gem_active *active)
+{
+       /* Performing a lockless retrieval of the active request is super
+        * tricky. SLAB_DESTROY_BY_RCU merely guarantees that the backing
+        * slab of request objects will not be freed whilst we hold the
+        * RCU read lock. It does not guarantee that the request itself
+        * will not be freed and then *reused*. Viz,
+        *
+        * Thread A                     Thread B
+        *
+        * req = active.request
+        *                              retire(req) -> free(req);
+        *                              (req is now first on the slab freelist)
+        *                              active.request = NULL
+        *
+        *                              req = new submission on a new object
+        * ref(req)
+        *
+        * To prevent the request from being reused whilst the caller
+        * uses it, we take a reference like normal. Whilst acquiring
+        * the reference we check that it is not in a destroyed state
+        * (refcnt == 0). That prevents the request being reallocated
+        * whilst the caller holds on to it. To check that the request
+        * was not reallocated as we acquired the reference we have to
+        * check that our request remains the active request across
+        * the lookup, in the same manner as a seqlock. The visibility
+        * of the pointer versus the reference counting is controlled
+        * by using RCU barriers (rcu_dereference and rcu_assign_pointer).
+        *
+        * In the middle of all that, we inspect whether the request is
+        * complete. Retiring is lazy so the request may be completed long
+        * before the active tracker is updated. Querying whether the
+        * request is complete is far cheaper (as it involves no locked
+        * instructions setting cachelines to exclusive) than acquiring
+        * the reference, so we do it first. The RCU read lock ensures the
+        * pointer dereference is valid, but does not ensure that the
+        * seqno nor HWS is the right one! However, if the request was
+        * reallocated, that means the active tracker's request was complete.
+        * If the new request is also complete, then both are and we can
+        * just report the active tracker is idle. If the new request is
+        * incomplete, then we acquire a reference on it and check that
+        * it remained the active request.
+        *
+        * It is then imperative that we do not zero the request on
+        * reallocation, so that we can chase the dangling pointers!
+        * See i915_gem_request_alloc().
+        */
+       do {
+               struct drm_i915_gem_request *request;
+
+               request = rcu_dereference(active->request);
+               if (!request || i915_gem_request_completed(request))
+                       return NULL;
+
+               /* An especially silly compiler could decide to recompute the
+                * result of i915_gem_request_completed, more specifically
+                * re-emit the load for request->fence.seqno. A race would catch
+                * a later seqno value, which could flip the result from true to
+                * false. Which means part of the instructions below might not
+                * be executed, while later on instructions are executed. Due to
+                * barriers within the refcounting the inconsistency can't reach
+                * past the call to i915_gem_request_get_rcu, but not executing
+                * that while still executing i915_gem_request_put() creates
+                * havoc enough.  Prevent this with a compiler barrier.
+                */
+               barrier();
+
+               request = i915_gem_request_get_rcu(request);
+
+               /* What stops the following rcu_access_pointer() from occurring
+                * before the above i915_gem_request_get_rcu()? If we were
+                * to read the value before pausing to get the reference to
+                * the request, we may not notice a change in the active
+                * tracker.
+                *
+                * The rcu_access_pointer() is a mere compiler barrier, which
+                * means both the CPU and compiler are free to perform the
+                * memory read without constraint. The compiler only has to
+                * ensure that any operations after the rcu_access_pointer()
+                * occur afterwards in program order. This means the read may
+                * be performed earlier by an out-of-order CPU, or adventurous
+                * compiler.
+                *
+                * The atomic operation at the heart of
+                * i915_gem_request_get_rcu(), see fence_get_rcu(), is
+                * atomic_inc_not_zero() which is only a full memory barrier
+                * when successful. That is, if i915_gem_request_get_rcu()
+                * returns the request (and so with the reference counted
+                * incremented) then the following read for rcu_access_pointer()
+                * must occur after the atomic operation and so confirm
+                * that this request is the one currently being tracked.
+                *
+                * The corresponding write barrier is part of
+                * rcu_assign_pointer().
+                */
+               if (!request || request == rcu_access_pointer(active->request))
+                       return rcu_pointer_handoff(request);
+
+               i915_gem_request_put(request);
+       } while (1);
+}
+
+/**
+ * i915_gem_active_get_unlocked - return a reference to the active request
+ * @active - the active tracker
+ *
+ * i915_gem_active_get_unlocked() returns a reference to the active request,
+ * or NULL if the active tracker is idle. The reference is obtained under RCU,
+ * so no locking is required by the caller.
+ *
+ * The reference should be freed with i915_gem_request_put().
+ */
+static inline struct drm_i915_gem_request *
+i915_gem_active_get_unlocked(const struct i915_gem_active *active)
+{
+       struct drm_i915_gem_request *request;
+
+       rcu_read_lock();
+       request = __i915_gem_active_get_rcu(active);
+       rcu_read_unlock();
+
+       return request;
+}
+
+/**
+ * i915_gem_active_isset - report whether the active tracker is assigned
+ * @active - the active tracker
+ *
+ * i915_gem_active_isset() returns true if the active tracker is currently
+ * assigned to a request. Due to the lazy retiring, that request may be idle
+ * and this may report stale information.
+ */
+static inline bool
+i915_gem_active_isset(const struct i915_gem_active *active)
+{
+       return rcu_access_pointer(active->request);
+}
+
+/**
+ * i915_gem_active_is_idle - report whether the active tracker is idle
+ * @active - the active tracker
+ *
+ * i915_gem_active_is_idle() returns true if the active tracker is currently
+ * unassigned or if the request is complete (but not yet retired). Requires
+ * the caller to hold struct_mutex (but that can be relaxed if desired).
+ */
+static inline bool
+i915_gem_active_is_idle(const struct i915_gem_active *active,
+                       struct mutex *mutex)
+{
+       return !i915_gem_active_peek(active, mutex);
+}
+
+/**
+ * i915_gem_active_wait - waits until the request is completed
+ * @active - the active request on which to wait
+ *
+ * i915_gem_active_wait() waits until the request is completed before
+ * returning. Note that it does not guarantee that the request is
+ * retired first, see i915_gem_active_retire().
+ *
+ * i915_gem_active_wait() returns immediately if the active
+ * request is already complete.
+ */
+static inline int __must_check
+i915_gem_active_wait(const struct i915_gem_active *active, struct mutex *mutex)
+{
+       struct drm_i915_gem_request *request;
+
+       request = i915_gem_active_peek(active, mutex);
+       if (!request)
+               return 0;
+
+       return i915_wait_request(request,
+                                I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
+                                NULL, NULL);
+}
+
+/**
+ * i915_gem_active_wait_unlocked - waits until the request is completed
+ * @active - the active request on which to wait
+ * @flags - how to wait
+ * @timeout - how long to wait at most
+ * @rps - userspace client to charge for a waitboost
+ *
+ * i915_gem_active_wait_unlocked() waits until the request is completed before
+ * returning, without requiring any locks to be held. Note that it does not
+ * retire any requests before returning.
+ *
+ * This function relies on RCU in order to acquire the reference to the active
+ * request without holding any locks. See __i915_gem_active_get_rcu() for the
+ * glory details on how that is managed. Once the reference is acquired, we
+ * can then wait upon the request, and afterwards release our reference,
+ * free of any locking.
+ *
+ * This function wraps i915_wait_request(), see it for the full details on
+ * the arguments.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+static inline int
+i915_gem_active_wait_unlocked(const struct i915_gem_active *active,
+                             unsigned int flags,
+                             s64 *timeout,
+                             struct intel_rps_client *rps)
+{
+       struct drm_i915_gem_request *request;
+       int ret = 0;
+
+       request = i915_gem_active_get_unlocked(active);
+       if (request) {
+               ret = i915_wait_request(request, flags, timeout, rps);
+               i915_gem_request_put(request);
+       }
+
+       return ret;
+}
+
+/**
+ * i915_gem_active_retire - waits until the request is retired
+ * @active - the active request on which to wait
+ *
+ * i915_gem_active_retire() waits until the request is completed,
+ * and then ensures that at least the retirement handler for this
+ * @active tracker is called before returning. If the @active
+ * tracker is idle, the function returns immediately.
+ */
+static inline int __must_check
+i915_gem_active_retire(struct i915_gem_active *active,
+                      struct mutex *mutex)
+{
+       struct drm_i915_gem_request *request;
+       int ret;
+
+       request = i915_gem_active_raw(active, mutex);
+       if (!request)
+               return 0;
+
+       ret = i915_wait_request(request,
+                               I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
+                               NULL, NULL);
+       if (ret)
+               return ret;
+
+       list_del_init(&active->link);
+       RCU_INIT_POINTER(active->request, NULL);
+
+       active->retire(active, request);
+
+       return 0;
+}
+
+/* Convenience functions for peeking at state inside active's request whilst
+ * guarded by the struct_mutex.
+ */
+
+static inline uint32_t
+i915_gem_active_get_seqno(const struct i915_gem_active *active,
+                         struct mutex *mutex)
+{
+       return i915_gem_request_get_seqno(i915_gem_active_peek(active, mutex));
+}
+
+static inline struct intel_engine_cs *
+i915_gem_active_get_engine(const struct i915_gem_active *active,
+                          struct mutex *mutex)
+{
+       return i915_gem_request_get_engine(i915_gem_active_peek(active, mutex));
+}
+
+#define for_each_active(mask, idx) \
+       for (; mask ? idx = ffs(mask) - 1, 1 : 0; mask &= ~BIT(idx))
+
+#endif /* I915_GEM_REQUEST_H */
index 6f10b42..1c237d0 100644 (file)
@@ -48,19 +48,15 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
 #endif
 }
 
-static int num_vma_bound(struct drm_i915_gem_object *obj)
+static bool any_vma_pinned(struct drm_i915_gem_object *obj)
 {
        struct i915_vma *vma;
-       int count = 0;
 
-       list_for_each_entry(vma, &obj->vma_list, obj_link) {
-               if (drm_mm_node_allocated(&vma->node))
-                       count++;
-               if (vma->pin_count)
-                       count++;
-       }
+       list_for_each_entry(vma, &obj->vma_list, obj_link)
+               if (i915_vma_is_pinned(vma))
+                       return true;
 
-       return count;
+       return false;
 }
 
 static bool swap_available(void)
@@ -82,7 +78,10 @@ static bool can_release_pages(struct drm_i915_gem_object *obj)
         * to the GPU, simply unbinding from the GPU is not going to succeed
         * in releasing our pin count on the pages themselves.
         */
-       if (obj->pages_pin_count != num_vma_bound(obj))
+       if (obj->pages_pin_count > obj->bind_count)
+               return false;
+
+       if (any_vma_pinned(obj))
                return false;
 
        /* We can only return physical pages to the system if we can either
@@ -163,17 +162,16 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
         */
        for (phase = phases; phase->list; phase++) {
                struct list_head still_in_list;
+               struct drm_i915_gem_object *obj;
 
                if ((flags & phase->bit) == 0)
                        continue;
 
                INIT_LIST_HEAD(&still_in_list);
-               while (count < target && !list_empty(phase->list)) {
-                       struct drm_i915_gem_object *obj;
-                       struct i915_vma *vma, *v;
-
-                       obj = list_first_entry(phase->list,
-                                              typeof(*obj), global_list);
+               while (count < target &&
+                      (obj = list_first_entry_or_null(phase->list,
+                                                      typeof(*obj),
+                                                      global_list))) {
                        list_move_tail(&obj->global_list, &still_in_list);
 
                        if (flags & I915_SHRINK_PURGEABLE &&
@@ -184,24 +182,21 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
                            !is_vmalloc_addr(obj->mapping))
                                continue;
 
-                       if ((flags & I915_SHRINK_ACTIVE) == 0 && obj->active)
+                       if ((flags & I915_SHRINK_ACTIVE) == 0 &&
+                           i915_gem_object_is_active(obj))
                                continue;
 
                        if (!can_release_pages(obj))
                                continue;
 
-                       drm_gem_object_reference(&obj->base);
+                       i915_gem_object_get(obj);
 
                        /* For the unbound phase, this should be a no-op! */
-                       list_for_each_entry_safe(vma, v,
-                                                &obj->vma_list, obj_link)
-                               if (i915_vma_unbind(vma))
-                                       break;
-
+                       i915_gem_object_unbind(obj);
                        if (i915_gem_object_put_pages(obj) == 0)
                                count += obj->base.size >> PAGE_SHIFT;
 
-                       drm_gem_object_unreference(&obj->base);
+                       i915_gem_object_put(obj);
                }
                list_splice(&still_in_list, phase->list);
        }
@@ -210,6 +205,8 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
                intel_runtime_pm_put(dev_priv);
 
        i915_gem_retire_requests(dev_priv);
+       /* expedite the RCU grace period to free some request slabs */
+       synchronize_rcu_expedited();
 
        return count;
 }
@@ -230,10 +227,15 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
  */
 unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv)
 {
-       return i915_gem_shrink(dev_priv, -1UL,
-                              I915_SHRINK_BOUND |
-                              I915_SHRINK_UNBOUND |
-                              I915_SHRINK_ACTIVE);
+       unsigned long freed;
+
+       freed = i915_gem_shrink(dev_priv, -1UL,
+                               I915_SHRINK_BOUND |
+                               I915_SHRINK_UNBOUND |
+                               I915_SHRINK_ACTIVE);
+       rcu_barrier(); /* wait until our RCU delayed slab frees are completed */
+
+       return freed;
 }
 
 static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock)
@@ -242,9 +244,6 @@ static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock)
                if (!mutex_is_locked_by(&dev->struct_mutex, current))
                        return false;
 
-               if (to_i915(dev)->mm.shrinker_no_lock_stealing)
-                       return false;
-
                *unlock = false;
        } else
                *unlock = true;
@@ -273,7 +272,7 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
                        count += obj->base.size >> PAGE_SHIFT;
 
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (!obj->active && can_release_pages(obj))
+               if (!i915_gem_object_is_active(obj) && can_release_pages(obj))
                        count += obj->base.size >> PAGE_SHIFT;
        }
 
@@ -321,17 +320,22 @@ i915_gem_shrinker_lock_uninterruptible(struct drm_i915_private *dev_priv,
                                       struct shrinker_lock_uninterruptible *slu,
                                       int timeout_ms)
 {
-       unsigned long timeout = msecs_to_jiffies(timeout_ms) + 1;
+       unsigned long timeout = jiffies + msecs_to_jiffies_timeout(timeout_ms);
+
+       do {
+               if (i915_gem_wait_for_idle(dev_priv, 0) == 0 &&
+                   i915_gem_shrinker_lock(&dev_priv->drm, &slu->unlock))
+                       break;
 
-       while (!i915_gem_shrinker_lock(&dev_priv->drm, &slu->unlock)) {
                schedule_timeout_killable(1);
                if (fatal_signal_pending(current))
                        return false;
-               if (--timeout == 0) {
+
+               if (time_after(jiffies, timeout)) {
                        pr_err("Unable to lock GPU to purge memory.\n");
                        return false;
                }
-       }
+       } while (1);
 
        slu->was_interruptible = dev_priv->mm.interruptible;
        dev_priv->mm.interruptible = false;
@@ -410,7 +414,7 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr
                return NOTIFY_DONE;
 
        /* Force everything onto the inactive lists */
-       ret = i915_gem_wait_for_idle(dev_priv);
+       ret = i915_gem_wait_for_idle(dev_priv, I915_WAIT_LOCKED);
        if (ret)
                goto out;
 
index 66be299..59989e8 100644 (file)
@@ -92,6 +92,7 @@ void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv,
 static unsigned long i915_stolen_to_physical(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
        struct resource *r;
        u32 base;
@@ -111,33 +112,44 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen >= 3) {
                u32 bsm;
 
-               pci_read_config_dword(dev->pdev, INTEL_BSM, &bsm);
+               pci_read_config_dword(pdev, INTEL_BSM, &bsm);
 
                base = bsm & INTEL_BSM_MASK;
        } else if (IS_I865G(dev)) {
+               u32 tseg_size = 0;
                u16 toud = 0;
+               u8 tmp;
 
-               /*
-                * FIXME is the graphics stolen memory region
-                * always at TOUD? Ie. is it always the last
-                * one to be allocated by the BIOS?
-                */
-               pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 0),
+               pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
+                                        I845_ESMRAMC, &tmp);
+
+               if (tmp & TSEG_ENABLE) {
+                       switch (tmp & I845_TSEG_SIZE_MASK) {
+                       case I845_TSEG_SIZE_512K:
+                               tseg_size = KB(512);
+                               break;
+                       case I845_TSEG_SIZE_1M:
+                               tseg_size = MB(1);
+                               break;
+                       }
+               }
+
+               pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0),
                                         I865_TOUD, &toud);
 
-               base = toud << 16;
+               base = (toud << 16) + tseg_size;
        } else if (IS_I85X(dev)) {
                u32 tseg_size = 0;
                u32 tom;
                u8 tmp;
 
-               pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+               pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
                                         I85X_ESMRAMC, &tmp);
 
                if (tmp & TSEG_ENABLE)
                        tseg_size = MB(1);
 
-               pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 1),
+               pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 1),
                                         I85X_DRB3, &tmp);
                tom = tmp * MB(32);
 
@@ -147,7 +159,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
                u32 tom;
                u8 tmp;
 
-               pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+               pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
                                         I845_ESMRAMC, &tmp);
 
                if (tmp & TSEG_ENABLE) {
@@ -161,7 +173,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
                        }
                }
 
-               pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+               pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
                                         I830_DRB3, &tmp);
                tom = tmp * MB(32);
 
@@ -171,7 +183,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
                u32 tom;
                u8 tmp;
 
-               pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+               pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
                                         I830_ESMRAMC, &tmp);
 
                if (tmp & TSEG_ENABLE) {
@@ -181,7 +193,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
                                tseg_size = KB(512);
                }
 
-               pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+               pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
                                         I830_DRB3, &tmp);
                tom = tmp * MB(32);
 
@@ -685,7 +697,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
        if (gtt_offset == I915_GTT_OFFSET_NONE)
                return obj;
 
-       vma = i915_gem_obj_lookup_or_create_vma(obj, &ggtt->base);
+       vma = i915_gem_obj_lookup_or_create_vma(obj, &ggtt->base, NULL);
        if (IS_ERR(vma)) {
                ret = PTR_ERR(vma);
                goto err;
@@ -698,24 +710,25 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
         */
        vma->node.start = gtt_offset;
        vma->node.size = size;
-       if (drm_mm_initialized(&ggtt->base.mm)) {
-               ret = drm_mm_reserve_node(&ggtt->base.mm, &vma->node);
-               if (ret) {
-                       DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
-                       goto err;
-               }
 
-               vma->bound |= GLOBAL_BIND;
-               __i915_vma_set_map_and_fenceable(vma);
-               list_add_tail(&vma->vm_link, &ggtt->base.inactive_list);
+       ret = drm_mm_reserve_node(&ggtt->base.mm, &vma->node);
+       if (ret) {
+               DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
+               goto err;
        }
 
+       vma->pages = obj->pages;
+       vma->flags |= I915_VMA_GLOBAL_BIND;
+       __i915_vma_set_map_and_fenceable(vma);
+       list_move_tail(&vma->vm_link, &ggtt->base.inactive_list);
+       obj->bind_count++;
+
        list_add_tail(&obj->global_list, &dev_priv->mm.bound_list);
        i915_gem_object_pin_pages(obj);
 
        return obj;
 
 err:
-       drm_gem_object_unreference(&obj->base);
+       i915_gem_object_put(obj);
        return NULL;
 }
index 8030199..a14b1e3 100644 (file)
@@ -68,6 +68,9 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
        if (tiling_mode == I915_TILING_NONE)
                return true;
 
+       if (tiling_mode > I915_TILING_LAST)
+               return false;
+
        if (IS_GEN2(dev) ||
            (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
                tile_width = 128;
@@ -113,36 +116,58 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
        return true;
 }
 
-/* Is the current GTT allocation valid for the change in tiling? */
-static bool
-i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode)
+static bool i915_vma_fence_prepare(struct i915_vma *vma, int tiling_mode)
 {
+       struct drm_i915_private *dev_priv = to_i915(vma->vm->dev);
        u32 size;
 
-       if (tiling_mode == I915_TILING_NONE)
-               return true;
-
-       if (INTEL_INFO(obj->base.dev)->gen >= 4)
+       if (!i915_vma_is_map_and_fenceable(vma))
                return true;
 
-       if (IS_GEN3(obj->base.dev)) {
-               if (i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK)
+       if (INTEL_GEN(dev_priv) == 3) {
+               if (vma->node.start & ~I915_FENCE_START_MASK)
                        return false;
        } else {
-               if (i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK)
+               if (vma->node.start & ~I830_FENCE_START_MASK)
                        return false;
        }
 
-       size = i915_gem_get_gtt_size(obj->base.dev, obj->base.size, tiling_mode);
-       if (i915_gem_obj_ggtt_size(obj) != size)
+       size = i915_gem_get_ggtt_size(dev_priv, vma->size, tiling_mode);
+       if (vma->node.size < size)
                return false;
 
-       if (i915_gem_obj_ggtt_offset(obj) & (size - 1))
+       if (vma->node.start & (size - 1))
                return false;
 
        return true;
 }
 
+/* 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)
+{
+       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))
+                       continue;
+
+               ret = i915_vma_unbind(vma);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 /**
  * i915_gem_set_tiling - IOCTL handler to set tiling mode
  * @dev: DRM device
@@ -164,15 +189,18 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
        struct drm_i915_gem_set_tiling *args = data;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_i915_gem_object *obj;
-       int ret = 0;
+       int err = 0;
+
+       /* Make sure we don't cross-contaminate obj->tiling_and_stride */
+       BUILD_BUG_ON(I915_TILING_LAST & STRIDE_MASK);
 
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->handle));
-       if (&obj->base == NULL)
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj)
                return -ENOENT;
 
        if (!i915_tiling_ok(dev,
                            args->stride, obj->base.size, args->tiling_mode)) {
-               drm_gem_object_unreference_unlocked(&obj->base);
+               i915_gem_object_put_unlocked(obj);
                return -EINVAL;
        }
 
@@ -180,7 +208,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
 
        mutex_lock(&dev->struct_mutex);
        if (obj->pin_display || obj->framebuffer_references) {
-               ret = -EBUSY;
+               err = -EBUSY;
                goto err;
        }
 
@@ -213,8 +241,8 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                }
        }
 
-       if (args->tiling_mode != obj->tiling_mode ||
-           args->stride != obj->stride) {
+       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
@@ -227,34 +255,36 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                 * has to also include the unfenced register the GPU uses
                 * whilst executing a fenced command for an untiled object.
                 */
-               if (obj->map_and_fenceable &&
-                   !i915_gem_object_fence_ok(obj, args->tiling_mode))
-                       ret = i915_vma_unbind(i915_gem_obj_to_ggtt(obj));
 
-               if (ret == 0) {
+               err = i915_gem_object_fence_prepare(obj, args->tiling_mode);
+               if (!err) {
+                       struct i915_vma *vma;
+
                        if (obj->pages &&
                            obj->madv == I915_MADV_WILLNEED &&
                            dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES) {
                                if (args->tiling_mode == I915_TILING_NONE)
                                        i915_gem_object_unpin_pages(obj);
-                               if (obj->tiling_mode == I915_TILING_NONE)
+                               if (!i915_gem_object_is_tiled(obj))
                                        i915_gem_object_pin_pages(obj);
                        }
 
-                       obj->fence_dirty =
-                               obj->last_fenced_req ||
-                               obj->fence_reg != I915_FENCE_REG_NONE;
+                       list_for_each_entry(vma, &obj->vma_list, obj_link) {
+                               if (!vma->fence)
+                                       continue;
 
-                       obj->tiling_mode = args->tiling_mode;
-                       obj->stride = args->stride;
+                               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... */
-       args->stride = obj->stride;
-       args->tiling_mode = obj->tiling_mode;
+       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)) {
@@ -268,12 +298,12 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
        }
 
 err:
-       drm_gem_object_unreference(&obj->base);
+       i915_gem_object_put(obj);
        mutex_unlock(&dev->struct_mutex);
 
        intel_runtime_pm_put(dev_priv);
 
-       return ret;
+       return err;
 }
 
 /**
@@ -297,14 +327,12 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_i915_gem_object *obj;
 
-       obj = to_intel_bo(drm_gem_object_lookup(file, args->handle));
-       if (&obj->base == NULL)
+       obj = i915_gem_object_lookup(file, args->handle);
+       if (!obj)
                return -ENOENT;
 
-       mutex_lock(&dev->struct_mutex);
-
-       args->tiling_mode = obj->tiling_mode;
-       switch (obj->tiling_mode) {
+       args->tiling_mode = READ_ONCE(obj->tiling_and_stride) & TILING_MASK;
+       switch (args->tiling_mode) {
        case I915_TILING_X:
                args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
                break;
@@ -328,8 +356,6 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
        if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
                args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10;
 
-       drm_gem_object_unreference(&obj->base);
-       mutex_unlock(&dev->struct_mutex);
-
+       i915_gem_object_put_unlocked(obj);
        return 0;
 }
index 2314c88..e537930 100644 (file)
@@ -63,33 +63,12 @@ struct i915_mmu_object {
 
 static void wait_rendering(struct drm_i915_gem_object *obj)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_gem_request *requests[I915_NUM_ENGINES];
-       int i, n;
-
-       if (!obj->active)
-               return;
-
-       n = 0;
-       for (i = 0; i < I915_NUM_ENGINES; i++) {
-               struct drm_i915_gem_request *req;
-
-               req = obj->last_read_req[i];
-               if (req == NULL)
-                       continue;
-
-               requests[n++] = i915_gem_request_reference(req);
-       }
-
-       mutex_unlock(&dev->struct_mutex);
-
-       for (i = 0; i < n; i++)
-               __i915_wait_request(requests[i], false, NULL, NULL);
-
-       mutex_lock(&dev->struct_mutex);
+       unsigned long active = __I915_BO_ACTIVE(obj);
+       int idx;
 
-       for (i = 0; i < n; i++)
-               i915_gem_request_unreference(requests[i]);
+       for_each_active(active, idx)
+               i915_gem_active_wait_unlocked(&obj->last_read[idx],
+                                             0, NULL, NULL);
 }
 
 static void cancel_userptr(struct work_struct *work)
@@ -98,28 +77,19 @@ static void cancel_userptr(struct work_struct *work)
        struct drm_i915_gem_object *obj = mo->obj;
        struct drm_device *dev = obj->base.dev;
 
+       wait_rendering(obj);
+
        mutex_lock(&dev->struct_mutex);
        /* Cancel any active worker and force us to re-evaluate gup */
        obj->userptr.work = NULL;
 
        if (obj->pages != NULL) {
-               struct drm_i915_private *dev_priv = to_i915(dev);
-               struct i915_vma *vma, *tmp;
-               bool was_interruptible;
-
-               wait_rendering(obj);
-
-               was_interruptible = dev_priv->mm.interruptible;
-               dev_priv->mm.interruptible = false;
-
-               list_for_each_entry_safe(vma, tmp, &obj->vma_list, obj_link)
-                       WARN_ON(i915_vma_unbind(vma));
+               /* We are inside a kthread context and can't be interrupted */
+               WARN_ON(i915_gem_object_unbind(obj));
                WARN_ON(i915_gem_object_put_pages(obj));
-
-               dev_priv->mm.interruptible = was_interruptible;
        }
 
-       drm_gem_object_unreference(&obj->base);
+       i915_gem_object_put(obj);
        mutex_unlock(&dev->struct_mutex);
 }
 
@@ -572,12 +542,10 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
                        }
                }
                obj->userptr.work = ERR_PTR(ret);
-               if (ret)
-                       __i915_gem_userptr_set_active(obj, false);
        }
 
        obj->userptr.workers--;
-       drm_gem_object_unreference(&obj->base);
+       i915_gem_object_put(obj);
        mutex_unlock(&dev->struct_mutex);
 
        release_pages(pvec, pinned, 0);
@@ -622,8 +590,7 @@ __i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj,
        obj->userptr.work = &work->work;
        obj->userptr.workers++;
 
-       work->obj = obj;
-       drm_gem_object_reference(&obj->base);
+       work->obj = i915_gem_object_get(obj);
 
        work->task = current;
        get_task_struct(work->task);
@@ -659,15 +626,14 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
         * to the vma (discard or cloning) which should prevent the more
         * egregious cases from causing harm.
         */
-       if (IS_ERR(obj->userptr.work)) {
-               /* active flag will have been dropped already by the worker */
-               ret = PTR_ERR(obj->userptr.work);
-               obj->userptr.work = NULL;
-               return ret;
-       }
-       if (obj->userptr.work)
+
+       if (obj->userptr.work) {
                /* active flag should still be held for the pending work */
-               return -EAGAIN;
+               if (IS_ERR(obj->userptr.work))
+                       return PTR_ERR(obj->userptr.work);
+               else
+                       return -EAGAIN;
+       }
 
        /* Let the mmu-notifier know that we have begun and need cancellation */
        ret = __i915_gem_userptr_set_active(obj, true);
@@ -846,7 +812,7 @@ i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file
                ret = drm_gem_handle_create(file, &obj->base, &handle);
 
        /* drop reference from allocate - handle holds it now */
-       drm_gem_object_unreference_unlocked(&obj->base);
+       i915_gem_object_put_unlocked(obj);
        if (ret)
                return ret;
 
index 9d73d22..334f15d 100644 (file)
@@ -30,9 +30,9 @@
 #include <generated/utsrelease.h>
 #include "i915_drv.h"
 
-static const char *ring_str(int ring)
+static const char *engine_str(int engine)
 {
-       switch (ring) {
+       switch (engine) {
        case RCS: return "render";
        case VCS: return "bsd";
        case BCS: return "blt";
@@ -42,16 +42,6 @@ static const char *ring_str(int ring)
        }
 }
 
-static const char *pin_flag(int pinned)
-{
-       if (pinned > 0)
-               return " P";
-       else if (pinned < 0)
-               return " p";
-       else
-               return "";
-}
-
 static const char *tiling_flag(int tiling)
 {
        switch (tiling) {
@@ -189,7 +179,7 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
 {
        int i;
 
-       err_printf(m, "  %s [%d]:\n", name, count);
+       err_printf(m, "%s [%d]:\n", name, count);
 
        while (count--) {
                err_printf(m, "    %08x_%08x %8u %02x %02x [ ",
@@ -202,13 +192,12 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
                        err_printf(m, "%02x ", err->rseqno[i]);
 
                err_printf(m, "] %02x", err->wseqno);
-               err_puts(m, pin_flag(err->pinned));
                err_puts(m, tiling_flag(err->tiling));
                err_puts(m, dirty_flag(err->dirty));
                err_puts(m, purgeable_flag(err->purgeable));
                err_puts(m, err->userptr ? " userptr" : "");
-               err_puts(m, err->ring != -1 ? " " : "");
-               err_puts(m, ring_str(err->ring));
+               err_puts(m, err->engine != -1 ? " " : "");
+               err_puts(m, engine_str(err->engine));
                err_puts(m, i915_cache_level_str(m->i915, err->cache_level));
 
                if (err->name)
@@ -221,7 +210,7 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
        }
 }
 
-static const char *hangcheck_action_to_str(enum intel_ring_hangcheck_action a)
+static const char *hangcheck_action_to_str(enum intel_engine_hangcheck_action a)
 {
        switch (a) {
        case HANGCHECK_IDLE:
@@ -239,70 +228,74 @@ static const char *hangcheck_action_to_str(enum intel_ring_hangcheck_action a)
        return "unknown";
 }
 
-static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
-                                 struct drm_device *dev,
-                                 struct drm_i915_error_state *error,
-                                 int ring_idx)
+static void error_print_engine(struct drm_i915_error_state_buf *m,
+                              struct drm_i915_error_engine *ee)
 {
-       struct drm_i915_error_ring *ring = &error->ring[ring_idx];
-
-       if (!ring->valid)
-               return;
-
-       err_printf(m, "%s command stream:\n", ring_str(ring_idx));
-       err_printf(m, "  START: 0x%08x\n", ring->start);
-       err_printf(m, "  HEAD:  0x%08x\n", ring->head);
-       err_printf(m, "  TAIL:  0x%08x\n", ring->tail);
-       err_printf(m, "  CTL:   0x%08x\n", ring->ctl);
-       err_printf(m, "  HWS:   0x%08x\n", ring->hws);
-       err_printf(m, "  ACTHD: 0x%08x %08x\n", (u32)(ring->acthd>>32), (u32)ring->acthd);
-       err_printf(m, "  IPEIR: 0x%08x\n", ring->ipeir);
-       err_printf(m, "  IPEHR: 0x%08x\n", ring->ipehr);
-       err_printf(m, "  INSTDONE: 0x%08x\n", ring->instdone);
-       if (INTEL_INFO(dev)->gen >= 4) {
-               err_printf(m, "  BBADDR: 0x%08x %08x\n", (u32)(ring->bbaddr>>32), (u32)ring->bbaddr);
-               err_printf(m, "  BB_STATE: 0x%08x\n", ring->bbstate);
-               err_printf(m, "  INSTPS: 0x%08x\n", ring->instps);
+       err_printf(m, "%s command stream:\n", engine_str(ee->engine_id));
+       err_printf(m, "  START: 0x%08x\n", ee->start);
+       err_printf(m, "  HEAD:  0x%08x\n", ee->head);
+       err_printf(m, "  TAIL:  0x%08x\n", ee->tail);
+       err_printf(m, "  CTL:   0x%08x\n", ee->ctl);
+       err_printf(m, "  MODE:  0x%08x\n", ee->mode);
+       err_printf(m, "  HWS:   0x%08x\n", ee->hws);
+       err_printf(m, "  ACTHD: 0x%08x %08x\n",
+                  (u32)(ee->acthd>>32), (u32)ee->acthd);
+       err_printf(m, "  IPEIR: 0x%08x\n", ee->ipeir);
+       err_printf(m, "  IPEHR: 0x%08x\n", ee->ipehr);
+       err_printf(m, "  INSTDONE: 0x%08x\n", ee->instdone);
+       if (ee->batchbuffer) {
+               u64 start = ee->batchbuffer->gtt_offset;
+               u64 end = start + ee->batchbuffer->gtt_size;
+
+               err_printf(m, "  batch: [0x%08x_%08x, 0x%08x_%08x]\n",
+                          upper_32_bits(start), lower_32_bits(start),
+                          upper_32_bits(end), lower_32_bits(end));
        }
-       err_printf(m, "  INSTPM: 0x%08x\n", ring->instpm);
-       err_printf(m, "  FADDR: 0x%08x %08x\n", upper_32_bits(ring->faddr),
-                  lower_32_bits(ring->faddr));
-       if (INTEL_INFO(dev)->gen >= 6) {
-               err_printf(m, "  RC PSMI: 0x%08x\n", ring->rc_psmi);
-               err_printf(m, "  FAULT_REG: 0x%08x\n", ring->fault_reg);
+       if (INTEL_GEN(m->i915) >= 4) {
+               err_printf(m, "  BBADDR: 0x%08x_%08x\n",
+                          (u32)(ee->bbaddr>>32), (u32)ee->bbaddr);
+               err_printf(m, "  BB_STATE: 0x%08x\n", ee->bbstate);
+               err_printf(m, "  INSTPS: 0x%08x\n", ee->instps);
+       }
+       err_printf(m, "  INSTPM: 0x%08x\n", ee->instpm);
+       err_printf(m, "  FADDR: 0x%08x %08x\n", upper_32_bits(ee->faddr),
+                  lower_32_bits(ee->faddr));
+       if (INTEL_GEN(m->i915) >= 6) {
+               err_printf(m, "  RC PSMI: 0x%08x\n", ee->rc_psmi);
+               err_printf(m, "  FAULT_REG: 0x%08x\n", ee->fault_reg);
                err_printf(m, "  SYNC_0: 0x%08x [last synced 0x%08x]\n",
-                          ring->semaphore_mboxes[0],
-                          ring->semaphore_seqno[0]);
+                          ee->semaphore_mboxes[0],
+                          ee->semaphore_seqno[0]);
                err_printf(m, "  SYNC_1: 0x%08x [last synced 0x%08x]\n",
-                          ring->semaphore_mboxes[1],
-                          ring->semaphore_seqno[1]);
-               if (HAS_VEBOX(dev)) {
+                          ee->semaphore_mboxes[1],
+                          ee->semaphore_seqno[1]);
+               if (HAS_VEBOX(m->i915)) {
                        err_printf(m, "  SYNC_2: 0x%08x [last synced 0x%08x]\n",
-                                  ring->semaphore_mboxes[2],
-                                  ring->semaphore_seqno[2]);
+                                  ee->semaphore_mboxes[2],
+                                  ee->semaphore_seqno[2]);
                }
        }
-       if (USES_PPGTT(dev)) {
-               err_printf(m, "  GFX_MODE: 0x%08x\n", ring->vm_info.gfx_mode);
+       if (USES_PPGTT(m->i915)) {
+               err_printf(m, "  GFX_MODE: 0x%08x\n", ee->vm_info.gfx_mode);
 
-               if (INTEL_INFO(dev)->gen >= 8) {
+               if (INTEL_GEN(m->i915) >= 8) {
                        int i;
                        for (i = 0; i < 4; i++)
                                err_printf(m, "  PDP%d: 0x%016llx\n",
-                                          i, ring->vm_info.pdp[i]);
+                                          i, ee->vm_info.pdp[i]);
                } else {
                        err_printf(m, "  PP_DIR_BASE: 0x%08x\n",
-                                  ring->vm_info.pp_dir_base);
+                                  ee->vm_info.pp_dir_base);
                }
        }
-       err_printf(m, "  seqno: 0x%08x\n", ring->seqno);
-       err_printf(m, "  last_seqno: 0x%08x\n", ring->last_seqno);
-       err_printf(m, "  waiting: %s\n", yesno(ring->waiting));
-       err_printf(m, "  ring->head: 0x%08x\n", ring->cpu_ring_head);
-       err_printf(m, "  ring->tail: 0x%08x\n", ring->cpu_ring_tail);
+       err_printf(m, "  seqno: 0x%08x\n", ee->seqno);
+       err_printf(m, "  last_seqno: 0x%08x\n", ee->last_seqno);
+       err_printf(m, "  waiting: %s\n", yesno(ee->waiting));
+       err_printf(m, "  ring->head: 0x%08x\n", ee->cpu_ring_head);
+       err_printf(m, "  ring->tail: 0x%08x\n", ee->cpu_ring_tail);
        err_printf(m, "  hangcheck: %s [%d]\n",
-                  hangcheck_action_to_str(ring->hangcheck_action),
-                  ring->hangcheck_score);
+                  hangcheck_action_to_str(ee->hangcheck_action),
+                  ee->hangcheck_score);
 }
 
 void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
@@ -328,11 +321,22 @@ static void print_error_obj(struct drm_i915_error_state_buf *m,
        }
 }
 
+static void err_print_capabilities(struct drm_i915_error_state_buf *m,
+                                  const struct intel_device_info *info)
+{
+#define PRINT_FLAG(x)  err_printf(m, #x ": %s\n", yesno(info->x))
+#define SEP_SEMICOLON ;
+       DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_SEMICOLON);
+#undef PRINT_FLAG
+#undef SEP_SEMICOLON
+}
+
 int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                            const struct i915_error_state_file_priv *error_priv)
 {
        struct drm_device *dev = error_priv->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        struct drm_i915_error_state *error = error_priv->error;
        struct drm_i915_error_object *obj;
        int i, j, offset, elt;
@@ -347,27 +351,28 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
                   error->time.tv_usec);
        err_printf(m, "Kernel: " UTS_RELEASE "\n");
+       err_print_capabilities(m, &error->device_info);
        max_hangcheck_score = 0;
-       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
-               if (error->ring[i].hangcheck_score > max_hangcheck_score)
-                       max_hangcheck_score = error->ring[i].hangcheck_score;
+       for (i = 0; i < ARRAY_SIZE(error->engine); i++) {
+               if (error->engine[i].hangcheck_score > max_hangcheck_score)
+                       max_hangcheck_score = error->engine[i].hangcheck_score;
        }
-       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
-               if (error->ring[i].hangcheck_score == max_hangcheck_score &&
-                   error->ring[i].pid != -1) {
+       for (i = 0; i < ARRAY_SIZE(error->engine); i++) {
+               if (error->engine[i].hangcheck_score == max_hangcheck_score &&
+                   error->engine[i].pid != -1) {
                        err_printf(m, "Active process (on ring %s): %s [%d]\n",
-                                  ring_str(i),
-                                  error->ring[i].comm,
-                                  error->ring[i].pid);
+                                  engine_str(i),
+                                  error->engine[i].comm,
+                                  error->engine[i].pid);
                }
        }
        err_printf(m, "Reset count: %u\n", error->reset_count);
        err_printf(m, "Suspend count: %u\n", error->suspend_count);
-       err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device);
-       err_printf(m, "PCI Revision: 0x%02x\n", dev->pdev->revision);
+       err_printf(m, "PCI ID: 0x%04x\n", pdev->device);
+       err_printf(m, "PCI Revision: 0x%02x\n", pdev->revision);
        err_printf(m, "PCI Subsystem: %04x:%04x\n",
-                  dev->pdev->subsystem_vendor,
-                  dev->pdev->subsystem_device);
+                  pdev->subsystem_vendor,
+                  pdev->subsystem_device);
        err_printf(m, "IOMMU enabled?: %d\n", error->iommu);
 
        if (HAS_CSR(dev)) {
@@ -414,36 +419,55 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        if (IS_GEN7(dev))
                err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
 
-       for (i = 0; i < ARRAY_SIZE(error->ring); i++)
-               i915_ring_error_state(m, dev, error, i);
+       for (i = 0; i < ARRAY_SIZE(error->engine); i++) {
+               if (error->engine[i].engine_id != -1)
+                       error_print_engine(m, &error->engine[i]);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(error->active_vm); i++) {
+               char buf[128];
+               int len, first = 1;
+
+               if (!error->active_vm[i])
+                       break;
 
-       for (i = 0; i < error->vm_count; i++) {
-               err_printf(m, "vm[%d]\n", i);
+               len = scnprintf(buf, sizeof(buf), "Active (");
+               for (j = 0; j < ARRAY_SIZE(error->engine); j++) {
+                       if (error->engine[j].vm != error->active_vm[i])
+                               continue;
 
-               print_error_buffers(m, "Active",
+                       len += scnprintf(buf + len, sizeof(buf), "%s%s",
+                                        first ? "" : ", ",
+                                        dev_priv->engine[j].name);
+                       first = 0;
+               }
+               scnprintf(buf + len, sizeof(buf), ")");
+               print_error_buffers(m, buf,
                                    error->active_bo[i],
                                    error->active_bo_count[i]);
-
-               print_error_buffers(m, "Pinned",
-                                   error->pinned_bo[i],
-                                   error->pinned_bo_count[i]);
        }
 
-       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
-               obj = error->ring[i].batchbuffer;
+       print_error_buffers(m, "Pinned (global)",
+                           error->pinned_bo,
+                           error->pinned_bo_count);
+
+       for (i = 0; i < ARRAY_SIZE(error->engine); i++) {
+               struct drm_i915_error_engine *ee = &error->engine[i];
+
+               obj = ee->batchbuffer;
                if (obj) {
                        err_puts(m, dev_priv->engine[i].name);
-                       if (error->ring[i].pid != -1)
+                       if (ee->pid != -1)
                                err_printf(m, " (submitted by %s [%d])",
-                                          error->ring[i].comm,
-                                          error->ring[i].pid);
+                                          ee->comm,
+                                          ee->pid);
                        err_printf(m, " --- gtt_offset = 0x%08x %08x\n",
                                   upper_32_bits(obj->gtt_offset),
                                   lower_32_bits(obj->gtt_offset));
                        print_error_obj(m, obj);
                }
 
-               obj = error->ring[i].wa_batchbuffer;
+               obj = ee->wa_batchbuffer;
                if (obj) {
                        err_printf(m, "%s (w/a) --- gtt_offset = 0x%08x\n",
                                   dev_priv->engine[i].name,
@@ -451,38 +475,43 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                        print_error_obj(m, obj);
                }
 
-               if (error->ring[i].num_requests) {
+               if (ee->num_requests) {
                        err_printf(m, "%s --- %d requests\n",
                                   dev_priv->engine[i].name,
-                                  error->ring[i].num_requests);
-                       for (j = 0; j < error->ring[i].num_requests; j++) {
-                               err_printf(m, "  seqno 0x%08x, emitted %ld, tail 0x%08x\n",
-                                          error->ring[i].requests[j].seqno,
-                                          error->ring[i].requests[j].jiffies,
-                                          error->ring[i].requests[j].tail);
+                                  ee->num_requests);
+                       for (j = 0; j < ee->num_requests; j++) {
+                               err_printf(m, "  pid %d, seqno 0x%08x, emitted %ld, head 0x%08x, tail 0x%08x\n",
+                                          ee->requests[j].pid,
+                                          ee->requests[j].seqno,
+                                          ee->requests[j].jiffies,
+                                          ee->requests[j].head,
+                                          ee->requests[j].tail);
                        }
                }
 
-               if (error->ring[i].num_waiters) {
+               if (IS_ERR(ee->waiters)) {
+                       err_printf(m, "%s --- ? waiters [unable to acquire spinlock]\n",
+                                  dev_priv->engine[i].name);
+               } else if (ee->num_waiters) {
                        err_printf(m, "%s --- %d waiters\n",
                                   dev_priv->engine[i].name,
-                                  error->ring[i].num_waiters);
-                       for (j = 0; j < error->ring[i].num_waiters; j++) {
+                                  ee->num_waiters);
+                       for (j = 0; j < ee->num_waiters; j++) {
                                err_printf(m, " seqno 0x%08x for %s [%d]\n",
-                                          error->ring[i].waiters[j].seqno,
-                                          error->ring[i].waiters[j].comm,
-                                          error->ring[i].waiters[j].pid);
+                                          ee->waiters[j].seqno,
+                                          ee->waiters[j].comm,
+                                          ee->waiters[j].pid);
                        }
                }
 
-               if ((obj = error->ring[i].ringbuffer)) {
+               if ((obj = ee->ringbuffer)) {
                        err_printf(m, "%s --- ringbuffer = 0x%08x\n",
                                   dev_priv->engine[i].name,
                                   lower_32_bits(obj->gtt_offset));
                        print_error_obj(m, obj);
                }
 
-               if ((obj = error->ring[i].hws_page)) {
+               if ((obj = ee->hws_page)) {
                        u64 hws_offset = obj->gtt_offset;
                        u32 *hws_page = &obj->pages[0][0];
 
@@ -504,7 +533,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                        }
                }
 
-               obj = error->ring[i].wa_ctx;
+               obj = ee->wa_ctx;
                if (obj) {
                        u64 wa_ctx_offset = obj->gtt_offset;
                        u32 *wa_ctx_page = &obj->pages[0][0];
@@ -526,7 +555,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                        }
                }
 
-               if ((obj = error->ring[i].ctx)) {
+               if ((obj = ee->ctx)) {
                        err_printf(m, "%s --- HW Context = 0x%08x\n",
                                   dev_priv->engine[i].name,
                                   lower_32_bits(obj->gtt_offset));
@@ -534,7 +563,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                }
        }
 
-       if ((obj = error->semaphore_obj)) {
+       if ((obj = error->semaphore)) {
                err_printf(m, "Semaphore page = 0x%08x\n",
                           lower_32_bits(obj->gtt_offset));
                for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
@@ -611,26 +640,27 @@ static void i915_error_state_free(struct kref *error_ref)
                                                          typeof(*error), ref);
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
-               i915_error_object_free(error->ring[i].batchbuffer);
-               i915_error_object_free(error->ring[i].wa_batchbuffer);
-               i915_error_object_free(error->ring[i].ringbuffer);
-               i915_error_object_free(error->ring[i].hws_page);
-               i915_error_object_free(error->ring[i].ctx);
-               i915_error_object_free(error->ring[i].wa_ctx);
-               kfree(error->ring[i].requests);
-               kfree(error->ring[i].waiters);
+       for (i = 0; i < ARRAY_SIZE(error->engine); i++) {
+               struct drm_i915_error_engine *ee = &error->engine[i];
+
+               i915_error_object_free(ee->batchbuffer);
+               i915_error_object_free(ee->wa_batchbuffer);
+               i915_error_object_free(ee->ringbuffer);
+               i915_error_object_free(ee->hws_page);
+               i915_error_object_free(ee->ctx);
+               i915_error_object_free(ee->wa_ctx);
+
+               kfree(ee->requests);
+               if (!IS_ERR_OR_NULL(ee->waiters))
+                       kfree(ee->waiters);
        }
 
-       i915_error_object_free(error->semaphore_obj);
+       i915_error_object_free(error->semaphore);
 
-       for (i = 0; i < error->vm_count; i++)
+       for (i = 0; i < ARRAY_SIZE(error->active_bo); i++)
                kfree(error->active_bo[i]);
-
-       kfree(error->active_bo);
-       kfree(error->active_bo_count);
        kfree(error->pinned_bo);
-       kfree(error->pinned_bo_count);
+
        kfree(error->overlay);
        kfree(error->display);
        kfree(error);
@@ -638,46 +668,45 @@ static void i915_error_state_free(struct kref *error_ref)
 
 static struct drm_i915_error_object *
 i915_error_object_create(struct drm_i915_private *dev_priv,
-                        struct drm_i915_gem_object *src,
-                        struct i915_address_space *vm)
+                        struct i915_vma *vma)
 {
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
+       struct drm_i915_gem_object *src;
        struct drm_i915_error_object *dst;
-       struct i915_vma *vma = NULL;
        int num_pages;
        bool use_ggtt;
        int i = 0;
        u64 reloc_offset;
 
-       if (src == NULL || src->pages == NULL)
+       if (!vma)
+               return NULL;
+
+       src = vma->obj;
+       if (!src->pages)
                return NULL;
 
        num_pages = src->base.size >> PAGE_SHIFT;
 
        dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC);
-       if (dst == NULL)
+       if (!dst)
                return NULL;
 
-       if (i915_gem_obj_bound(src, vm))
-               dst->gtt_offset = i915_gem_obj_offset(src, vm);
-       else
-               dst->gtt_offset = -1;
+       dst->gtt_offset = vma->node.start;
+       dst->gtt_size = vma->node.size;
 
        reloc_offset = dst->gtt_offset;
-       if (i915_is_ggtt(vm))
-               vma = i915_gem_obj_to_ggtt(src);
        use_ggtt = (src->cache_level == I915_CACHE_NONE &&
-                  vma && (vma->bound & GLOBAL_BIND) &&
+                  (vma->flags & I915_VMA_GLOBAL_BIND) &&
                   reloc_offset + num_pages * PAGE_SIZE <= ggtt->mappable_end);
 
        /* Cannot access stolen address directly, try to use the aperture */
        if (src->stolen) {
                use_ggtt = true;
 
-               if (!(vma && vma->bound & GLOBAL_BIND))
+               if (!(vma->flags & I915_VMA_GLOBAL_BIND))
                        goto unwind;
 
-               reloc_offset = i915_gem_obj_ggtt_offset(src);
+               reloc_offset = vma->node.start;
                if (reloc_offset + num_pages * PAGE_SIZE > ggtt->mappable_end)
                        goto unwind;
        }
@@ -705,7 +734,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
                         * captures what the GPU read.
                         */
 
-                       s = io_mapping_map_atomic_wc(ggtt->mappable,
+                       s = io_mapping_map_atomic_wc(&ggtt->mappable,
                                                     reloc_offset);
                        memcpy_fromio(d, s, PAGE_SIZE);
                        io_mapping_unmap_atomic(s);
@@ -737,8 +766,24 @@ unwind:
        kfree(dst);
        return NULL;
 }
-#define i915_error_ggtt_object_create(dev_priv, src) \
-       i915_error_object_create((dev_priv), (src), &(dev_priv)->ggtt.base)
+
+/* The error capture is special as tries to run underneath the normal
+ * locking rules - so we use the raw version of the i915_gem_active lookup.
+ */
+static inline uint32_t
+__active_get_seqno(struct i915_gem_active *active)
+{
+       return i915_gem_request_get_seqno(__i915_gem_active_peek(active));
+}
+
+static inline int
+__active_get_engine_id(struct i915_gem_active *active)
+{
+       struct intel_engine_cs *engine;
+
+       engine = i915_gem_request_get_engine(__i915_gem_active_peek(active));
+       return engine ? engine->id : -1;
+}
 
 static void capture_bo(struct drm_i915_error_buffer *err,
                       struct i915_vma *vma)
@@ -748,32 +793,34 @@ static void capture_bo(struct drm_i915_error_buffer *err,
 
        err->size = obj->base.size;
        err->name = obj->base.name;
+
        for (i = 0; i < I915_NUM_ENGINES; i++)
-               err->rseqno[i] = i915_gem_request_get_seqno(obj->last_read_req[i]);
-       err->wseqno = i915_gem_request_get_seqno(obj->last_write_req);
+               err->rseqno[i] = __active_get_seqno(&obj->last_read[i]);
+       err->wseqno = __active_get_seqno(&obj->last_write);
+       err->engine = __active_get_engine_id(&obj->last_write);
+
        err->gtt_offset = vma->node.start;
        err->read_domains = obj->base.read_domains;
        err->write_domain = obj->base.write_domain;
-       err->fence_reg = obj->fence_reg;
-       err->pinned = 0;
-       if (i915_gem_obj_is_pinned(obj))
-               err->pinned = 1;
-       err->tiling = obj->tiling_mode;
+       err->fence_reg = vma->fence ? vma->fence->id : -1;
+       err->tiling = i915_gem_object_get_tiling(obj);
        err->dirty = obj->dirty;
        err->purgeable = obj->madv != I915_MADV_WILLNEED;
        err->userptr = obj->userptr.mm != NULL;
-       err->ring = obj->last_write_req ?
-                       i915_gem_request_get_engine(obj->last_write_req)->id : -1;
        err->cache_level = obj->cache_level;
 }
 
-static u32 capture_active_bo(struct drm_i915_error_buffer *err,
-                            int count, struct list_head *head)
+static u32 capture_error_bo(struct drm_i915_error_buffer *err,
+                           int count, struct list_head *head,
+                           bool pinned_only)
 {
        struct i915_vma *vma;
        int i = 0;
 
        list_for_each_entry(vma, head, vm_link) {
+               if (pinned_only && !i915_vma_is_pinned(vma))
+                       continue;
+
                capture_bo(err++, vma);
                if (++i == count)
                        break;
@@ -782,28 +829,6 @@ static u32 capture_active_bo(struct drm_i915_error_buffer *err,
        return i;
 }
 
-static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
-                            int count, struct list_head *head,
-                            struct i915_address_space *vm)
-{
-       struct drm_i915_gem_object *obj;
-       struct drm_i915_error_buffer * const first = err;
-       struct drm_i915_error_buffer * const last = err + count;
-
-       list_for_each_entry(obj, head, global_list) {
-               struct i915_vma *vma;
-
-               if (err == last)
-                       break;
-
-               list_for_each_entry(vma, &obj->vma_list, obj_link)
-                       if (vma->vm == vm && vma->pin_count > 0)
-                               capture_bo(err++, vma);
-       }
-
-       return err - first;
-}
-
 /* Generate a semi-unique error code. The code is not meant to have meaning, The
  * code's only purpose is to try to prevent false duplicated bug reports by
  * grossly estimating a GPU error state.
@@ -815,7 +840,7 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
  */
 static uint32_t i915_error_generate_code(struct drm_i915_private *dev_priv,
                                         struct drm_i915_error_state *error,
-                                        int *ring_id)
+                                        int *engine_id)
 {
        uint32_t error_code = 0;
        int i;
@@ -826,11 +851,11 @@ static uint32_t i915_error_generate_code(struct drm_i915_private *dev_priv,
         * strictly a client bug. Use instdone to differentiate those some.
         */
        for (i = 0; i < I915_NUM_ENGINES; i++) {
-               if (error->ring[i].hangcheck_action == HANGCHECK_HUNG) {
-                       if (ring_id)
-                               *ring_id = i;
+               if (error->engine[i].hangcheck_action == HANGCHECK_HUNG) {
+                       if (engine_id)
+                               *engine_id = i;
 
-                       return error->ring[i].ipehr ^ error->ring[i].instdone;
+                       return error->engine[i].ipehr ^ error->engine[i].instdone;
                }
        }
 
@@ -855,22 +880,17 @@ static void i915_gem_record_fences(struct drm_i915_private *dev_priv,
 }
 
 
-static void gen8_record_semaphore_state(struct drm_i915_private *dev_priv,
-                                       struct drm_i915_error_state *error,
+static void gen8_record_semaphore_state(struct drm_i915_error_state *error,
                                        struct intel_engine_cs *engine,
-                                       struct drm_i915_error_ring *ering)
+                                       struct drm_i915_error_engine *ee)
 {
+       struct drm_i915_private *dev_priv = engine->i915;
        struct intel_engine_cs *to;
        enum intel_engine_id id;
 
-       if (!i915_semaphore_is_enabled(dev_priv))
+       if (!error->semaphore)
                return;
 
-       if (!error->semaphore_obj)
-               error->semaphore_obj =
-                       i915_error_ggtt_object_create(dev_priv,
-                                                     dev_priv->semaphore_obj);
-
        for_each_engine_id(to, dev_priv, id) {
                int idx;
                u16 signal_offset;
@@ -879,44 +899,52 @@ static void gen8_record_semaphore_state(struct drm_i915_private *dev_priv,
                if (engine == to)
                        continue;
 
-               signal_offset = (GEN8_SIGNAL_OFFSET(engine, id) & (PAGE_SIZE - 1))
-                               / 4;
-               tmp = error->semaphore_obj->pages[0];
-               idx = intel_ring_sync_index(engine, to);
+               signal_offset =
+                       (GEN8_SIGNAL_OFFSET(engine, id) & (PAGE_SIZE - 1)) / 4;
+               tmp = error->semaphore->pages[0];
+               idx = intel_engine_sync_index(engine, to);
 
-               ering->semaphore_mboxes[idx] = tmp[signal_offset];
-               ering->semaphore_seqno[idx] = engine->semaphore.sync_seqno[idx];
+               ee->semaphore_mboxes[idx] = tmp[signal_offset];
+               ee->semaphore_seqno[idx] = engine->semaphore.sync_seqno[idx];
        }
 }
 
-static void gen6_record_semaphore_state(struct drm_i915_private *dev_priv,
-                                       struct intel_engine_cs *engine,
-                                       struct drm_i915_error_ring *ering)
+static void gen6_record_semaphore_state(struct intel_engine_cs *engine,
+                                       struct drm_i915_error_engine *ee)
 {
-       ering->semaphore_mboxes[0] = I915_READ(RING_SYNC_0(engine->mmio_base));
-       ering->semaphore_mboxes[1] = I915_READ(RING_SYNC_1(engine->mmio_base));
-       ering->semaphore_seqno[0] = engine->semaphore.sync_seqno[0];
-       ering->semaphore_seqno[1] = engine->semaphore.sync_seqno[1];
+       struct drm_i915_private *dev_priv = engine->i915;
+
+       ee->semaphore_mboxes[0] = I915_READ(RING_SYNC_0(engine->mmio_base));
+       ee->semaphore_mboxes[1] = I915_READ(RING_SYNC_1(engine->mmio_base));
+       ee->semaphore_seqno[0] = engine->semaphore.sync_seqno[0];
+       ee->semaphore_seqno[1] = engine->semaphore.sync_seqno[1];
 
        if (HAS_VEBOX(dev_priv)) {
-               ering->semaphore_mboxes[2] =
+               ee->semaphore_mboxes[2] =
                        I915_READ(RING_SYNC_2(engine->mmio_base));
-               ering->semaphore_seqno[2] = engine->semaphore.sync_seqno[2];
+               ee->semaphore_seqno[2] = engine->semaphore.sync_seqno[2];
        }
 }
 
-static void engine_record_waiters(struct intel_engine_cs *engine,
-                                 struct drm_i915_error_ring *ering)
+static void error_record_engine_waiters(struct intel_engine_cs *engine,
+                                       struct drm_i915_error_engine *ee)
 {
        struct intel_breadcrumbs *b = &engine->breadcrumbs;
        struct drm_i915_error_waiter *waiter;
        struct rb_node *rb;
        int count;
 
-       ering->num_waiters = 0;
-       ering->waiters = NULL;
+       ee->num_waiters = 0;
+       ee->waiters = NULL;
+
+       if (RB_EMPTY_ROOT(&b->waiters))
+               return;
+
+       if (!spin_trylock(&b->lock)) {
+               ee->waiters = ERR_PTR(-EDEADLK);
+               return;
+       }
 
-       spin_lock(&b->lock);
        count = 0;
        for (rb = rb_first(&b->waiters); rb != NULL; rb = rb_next(rb))
                count++;
@@ -930,9 +958,13 @@ static void engine_record_waiters(struct intel_engine_cs *engine,
        if (!waiter)
                return;
 
-       ering->waiters = waiter;
+       if (!spin_trylock(&b->lock)) {
+               kfree(waiter);
+               ee->waiters = ERR_PTR(-EDEADLK);
+               return;
+       }
 
-       spin_lock(&b->lock);
+       ee->waiters = waiter;
        for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
                struct intel_wait *w = container_of(rb, typeof(*w), node);
 
@@ -941,57 +973,59 @@ static void engine_record_waiters(struct intel_engine_cs *engine,
                waiter->seqno = w->seqno;
                waiter++;
 
-               if (++ering->num_waiters == count)
+               if (++ee->num_waiters == count)
                        break;
        }
        spin_unlock(&b->lock);
 }
 
-static void i915_record_ring_state(struct drm_i915_private *dev_priv,
-                                  struct drm_i915_error_state *error,
-                                  struct intel_engine_cs *engine,
-                                  struct drm_i915_error_ring *ering)
+static void error_record_engine_registers(struct drm_i915_error_state *error,
+                                         struct intel_engine_cs *engine,
+                                         struct drm_i915_error_engine *ee)
 {
+       struct drm_i915_private *dev_priv = engine->i915;
+
        if (INTEL_GEN(dev_priv) >= 6) {
-               ering->rc_psmi = I915_READ(RING_PSMI_CTL(engine->mmio_base));
-               ering->fault_reg = I915_READ(RING_FAULT_REG(engine));
+               ee->rc_psmi = I915_READ(RING_PSMI_CTL(engine->mmio_base));
+               ee->fault_reg = I915_READ(RING_FAULT_REG(engine));
                if (INTEL_GEN(dev_priv) >= 8)
-                       gen8_record_semaphore_state(dev_priv, error, engine,
-                                                   ering);
+                       gen8_record_semaphore_state(error, engine, ee);
                else
-                       gen6_record_semaphore_state(dev_priv, engine, ering);
+                       gen6_record_semaphore_state(engine, ee);
        }
 
        if (INTEL_GEN(dev_priv) >= 4) {
-               ering->faddr = I915_READ(RING_DMA_FADD(engine->mmio_base));
-               ering->ipeir = I915_READ(RING_IPEIR(engine->mmio_base));
-               ering->ipehr = I915_READ(RING_IPEHR(engine->mmio_base));
-               ering->instdone = I915_READ(RING_INSTDONE(engine->mmio_base));
-               ering->instps = I915_READ(RING_INSTPS(engine->mmio_base));
-               ering->bbaddr = I915_READ(RING_BBADDR(engine->mmio_base));
+               ee->faddr = I915_READ(RING_DMA_FADD(engine->mmio_base));
+               ee->ipeir = I915_READ(RING_IPEIR(engine->mmio_base));
+               ee->ipehr = I915_READ(RING_IPEHR(engine->mmio_base));
+               ee->instdone = I915_READ(RING_INSTDONE(engine->mmio_base));
+               ee->instps = I915_READ(RING_INSTPS(engine->mmio_base));
+               ee->bbaddr = I915_READ(RING_BBADDR(engine->mmio_base));
                if (INTEL_GEN(dev_priv) >= 8) {
-                       ering->faddr |= (u64) I915_READ(RING_DMA_FADD_UDW(engine->mmio_base)) << 32;
-                       ering->bbaddr |= (u64) I915_READ(RING_BBADDR_UDW(engine->mmio_base)) << 32;
+                       ee->faddr |= (u64) I915_READ(RING_DMA_FADD_UDW(engine->mmio_base)) << 32;
+                       ee->bbaddr |= (u64) I915_READ(RING_BBADDR_UDW(engine->mmio_base)) << 32;
                }
-               ering->bbstate = I915_READ(RING_BBSTATE(engine->mmio_base));
+               ee->bbstate = I915_READ(RING_BBSTATE(engine->mmio_base));
        } else {
-               ering->faddr = I915_READ(DMA_FADD_I8XX);
-               ering->ipeir = I915_READ(IPEIR);
-               ering->ipehr = I915_READ(IPEHR);
-               ering->instdone = I915_READ(GEN2_INSTDONE);
+               ee->faddr = I915_READ(DMA_FADD_I8XX);
+               ee->ipeir = I915_READ(IPEIR);
+               ee->ipehr = I915_READ(IPEHR);
+               ee->instdone = I915_READ(GEN2_INSTDONE);
        }
 
-       ering->waiting = intel_engine_has_waiter(engine);
-       ering->instpm = I915_READ(RING_INSTPM(engine->mmio_base));
-       ering->acthd = intel_ring_get_active_head(engine);
-       ering->seqno = intel_engine_get_seqno(engine);
-       ering->last_seqno = engine->last_submitted_seqno;
-       ering->start = I915_READ_START(engine);
-       ering->head = I915_READ_HEAD(engine);
-       ering->tail = I915_READ_TAIL(engine);
-       ering->ctl = I915_READ_CTL(engine);
-
-       if (I915_NEED_GFX_HWS(dev_priv)) {
+       ee->waiting = intel_engine_has_waiter(engine);
+       ee->instpm = I915_READ(RING_INSTPM(engine->mmio_base));
+       ee->acthd = intel_engine_get_active_head(engine);
+       ee->seqno = intel_engine_get_seqno(engine);
+       ee->last_seqno = engine->last_submitted_seqno;
+       ee->start = I915_READ_START(engine);
+       ee->head = I915_READ_HEAD(engine);
+       ee->tail = I915_READ_TAIL(engine);
+       ee->ctl = I915_READ_CTL(engine);
+       if (INTEL_GEN(dev_priv) > 2)
+               ee->mode = I915_READ_MODE(engine);
+
+       if (!HWS_NEEDS_PHYSICAL(dev_priv)) {
                i915_reg_t mmio;
 
                if (IS_GEN7(dev_priv)) {
@@ -1017,107 +1051,150 @@ static void i915_record_ring_state(struct drm_i915_private *dev_priv,
                        mmio = RING_HWS_PGA(engine->mmio_base);
                }
 
-               ering->hws = I915_READ(mmio);
+               ee->hws = I915_READ(mmio);
        }
 
-       ering->hangcheck_score = engine->hangcheck.score;
-       ering->hangcheck_action = engine->hangcheck.action;
+       ee->hangcheck_score = engine->hangcheck.score;
+       ee->hangcheck_action = engine->hangcheck.action;
 
        if (USES_PPGTT(dev_priv)) {
                int i;
 
-               ering->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(engine));
+               ee->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(engine));
 
                if (IS_GEN6(dev_priv))
-                       ering->vm_info.pp_dir_base =
+                       ee->vm_info.pp_dir_base =
                                I915_READ(RING_PP_DIR_BASE_READ(engine));
                else if (IS_GEN7(dev_priv))
-                       ering->vm_info.pp_dir_base =
+                       ee->vm_info.pp_dir_base =
                                I915_READ(RING_PP_DIR_BASE(engine));
                else if (INTEL_GEN(dev_priv) >= 8)
                        for (i = 0; i < 4; i++) {
-                               ering->vm_info.pdp[i] =
+                               ee->vm_info.pdp[i] =
                                        I915_READ(GEN8_RING_PDP_UDW(engine, i));
-                               ering->vm_info.pdp[i] <<= 32;
-                               ering->vm_info.pdp[i] |=
+                               ee->vm_info.pdp[i] <<= 32;
+                               ee->vm_info.pdp[i] |=
                                        I915_READ(GEN8_RING_PDP_LDW(engine, i));
                        }
        }
 }
 
-
-static void i915_gem_record_active_context(struct intel_engine_cs *engine,
-                                          struct drm_i915_error_state *error,
-                                          struct drm_i915_error_ring *ering)
+static void engine_record_requests(struct intel_engine_cs *engine,
+                                  struct drm_i915_gem_request *first,
+                                  struct drm_i915_error_engine *ee)
 {
-       struct drm_i915_private *dev_priv = engine->i915;
-       struct drm_i915_gem_object *obj;
+       struct drm_i915_gem_request *request;
+       int count;
 
-       /* Currently render ring is the only HW context user */
-       if (engine->id != RCS || !error->ccid)
+       count = 0;
+       request = first;
+       list_for_each_entry_from(request, &engine->request_list, link)
+               count++;
+       if (!count)
                return;
 
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (!i915_gem_obj_ggtt_bound(obj))
-                       continue;
+       ee->requests = kcalloc(count, sizeof(*ee->requests), GFP_ATOMIC);
+       if (!ee->requests)
+               return;
 
-               if ((error->ccid & PAGE_MASK) == i915_gem_obj_ggtt_offset(obj)) {
-                       ering->ctx = i915_error_ggtt_object_create(dev_priv, obj);
+       ee->num_requests = count;
+
+       count = 0;
+       request = first;
+       list_for_each_entry_from(request, &engine->request_list, link) {
+               struct drm_i915_error_request *erq;
+
+               if (count >= ee->num_requests) {
+                       /*
+                        * If the ring request list was changed in
+                        * between the point where the error request
+                        * list was created and dimensioned and this
+                        * point then just exit early to avoid crashes.
+                        *
+                        * We don't need to communicate that the
+                        * request list changed state during error
+                        * state capture and that the error state is
+                        * slightly incorrect as a consequence since we
+                        * are typically only interested in the request
+                        * list state at the point of error state
+                        * capture, not in any changes happening during
+                        * the capture.
+                        */
                        break;
                }
+
+               erq = &ee->requests[count++];
+               erq->seqno = request->fence.seqno;
+               erq->jiffies = request->emitted_jiffies;
+               erq->head = request->head;
+               erq->tail = request->tail;
+
+               rcu_read_lock();
+               erq->pid = request->ctx->pid ? pid_nr(request->ctx->pid) : 0;
+               rcu_read_unlock();
        }
+       ee->num_requests = count;
 }
 
 static void i915_gem_record_rings(struct drm_i915_private *dev_priv,
                                  struct drm_i915_error_state *error)
 {
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       struct drm_i915_gem_request *request;
-       int i, count;
+       int i;
+
+       error->semaphore =
+               i915_error_object_create(dev_priv, dev_priv->semaphore);
 
        for (i = 0; i < I915_NUM_ENGINES; i++) {
                struct intel_engine_cs *engine = &dev_priv->engine[i];
+               struct drm_i915_error_engine *ee = &error->engine[i];
+               struct drm_i915_gem_request *request;
 
-               error->ring[i].pid = -1;
+               ee->pid = -1;
+               ee->engine_id = -1;
 
                if (!intel_engine_initialized(engine))
                        continue;
 
-               error->ring[i].valid = true;
+               ee->engine_id = i;
 
-               i915_record_ring_state(dev_priv, error, engine, &error->ring[i]);
-               engine_record_waiters(engine, &error->ring[i]);
+               error_record_engine_registers(error, engine, ee);
+               error_record_engine_waiters(engine, ee);
 
                request = i915_gem_find_active_request(engine);
                if (request) {
-                       struct i915_address_space *vm;
-                       struct intel_ringbuffer *rb;
+                       struct intel_ring *ring;
+                       struct pid *pid;
 
-                       vm = request->ctx->ppgtt ?
+                       ee->vm = request->ctx->ppgtt ?
                                &request->ctx->ppgtt->base : &ggtt->base;
 
                        /* We need to copy these to an anonymous buffer
                         * as the simplest method to avoid being overwritten
                         * by userspace.
                         */
-                       error->ring[i].batchbuffer =
+                       ee->batchbuffer =
                                i915_error_object_create(dev_priv,
-                                                        request->batch_obj,
-                                                        vm);
+                                                        request->batch);
 
                        if (HAS_BROKEN_CS_TLB(dev_priv))
-                               error->ring[i].wa_batchbuffer =
-                                       i915_error_ggtt_object_create(dev_priv,
-                                                            engine->scratch.obj);
+                               ee->wa_batchbuffer =
+                                       i915_error_object_create(dev_priv,
+                                                                engine->scratch);
+
+                       ee->ctx =
+                               i915_error_object_create(dev_priv,
+                                                        request->ctx->engine[i].state);
 
-                       if (request->pid) {
+                       pid = request->ctx->pid;
+                       if (pid) {
                                struct task_struct *task;
 
                                rcu_read_lock();
-                               task = pid_task(request->pid, PIDTYPE_PID);
+                               task = pid_task(pid, PIDTYPE_PID);
                                if (task) {
-                                       strcpy(error->ring[i].comm, task->comm);
-                                       error->ring[i].pid = task->pid;
+                                       strcpy(ee->comm, task->comm);
+                                       ee->pid = task->pid;
                                }
                                rcu_read_unlock();
                        }
@@ -1125,153 +1202,106 @@ static void i915_gem_record_rings(struct drm_i915_private *dev_priv,
                        error->simulated |=
                                request->ctx->flags & CONTEXT_NO_ERROR_CAPTURE;
 
-                       rb = request->ringbuf;
-                       error->ring[i].cpu_ring_head = rb->head;
-                       error->ring[i].cpu_ring_tail = rb->tail;
-                       error->ring[i].ringbuffer =
-                               i915_error_ggtt_object_create(dev_priv,
-                                                             rb->obj);
-               }
-
-               error->ring[i].hws_page =
-                       i915_error_ggtt_object_create(dev_priv,
-                                                     engine->status_page.obj);
+                       ring = request->ring;
+                       ee->cpu_ring_head = ring->head;
+                       ee->cpu_ring_tail = ring->tail;
+                       ee->ringbuffer =
+                               i915_error_object_create(dev_priv, ring->vma);
 
-               if (engine->wa_ctx.obj) {
-                       error->ring[i].wa_ctx =
-                               i915_error_ggtt_object_create(dev_priv,
-                                                             engine->wa_ctx.obj);
+                       engine_record_requests(engine, request, ee);
                }
 
-               i915_gem_record_active_context(engine, error, &error->ring[i]);
-
-               count = 0;
-               list_for_each_entry(request, &engine->request_list, list)
-                       count++;
-
-               error->ring[i].num_requests = count;
-               error->ring[i].requests =
-                       kcalloc(count, sizeof(*error->ring[i].requests),
-                               GFP_ATOMIC);
-               if (error->ring[i].requests == NULL) {
-                       error->ring[i].num_requests = 0;
-                       continue;
-               }
-
-               count = 0;
-               list_for_each_entry(request, &engine->request_list, list) {
-                       struct drm_i915_error_request *erq;
-
-                       if (count >= error->ring[i].num_requests) {
-                               /*
-                                * If the ring request list was changed in
-                                * between the point where the error request
-                                * list was created and dimensioned and this
-                                * point then just exit early to avoid crashes.
-                                *
-                                * We don't need to communicate that the
-                                * request list changed state during error
-                                * state capture and that the error state is
-                                * slightly incorrect as a consequence since we
-                                * are typically only interested in the request
-                                * list state at the point of error state
-                                * capture, not in any changes happening during
-                                * the capture.
-                                */
-                               break;
-                       }
+               ee->hws_page =
+                       i915_error_object_create(dev_priv,
+                                                engine->status_page.vma);
 
-                       erq = &error->ring[i].requests[count++];
-                       erq->seqno = request->seqno;
-                       erq->jiffies = request->emitted_jiffies;
-                       erq->tail = request->postfix;
-               }
+               ee->wa_ctx =
+                       i915_error_object_create(dev_priv, engine->wa_ctx.vma);
        }
 }
 
-/* FIXME: Since pin count/bound list is global, we duplicate what we capture per
- * VM.
- */
 static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
                                struct drm_i915_error_state *error,
                                struct i915_address_space *vm,
-                               const int ndx)
+                               int idx)
 {
-       struct drm_i915_error_buffer *active_bo = NULL, *pinned_bo = NULL;
-       struct drm_i915_gem_object *obj;
+       struct drm_i915_error_buffer *active_bo;
        struct i915_vma *vma;
-       int i;
+       int count;
 
-       i = 0;
+       count = 0;
        list_for_each_entry(vma, &vm->active_list, vm_link)
-               i++;
-       error->active_bo_count[ndx] = i;
-
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               list_for_each_entry(vma, &obj->vma_list, obj_link)
-                       if (vma->vm == vm && vma->pin_count > 0)
-                               i++;
-       }
-       error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx];
-
-       if (i) {
-               active_bo = kcalloc(i, sizeof(*active_bo), GFP_ATOMIC);
-               if (active_bo)
-                       pinned_bo = active_bo + error->active_bo_count[ndx];
-       }
+               count++;
 
+       active_bo = NULL;
+       if (count)
+               active_bo = kcalloc(count, sizeof(*active_bo), GFP_ATOMIC);
        if (active_bo)
-               error->active_bo_count[ndx] =
-                       capture_active_bo(active_bo,
-                                         error->active_bo_count[ndx],
-                                         &vm->active_list);
-
-       if (pinned_bo)
-               error->pinned_bo_count[ndx] =
-                       capture_pinned_bo(pinned_bo,
-                                         error->pinned_bo_count[ndx],
-                                         &dev_priv->mm.bound_list, vm);
-       error->active_bo[ndx] = active_bo;
-       error->pinned_bo[ndx] = pinned_bo;
+               count = capture_error_bo(active_bo, count, &vm->active_list, false);
+       else
+               count = 0;
+
+       error->active_vm[idx] = vm;
+       error->active_bo[idx] = active_bo;
+       error->active_bo_count[idx] = count;
 }
 
-static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
-                                    struct drm_i915_error_state *error)
+static void i915_capture_active_buffers(struct drm_i915_private *dev_priv,
+                                       struct drm_i915_error_state *error)
 {
-       struct i915_address_space *vm;
-       int cnt = 0, i = 0;
-
-       list_for_each_entry(vm, &dev_priv->vm_list, global_link)
-               cnt++;
-
-       error->active_bo = kcalloc(cnt, sizeof(*error->active_bo), GFP_ATOMIC);
-       error->pinned_bo = kcalloc(cnt, sizeof(*error->pinned_bo), GFP_ATOMIC);
-       error->active_bo_count = kcalloc(cnt, sizeof(*error->active_bo_count),
-                                        GFP_ATOMIC);
-       error->pinned_bo_count = kcalloc(cnt, sizeof(*error->pinned_bo_count),
-                                        GFP_ATOMIC);
-
-       if (error->active_bo == NULL ||
-           error->pinned_bo == NULL ||
-           error->active_bo_count == NULL ||
-           error->pinned_bo_count == NULL) {
-               kfree(error->active_bo);
-               kfree(error->active_bo_count);
-               kfree(error->pinned_bo);
-               kfree(error->pinned_bo_count);
-
-               error->active_bo = NULL;
-               error->active_bo_count = NULL;
-               error->pinned_bo = NULL;
-               error->pinned_bo_count = NULL;
-       } else {
-               list_for_each_entry(vm, &dev_priv->vm_list, global_link)
-                       i915_gem_capture_vm(dev_priv, error, vm, i++);
+       int cnt = 0, i, j;
 
-               error->vm_count = cnt;
+       BUILD_BUG_ON(ARRAY_SIZE(error->engine) > ARRAY_SIZE(error->active_bo));
+       BUILD_BUG_ON(ARRAY_SIZE(error->active_bo) != ARRAY_SIZE(error->active_vm));
+       BUILD_BUG_ON(ARRAY_SIZE(error->active_bo) != ARRAY_SIZE(error->active_bo_count));
+
+       /* Scan each engine looking for unique active contexts/vm */
+       for (i = 0; i < ARRAY_SIZE(error->engine); i++) {
+               struct drm_i915_error_engine *ee = &error->engine[i];
+               bool found;
+
+               if (!ee->vm)
+                       continue;
+
+               found = false;
+               for (j = 0; j < i && !found; j++)
+                       found = error->engine[j].vm == ee->vm;
+               if (!found)
+                       i915_gem_capture_vm(dev_priv, error, ee->vm, cnt++);
        }
 }
 
+static void i915_capture_pinned_buffers(struct drm_i915_private *dev_priv,
+                                       struct drm_i915_error_state *error)
+{
+       struct i915_address_space *vm = &dev_priv->ggtt.base;
+       struct drm_i915_error_buffer *bo;
+       struct i915_vma *vma;
+       int count_inactive, count_active;
+
+       count_inactive = 0;
+       list_for_each_entry(vma, &vm->active_list, vm_link)
+               count_inactive++;
+
+       count_active = 0;
+       list_for_each_entry(vma, &vm->inactive_list, vm_link)
+               count_active++;
+
+       bo = NULL;
+       if (count_inactive + count_active)
+               bo = kcalloc(count_inactive + count_active,
+                            sizeof(*bo), GFP_ATOMIC);
+       if (!bo)
+               return;
+
+       count_inactive = capture_error_bo(bo, count_inactive,
+                                         &vm->active_list, true);
+       count_active = capture_error_bo(bo + count_inactive, count_active,
+                                       &vm->inactive_list, true);
+       error->pinned_bo_count = count_inactive + count_active;
+       error->pinned_bo = bo;
+}
+
 /* Capture all registers which don't fit into another category. */
 static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
                                   struct drm_i915_error_state *error)
@@ -1352,20 +1382,20 @@ static void i915_error_capture_msg(struct drm_i915_private *dev_priv,
                                   const char *error_msg)
 {
        u32 ecode;
-       int ring_id = -1, len;
+       int engine_id = -1, len;
 
-       ecode = i915_error_generate_code(dev_priv, error, &ring_id);
+       ecode = i915_error_generate_code(dev_priv, error, &engine_id);
 
        len = scnprintf(error->error_msg, sizeof(error->error_msg),
                        "GPU HANG: ecode %d:%d:0x%08x",
-                       INTEL_GEN(dev_priv), ring_id, ecode);
+                       INTEL_GEN(dev_priv), engine_id, ecode);
 
-       if (ring_id != -1 && error->ring[ring_id].pid != -1)
+       if (engine_id != -1 && error->engine[engine_id].pid != -1)
                len += scnprintf(error->error_msg + len,
                                 sizeof(error->error_msg) - len,
                                 ", in %s [%d]",
-                                error->ring[ring_id].comm,
-                                error->ring[ring_id].pid);
+                                error->engine[engine_id].comm,
+                                error->engine[engine_id].pid);
 
        scnprintf(error->error_msg + len, sizeof(error->error_msg) - len,
                  ", reason: %s, action: %s",
@@ -1382,6 +1412,10 @@ static void i915_capture_gen_state(struct drm_i915_private *dev_priv,
 #endif
        error->reset_count = i915_reset_count(&dev_priv->gpu_error);
        error->suspend_count = dev_priv->suspend_count;
+
+       memcpy(&error->device_info,
+              INTEL_INFO(dev_priv),
+              sizeof(error->device_info));
 }
 
 /**
@@ -1415,9 +1449,10 @@ void i915_capture_error_state(struct drm_i915_private *dev_priv,
 
        i915_capture_gen_state(dev_priv, error);
        i915_capture_reg_state(dev_priv, error);
-       i915_gem_capture_buffers(dev_priv, error);
        i915_gem_record_fences(dev_priv, error);
        i915_gem_record_rings(dev_priv, error);
+       i915_capture_active_buffers(dev_priv, error);
+       i915_capture_pinned_buffers(dev_priv, error);
 
        do_gettimeofday(&error->time);
 
index cf5a65b..a47e1e4 100644 (file)
 #define HOST2GUC_INTERRUPT             _MMIO(0xc4c8)
 #define   HOST2GUC_TRIGGER               (1<<0)
 
-#define DRBMISC1                       0x1984
-#define   DOORBELL_ENABLE                (1<<0)
-
 #define GEN8_DRBREGL(x)                        _MMIO(0x1000 + (x) * 8)
 #define   GEN8_DRB_VALID                 (1<<0)
 #define GEN8_DRBREGU(x)                        _MMIO(0x1000 + (x) * 8 + 4)
index 2112e02..3106dcc 100644 (file)
@@ -59,7 +59,7 @@
  * WQ_TYPE_INORDER is needed to support legacy submission via GuC, which
  * represents in-order queue. The kernel driver packs ring tail pointer and an
  * ELSP context descriptor dword into Work Item.
- * See guc_add_workqueue_item()
+ * See guc_wq_item_append()
  *
  */
 
@@ -114,10 +114,8 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
                if (ret != -ETIMEDOUT)
                        ret = -EIO;
 
-               DRM_ERROR("GUC: host2guc action 0x%X failed. ret=%d "
-                               "status=0x%08X response=0x%08X\n",
-                               data[0], ret, status,
-                               I915_READ(SOFT_SCRATCH(15)));
+               DRM_WARN("Action 0x%X failed; ret=%d status=0x%08X response=0x%08X\n",
+                        data[0], ret, status, I915_READ(SOFT_SCRATCH(15)));
 
                dev_priv->guc.action_fail += 1;
                dev_priv->guc.action_err = ret;
@@ -183,7 +181,7 @@ static int guc_update_doorbell_id(struct intel_guc *guc,
                                  struct i915_guc_client *client,
                                  u16 new_id)
 {
-       struct sg_table *sg = guc->ctx_pool_obj->pages;
+       struct sg_table *sg = guc->ctx_pool_vma->pages;
        void *doorbell_bitmap = guc->doorbell_bitmap;
        struct guc_doorbell_info *doorbell;
        struct guc_context_desc desc;
@@ -290,7 +288,7 @@ static uint32_t select_doorbell_cacheline(struct intel_guc *guc)
 /*
  * Initialise the process descriptor shared with the GuC firmware.
  */
-static void guc_init_proc_desc(struct intel_guc *guc,
+static void guc_proc_desc_init(struct intel_guc *guc,
                               struct i915_guc_client *client)
 {
        struct guc_process_desc *desc;
@@ -322,15 +320,15 @@ static void guc_init_proc_desc(struct intel_guc *guc,
  * write queue, etc).
  */
 
-static void guc_init_ctx_desc(struct intel_guc *guc,
+static void guc_ctx_desc_init(struct intel_guc *guc,
                              struct i915_guc_client *client)
 {
-       struct drm_i915_gem_object *client_obj = client->client_obj;
        struct drm_i915_private *dev_priv = guc_to_i915(guc);
        struct intel_engine_cs *engine;
        struct i915_gem_context *ctx = client->owner;
        struct guc_context_desc desc;
        struct sg_table *sg;
+       unsigned int tmp;
        u32 gfx_addr;
 
        memset(&desc, 0, sizeof(desc));
@@ -340,10 +338,10 @@ static void guc_init_ctx_desc(struct intel_guc *guc,
        desc.priority = client->priority;
        desc.db_id = client->doorbell_id;
 
-       for_each_engine(engine, dev_priv) {
+       for_each_engine_masked(engine, dev_priv, client->engines, tmp) {
                struct intel_context *ce = &ctx->engine[engine->id];
-               struct guc_execlist_context *lrc = &desc.lrc[engine->guc_id];
-               struct drm_i915_gem_object *obj;
+               uint32_t guc_engine_id = engine->guc_id;
+               struct guc_execlist_context *lrc = &desc.lrc[guc_engine_id];
 
                /* TODO: We have a design issue to be solved here. Only when we
                 * receive the first batch, we know which engine is used by the
@@ -358,30 +356,29 @@ static void guc_init_ctx_desc(struct intel_guc *guc,
                lrc->context_desc = lower_32_bits(ce->lrc_desc);
 
                /* The state page is after PPHWSP */
-               gfx_addr = i915_gem_obj_ggtt_offset(ce->state);
-               lrc->ring_lcra = gfx_addr + LRC_STATE_PN * PAGE_SIZE;
+               lrc->ring_lcra =
+                       i915_ggtt_offset(ce->state) + LRC_STATE_PN * PAGE_SIZE;
                lrc->context_id = (client->ctx_index << GUC_ELC_CTXID_OFFSET) |
-                               (engine->guc_id << GUC_ELC_ENGINE_OFFSET);
-
-               obj = ce->ringbuf->obj;
-               gfx_addr = i915_gem_obj_ggtt_offset(obj);
+                               (guc_engine_id << GUC_ELC_ENGINE_OFFSET);
 
-               lrc->ring_begin = gfx_addr;
-               lrc->ring_end = gfx_addr + obj->base.size - 1;
-               lrc->ring_next_free_location = gfx_addr;
+               lrc->ring_begin = i915_ggtt_offset(ce->ring->vma);
+               lrc->ring_end = lrc->ring_begin + ce->ring->size - 1;
+               lrc->ring_next_free_location = lrc->ring_begin;
                lrc->ring_current_tail_pointer_value = 0;
 
-               desc.engines_used |= (1 << engine->guc_id);
+               desc.engines_used |= (1 << guc_engine_id);
        }
 
+       DRM_DEBUG_DRIVER("Host engines 0x%x => GuC engines used 0x%x\n",
+                       client->engines, desc.engines_used);
        WARN_ON(desc.engines_used == 0);
 
        /*
         * The doorbell, process descriptor, and workqueue are all parts
         * of the client object, which the GuC will reference via the GGTT
         */
-       gfx_addr = i915_gem_obj_ggtt_offset(client_obj);
-       desc.db_trigger_phy = sg_dma_address(client_obj->pages->sgl) +
+       gfx_addr = i915_ggtt_offset(client->vma);
+       desc.db_trigger_phy = sg_dma_address(client->vma->pages->sgl) +
                                client->doorbell_offset;
        desc.db_trigger_cpu = (uintptr_t)client->client_base +
                                client->doorbell_offset;
@@ -397,12 +394,12 @@ static void guc_init_ctx_desc(struct intel_guc *guc,
        desc.desc_private = (uintptr_t)client;
 
        /* Pool context is pinned already */
-       sg = guc->ctx_pool_obj->pages;
+       sg = guc->ctx_pool_vma->pages;
        sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
                             sizeof(desc) * client->ctx_index);
 }
 
-static void guc_fini_ctx_desc(struct intel_guc *guc,
+static void guc_ctx_desc_fini(struct intel_guc *guc,
                              struct i915_guc_client *client)
 {
        struct guc_context_desc desc;
@@ -410,13 +407,13 @@ static void guc_fini_ctx_desc(struct intel_guc *guc,
 
        memset(&desc, 0, sizeof(desc));
 
-       sg = guc->ctx_pool_obj->pages;
+       sg = guc->ctx_pool_vma->pages;
        sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
                             sizeof(desc) * client->ctx_index);
 }
 
 /**
- * i915_guc_wq_check_space() - check that the GuC can accept a request
+ * i915_guc_wq_reserve() - reserve space in the GuC's workqueue
  * @request:   request associated with the commands
  *
  * Return:     0 if space is available
@@ -424,39 +421,56 @@ static void guc_fini_ctx_desc(struct intel_guc *guc,
  *
  * This function must be called (and must return 0) before a request
  * is submitted to the GuC via i915_guc_submit() below. Once a result
- * of 0 has been returned, it remains valid until (but only until)
- * the next call to submit().
+ * of 0 has been returned, it must be balanced by a corresponding
+ * call to submit().
  *
- * This precheck allows the caller to determine in advance that space
+ * Reservation allows the caller to determine in advance that space
  * will be available for the next submission before committing resources
  * to it, and helps avoid late failures with complicated recovery paths.
  */
-int i915_guc_wq_check_space(struct drm_i915_gem_request *request)
+int i915_guc_wq_reserve(struct drm_i915_gem_request *request)
 {
        const size_t wqi_size = sizeof(struct guc_wq_item);
        struct i915_guc_client *gc = request->i915->guc.execbuf_client;
-       struct guc_process_desc *desc;
+       struct guc_process_desc *desc = gc->client_base + gc->proc_desc_offset;
        u32 freespace;
+       int ret;
 
-       GEM_BUG_ON(gc == NULL);
+       spin_lock(&gc->wq_lock);
+       freespace = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size);
+       freespace -= gc->wq_rsvd;
+       if (likely(freespace >= wqi_size)) {
+               gc->wq_rsvd += wqi_size;
+               ret = 0;
+       } else {
+               gc->no_wq_space++;
+               ret = -EAGAIN;
+       }
+       spin_unlock(&gc->wq_lock);
 
-       desc = gc->client_base + gc->proc_desc_offset;
+       return ret;
+}
 
-       freespace = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size);
-       if (likely(freespace >= wqi_size))
-               return 0;
+void i915_guc_wq_unreserve(struct drm_i915_gem_request *request)
+{
+       const size_t wqi_size = sizeof(struct guc_wq_item);
+       struct i915_guc_client *gc = request->i915->guc.execbuf_client;
 
-       gc->no_wq_space += 1;
+       GEM_BUG_ON(READ_ONCE(gc->wq_rsvd) < wqi_size);
 
-       return -EAGAIN;
+       spin_lock(&gc->wq_lock);
+       gc->wq_rsvd -= wqi_size;
+       spin_unlock(&gc->wq_lock);
 }
 
-static void guc_add_workqueue_item(struct i915_guc_client *gc,
-                                  struct drm_i915_gem_request *rq)
+/* Construct a Work Item and append it to the GuC's Work Queue */
+static void guc_wq_item_append(struct i915_guc_client *gc,
+                              struct drm_i915_gem_request *rq)
 {
        /* wqi_len is in DWords, and does not include the one-word header */
        const size_t wqi_size = sizeof(struct guc_wq_item);
        const u32 wqi_len = wqi_size/sizeof(u32) - 1;
+       struct intel_engine_cs *engine = rq->engine;
        struct guc_process_desc *desc;
        struct guc_wq_item *wqi;
        void *base;
@@ -464,7 +478,7 @@ static void guc_add_workqueue_item(struct i915_guc_client *gc,
 
        desc = gc->client_base + gc->proc_desc_offset;
 
-       /* Free space is guaranteed, see i915_guc_wq_check_space() above */
+       /* Free space is guaranteed, see i915_guc_wq_reserve() above */
        freespace = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size);
        GEM_BUG_ON(freespace < wqi_size);
 
@@ -482,31 +496,32 @@ static void guc_add_workqueue_item(struct i915_guc_client *gc,
         * workqueue buffer dw by dw.
         */
        BUILD_BUG_ON(wqi_size != 16);
+       GEM_BUG_ON(gc->wq_rsvd < wqi_size);
 
        /* postincrement WQ tail for next time */
        wq_off = gc->wq_tail;
+       GEM_BUG_ON(wq_off & (wqi_size - 1));
        gc->wq_tail += wqi_size;
        gc->wq_tail &= gc->wq_size - 1;
-       GEM_BUG_ON(wq_off & (wqi_size - 1));
+       gc->wq_rsvd -= wqi_size;
 
        /* WQ starts from the page after doorbell / process_desc */
        wq_page = (wq_off + GUC_DB_SIZE) >> PAGE_SHIFT;
        wq_off &= PAGE_SIZE - 1;
-       base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, wq_page));
+       base = kmap_atomic(i915_gem_object_get_page(gc->vma->obj, wq_page));
        wqi = (struct guc_wq_item *)((char *)base + wq_off);
 
        /* Now fill in the 4-word work queue item */
        wqi->header = WQ_TYPE_INORDER |
                        (wqi_len << WQ_LEN_SHIFT) |
-                       (rq->engine->guc_id << WQ_TARGET_SHIFT) |
+                       (engine->guc_id << WQ_TARGET_SHIFT) |
                        WQ_NO_WCFLUSH_WAIT;
 
        /* The GuC wants only the low-order word of the context descriptor */
-       wqi->context_desc = (u32)intel_lr_context_descriptor(rq->ctx,
-                                                            rq->engine);
+       wqi->context_desc = (u32)intel_lr_context_descriptor(rq->ctx, engine);
 
        wqi->ring_tail = tail << WQ_RING_TAIL_SHIFT;
-       wqi->fence_id = rq->seqno;
+       wqi->fence_id = rq->fence.seqno;
 
        kunmap_atomic(base);
 }
@@ -553,8 +568,8 @@ static int guc_ring_doorbell(struct i915_guc_client *gc)
                if (db_ret.db_status == GUC_DOORBELL_DISABLED)
                        break;
 
-               DRM_ERROR("Cookie mismatch. Expected %d, returned %d\n",
-                         db_cmp.cookie, db_ret.cookie);
+               DRM_WARN("Cookie mismatch. Expected %d, found %d\n",
+                        db_cmp.cookie, db_ret.cookie);
 
                /* update the cookie to newly read cookie from GuC */
                db_cmp.cookie = db_ret.cookie;
@@ -573,26 +588,26 @@ static int guc_ring_doorbell(struct i915_guc_client *gc)
  * Return:     0 on success, otherwise an errno.
  *             (Note: nonzero really shouldn't happen!)
  *
- * The caller must have already called i915_guc_wq_check_space() above
- * with a result of 0 (success) since the last request submission. This
- * guarantees that there is space in the work queue for the new request,
- * so enqueuing the item cannot fail.
+ * The caller must have already called i915_guc_wq_reserve() above with
+ * a result of 0 (success), guaranteeing that there is space in the work
+ * queue for the new request, so enqueuing the item cannot fail.
  *
  * Bad Things Will Happen if the caller violates this protocol e.g. calls
- * submit() when check() says there's no space, or calls submit() multiple
- * times with no intervening check().
+ * submit() when _reserve() says there's no space, or calls _submit()
+ * a different number of times from (successful) calls to _reserve().
  *
  * The only error here arises if the doorbell hardware isn't functioning
  * as expected, which really shouln't happen.
  */
-int i915_guc_submit(struct drm_i915_gem_request *rq)
+static void i915_guc_submit(struct drm_i915_gem_request *rq)
 {
        unsigned int engine_id = rq->engine->id;
        struct intel_guc *guc = &rq->i915->guc;
        struct i915_guc_client *client = guc->execbuf_client;
        int b_ret;
 
-       guc_add_workqueue_item(client, rq);
+       spin_lock(&client->wq_lock);
+       guc_wq_item_append(client, rq);
        b_ret = guc_ring_doorbell(client);
 
        client->submissions[engine_id] += 1;
@@ -601,9 +616,8 @@ int i915_guc_submit(struct drm_i915_gem_request *rq)
                client->b_fail += 1;
 
        guc->submissions[engine_id] += 1;
-       guc->last_seqno[engine_id] = rq->seqno;
-
-       return b_ret;
+       guc->last_seqno[engine_id] = rq->fence.seqno;
+       spin_unlock(&client->wq_lock);
 }
 
 /*
@@ -613,55 +627,48 @@ int i915_guc_submit(struct drm_i915_gem_request *rq)
  */
 
 /**
- * gem_allocate_guc_obj() - Allocate gem object for GuC usage
- * @dev_priv:  driver private data structure
- * @size:      size of object
+ * guc_allocate_vma() - Allocate a GGTT VMA for GuC usage
+ * @guc:       the guc
+ * @size:      size of area to allocate (both virtual space and memory)
  *
- * This is a wrapper to create a gem obj. In order to use it inside GuC, the
- * object needs to be pinned lifetime. Also we must pin it to gtt space other
- * than [0, GUC_WOPCM_TOP) because this range is reserved inside GuC.
+ * This is a wrapper to create an object for use with the GuC. In order to
+ * use it inside the GuC, an object needs to be pinned lifetime, so we allocate
+ * both some backing storage and a range inside the Global GTT. We must pin
+ * it in the GGTT somewhere other than than [0, GUC_WOPCM_TOP) because that
+ * range is reserved inside GuC.
  *
- * Return:     A drm_i915_gem_object if successful, otherwise NULL.
+ * Return:     A i915_vma if successful, otherwise an ERR_PTR.
  */
-static struct drm_i915_gem_object *
-gem_allocate_guc_obj(struct drm_i915_private *dev_priv, u32 size)
+static struct i915_vma *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;
+       struct i915_vma *vma;
+       int ret;
 
        obj = i915_gem_object_create(&dev_priv->drm, size);
        if (IS_ERR(obj))
-               return NULL;
+               return ERR_CAST(obj);
 
-       if (i915_gem_object_get_pages(obj)) {
-               drm_gem_object_unreference(&obj->base);
-               return NULL;
-       }
+       vma = i915_vma_create(obj, &dev_priv->ggtt.base, NULL);
+       if (IS_ERR(vma))
+               goto err;
 
-       if (i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
-                       PIN_OFFSET_BIAS | GUC_WOPCM_TOP)) {
-               drm_gem_object_unreference(&obj->base);
-               return NULL;
+       ret = i915_vma_pin(vma, 0, PAGE_SIZE,
+                          PIN_GLOBAL | PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
+       if (ret) {
+               vma = ERR_PTR(ret);
+               goto err;
        }
 
        /* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
        I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
 
-       return obj;
-}
+       return vma;
 
-/**
- * gem_release_guc_obj() - Release gem object allocated for GuC usage
- * @obj:       gem obj to be released
- */
-static void gem_release_guc_obj(struct drm_i915_gem_object *obj)
-{
-       if (!obj)
-               return;
-
-       if (i915_gem_obj_is_pinned(obj))
-               i915_gem_object_ggtt_unpin(obj);
-
-       drm_gem_object_unreference(&obj->base);
+err:
+       i915_gem_object_put(obj);
+       return vma;
 }
 
 static void
@@ -688,61 +695,74 @@ guc_client_free(struct drm_i915_private *dev_priv,
                kunmap(kmap_to_page(client->client_base));
        }
 
-       gem_release_guc_obj(client->client_obj);
+       i915_vma_unpin_and_release(&client->vma);
 
        if (client->ctx_index != GUC_INVALID_CTX_ID) {
-               guc_fini_ctx_desc(guc, client);
+               guc_ctx_desc_fini(guc, client);
                ida_simple_remove(&guc->ctx_ids, client->ctx_index);
        }
 
        kfree(client);
 }
 
+/* Check that a doorbell register is in the expected state */
+static bool guc_doorbell_check(struct intel_guc *guc, uint16_t db_id)
+{
+       struct drm_i915_private *dev_priv = guc_to_i915(guc);
+       i915_reg_t drbreg = GEN8_DRBREGL(db_id);
+       uint32_t value = I915_READ(drbreg);
+       bool enabled = (value & GUC_DOORBELL_ENABLED) != 0;
+       bool expected = test_bit(db_id, guc->doorbell_bitmap);
+
+       if (enabled == expected)
+               return true;
+
+       DRM_DEBUG_DRIVER("Doorbell %d (reg 0x%x) 0x%x, should be %s\n",
+                        db_id, drbreg.reg, value,
+                        expected ? "active" : "inactive");
+
+       return false;
+}
+
 /*
- * Borrow the first client to set up & tear down every doorbell
+ * Borrow the first client to set up & tear down each unused doorbell
  * in turn, to ensure that all doorbell h/w is (re)initialised.
  */
 static void guc_init_doorbell_hw(struct intel_guc *guc)
 {
-       struct drm_i915_private *dev_priv = guc_to_i915(guc);
        struct i915_guc_client *client = guc->execbuf_client;
-       uint16_t db_id, i;
-       int err;
+       uint16_t db_id;
+       int i, err;
 
+       /* Save client's original doorbell selection */
        db_id = client->doorbell_id;
 
        for (i = 0; i < GUC_MAX_DOORBELLS; ++i) {
-               i915_reg_t drbreg = GEN8_DRBREGL(i);
-               u32 value = I915_READ(drbreg);
+               /* Skip if doorbell is OK */
+               if (guc_doorbell_check(guc, i))
+                       continue;
 
                err = guc_update_doorbell_id(guc, client, i);
-
-               /* Report update failure or unexpectedly active doorbell */
-               if (err || (i != db_id && (value & GUC_DOORBELL_ENABLED)))
-                       DRM_DEBUG_DRIVER("Doorbell %d (reg 0x%x) was 0x%x, err %d\n",
-                                         i, drbreg.reg, value, err);
+               if (err)
+                       DRM_DEBUG_DRIVER("Doorbell %d update failed, err %d\n",
+                                       i, err);
        }
 
        /* Restore to original value */
        err = guc_update_doorbell_id(guc, client, db_id);
        if (err)
-               DRM_ERROR("Failed to restore doorbell to %d, err %d\n",
-                       db_id, err);
+               DRM_WARN("Failed to restore doorbell to %d, err %d\n",
+                        db_id, err);
 
-       for (i = 0; i < GUC_MAX_DOORBELLS; ++i) {
-               i915_reg_t drbreg = GEN8_DRBREGL(i);
-               u32 value = I915_READ(drbreg);
-
-               if (i != db_id && (value & GUC_DOORBELL_ENABLED))
-                       DRM_DEBUG_DRIVER("Doorbell %d (reg 0x%x) finally 0x%x\n",
-                                         i, drbreg.reg, value);
-
-       }
+       /* Read back & verify all doorbell registers */
+       for (i = 0; i < GUC_MAX_DOORBELLS; ++i)
+               (void)guc_doorbell_check(guc, i);
 }
 
 /**
  * guc_client_alloc() - Allocate an i915_guc_client
  * @dev_priv:  driver private data structure
+ * @engines:   The set of engines to enable for this client
  * @priority:  four levels priority _CRITICAL, _HIGH, _NORMAL and _LOW
  *             The kernel client to replace ExecList submission is created with
  *             NORMAL priority. Priority of a client for scheduler can be HIGH,
@@ -754,22 +774,24 @@ static void guc_init_doorbell_hw(struct intel_guc *guc)
  */
 static struct i915_guc_client *
 guc_client_alloc(struct drm_i915_private *dev_priv,
+                uint32_t engines,
                 uint32_t priority,
                 struct i915_gem_context *ctx)
 {
        struct i915_guc_client *client;
        struct intel_guc *guc = &dev_priv->guc;
-       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
        uint16_t db_id;
 
        client = kzalloc(sizeof(*client), GFP_KERNEL);
        if (!client)
                return NULL;
 
-       client->doorbell_id = GUC_INVALID_DOORBELL_ID;
-       client->priority = priority;
        client->owner = ctx;
        client->guc = guc;
+       client->engines = engines;
+       client->priority = priority;
+       client->doorbell_id = GUC_INVALID_DOORBELL_ID;
 
        client->ctx_index = (uint32_t)ida_simple_get(&guc->ctx_ids, 0,
                        GUC_MAX_GPU_CONTEXTS, GFP_KERNEL);
@@ -779,13 +801,15 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
        }
 
        /* The first page is doorbell/proc_desc. Two followed pages are wq. */
-       obj = gem_allocate_guc_obj(dev_priv, GUC_DB_SIZE + GUC_WQ_SIZE);
-       if (!obj)
+       vma = guc_allocate_vma(guc, GUC_DB_SIZE + GUC_WQ_SIZE);
+       if (IS_ERR(vma))
                goto err;
 
        /* We'll keep just the first (doorbell/proc) page permanently kmap'd. */
-       client->client_obj = obj;
-       client->client_base = kmap(i915_gem_object_get_page(obj, 0));
+       client->vma = vma;
+       client->client_base = kmap(i915_vma_first_page(vma));
+
+       spin_lock_init(&client->wq_lock);
        client->wq_offset = GUC_DB_SIZE;
        client->wq_size = GUC_WQ_SIZE;
 
@@ -806,29 +830,26 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
        else
                client->proc_desc_offset = (GUC_DB_SIZE / 2);
 
-       guc_init_proc_desc(guc, client);
-       guc_init_ctx_desc(guc, client);
+       guc_proc_desc_init(guc, client);
+       guc_ctx_desc_init(guc, client);
        if (guc_init_doorbell(guc, client, db_id))
                goto err;
 
-       DRM_DEBUG_DRIVER("new priority %u client %p: ctx_index %u\n",
-               priority, client, client->ctx_index);
+       DRM_DEBUG_DRIVER("new priority %u client %p for engine(s) 0x%x: ctx_index %u\n",
+               priority, client, client->engines, client->ctx_index);
        DRM_DEBUG_DRIVER("doorbell id %u, cacheline offset 0x%x\n",
                client->doorbell_id, client->doorbell_offset);
 
        return client;
 
 err:
-       DRM_ERROR("FAILED to create priority %u GuC client!\n", priority);
-
        guc_client_free(dev_priv, client);
        return NULL;
 }
 
-static void guc_create_log(struct intel_guc *guc)
+static void guc_log_create(struct intel_guc *guc)
 {
-       struct drm_i915_private *dev_priv = guc_to_i915(guc);
-       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
        unsigned long offset;
        uint32_t size, flags;
 
@@ -844,16 +865,16 @@ static void guc_create_log(struct intel_guc *guc)
                GUC_LOG_ISR_PAGES + 1 +
                GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT;
 
-       obj = guc->log_obj;
-       if (!obj) {
-               obj = gem_allocate_guc_obj(dev_priv, size);
-               if (!obj) {
+       vma = guc->log_vma;
+       if (!vma) {
+               vma = guc_allocate_vma(guc, size);
+               if (IS_ERR(vma)) {
                        /* logging will be off */
                        i915.guc_log_level = -1;
                        return;
                }
 
-               guc->log_obj = obj;
+               guc->log_vma = vma;
        }
 
        /* each allocated unit is a page */
@@ -862,11 +883,11 @@ static void guc_create_log(struct intel_guc *guc)
                (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) |
                (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT);
 
-       offset = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; /* in pages */
+       offset = i915_ggtt_offset(vma) >> PAGE_SHIFT; /* in pages */
        guc->log_flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
 }
 
-static void init_guc_policies(struct guc_policies *policies)
+static void guc_policies_init(struct guc_policies *policies)
 {
        struct guc_policy *policy;
        u32 p, i;
@@ -888,10 +909,10 @@ static void init_guc_policies(struct guc_policies *policies)
        policies->is_valid = 1;
 }
 
-static void guc_create_ads(struct intel_guc *guc)
+static void guc_addon_create(struct intel_guc *guc)
 {
        struct drm_i915_private *dev_priv = guc_to_i915(guc);
-       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
        struct guc_ads *ads;
        struct guc_policies *policies;
        struct guc_mmio_reg_state *reg_state;
@@ -904,16 +925,16 @@ static void guc_create_ads(struct intel_guc *guc)
                        sizeof(struct guc_mmio_reg_state) +
                        GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE;
 
-       obj = guc->ads_obj;
-       if (!obj) {
-               obj = gem_allocate_guc_obj(dev_priv, PAGE_ALIGN(size));
-               if (!obj)
+       vma = guc->ads_vma;
+       if (!vma) {
+               vma = guc_allocate_vma(guc, PAGE_ALIGN(size));
+               if (IS_ERR(vma))
                        return;
 
-               guc->ads_obj = obj;
+               guc->ads_vma = vma;
        }
 
-       page = i915_gem_object_get_page(obj, 0);
+       page = i915_vma_first_page(vma);
        ads = kmap(page);
 
        /*
@@ -924,17 +945,17 @@ static void guc_create_ads(struct intel_guc *guc)
         * to find it.
         */
        engine = &dev_priv->engine[RCS];
-       ads->golden_context_lrca = engine->status_page.gfx_addr;
+       ads->golden_context_lrca = engine->status_page.ggtt_offset;
 
        for_each_engine(engine, dev_priv)
                ads->eng_state_size[engine->guc_id] = intel_lr_context_size(engine);
 
        /* GuC scheduling policies */
        policies = (void *)ads + sizeof(struct guc_ads);
-       init_guc_policies(policies);
+       guc_policies_init(policies);
 
-       ads->scheduler_policies = i915_gem_obj_ggtt_offset(obj) +
-                       sizeof(struct guc_ads);
+       ads->scheduler_policies =
+               i915_ggtt_offset(vma) + sizeof(struct guc_ads);
 
        /* MMIO reg state */
        reg_state = (void *)policies + sizeof(struct guc_policies);
@@ -966,6 +987,7 @@ int i915_guc_submission_init(struct drm_i915_private *dev_priv)
        const size_t poolsize = GUC_MAX_GPU_CONTEXTS * ctxsize;
        const size_t gemsize = round_up(poolsize, PAGE_SIZE);
        struct intel_guc *guc = &dev_priv->guc;
+       struct i915_vma *vma;
 
        /* Wipe bitmap & delete client in case of reinitialisation */
        bitmap_clear(guc->doorbell_bitmap, 0, GUC_MAX_DOORBELLS);
@@ -974,16 +996,17 @@ int i915_guc_submission_init(struct drm_i915_private *dev_priv)
        if (!i915.enable_guc_submission)
                return 0; /* not enabled  */
 
-       if (guc->ctx_pool_obj)
+       if (guc->ctx_pool_vma)
                return 0; /* already allocated */
 
-       guc->ctx_pool_obj = gem_allocate_guc_obj(dev_priv, gemsize);
-       if (!guc->ctx_pool_obj)
-               return -ENOMEM;
+       vma = guc_allocate_vma(guc, gemsize);
+       if (IS_ERR(vma))
+               return PTR_ERR(vma);
 
+       guc->ctx_pool_vma = vma;
        ida_init(&guc->ctx_ids);
-       guc_create_log(guc);
-       guc_create_ads(guc);
+       guc_log_create(guc);
+       guc_addon_create(guc);
 
        return 0;
 }
@@ -992,13 +1015,16 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
 {
        struct intel_guc *guc = &dev_priv->guc;
        struct i915_guc_client *client;
+       struct intel_engine_cs *engine;
+       struct drm_i915_gem_request *request;
 
        /* client for execbuf submission */
        client = guc_client_alloc(dev_priv,
+                                 INTEL_INFO(dev_priv)->ring_mask,
                                  GUC_CTX_PRIORITY_KMD_NORMAL,
                                  dev_priv->kernel_context);
        if (!client) {
-               DRM_ERROR("Failed to create execbuf guc_client\n");
+               DRM_ERROR("Failed to create normal GuC client!\n");
                return -ENOMEM;
        }
 
@@ -1006,6 +1032,18 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
        host2guc_sample_forcewake(guc, client);
        guc_init_doorbell_hw(guc);
 
+       /* Take over from manual control of ELSP (execlists) */
+       for_each_engine(engine, dev_priv) {
+               engine->submit_request = i915_guc_submit;
+
+               /* Replay the current set of previously submitted requests */
+               list_for_each_entry(request, &engine->request_list, link) {
+                       client->wq_rsvd += sizeof(struct guc_wq_item);
+                       if (i915_sw_fence_done(&request->submit))
+                               i915_guc_submit(request);
+               }
+       }
+
        return 0;
 }
 
@@ -1013,6 +1051,12 @@ void i915_guc_submission_disable(struct drm_i915_private *dev_priv)
 {
        struct intel_guc *guc = &dev_priv->guc;
 
+       if (!guc->execbuf_client)
+               return;
+
+       /* Revert back to manual ELSP submission */
+       intel_execlists_enable_submission(dev_priv);
+
        guc_client_free(dev_priv, guc->execbuf_client);
        guc->execbuf_client = NULL;
 }
@@ -1021,16 +1065,12 @@ void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
 {
        struct intel_guc *guc = &dev_priv->guc;
 
-       gem_release_guc_obj(dev_priv->guc.ads_obj);
-       guc->ads_obj = NULL;
-
-       gem_release_guc_obj(dev_priv->guc.log_obj);
-       guc->log_obj = NULL;
+       i915_vma_unpin_and_release(&guc->ads_vma);
+       i915_vma_unpin_and_release(&guc->log_vma);
 
-       if (guc->ctx_pool_obj)
+       if (guc->ctx_pool_vma)
                ida_destroy(&guc->ctx_ids);
-       gem_release_guc_obj(guc->ctx_pool_obj);
-       guc->ctx_pool_obj = NULL;
+       i915_vma_unpin_and_release(&guc->ctx_pool_vma);
 }
 
 /**
@@ -1053,7 +1093,7 @@ int intel_guc_suspend(struct drm_device *dev)
        /* any value greater than GUC_POWER_D0 */
        data[1] = GUC_POWER_D1;
        /* first page is shared data with GuC */
-       data[2] = i915_gem_obj_ggtt_offset(ctx->engine[RCS].state);
+       data[2] = i915_ggtt_offset(ctx->engine[RCS].state);
 
        return host2guc_action(guc, data, ARRAY_SIZE(data));
 }
@@ -1078,7 +1118,7 @@ int intel_guc_resume(struct drm_device *dev)
        data[0] = HOST2GUC_ACTION_EXIT_S_STATE;
        data[1] = GUC_POWER_D0;
        /* first page is shared data with GuC */
-       data[2] = i915_gem_obj_ggtt_offset(ctx->engine[RCS].state);
+       data[2] = i915_ggtt_offset(ctx->engine[RCS].state);
 
        return host2guc_action(guc, data, ARRAY_SIZE(data));
 }
index 1c2aec3..3fc286c 100644 (file)
@@ -350,6 +350,9 @@ void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
 
 void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv)
 {
+       if (READ_ONCE(dev_priv->rps.interrupts_enabled))
+               return;
+
        spin_lock_irq(&dev_priv->irq_lock);
        WARN_ON_ONCE(dev_priv->rps.pm_iir);
        WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events);
@@ -368,10 +371,13 @@ u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask)
 
 void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
 {
+       if (!READ_ONCE(dev_priv->rps.interrupts_enabled))
+               return;
+
        spin_lock_irq(&dev_priv->irq_lock);
        dev_priv->rps.interrupts_enabled = false;
 
-       I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0));
+       I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0u));
 
        __gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
        I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
@@ -656,12 +662,6 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
  *   of horizontal active on the first line of vertical active
  */
 
-static u32 i8xx_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
-{
-       /* Gen2 doesn't have a hardware frame counter */
-       return 0;
-}
-
 /* Called from drm generic code, passed a 'crtc', which
  * we use as a pipe index
  */
@@ -978,10 +978,8 @@ static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv)
 static void notify_ring(struct intel_engine_cs *engine)
 {
        smp_store_mb(engine->breadcrumbs.irq_posted, true);
-       if (intel_engine_wakeup(engine)) {
+       if (intel_engine_wakeup(engine))
                trace_i915_gem_request_notify(engine);
-               engine->breadcrumbs.irq_wakeups++;
-       }
 }
 
 static void vlv_c0_read(struct drm_i915_private *dev_priv,
@@ -1105,9 +1103,10 @@ static void gen6_pm_rps_work(struct work_struct *work)
        new_delay = dev_priv->rps.cur_freq;
        min = dev_priv->rps.min_freq_softlimit;
        max = dev_priv->rps.max_freq_softlimit;
-
-       if (client_boost) {
-               new_delay = dev_priv->rps.max_freq_softlimit;
+       if (client_boost || any_waiters(dev_priv))
+               max = dev_priv->rps.max_freq;
+       if (client_boost && new_delay < dev_priv->rps.boost_freq) {
+               new_delay = dev_priv->rps.boost_freq;
                adj = 0;
        } else if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
                if (adj > 0)
@@ -1122,7 +1121,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
                        new_delay = dev_priv->rps.efficient_freq;
                        adj = 0;
                }
-       } else if (any_waiters(dev_priv)) {
+       } else if (client_boost || any_waiters(dev_priv)) {
                adj = 0;
        } else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) {
                if (dev_priv->rps.cur_freq > dev_priv->rps.efficient_freq)
@@ -2504,57 +2503,52 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv)
        char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
        char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
        char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
-       int ret;
 
        kobject_uevent_env(kobj, KOBJ_CHANGE, error_event);
 
+       DRM_DEBUG_DRIVER("resetting chip\n");
+       kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event);
+
        /*
-        * Note that there's only one work item which does gpu resets, so we
-        * need not worry about concurrent gpu resets potentially incrementing
-        * error->reset_counter twice. We only need to take care of another
-        * racing irq/hangcheck declaring the gpu dead for a second time. A
-        * quick check for that is good enough: schedule_work ensures the
-        * correct ordering between hang detection and this work item, and since
-        * the reset in-progress bit is only ever set by code outside of this
-        * work we don't need to worry about any other races.
+        * In most cases it's guaranteed that we get here with an RPM
+        * reference held, for example because there is a pending GPU
+        * request that won't finish until the reset is done. This
+        * isn't the case at least when we get here by doing a
+        * simulated reset via debugs, so get an RPM reference.
         */
-       if (i915_reset_in_progress(&dev_priv->gpu_error)) {
-               DRM_DEBUG_DRIVER("resetting chip\n");
-               kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event);
-
-               /*
-                * In most cases it's guaranteed that we get here with an RPM
-                * reference held, for example because there is a pending GPU
-                * request that won't finish until the reset is done. This
-                * isn't the case at least when we get here by doing a
-                * simulated reset via debugs, so get an RPM reference.
-                */
-               intel_runtime_pm_get(dev_priv);
-
-               intel_prepare_reset(dev_priv);
+       intel_runtime_pm_get(dev_priv);
+       intel_prepare_reset(dev_priv);
 
+       do {
                /*
                 * All state reset _must_ be completed before we update the
                 * reset counter, for otherwise waiters might miss the reset
                 * pending state and not properly drop locks, resulting in
                 * deadlocks with the reset work.
                 */
-               ret = i915_reset(dev_priv);
+               if (mutex_trylock(&dev_priv->drm.struct_mutex)) {
+                       i915_reset(dev_priv);
+                       mutex_unlock(&dev_priv->drm.struct_mutex);
+               }
 
-               intel_finish_reset(dev_priv);
+               /* We need to wait for anyone holding the lock to wakeup */
+       } while (wait_on_bit_timeout(&dev_priv->gpu_error.flags,
+                                    I915_RESET_IN_PROGRESS,
+                                    TASK_UNINTERRUPTIBLE,
+                                    HZ));
 
-               intel_runtime_pm_put(dev_priv);
+       intel_finish_reset(dev_priv);
+       intel_runtime_pm_put(dev_priv);
 
-               if (ret == 0)
-                       kobject_uevent_env(kobj,
-                                          KOBJ_CHANGE, reset_done_event);
+       if (!test_bit(I915_WEDGED, &dev_priv->gpu_error.flags))
+               kobject_uevent_env(kobj,
+                                  KOBJ_CHANGE, reset_done_event);
 
-               /*
-                * Note: The wake_up also serves as a memory barrier so that
-                * waiters see the update value of the reset counter atomic_t.
-                */
-               wake_up_all(&dev_priv->gpu_error.reset_queue);
-       }
+       /*
+        * Note: The wake_up also serves as a memory barrier so that
+        * waiters see the updated value of the dev_priv->gpu_error.
+        */
+       wake_up_all(&dev_priv->gpu_error.reset_queue);
 }
 
 static void i915_report_and_clear_eir(struct drm_i915_private *dev_priv)
@@ -2673,25 +2667,26 @@ void i915_handle_error(struct drm_i915_private *dev_priv,
        i915_capture_error_state(dev_priv, engine_mask, error_msg);
        i915_report_and_clear_eir(dev_priv);
 
-       if (engine_mask) {
-               atomic_or(I915_RESET_IN_PROGRESS_FLAG,
-                               &dev_priv->gpu_error.reset_counter);
+       if (!engine_mask)
+               return;
 
-               /*
-                * Wakeup waiting processes so that the reset function
-                * i915_reset_and_wakeup doesn't deadlock trying to grab
-                * various locks. By bumping the reset counter first, the woken
-                * processes will see a reset in progress and back off,
-                * releasing their locks and then wait for the reset completion.
-                * We must do this for _all_ gpu waiters that might hold locks
-                * that the reset work needs to acquire.
-                *
-                * Note: The wake_up serves as the required memory barrier to
-                * ensure that the waiters see the updated value of the reset
-                * counter atomic_t.
-                */
-               i915_error_wake_up(dev_priv);
-       }
+       if (test_and_set_bit(I915_RESET_IN_PROGRESS,
+                            &dev_priv->gpu_error.flags))
+               return;
+
+       /*
+        * Wakeup waiting processes so that the reset function
+        * i915_reset_and_wakeup doesn't deadlock trying to grab
+        * various locks. By bumping the reset counter first, the woken
+        * processes will see a reset in progress and back off,
+        * releasing their locks and then wait for the reset completion.
+        * We must do this for _all_ gpu waiters that might hold locks
+        * that the reset work needs to acquire.
+        *
+        * Note: The wake_up also provides a memory barrier to ensure that the
+        * waiters see the updated value of the reset flags.
+        */
+       i915_error_wake_up(dev_priv);
 
        i915_reset_and_wakeup(dev_priv);
 }
@@ -2803,13 +2798,6 @@ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-static bool
-ring_idle(struct intel_engine_cs *engine, u32 seqno)
-{
-       return i915_seqno_passed(seqno,
-                                READ_ONCE(engine->last_submitted_seqno));
-}
-
 static bool
 ipehr_is_semaphore_wait(struct intel_engine_cs *engine, u32 ipehr)
 {
@@ -2834,7 +2822,7 @@ semaphore_wait_to_signaller_ring(struct intel_engine_cs *engine, u32 ipehr,
                        if (engine == signaller)
                                continue;
 
-                       if (offset == signaller->semaphore.signal_ggtt[engine->id])
+                       if (offset == signaller->semaphore.signal_ggtt[engine->hw_id])
                                return signaller;
                }
        } else {
@@ -2844,21 +2832,22 @@ semaphore_wait_to_signaller_ring(struct intel_engine_cs *engine, u32 ipehr,
                        if(engine == signaller)
                                continue;
 
-                       if (sync_bits == signaller->semaphore.mbox.wait[engine->id])
+                       if (sync_bits == signaller->semaphore.mbox.wait[engine->hw_id])
                                return signaller;
                }
        }
 
-       DRM_ERROR("No signaller ring found for ring %i, ipehr 0x%08x, offset 0x%016llx\n",
-                 engine->id, ipehr, offset);
+       DRM_DEBUG_DRIVER("No signaller ring found for %s, ipehr 0x%08x, offset 0x%016llx\n",
+                        engine->name, ipehr, offset);
 
-       return NULL;
+       return ERR_PTR(-ENODEV);
 }
 
 static struct intel_engine_cs *
 semaphore_waits_for(struct intel_engine_cs *engine, u32 *seqno)
 {
        struct drm_i915_private *dev_priv = engine->i915;
+       void __iomem *vaddr;
        u32 cmd, ipehr, head;
        u64 offset = 0;
        int i, backwards;
@@ -2897,6 +2886,7 @@ semaphore_waits_for(struct intel_engine_cs *engine, u32 *seqno)
         */
        head = I915_READ_HEAD(engine) & HEAD_ADDR;
        backwards = (INTEL_GEN(dev_priv) >= 8) ? 5 : 4;
+       vaddr = (void __iomem *)engine->buffer->vaddr;
 
        for (i = backwards; i; --i) {
                /*
@@ -2907,7 +2897,7 @@ semaphore_waits_for(struct intel_engine_cs *engine, u32 *seqno)
                head &= engine->buffer->size - 1;
 
                /* This here seems to blow up */
-               cmd = ioread32(engine->buffer->virtual_start + head);
+               cmd = ioread32(vaddr + head);
                if (cmd == ipehr)
                        break;
 
@@ -2917,11 +2907,11 @@ semaphore_waits_for(struct intel_engine_cs *engine, u32 *seqno)
        if (!i)
                return NULL;
 
-       *seqno = ioread32(engine->buffer->virtual_start + head + 4) + 1;
+       *seqno = ioread32(vaddr + head + 4) + 1;
        if (INTEL_GEN(dev_priv) >= 8) {
-               offset = ioread32(engine->buffer->virtual_start + head + 12);
+               offset = ioread32(vaddr + head + 12);
                offset <<= 32;
-               offset = ioread32(engine->buffer->virtual_start + head + 8);
+               offset |= ioread32(vaddr + head + 8);
        }
        return semaphore_wait_to_signaller_ring(engine, ipehr, offset);
 }
@@ -2938,6 +2928,9 @@ static int semaphore_passed(struct intel_engine_cs *engine)
        if (signaller == NULL)
                return -1;
 
+       if (IS_ERR(signaller))
+               return 0;
+
        /* Prevent pathological recursion due to driver bugs */
        if (signaller->hangcheck.deadlock >= I915_NUM_ENGINES)
                return -1;
@@ -2990,7 +2983,7 @@ static bool subunits_stuck(struct intel_engine_cs *engine)
        return stuck;
 }
 
-static enum intel_ring_hangcheck_action
+static enum intel_engine_hangcheck_action
 head_stuck(struct intel_engine_cs *engine, u64 acthd)
 {
        if (acthd != engine->hangcheck.acthd) {
@@ -3008,11 +3001,11 @@ head_stuck(struct intel_engine_cs *engine, u64 acthd)
        return HANGCHECK_HUNG;
 }
 
-static enum intel_ring_hangcheck_action
-ring_stuck(struct intel_engine_cs *engine, u64 acthd)
+static enum intel_engine_hangcheck_action
+engine_stuck(struct intel_engine_cs *engine, u64 acthd)
 {
        struct drm_i915_private *dev_priv = engine->i915;
-       enum intel_ring_hangcheck_action ha;
+       enum intel_engine_hangcheck_action ha;
        u32 tmp;
 
        ha = head_stuck(engine, acthd);
@@ -3054,22 +3047,6 @@ ring_stuck(struct intel_engine_cs *engine, u64 acthd)
        return HANGCHECK_HUNG;
 }
 
-static unsigned long kick_waiters(struct intel_engine_cs *engine)
-{
-       struct drm_i915_private *i915 = engine->i915;
-       unsigned long irq_count = READ_ONCE(engine->breadcrumbs.irq_wakeups);
-
-       if (engine->hangcheck.user_interrupts == irq_count &&
-           !test_and_set_bit(engine->id, &i915->gpu_error.missed_irq_rings)) {
-               if (!test_bit(engine->id, &i915->gpu_error.test_irq_rings))
-                       DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
-                                 engine->name);
-
-               intel_engine_enable_fake_irq(engine);
-       }
-
-       return irq_count;
-}
 /*
  * This is called when the chip hasn't reported back with completed
  * batchbuffers in a long time. We keep track per ring seqno progress and
@@ -3107,7 +3084,7 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
                bool busy = intel_engine_has_waiter(engine);
                u64 acthd;
                u32 seqno;
-               unsigned user_interrupts;
+               u32 submit;
 
                semaphore_clear_deadlocks(dev_priv);
 
@@ -3121,29 +3098,22 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
                if (engine->irq_seqno_barrier)
                        engine->irq_seqno_barrier(engine);
 
-               acthd = intel_ring_get_active_head(engine);
+               acthd = intel_engine_get_active_head(engine);
                seqno = intel_engine_get_seqno(engine);
-
-               /* Reset stuck interrupts between batch advances */
-               user_interrupts = 0;
+               submit = READ_ONCE(engine->last_submitted_seqno);
 
                if (engine->hangcheck.seqno == seqno) {
-                       if (ring_idle(engine, seqno)) {
+                       if (i915_seqno_passed(seqno, submit)) {
                                engine->hangcheck.action = HANGCHECK_IDLE;
-                               if (busy) {
-                                       /* Safeguard against driver failure */
-                                       user_interrupts = kick_waiters(engine);
-                                       engine->hangcheck.score += BUSY;
-                               }
                        } else {
                                /* We always increment the hangcheck score
-                                * if the ring is busy and still processing
+                                * if the engine is busy and still processing
                                 * the same request, so that no single request
                                 * can run indefinitely (such as a chain of
                                 * batches). The only time we do not increment
                                 * the hangcheck score on this ring, if this
-                                * ring is in a legitimate wait for another
-                                * ring. In that case the waiting ring is a
+                                * engine is in a legitimate wait for another
+                                * engine. In that case the waiting engine is a
                                 * victim and we want to be sure we catch the
                                 * right culprit. Then every time we do kick
                                 * the ring, add a small increment to the
@@ -3151,8 +3121,8 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
                                 * being repeatedly kicked and so responsible
                                 * for stalling the machine.
                                 */
-                               engine->hangcheck.action = ring_stuck(engine,
-                                                                     acthd);
+                               engine->hangcheck.action =
+                                       engine_stuck(engine, acthd);
 
                                switch (engine->hangcheck.action) {
                                case HANGCHECK_IDLE:
@@ -3195,12 +3165,12 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
 
                engine->hangcheck.seqno = seqno;
                engine->hangcheck.acthd = acthd;
-               engine->hangcheck.user_interrupts = user_interrupts;
                busy_count += busy;
        }
 
        if (hung) {
                char msg[80];
+               unsigned int tmp;
                int len;
 
                /* If some rings hung but others were still busy, only
@@ -3210,7 +3180,7 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
                        hung &= ~stuck;
                len = scnprintf(msg, sizeof(msg),
                                "%s on ", stuck == hung ? "No progress" : "Hang");
-               for_each_engine_masked(engine, dev_priv, hung)
+               for_each_engine_masked(engine, dev_priv, hung, tmp)
                        len += scnprintf(msg + len, sizeof(msg) - len,
                                         "%s, ", engine->name);
                msg[len-2] = '\0';
@@ -4536,14 +4506,15 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
                dev_priv->rps.pm_intr_keep |= GEN6_PM_RP_UP_EI_EXPIRED;
 
        if (INTEL_INFO(dev_priv)->gen >= 8)
-               dev_priv->rps.pm_intr_keep |= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
+               dev_priv->rps.pm_intr_keep |= GEN8_PMINTR_REDIRECT_TO_GUC;
 
        INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work,
                          i915_hangcheck_elapsed);
 
        if (IS_GEN2(dev_priv)) {
+               /* Gen2 doesn't have a hardware frame counter */
                dev->max_vblank_count = 0;
-               dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
+               dev->driver->get_vblank_counter = drm_vblank_no_hw_counter;
        } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) {
                dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
                dev->driver->get_vblank_counter = g4x_get_vblank_counter;
diff --git a/drivers/gpu/drm/i915/i915_memcpy.c b/drivers/gpu/drm/i915/i915_memcpy.c
new file mode 100644 (file)
index 0000000..49a0794
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2016 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/kernel.h>
+#include <asm/fpu/api.h>
+
+#include "i915_drv.h"
+
+static DEFINE_STATIC_KEY_FALSE(has_movntdqa);
+
+#ifdef CONFIG_AS_MOVNTDQA
+static void __memcpy_ntdqa(void *dst, const void *src, unsigned long len)
+{
+       kernel_fpu_begin();
+
+       len >>= 4;
+       while (len >= 4) {
+               asm("movntdqa   (%0), %%xmm0\n"
+                   "movntdqa 16(%0), %%xmm1\n"
+                   "movntdqa 32(%0), %%xmm2\n"
+                   "movntdqa 48(%0), %%xmm3\n"
+                   "movaps %%xmm0,   (%1)\n"
+                   "movaps %%xmm1, 16(%1)\n"
+                   "movaps %%xmm2, 32(%1)\n"
+                   "movaps %%xmm3, 48(%1)\n"
+                   :: "r" (src), "r" (dst) : "memory");
+               src += 64;
+               dst += 64;
+               len -= 4;
+       }
+       while (len--) {
+               asm("movntdqa (%0), %%xmm0\n"
+                   "movaps %%xmm0, (%1)\n"
+                   :: "r" (src), "r" (dst) : "memory");
+               src += 16;
+               dst += 16;
+       }
+
+       kernel_fpu_end();
+}
+#endif
+
+/**
+ * i915_memcpy_from_wc: perform an accelerated *aligned* read from WC
+ * @dst: destination pointer
+ * @src: source pointer
+ * @len: how many bytes to copy
+ *
+ * i915_memcpy_from_wc copies @len bytes from @src to @dst using
+ * non-temporal instructions where available. Note that all arguments
+ * (@src, @dst) must be aligned to 16 bytes and @len must be a multiple
+ * of 16.
+ *
+ * To test whether accelerated reads from WC are supported, use
+ * i915_memcpy_from_wc(NULL, NULL, 0);
+ *
+ * Returns true if the copy was successful, false if the preconditions
+ * are not met.
+ */
+bool i915_memcpy_from_wc(void *dst, const void *src, unsigned long len)
+{
+       if (unlikely(((unsigned long)dst | (unsigned long)src | len) & 15))
+               return false;
+
+#ifdef CONFIG_AS_MOVNTDQA
+       if (static_branch_likely(&has_movntdqa)) {
+               if (likely(len))
+                       __memcpy_ntdqa(dst, src, len);
+               return true;
+       }
+#endif
+
+       return false;
+}
+
+void i915_memcpy_init_early(struct drm_i915_private *dev_priv)
+{
+       if (static_cpu_has(X86_FEATURE_XMM4_1))
+               static_branch_enable(&has_movntdqa);
+}
diff --git a/drivers/gpu/drm/i915/i915_mm.c b/drivers/gpu/drm/i915/i915_mm.c
new file mode 100644 (file)
index 0000000..e4935dd
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2014 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/mm.h>
+#include <linux/io-mapping.h>
+
+#include <asm/pgtable.h>
+
+#include "i915_drv.h"
+
+struct remap_pfn {
+       struct mm_struct *mm;
+       unsigned long pfn;
+       pgprot_t prot;
+};
+
+static int remap_pfn(pte_t *pte, pgtable_t token,
+                    unsigned long addr, void *data)
+{
+       struct remap_pfn *r = data;
+
+       /* Special PTE are not associated with any struct page */
+       set_pte_at(r->mm, addr, pte, pte_mkspecial(pfn_pte(r->pfn, r->prot)));
+       r->pfn++;
+
+       return 0;
+}
+
+/**
+ * remap_io_mapping - remap an IO mapping to userspace
+ * @vma: user vma to map to
+ * @addr: target user address to start at
+ * @pfn: physical address of kernel memory
+ * @size: size of map area
+ * @iomap: the source io_mapping
+ *
+ *  Note: this is only safe if the mm semaphore is held when called.
+ */
+int remap_io_mapping(struct vm_area_struct *vma,
+                    unsigned long addr, unsigned long pfn, unsigned long size,
+                    struct io_mapping *iomap)
+{
+       struct remap_pfn r;
+       int err;
+
+       GEM_BUG_ON((vma->vm_flags &
+                   (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)) !=
+                  (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP));
+
+       /* We rely on prevalidation of the io-mapping to skip track_pfn(). */
+       r.mm = vma->vm_mm;
+       r.pfn = pfn;
+       r.prot = __pgprot((pgprot_val(iomap->prot) & _PAGE_CACHE_MASK) |
+                         (pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK));
+
+       err = apply_to_page_range(r.mm, addr, size, remap_pfn, &r);
+       if (unlikely(err)) {
+               zap_vma_ptes(vma, addr, (r.pfn - pfn) << PAGE_SHIFT);
+               return err;
+       }
+
+       return 0;
+}
index b6e404c..768ad89 100644 (file)
@@ -45,6 +45,7 @@ struct i915_params i915 __read_mostly = {
        .fastboot = 0,
        .prefault_disable = 0,
        .load_detect_test = 0,
+       .force_reset_modeset_test = 0,
        .reset = true,
        .invert_brightness = 0,
        .disable_display = 0,
@@ -161,6 +162,11 @@ MODULE_PARM_DESC(load_detect_test,
        "Force-enable the VGA load detect code for testing (default:false). "
        "For developers only.");
 
+module_param_named_unsafe(force_reset_modeset_test, i915.force_reset_modeset_test, bool, 0600);
+MODULE_PARM_DESC(force_reset_modeset_test,
+       "Force a modeset during gpu reset for testing (default:false). "
+       "For developers only.");
+
 module_param_named_unsafe(invert_brightness, i915.invert_brightness, int, 0600);
 MODULE_PARM_DESC(invert_brightness,
        "Invert backlight brightness "
index 0ad020b..3a0dd78 100644 (file)
@@ -57,6 +57,7 @@ struct i915_params {
        bool fastboot;
        bool prefault_disable;
        bool load_detect_test;
+       bool force_reset_modeset_test;
        bool reset;
        bool disable_display;
        bool verbose_state_checks;
index 949c016..687c768 100644 (file)
 #define CHV_COLORS \
        .color = { .degamma_lut_size = 65, .gamma_lut_size = 257 }
 
+#define GEN2_FEATURES \
+       .gen = 2, .num_pipes = 1, \
+       .has_overlay = 1, .overlay_needs_physical = 1, \
+       .has_gmch_display = 1, \
+       .hws_needs_physical = 1, \
+       .ring_mask = RENDER_RING, \
+       GEN_DEFAULT_PIPEOFFSETS, \
+       CURSOR_OFFSETS
+
 static const struct intel_device_info intel_i830_info = {
-       .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
-       .has_overlay = 1, .overlay_needs_physical = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       GEN2_FEATURES,
+       .is_mobile = 1, .cursor_needs_physical = 1,
+       .num_pipes = 2, /* legal, last one wins */
 };
 
 static const struct intel_device_info intel_845g_info = {
-       .gen = 2, .num_pipes = 1,
-       .has_overlay = 1, .overlay_needs_physical = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       GEN2_FEATURES,
 };
 
 static const struct intel_device_info intel_i85x_info = {
-       .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2,
+       GEN2_FEATURES,
+       .is_i85x = 1, .is_mobile = 1,
+       .num_pipes = 2, /* legal, last one wins */
        .cursor_needs_physical = 1,
-       .has_overlay = 1, .overlay_needs_physical = 1,
        .has_fbc = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
 };
 
 static const struct intel_device_info intel_i865g_info = {
-       .gen = 2, .num_pipes = 1,
-       .has_overlay = 1, .overlay_needs_physical = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       GEN2_FEATURES,
 };
 
+#define GEN3_FEATURES \
+       .gen = 3, .num_pipes = 2, \
+       .has_gmch_display = 1, \
+       .ring_mask = RENDER_RING, \
+       GEN_DEFAULT_PIPEOFFSETS, \
+       CURSOR_OFFSETS
+
 static const struct intel_device_info intel_i915g_info = {
-       .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2,
+       GEN3_FEATURES,
+       .is_i915g = 1, .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       .hws_needs_physical = 1,
 };
 static const struct intel_device_info intel_i915gm_info = {
-       .gen = 3, .is_mobile = 1, .num_pipes = 2,
+       GEN3_FEATURES,
+       .is_mobile = 1,
        .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .supports_tv = 1,
        .has_fbc = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       .hws_needs_physical = 1,
 };
 static const struct intel_device_info intel_i945g_info = {
-       .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2,
+       GEN3_FEATURES,
+       .has_hotplug = 1, .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       .hws_needs_physical = 1,
 };
 static const struct intel_device_info intel_i945gm_info = {
-       .gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2,
+       GEN3_FEATURES,
+       .is_i945gm = 1, .is_mobile = 1,
        .has_hotplug = 1, .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .supports_tv = 1,
        .has_fbc = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       .hws_needs_physical = 1,
 };
 
+#define GEN4_FEATURES \
+       .gen = 4, .num_pipes = 2, \
+       .has_hotplug = 1, \
+       .has_gmch_display = 1, \
+       .ring_mask = RENDER_RING, \
+       GEN_DEFAULT_PIPEOFFSETS, \
+       CURSOR_OFFSETS
+
 static const struct intel_device_info intel_i965g_info = {
-       .gen = 4, .is_broadwater = 1, .num_pipes = 2,
-       .has_hotplug = 1,
+       GEN4_FEATURES,
+       .is_broadwater = 1,
        .has_overlay = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       .hws_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i965gm_info = {
-       .gen = 4, .is_crestline = 1, .num_pipes = 2,
-       .is_mobile = 1, .has_fbc = 1, .has_hotplug = 1,
+       GEN4_FEATURES,
+       .is_crestline = 1,
+       .is_mobile = 1, .has_fbc = 1,
        .has_overlay = 1,
        .supports_tv = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       .hws_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_g33_info = {
-       .gen = 3, .is_g33 = 1, .num_pipes = 2,
-       .need_gfx_hws = 1, .has_hotplug = 1,
+       GEN3_FEATURES,
+       .is_g33 = 1,
+       .has_hotplug = 1,
        .has_overlay = 1,
-       .ring_mask = RENDER_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
 };
 
 static const struct intel_device_info intel_g45_info = {
-       .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2,
-       .has_pipe_cxsr = 1, .has_hotplug = 1,
+       GEN4_FEATURES,
+       .is_g4x = 1,
+       .has_pipe_cxsr = 1,
        .ring_mask = RENDER_RING | BSD_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
 };
 
 static const struct intel_device_info intel_gm45_info = {
-       .gen = 4, .is_g4x = 1, .num_pipes = 2,
-       .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1,
-       .has_pipe_cxsr = 1, .has_hotplug = 1,
+       GEN4_FEATURES,
+       .is_g4x = 1,
+       .is_mobile = 1, .has_fbc = 1,
+       .has_pipe_cxsr = 1,
        .supports_tv = 1,
        .ring_mask = RENDER_RING | BSD_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
 };
 
 static const struct intel_device_info intel_pineview_info = {
-       .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2,
-       .need_gfx_hws = 1, .has_hotplug = 1,
+       GEN3_FEATURES,
+       .is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
+       .has_hotplug = 1,
        .has_overlay = 1,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
 };
 
+#define GEN5_FEATURES \
+       .gen = 5, .num_pipes = 2, \
+       .has_hotplug = 1, \
+       .has_gmbus_irq = 1, \
+       .ring_mask = RENDER_RING | BSD_RING, \
+       GEN_DEFAULT_PIPEOFFSETS, \
+       CURSOR_OFFSETS
+
 static const struct intel_device_info intel_ironlake_d_info = {
-       .gen = 5, .num_pipes = 2,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .ring_mask = RENDER_RING | BSD_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       GEN5_FEATURES,
 };
 
 static const struct intel_device_info intel_ironlake_m_info = {
-       .gen = 5, .is_mobile = 1, .num_pipes = 2,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_fbc = 1,
-       .ring_mask = RENDER_RING | BSD_RING,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       GEN5_FEATURES,
+       .is_mobile = 1,
 };
 
+#define GEN6_FEATURES \
+       .gen = 6, .num_pipes = 2, \
+       .has_hotplug = 1, \
+       .has_fbc = 1, \
+       .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
+       .has_llc = 1, \
+       .has_rc6 = 1, \
+       .has_rc6p = 1, \
+       .has_gmbus_irq = 1, \
+       .has_hw_contexts = 1, \
+       GEN_DEFAULT_PIPEOFFSETS, \
+       CURSOR_OFFSETS
+
 static const struct intel_device_info intel_sandybridge_d_info = {
-       .gen = 6, .num_pipes = 2,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_fbc = 1,
-       .ring_mask = RENDER_RING | BSD_RING | BLT_RING,
-       .has_llc = 1,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       GEN6_FEATURES,
 };
 
 static const struct intel_device_info intel_sandybridge_m_info = {
-       .gen = 6, .is_mobile = 1, .num_pipes = 2,
-       .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_fbc = 1,
-       .ring_mask = RENDER_RING | BSD_RING | BLT_RING,
-       .has_llc = 1,
-       GEN_DEFAULT_PIPEOFFSETS,
-       CURSOR_OFFSETS,
+       GEN6_FEATURES,
+       .is_mobile = 1,
 };
 
 #define GEN7_FEATURES  \
        .gen = 7, .num_pipes = 3, \
-       .need_gfx_hws = 1, .has_hotplug = 1, \
+       .has_hotplug = 1, \
        .has_fbc = 1, \
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
        .has_llc = 1, \
+       .has_rc6 = 1, \
+       .has_rc6p = 1, \
+       .has_gmbus_irq = 1, \
+       .has_hw_contexts = 1, \
        GEN_DEFAULT_PIPEOFFSETS, \
        IVB_CURSOR_OFFSETS
 
 static const struct intel_device_info intel_ivybridge_d_info = {
        GEN7_FEATURES,
        .is_ivybridge = 1,
+       .has_l3_dpf = 1,
 };
 
 static const struct intel_device_info intel_ivybridge_m_info = {
        GEN7_FEATURES,
        .is_ivybridge = 1,
        .is_mobile = 1,
+       .has_l3_dpf = 1,
 };
 
 static const struct intel_device_info intel_ivybridge_q_info = {
        GEN7_FEATURES,
        .is_ivybridge = 1,
        .num_pipes = 0, /* legal, last one wins */
+       .has_l3_dpf = 1,
 };
 
 #define VLV_FEATURES  \
        .gen = 7, .num_pipes = 2, \
-       .need_gfx_hws = 1, .has_hotplug = 1, \
+       .has_psr = 1, \
+       .has_runtime_pm = 1, \
+       .has_rc6 = 1, \
+       .has_gmbus_irq = 1, \
+       .has_hw_contexts = 1, \
+       .has_gmch_display = 1, \
+       .has_hotplug = 1, \
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
        .display_mmio_offset = VLV_DISPLAY_BASE, \
        GEN_DEFAULT_PIPEOFFSETS, \
        CURSOR_OFFSETS
 
-static const struct intel_device_info intel_valleyview_m_info = {
-       VLV_FEATURES,
-       .is_valleyview = 1,
-       .is_mobile = 1,
-};
-
-static const struct intel_device_info intel_valleyview_d_info = {
+static const struct intel_device_info intel_valleyview_info = {
        VLV_FEATURES,
        .is_valleyview = 1,
 };
@@ -263,54 +272,50 @@ static const struct intel_device_info intel_valleyview_d_info = {
        GEN7_FEATURES, \
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, \
        .has_ddi = 1, \
-       .has_fpga_dbg = 1
-
-static const struct intel_device_info intel_haswell_d_info = {
-       HSW_FEATURES,
-       .is_haswell = 1,
-};
-
-static const struct intel_device_info intel_haswell_m_info = {
+       .has_fpga_dbg = 1, \
+       .has_psr = 1, \
+       .has_resource_streamer = 1, \
+       .has_dp_mst = 1, \
+       .has_rc6p = 0 /* RC6p removed-by HSW */, \
+       .has_runtime_pm = 1
+
+static const struct intel_device_info intel_haswell_info = {
        HSW_FEATURES,
        .is_haswell = 1,
-       .is_mobile = 1,
+       .has_l3_dpf = 1,
 };
 
 #define BDW_FEATURES \
        HSW_FEATURES, \
-       BDW_COLORS
+       BDW_COLORS, \
+       .has_logical_ring_contexts = 1
 
-static const struct intel_device_info intel_broadwell_d_info = {
+static const struct intel_device_info intel_broadwell_info = {
        BDW_FEATURES,
        .gen = 8,
        .is_broadwell = 1,
 };
 
-static const struct intel_device_info intel_broadwell_m_info = {
-       BDW_FEATURES,
-       .gen = 8, .is_mobile = 1,
-       .is_broadwell = 1,
-};
-
-static const struct intel_device_info intel_broadwell_gt3d_info = {
+static const struct intel_device_info intel_broadwell_gt3_info = {
        BDW_FEATURES,
        .gen = 8,
        .is_broadwell = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
 };
 
-static const struct intel_device_info intel_broadwell_gt3m_info = {
-       BDW_FEATURES,
-       .gen = 8, .is_mobile = 1,
-       .is_broadwell = 1,
-       .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
-};
-
 static const struct intel_device_info intel_cherryview_info = {
        .gen = 8, .num_pipes = 3,
-       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_hotplug = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
        .is_cherryview = 1,
+       .has_psr = 1,
+       .has_runtime_pm = 1,
+       .has_resource_streamer = 1,
+       .has_rc6 = 1,
+       .has_gmbus_irq = 1,
+       .has_hw_contexts = 1,
+       .has_logical_ring_contexts = 1,
+       .has_gmch_display = 1,
        .display_mmio_offset = VLV_DISPLAY_BASE,
        GEN_CHV_PIPEOFFSETS,
        CURSOR_OFFSETS,
@@ -321,25 +326,41 @@ static const struct intel_device_info intel_skylake_info = {
        BDW_FEATURES,
        .is_skylake = 1,
        .gen = 9,
+       .has_csr = 1,
+       .has_guc = 1,
+       .ddb_size = 896,
 };
 
 static const struct intel_device_info intel_skylake_gt3_info = {
        BDW_FEATURES,
        .is_skylake = 1,
        .gen = 9,
+       .has_csr = 1,
+       .has_guc = 1,
+       .ddb_size = 896,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
 };
 
 static const struct intel_device_info intel_broxton_info = {
        .is_broxton = 1,
        .gen = 9,
-       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_hotplug = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
        .num_pipes = 3,
        .has_ddi = 1,
        .has_fpga_dbg = 1,
        .has_fbc = 1,
+       .has_runtime_pm = 1,
        .has_pooled_eu = 0,
+       .has_csr = 1,
+       .has_resource_streamer = 1,
+       .has_rc6 = 1,
+       .has_dp_mst = 1,
+       .has_gmbus_irq = 1,
+       .has_hw_contexts = 1,
+       .has_logical_ring_contexts = 1,
+       .has_guc = 1,
+       .ddb_size = 512,
        GEN_DEFAULT_PIPEOFFSETS,
        IVB_CURSOR_OFFSETS,
        BDW_COLORS,
@@ -349,12 +370,18 @@ static const struct intel_device_info intel_kabylake_info = {
        BDW_FEATURES,
        .is_kabylake = 1,
        .gen = 9,
+       .has_csr = 1,
+       .has_guc = 1,
+       .ddb_size = 896,
 };
 
 static const struct intel_device_info intel_kabylake_gt3_info = {
        BDW_FEATURES,
        .is_kabylake = 1,
        .gen = 9,
+       .has_csr = 1,
+       .has_guc = 1,
+       .ddb_size = 896,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
 };
 
@@ -386,14 +413,10 @@ static const struct pci_device_id pciidlist[] = {
        INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */
        INTEL_IVB_M_IDS(&intel_ivybridge_m_info),
        INTEL_IVB_D_IDS(&intel_ivybridge_d_info),
-       INTEL_HSW_D_IDS(&intel_haswell_d_info),
-       INTEL_HSW_M_IDS(&intel_haswell_m_info),
-       INTEL_VLV_M_IDS(&intel_valleyview_m_info),
-       INTEL_VLV_D_IDS(&intel_valleyview_d_info),
-       INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info),
-       INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info),
-       INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info),
-       INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info),
+       INTEL_HSW_IDS(&intel_haswell_info),
+       INTEL_VLV_IDS(&intel_valleyview_info),
+       INTEL_BDW_GT12_IDS(&intel_broadwell_info),
+       INTEL_BDW_GT3_IDS(&intel_broadwell_gt3_info),
        INTEL_CHV_IDS(&intel_cherryview_info),
        INTEL_SKL_GT1_IDS(&intel_skylake_info),
        INTEL_SKL_GT2_IDS(&intel_skylake_info),
index bf2cad3..70d9616 100644 (file)
@@ -186,13 +186,13 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define  GEN9_GRDOM_GUC                        (1 << 5)
 #define  GEN8_GRDOM_MEDIA2             (1 << 7)
 
-#define RING_PP_DIR_BASE(ring)         _MMIO((ring)->mmio_base+0x228)
-#define RING_PP_DIR_BASE_READ(ring)    _MMIO((ring)->mmio_base+0x518)
-#define RING_PP_DIR_DCLV(ring)         _MMIO((ring)->mmio_base+0x220)
+#define RING_PP_DIR_BASE(engine)       _MMIO((engine)->mmio_base+0x228)
+#define RING_PP_DIR_BASE_READ(engine)  _MMIO((engine)->mmio_base+0x518)
+#define RING_PP_DIR_DCLV(engine)       _MMIO((engine)->mmio_base+0x220)
 #define   PP_DIR_DCLV_2G               0xffffffff
 
-#define GEN8_RING_PDP_UDW(ring, n)     _MMIO((ring)->mmio_base+0x270 + (n) * 8 + 4)
-#define GEN8_RING_PDP_LDW(ring, n)     _MMIO((ring)->mmio_base+0x270 + (n) * 8)
+#define GEN8_RING_PDP_UDW(engine, n)   _MMIO((engine)->mmio_base+0x270 + (n) * 8 + 4)
+#define GEN8_RING_PDP_LDW(engine, n)   _MMIO((engine)->mmio_base+0x270 + (n) * 8)
 
 #define GEN8_R_PWR_CLK_STATE           _MMIO(0x20C8)
 #define   GEN8_RPCS_ENABLE             (1 << 31)
@@ -1648,7 +1648,7 @@ enum skl_disp_power_wells {
 #define   ARB_MODE_BWGTLB_DISABLE (1<<9)
 #define   ARB_MODE_SWIZZLE_BDW (1<<1)
 #define RENDER_HWS_PGA_GEN7    _MMIO(0x04080)
-#define RING_FAULT_REG(ring)   _MMIO(0x4094 + 0x100*(ring)->id)
+#define RING_FAULT_REG(engine) _MMIO(0x4094 + 0x100*(engine)->hw_id)
 #define   RING_FAULT_GTTSEL_MASK (1<<11)
 #define   RING_FAULT_SRCID(x)  (((x) >> 3) & 0xff)
 #define   RING_FAULT_FAULT_TYPE(x) (((x) >> 1) & 0x3)
@@ -1846,7 +1846,7 @@ enum skl_disp_power_wells {
 
 #define GFX_MODE       _MMIO(0x2520)
 #define GFX_MODE_GEN7  _MMIO(0x229c)
-#define RING_MODE_GEN7(ring)   _MMIO((ring)->mmio_base+0x29c)
+#define RING_MODE_GEN7(engine) _MMIO((engine)->mmio_base+0x29c)
 #define   GFX_RUN_LIST_ENABLE          (1<<15)
 #define   GFX_INTERRUPT_STEERING       (1<<14)
 #define   GFX_TLB_INVALIDATE_EXPLICIT  (1<<13)
@@ -3660,8 +3660,17 @@ enum {
 #define   VIDEO_DIP_ENABLE_SPD_HSW     (1 << 0)
 
 /* Panel power sequencing */
-#define PP_STATUS      _MMIO(0x61200)
-#define   PP_ON                (1 << 31)
+#define PPS_BASE                       0x61200
+#define VLV_PPS_BASE                   (VLV_DISPLAY_BASE + PPS_BASE)
+#define PCH_PPS_BASE                   0xC7200
+
+#define _MMIO_PPS(pps_idx, reg)                _MMIO(dev_priv->pps_mmio_base - \
+                                             PPS_BASE + (reg) +        \
+                                             (pps_idx) * 0x100)
+
+#define _PP_STATUS                     0x61200
+#define PP_STATUS(pps_idx)             _MMIO_PPS(pps_idx, _PP_STATUS)
+#define   PP_ON                                (1 << 31)
 /*
  * Indicates that all dependencies of the panel are on:
  *
@@ -3669,14 +3678,14 @@ enum {
  * - pipe enabled
  * - LVDS/DVOB/DVOC on
  */
-#define   PP_READY             (1 << 30)
-#define   PP_SEQUENCE_NONE     (0 << 28)
-#define   PP_SEQUENCE_POWER_UP (1 << 28)
-#define   PP_SEQUENCE_POWER_DOWN (2 << 28)
-#define   PP_SEQUENCE_MASK     (3 << 28)
-#define   PP_SEQUENCE_SHIFT    28
-#define   PP_CYCLE_DELAY_ACTIVE        (1 << 27)
-#define   PP_SEQUENCE_STATE_MASK 0x0000000f
+#define   PP_READY                     (1 << 30)
+#define   PP_SEQUENCE_NONE             (0 << 28)
+#define   PP_SEQUENCE_POWER_UP         (1 << 28)
+#define   PP_SEQUENCE_POWER_DOWN       (2 << 28)
+#define   PP_SEQUENCE_MASK             (3 << 28)
+#define   PP_SEQUENCE_SHIFT            28
+#define   PP_CYCLE_DELAY_ACTIVE                (1 << 27)
+#define   PP_SEQUENCE_STATE_MASK       0x0000000f
 #define   PP_SEQUENCE_STATE_OFF_IDLE   (0x0 << 0)
 #define   PP_SEQUENCE_STATE_OFF_S0_1   (0x1 << 0)
 #define   PP_SEQUENCE_STATE_OFF_S0_2   (0x2 << 0)
@@ -3686,11 +3695,46 @@ enum {
 #define   PP_SEQUENCE_STATE_ON_S1_2    (0xa << 0)
 #define   PP_SEQUENCE_STATE_ON_S1_3    (0xb << 0)
 #define   PP_SEQUENCE_STATE_RESET      (0xf << 0)
-#define PP_CONTROL     _MMIO(0x61204)
-#define   POWER_TARGET_ON      (1 << 0)
-#define PP_ON_DELAYS   _MMIO(0x61208)
-#define PP_OFF_DELAYS  _MMIO(0x6120c)
-#define PP_DIVISOR     _MMIO(0x61210)
+
+#define _PP_CONTROL                    0x61204
+#define PP_CONTROL(pps_idx)            _MMIO_PPS(pps_idx, _PP_CONTROL)
+#define  PANEL_UNLOCK_REGS             (0xabcd << 16)
+#define  PANEL_UNLOCK_MASK             (0xffff << 16)
+#define  BXT_POWER_CYCLE_DELAY_MASK    0x1f0
+#define  BXT_POWER_CYCLE_DELAY_SHIFT   4
+#define  EDP_FORCE_VDD                 (1 << 3)
+#define  EDP_BLC_ENABLE                        (1 << 2)
+#define  PANEL_POWER_RESET             (1 << 1)
+#define  PANEL_POWER_OFF               (0 << 0)
+#define  PANEL_POWER_ON                        (1 << 0)
+
+#define _PP_ON_DELAYS                  0x61208
+#define PP_ON_DELAYS(pps_idx)          _MMIO_PPS(pps_idx, _PP_ON_DELAYS)
+#define  PANEL_PORT_SELECT_SHIFT       30
+#define  PANEL_PORT_SELECT_MASK                (3 << 30)
+#define  PANEL_PORT_SELECT_LVDS                (0 << 30)
+#define  PANEL_PORT_SELECT_DPA         (1 << 30)
+#define  PANEL_PORT_SELECT_DPC         (2 << 30)
+#define  PANEL_PORT_SELECT_DPD         (3 << 30)
+#define  PANEL_PORT_SELECT_VLV(port)   ((port) << 30)
+#define  PANEL_POWER_UP_DELAY_MASK     0x1fff0000
+#define  PANEL_POWER_UP_DELAY_SHIFT    16
+#define  PANEL_LIGHT_ON_DELAY_MASK     0x1fff
+#define  PANEL_LIGHT_ON_DELAY_SHIFT    0
+
+#define _PP_OFF_DELAYS                 0x6120C
+#define PP_OFF_DELAYS(pps_idx)         _MMIO_PPS(pps_idx, _PP_OFF_DELAYS)
+#define  PANEL_POWER_DOWN_DELAY_MASK   0x1fff0000
+#define  PANEL_POWER_DOWN_DELAY_SHIFT  16
+#define  PANEL_LIGHT_OFF_DELAY_MASK    0x1fff
+#define  PANEL_LIGHT_OFF_DELAY_SHIFT   0
+
+#define _PP_DIVISOR                    0x61210
+#define PP_DIVISOR(pps_idx)            _MMIO_PPS(pps_idx, _PP_DIVISOR)
+#define  PP_REFERENCE_DIVIDER_MASK     0xffffff00
+#define  PP_REFERENCE_DIVIDER_SHIFT    8
+#define  PANEL_POWER_CYCLE_DELAY_MASK  0x1f
+#define  PANEL_POWER_CYCLE_DELAY_SHIFT 0
 
 /* Panel fitting */
 #define PFIT_CONTROL   _MMIO(dev_priv->info.display_mmio_offset + 0x61230)
@@ -6133,6 +6177,7 @@ enum {
 # define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC     ((1<<10) | (1<<26))
 # define GEN9_RHWO_OPTIMIZATION_DISABLE                (1<<14)
 #define COMMON_SLICE_CHICKEN2                  _MMIO(0x7014)
+# define GEN9_DISABLE_GATHER_AT_SET_SHADER_COMMON_SLICE (1<<12)
 # define GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION (1<<8)
 # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE  (1<<0)
 
@@ -6749,77 +6794,6 @@ enum {
 #define PCH_LVDS       _MMIO(0xe1180)
 #define  LVDS_DETECTED (1 << 1)
 
-/* vlv has 2 sets of panel control regs. */
-#define _PIPEA_PP_STATUS         (VLV_DISPLAY_BASE + 0x61200)
-#define _PIPEA_PP_CONTROL        (VLV_DISPLAY_BASE + 0x61204)
-#define _PIPEA_PP_ON_DELAYS      (VLV_DISPLAY_BASE + 0x61208)
-#define  PANEL_PORT_SELECT_VLV(port)   ((port) << 30)
-#define _PIPEA_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6120c)
-#define _PIPEA_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61210)
-
-#define _PIPEB_PP_STATUS         (VLV_DISPLAY_BASE + 0x61300)
-#define _PIPEB_PP_CONTROL        (VLV_DISPLAY_BASE + 0x61304)
-#define _PIPEB_PP_ON_DELAYS      (VLV_DISPLAY_BASE + 0x61308)
-#define _PIPEB_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6130c)
-#define _PIPEB_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61310)
-
-#define VLV_PIPE_PP_STATUS(pipe)       _MMIO_PIPE(pipe, _PIPEA_PP_STATUS, _PIPEB_PP_STATUS)
-#define VLV_PIPE_PP_CONTROL(pipe)      _MMIO_PIPE(pipe, _PIPEA_PP_CONTROL, _PIPEB_PP_CONTROL)
-#define VLV_PIPE_PP_ON_DELAYS(pipe)    _MMIO_PIPE(pipe, _PIPEA_PP_ON_DELAYS, _PIPEB_PP_ON_DELAYS)
-#define VLV_PIPE_PP_OFF_DELAYS(pipe)   _MMIO_PIPE(pipe, _PIPEA_PP_OFF_DELAYS, _PIPEB_PP_OFF_DELAYS)
-#define VLV_PIPE_PP_DIVISOR(pipe)      _MMIO_PIPE(pipe, _PIPEA_PP_DIVISOR, _PIPEB_PP_DIVISOR)
-
-#define _PCH_PP_STATUS         0xc7200
-#define _PCH_PP_CONTROL                0xc7204
-#define  PANEL_UNLOCK_REGS     (0xabcd << 16)
-#define  PANEL_UNLOCK_MASK     (0xffff << 16)
-#define  BXT_POWER_CYCLE_DELAY_MASK    (0x1f0)
-#define  BXT_POWER_CYCLE_DELAY_SHIFT   4
-#define  EDP_FORCE_VDD         (1 << 3)
-#define  EDP_BLC_ENABLE                (1 << 2)
-#define  PANEL_POWER_RESET     (1 << 1)
-#define  PANEL_POWER_OFF       (0 << 0)
-#define  PANEL_POWER_ON                (1 << 0)
-#define _PCH_PP_ON_DELAYS      0xc7208
-#define  PANEL_PORT_SELECT_MASK        (3 << 30)
-#define  PANEL_PORT_SELECT_LVDS        (0 << 30)
-#define  PANEL_PORT_SELECT_DPA (1 << 30)
-#define  PANEL_PORT_SELECT_DPC (2 << 30)
-#define  PANEL_PORT_SELECT_DPD (3 << 30)
-#define  PANEL_POWER_UP_DELAY_MASK     (0x1fff0000)
-#define  PANEL_POWER_UP_DELAY_SHIFT    16
-#define  PANEL_LIGHT_ON_DELAY_MASK     (0x1fff)
-#define  PANEL_LIGHT_ON_DELAY_SHIFT    0
-
-#define _PCH_PP_OFF_DELAYS             0xc720c
-#define  PANEL_POWER_DOWN_DELAY_MASK   (0x1fff0000)
-#define  PANEL_POWER_DOWN_DELAY_SHIFT  16
-#define  PANEL_LIGHT_OFF_DELAY_MASK    (0x1fff)
-#define  PANEL_LIGHT_OFF_DELAY_SHIFT   0
-
-#define _PCH_PP_DIVISOR                        0xc7210
-#define  PP_REFERENCE_DIVIDER_MASK     (0xffffff00)
-#define  PP_REFERENCE_DIVIDER_SHIFT    8
-#define  PANEL_POWER_CYCLE_DELAY_MASK  (0x1f)
-#define  PANEL_POWER_CYCLE_DELAY_SHIFT 0
-
-#define PCH_PP_STATUS                  _MMIO(_PCH_PP_STATUS)
-#define PCH_PP_CONTROL                 _MMIO(_PCH_PP_CONTROL)
-#define PCH_PP_ON_DELAYS               _MMIO(_PCH_PP_ON_DELAYS)
-#define PCH_PP_OFF_DELAYS              _MMIO(_PCH_PP_OFF_DELAYS)
-#define PCH_PP_DIVISOR                 _MMIO(_PCH_PP_DIVISOR)
-
-/* BXT PPS changes - 2nd set of PPS registers */
-#define _BXT_PP_STATUS2        0xc7300
-#define _BXT_PP_CONTROL2       0xc7304
-#define _BXT_PP_ON_DELAYS2     0xc7308
-#define _BXT_PP_OFF_DELAYS2    0xc730c
-
-#define BXT_PP_STATUS(n)       _MMIO_PIPE(n, _PCH_PP_STATUS, _BXT_PP_STATUS2)
-#define BXT_PP_CONTROL(n)      _MMIO_PIPE(n, _PCH_PP_CONTROL, _BXT_PP_CONTROL2)
-#define BXT_PP_ON_DELAYS(n)    _MMIO_PIPE(n, _PCH_PP_ON_DELAYS, _BXT_PP_ON_DELAYS2)
-#define BXT_PP_OFF_DELAYS(n)   _MMIO_PIPE(n, _PCH_PP_OFF_DELAYS, _BXT_PP_OFF_DELAYS2)
-
 #define _PCH_DP_B              0xe4100
 #define PCH_DP_B               _MMIO(_PCH_DP_B)
 #define _PCH_DPB_AUX_CH_CTL    0xe4110
@@ -6959,6 +6933,9 @@ enum {
 #define  ECOBUS                                        _MMIO(0xa180)
 #define    FORCEWAKE_MT_ENABLE                 (1<<5)
 #define  VLV_SPAREG2H                          _MMIO(0xA194)
+#define  GEN9_PWRGT_DOMAIN_STATUS              _MMIO(0xA2A0)
+#define   GEN9_PWRGT_MEDIA_STATUS_MASK         (1 << 0)
+#define   GEN9_PWRGT_RENDER_STATUS_MASK                (1 << 1)
 
 #define  GTFIFODBG                             _MMIO(0x120000)
 #define    GT_FIFO_SBDEDICATE_FREE_ENTRY_CHV   (0x1f << 20)
@@ -7059,12 +7036,13 @@ enum {
 #define GEN6_RP_UP_THRESHOLD                   _MMIO(0xA02C)
 #define GEN6_RP_DOWN_THRESHOLD                 _MMIO(0xA030)
 #define GEN6_RP_CUR_UP_EI                      _MMIO(0xA050)
-#define   GEN6_CURICONT_MASK                   0xffffff
+#define   GEN6_RP_EI_MASK                      0xffffff
+#define   GEN6_CURICONT_MASK                   GEN6_RP_EI_MASK
 #define GEN6_RP_CUR_UP                         _MMIO(0xA054)
-#define   GEN6_CURBSYTAVG_MASK                 0xffffff
+#define   GEN6_CURBSYTAVG_MASK                 GEN6_RP_EI_MASK
 #define GEN6_RP_PREV_UP                                _MMIO(0xA058)
 #define GEN6_RP_CUR_DOWN_EI                    _MMIO(0xA05C)
-#define   GEN6_CURIAVG_MASK                    0xffffff
+#define   GEN6_CURIAVG_MASK                    GEN6_RP_EI_MASK
 #define GEN6_RP_CUR_DOWN                       _MMIO(0xA060)
 #define GEN6_RP_PREV_DOWN                      _MMIO(0xA064)
 #define GEN6_RP_UP_EI                          _MMIO(0xA068)
@@ -7089,7 +7067,7 @@ enum {
 #define VLV_RCEDATA                            _MMIO(0xA0BC)
 #define GEN6_RC6pp_THRESHOLD                   _MMIO(0xA0C0)
 #define GEN6_PMINTRMSK                         _MMIO(0xA168)
-#define   GEN8_PMINTR_REDIRECT_TO_NON_DISP     (1<<31)
+#define   GEN8_PMINTR_REDIRECT_TO_GUC            (1<<31)
 #define GEN8_MISC_CTRL0                                _MMIO(0xA180)
 #define VLV_PWRDWNUPCTL                                _MMIO(0xA294)
 #define GEN9_MEDIA_PG_IDLE_HYSTERESIS          _MMIO(0xA0C4)
@@ -7499,6 +7477,7 @@ enum {
 #define _DDI_BUF_TRANS_A               0x64E00
 #define _DDI_BUF_TRANS_B               0x64E60
 #define DDI_BUF_TRANS_LO(port, i)      _MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8)
+#define  DDI_BUF_BALANCE_LEG_ENABLE    (1 << 31)
 #define DDI_BUF_TRANS_HI(port, i)      _MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8 + 4)
 
 /* Sideband Interface (SBI) is programmed indirectly, via
index 5cfe4c7..a0af170 100644 (file)
@@ -37,25 +37,6 @@ static void i915_save_display(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen <= 4)
                dev_priv->regfile.saveDSPARB = I915_READ(DSPARB);
 
-       /* LVDS state */
-       if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
-               dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS);
-       else if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev))
-               dev_priv->regfile.saveLVDS = I915_READ(LVDS);
-
-       /* Panel power sequencer */
-       if (HAS_PCH_SPLIT(dev)) {
-               dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL);
-               dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS);
-               dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS);
-               dev_priv->regfile.savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR);
-       } else if (INTEL_INFO(dev)->gen <= 4) {
-               dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
-               dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS);
-               dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
-               dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR);
-       }
-
        /* save FBC interval */
        if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
                dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL);
@@ -64,33 +45,11 @@ static void i915_save_display(struct drm_device *dev)
 static void i915_restore_display(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 mask = 0xffffffff;
 
        /* Display arbitration */
        if (INTEL_INFO(dev)->gen <= 4)
                I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB);
 
-       mask = ~LVDS_PORT_EN;
-
-       /* LVDS state */
-       if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
-               I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS & mask);
-       else if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev))
-               I915_WRITE(LVDS, dev_priv->regfile.saveLVDS & mask);
-
-       /* Panel power sequencer */
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS);
-               I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
-               I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR);
-               I915_WRITE(PCH_PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
-       } else if (INTEL_INFO(dev)->gen <= 4) {
-               I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS);
-               I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
-               I915_WRITE(PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR);
-               I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
-       }
-
        /* only restore FBC info on the platform that supports FBC*/
        intel_fbc_global_disable(dev_priv);
 
@@ -104,6 +63,7 @@ static void i915_restore_display(struct drm_device *dev)
 int i915_save_state(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        int i;
 
        mutex_lock(&dev->struct_mutex);
@@ -111,7 +71,7 @@ int i915_save_state(struct drm_device *dev)
        i915_save_display(dev);
 
        if (IS_GEN4(dev))
-               pci_read_config_word(dev->pdev, GCDGMBUS,
+               pci_read_config_word(pdev, GCDGMBUS,
                                     &dev_priv->regfile.saveGCDGMBUS);
 
        /* Cache mode state */
@@ -149,6 +109,7 @@ int i915_save_state(struct drm_device *dev)
 int i915_restore_state(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        int i;
 
        mutex_lock(&dev->struct_mutex);
@@ -156,7 +117,7 @@ int i915_restore_state(struct drm_device *dev)
        i915_gem_restore_fences(dev);
 
        if (IS_GEN4(dev))
-               pci_write_config_word(dev->pdev, GCDGMBUS,
+               pci_write_config_word(pdev, GCDGMBUS,
                                      dev_priv->regfile.saveGCDGMBUS);
        i915_restore_display(dev);
 
diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c
new file mode 100644 (file)
index 0000000..1e5cbc5
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * (C) Copyright 2016 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <linux/slab.h>
+#include <linux/fence.h>
+#include <linux/reservation.h>
+
+#include "i915_sw_fence.h"
+
+static DEFINE_SPINLOCK(i915_sw_fence_lock);
+
+static int __i915_sw_fence_notify(struct i915_sw_fence *fence,
+                                 enum i915_sw_fence_notify state)
+{
+       i915_sw_fence_notify_t fn;
+
+       fn = (i915_sw_fence_notify_t)(fence->flags & I915_SW_FENCE_MASK);
+       return fn(fence, state);
+}
+
+static void i915_sw_fence_free(struct kref *kref)
+{
+       struct i915_sw_fence *fence = container_of(kref, typeof(*fence), kref);
+
+       WARN_ON(atomic_read(&fence->pending) > 0);
+
+       if (fence->flags & I915_SW_FENCE_MASK)
+               __i915_sw_fence_notify(fence, FENCE_FREE);
+       else
+               kfree(fence);
+}
+
+static void i915_sw_fence_put(struct i915_sw_fence *fence)
+{
+       kref_put(&fence->kref, i915_sw_fence_free);
+}
+
+static struct i915_sw_fence *i915_sw_fence_get(struct i915_sw_fence *fence)
+{
+       kref_get(&fence->kref);
+       return fence;
+}
+
+static void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence,
+                                       struct list_head *continuation)
+{
+       wait_queue_head_t *x = &fence->wait;
+       wait_queue_t *pos, *next;
+       unsigned long flags;
+
+       atomic_set_release(&fence->pending, -1); /* 0 -> -1 [done] */
+
+       /*
+        * To prevent unbounded recursion as we traverse the graph of
+        * i915_sw_fences, we move the task_list from this, the next ready
+        * fence, to the tail of the original fence's task_list
+        * (and so added to the list to be woken).
+        */
+
+       spin_lock_irqsave_nested(&x->lock, flags, 1 + !!continuation);
+       if (continuation) {
+               list_for_each_entry_safe(pos, next, &x->task_list, task_list) {
+                       if (pos->func == autoremove_wake_function)
+                               pos->func(pos, TASK_NORMAL, 0, continuation);
+                       else
+                               list_move_tail(&pos->task_list, continuation);
+               }
+       } else {
+               LIST_HEAD(extra);
+
+               do {
+                       list_for_each_entry_safe(pos, next,
+                                                &x->task_list, task_list)
+                               pos->func(pos, TASK_NORMAL, 0, &extra);
+
+                       if (list_empty(&extra))
+                               break;
+
+                       list_splice_tail_init(&extra, &x->task_list);
+               } while (1);
+       }
+       spin_unlock_irqrestore(&x->lock, flags);
+}
+
+static void __i915_sw_fence_complete(struct i915_sw_fence *fence,
+                                    struct list_head *continuation)
+{
+       if (!atomic_dec_and_test(&fence->pending))
+               return;
+
+       if (fence->flags & I915_SW_FENCE_MASK &&
+           __i915_sw_fence_notify(fence, FENCE_COMPLETE) != NOTIFY_DONE)
+               return;
+
+       __i915_sw_fence_wake_up_all(fence, continuation);
+}
+
+static void i915_sw_fence_complete(struct i915_sw_fence *fence)
+{
+       if (WARN_ON(i915_sw_fence_done(fence)))
+               return;
+
+       __i915_sw_fence_complete(fence, NULL);
+}
+
+static void i915_sw_fence_await(struct i915_sw_fence *fence)
+{
+       WARN_ON(atomic_inc_return(&fence->pending) <= 1);
+}
+
+void i915_sw_fence_init(struct i915_sw_fence *fence, i915_sw_fence_notify_t fn)
+{
+       BUG_ON((unsigned long)fn & ~I915_SW_FENCE_MASK);
+
+       init_waitqueue_head(&fence->wait);
+       kref_init(&fence->kref);
+       atomic_set(&fence->pending, 1);
+       fence->flags = (unsigned long)fn;
+}
+
+void i915_sw_fence_commit(struct i915_sw_fence *fence)
+{
+       i915_sw_fence_complete(fence);
+       i915_sw_fence_put(fence);
+}
+
+static int i915_sw_fence_wake(wait_queue_t *wq, unsigned mode, int flags, void *key)
+{
+       list_del(&wq->task_list);
+       __i915_sw_fence_complete(wq->private, key);
+       i915_sw_fence_put(wq->private);
+       return 0;
+}
+
+static bool __i915_sw_fence_check_if_after(struct i915_sw_fence *fence,
+                                   const struct i915_sw_fence * const signaler)
+{
+       wait_queue_t *wq;
+
+       if (__test_and_set_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags))
+               return false;
+
+       if (fence == signaler)
+               return true;
+
+       list_for_each_entry(wq, &fence->wait.task_list, task_list) {
+               if (wq->func != i915_sw_fence_wake)
+                       continue;
+
+               if (__i915_sw_fence_check_if_after(wq->private, signaler))
+                       return true;
+       }
+
+       return false;
+}
+
+static void __i915_sw_fence_clear_checked_bit(struct i915_sw_fence *fence)
+{
+       wait_queue_t *wq;
+
+       if (!__test_and_clear_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags))
+               return;
+
+       list_for_each_entry(wq, &fence->wait.task_list, task_list) {
+               if (wq->func != i915_sw_fence_wake)
+                       continue;
+
+               __i915_sw_fence_clear_checked_bit(wq->private);
+       }
+}
+
+static bool i915_sw_fence_check_if_after(struct i915_sw_fence *fence,
+                                 const struct i915_sw_fence * const signaler)
+{
+       unsigned long flags;
+       bool err;
+
+       if (!IS_ENABLED(CONFIG_I915_SW_FENCE_CHECK_DAG))
+               return false;
+
+       spin_lock_irqsave(&i915_sw_fence_lock, flags);
+       err = __i915_sw_fence_check_if_after(fence, signaler);
+       __i915_sw_fence_clear_checked_bit(fence);
+       spin_unlock_irqrestore(&i915_sw_fence_lock, flags);
+
+       return err;
+}
+
+int i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
+                                struct i915_sw_fence *signaler,
+                                wait_queue_t *wq)
+{
+       unsigned long flags;
+       int pending;
+
+       if (i915_sw_fence_done(signaler))
+               return 0;
+
+       /* The dependency graph must be acyclic. */
+       if (unlikely(i915_sw_fence_check_if_after(fence, signaler)))
+               return -EINVAL;
+
+       INIT_LIST_HEAD(&wq->task_list);
+       wq->flags = 0;
+       wq->func = i915_sw_fence_wake;
+       wq->private = i915_sw_fence_get(fence);
+
+       i915_sw_fence_await(fence);
+
+       spin_lock_irqsave(&signaler->wait.lock, flags);
+       if (likely(!i915_sw_fence_done(signaler))) {
+               __add_wait_queue_tail(&signaler->wait, wq);
+               pending = 1;
+       } else {
+               i915_sw_fence_wake(wq, 0, 0, NULL);
+               pending = 0;
+       }
+       spin_unlock_irqrestore(&signaler->wait.lock, flags);
+
+       return pending;
+}
+
+struct dma_fence_cb {
+       struct fence_cb base;
+       struct i915_sw_fence *fence;
+       struct fence *dma;
+       struct timer_list timer;
+};
+
+static void timer_i915_sw_fence_wake(unsigned long data)
+{
+       struct dma_fence_cb *cb = (struct dma_fence_cb *)data;
+
+       printk(KERN_WARNING "asynchronous wait on fence %s:%s:%x timed out\n",
+              cb->dma->ops->get_driver_name(cb->dma),
+              cb->dma->ops->get_timeline_name(cb->dma),
+              cb->dma->seqno);
+       fence_put(cb->dma);
+       cb->dma = NULL;
+
+       i915_sw_fence_commit(cb->fence);
+       cb->timer.function = NULL;
+}
+
+static void dma_i915_sw_fence_wake(struct fence *dma, struct fence_cb *data)
+{
+       struct dma_fence_cb *cb = container_of(data, typeof(*cb), base);
+
+       del_timer_sync(&cb->timer);
+       if (cb->timer.function)
+               i915_sw_fence_commit(cb->fence);
+       fence_put(cb->dma);
+
+       kfree(cb);
+}
+
+int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
+                                 struct fence *dma,
+                                 unsigned long timeout,
+                                 gfp_t gfp)
+{
+       struct dma_fence_cb *cb;
+       int ret;
+
+       if (fence_is_signaled(dma))
+               return 0;
+
+       cb = kmalloc(sizeof(*cb), gfp);
+       if (!cb) {
+               if (!gfpflags_allow_blocking(gfp))
+                       return -ENOMEM;
+
+               return fence_wait(dma, false);
+       }
+
+       cb->fence = i915_sw_fence_get(fence);
+       i915_sw_fence_await(fence);
+
+       cb->dma = NULL;
+       __setup_timer(&cb->timer,
+                     timer_i915_sw_fence_wake, (unsigned long)cb,
+                     TIMER_IRQSAFE);
+       if (timeout) {
+               cb->dma = fence_get(dma);
+               mod_timer(&cb->timer, round_jiffies_up(jiffies + timeout));
+       }
+
+       ret = fence_add_callback(dma, &cb->base, dma_i915_sw_fence_wake);
+       if (ret == 0) {
+               ret = 1;
+       } else {
+               dma_i915_sw_fence_wake(dma, &cb->base);
+               if (ret == -ENOENT) /* fence already signaled */
+                       ret = 0;
+       }
+
+       return ret;
+}
+
+int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
+                                   struct reservation_object *resv,
+                                   const struct fence_ops *exclude,
+                                   bool write,
+                                   unsigned long timeout,
+                                   gfp_t gfp)
+{
+       struct fence *excl;
+       int ret = 0, pending;
+
+       if (write) {
+               struct fence **shared;
+               unsigned int count, i;
+
+               ret = reservation_object_get_fences_rcu(resv,
+                                                       &excl, &count, &shared);
+               if (ret)
+                       return ret;
+
+               for (i = 0; i < count; i++) {
+                       if (shared[i]->ops == exclude)
+                               continue;
+
+                       pending = i915_sw_fence_await_dma_fence(fence,
+                                                               shared[i],
+                                                               timeout,
+                                                               gfp);
+                       if (pending < 0) {
+                               ret = pending;
+                               break;
+                       }
+
+                       ret |= pending;
+               }
+
+               for (i = 0; i < count; i++)
+                       fence_put(shared[i]);
+               kfree(shared);
+       } else {
+               excl = reservation_object_get_excl_rcu(resv);
+       }
+
+       if (ret >= 0 && excl && excl->ops != exclude) {
+               pending = i915_sw_fence_await_dma_fence(fence,
+                                                       excl,
+                                                       timeout,
+                                                       gfp);
+               if (pending < 0)
+                       ret = pending;
+               else
+                       ret |= pending;
+       }
+
+       fence_put(excl);
+
+       return ret;
+}
diff --git a/drivers/gpu/drm/i915/i915_sw_fence.h b/drivers/gpu/drm/i915/i915_sw_fence.h
new file mode 100644 (file)
index 0000000..3731416
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * i915_sw_fence.h - library routines for N:M synchronisation points
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#ifndef _I915_SW_FENCE_H_
+#define _I915_SW_FENCE_H_
+
+#include <linux/gfp.h>
+#include <linux/kref.h>
+#include <linux/notifier.h> /* for NOTIFY_DONE */
+#include <linux/wait.h>
+
+struct completion;
+struct fence;
+struct fence_ops;
+struct reservation_object;
+
+struct i915_sw_fence {
+       wait_queue_head_t wait;
+       unsigned long flags;
+       struct kref kref;
+       atomic_t pending;
+};
+
+#define I915_SW_FENCE_CHECKED_BIT      0 /* used internally for DAG checking */
+#define I915_SW_FENCE_PRIVATE_BIT      1 /* available for use by owner */
+#define I915_SW_FENCE_MASK             (~3)
+
+enum i915_sw_fence_notify {
+       FENCE_COMPLETE,
+       FENCE_FREE
+};
+
+typedef int (*i915_sw_fence_notify_t)(struct i915_sw_fence *,
+                                     enum i915_sw_fence_notify state);
+#define __i915_sw_fence_call __aligned(4)
+
+void i915_sw_fence_init(struct i915_sw_fence *fence, i915_sw_fence_notify_t fn);
+void i915_sw_fence_commit(struct i915_sw_fence *fence);
+
+int i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
+                                struct i915_sw_fence *after,
+                                wait_queue_t *wq);
+int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
+                                 struct fence *dma,
+                                 unsigned long timeout,
+                                 gfp_t gfp);
+int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
+                                   struct reservation_object *resv,
+                                   const struct fence_ops *exclude,
+                                   bool write,
+                                   unsigned long timeout,
+                                   gfp_t gfp);
+
+static inline bool i915_sw_fence_done(const struct i915_sw_fence *fence)
+{
+       return atomic_read(&fence->pending) < 0;
+}
+
+#endif /* _I915_SW_FENCE_H_ */
index d61829e..1012eee 100644 (file)
 #include "intel_drv.h"
 #include "i915_drv.h"
 
-#define dev_to_drm_minor(d) dev_get_drvdata((d))
+static inline struct drm_i915_private *kdev_minor_to_i915(struct device *kdev)
+{
+       struct drm_minor *minor = dev_get_drvdata(kdev);
+       return to_i915(minor->dev);
+}
 
 #ifdef CONFIG_PM
-static u32 calc_residency(struct drm_device *dev,
+static u32 calc_residency(struct drm_i915_private *dev_priv,
                          i915_reg_t reg)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u64 raw_time; /* 32b value may overflow during fixed point math */
        u64 units = 128ULL, div = 100000ULL;
        u32 ret;
@@ -49,13 +52,13 @@ static u32 calc_residency(struct drm_device *dev,
        intel_runtime_pm_get(dev_priv);
 
        /* On VLV and CHV, residency time is in CZ units rather than 1.28us */
-       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
                units = 1;
                div = dev_priv->czclk_freq;
 
                if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
                        units <<= 8;
-       } else if (IS_BROXTON(dev)) {
+       } else if (IS_BROXTON(dev_priv)) {
                units = 1;
                div = 1200;             /* 833.33ns */
        }
@@ -76,32 +79,32 @@ show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf)
 static ssize_t
 show_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *dminor = dev_get_drvdata(kdev);
-       u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+       u32 rc6_residency = calc_residency(dev_priv, GEN6_GT_GFX_RC6);
        return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency);
 }
 
 static ssize_t
 show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *dminor = dev_to_drm_minor(kdev);
-       u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+       u32 rc6p_residency = calc_residency(dev_priv, GEN6_GT_GFX_RC6p);
        return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency);
 }
 
 static ssize_t
 show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *dminor = dev_to_drm_minor(kdev);
-       u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+       u32 rc6pp_residency = calc_residency(dev_priv, GEN6_GT_GFX_RC6pp);
        return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency);
 }
 
 static ssize_t
 show_media_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *dminor = dev_get_drvdata(kdev);
-       u32 rc6_residency = calc_residency(dminor->dev, VLV_GT_MEDIA_RC6);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+       u32 rc6_residency = calc_residency(dev_priv, VLV_GT_MEDIA_RC6);
        return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency);
 }
 
@@ -144,9 +147,9 @@ static struct attribute_group media_rc6_attr_group = {
 };
 #endif
 
-static int l3_access_valid(struct drm_device *dev, loff_t offset)
+static int l3_access_valid(struct drm_i915_private *dev_priv, loff_t offset)
 {
-       if (!HAS_L3_DPF(dev))
+       if (!HAS_L3_DPF(dev_priv))
                return -EPERM;
 
        if (offset % 4 != 0)
@@ -163,22 +166,21 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
             struct bin_attribute *attr, char *buf,
             loff_t offset, size_t count)
 {
-       struct device *dev = kobj_to_dev(kobj);
-       struct drm_minor *dminor = dev_to_drm_minor(dev);
-       struct drm_device *drm_dev = dminor->dev;
-       struct drm_i915_private *dev_priv = to_i915(drm_dev);
+       struct device *kdev = kobj_to_dev(kobj);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+       struct drm_device *dev = &dev_priv->drm;
        int slice = (int)(uintptr_t)attr->private;
        int ret;
 
        count = round_down(count, 4);
 
-       ret = l3_access_valid(drm_dev, offset);
+       ret = l3_access_valid(dev_priv, offset);
        if (ret)
                return ret;
 
        count = min_t(size_t, GEN7_L3LOG_SIZE - offset, count);
 
-       ret = i915_mutex_lock_interruptible(drm_dev);
+       ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                return ret;
 
@@ -189,7 +191,7 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
        else
                memset(buf, 0, count);
 
-       mutex_unlock(&drm_dev->struct_mutex);
+       mutex_unlock(&dev->struct_mutex);
 
        return count;
 }
@@ -199,30 +201,29 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
              struct bin_attribute *attr, char *buf,
              loff_t offset, size_t count)
 {
-       struct device *dev = kobj_to_dev(kobj);
-       struct drm_minor *dminor = dev_to_drm_minor(dev);
-       struct drm_device *drm_dev = dminor->dev;
-       struct drm_i915_private *dev_priv = to_i915(drm_dev);
+       struct device *kdev = kobj_to_dev(kobj);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+       struct drm_device *dev = &dev_priv->drm;
        struct i915_gem_context *ctx;
        u32 *temp = NULL; /* Just here to make handling failures easy */
        int slice = (int)(uintptr_t)attr->private;
        int ret;
 
-       if (!HAS_HW_CONTEXTS(drm_dev))
+       if (!HAS_HW_CONTEXTS(dev_priv))
                return -ENXIO;
 
-       ret = l3_access_valid(drm_dev, offset);
+       ret = l3_access_valid(dev_priv, offset);
        if (ret)
                return ret;
 
-       ret = i915_mutex_lock_interruptible(drm_dev);
+       ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                return ret;
 
        if (!dev_priv->l3_parity.remap_info[slice]) {
                temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
                if (!temp) {
-                       mutex_unlock(&drm_dev->struct_mutex);
+                       mutex_unlock(&dev->struct_mutex);
                        return -ENOMEM;
                }
        }
@@ -240,7 +241,7 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
        list_for_each_entry(ctx, &dev_priv->context_list, link)
                ctx->remap_slice |= (1<<slice);
 
-       mutex_unlock(&drm_dev->struct_mutex);
+       mutex_unlock(&dev->struct_mutex);
 
        return count;
 }
@@ -266,13 +267,9 @@ static struct bin_attribute dpf_attrs_1 = {
 static ssize_t gt_act_freq_mhz_show(struct device *kdev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
        int ret;
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
        intel_runtime_pm_get(dev_priv);
 
        mutex_lock(&dev_priv->rps.hw_lock);
@@ -300,59 +297,70 @@ static ssize_t gt_act_freq_mhz_show(struct device *kdev,
 static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret;
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       intel_gpu_freq(dev_priv,
+                                      dev_priv->rps.cur_freq));
+}
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+static ssize_t gt_boost_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
+{
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
 
-       intel_runtime_pm_get(dev_priv);
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       intel_gpu_freq(dev_priv,
+                                      dev_priv->rps.boost_freq));
+}
+
+static ssize_t gt_boost_freq_mhz_store(struct device *kdev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+       u32 val;
+       ssize_t ret;
+
+       ret = kstrtou32(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       /* Validate against (static) hardware limits */
+       val = intel_freq_opcode(dev_priv, val);
+       if (val < dev_priv->rps.min_freq || val > dev_priv->rps.max_freq)
+               return -EINVAL;
 
        mutex_lock(&dev_priv->rps.hw_lock);
-       ret = intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq);
+       dev_priv->rps.boost_freq = val;
        mutex_unlock(&dev_priv->rps.hw_lock);
 
-       intel_runtime_pm_put(dev_priv);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return count;
 }
 
 static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
 
-       return snprintf(buf, PAGE_SIZE,
-                       "%d\n",
-                       intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       intel_gpu_freq(dev_priv,
+                                      dev_priv->rps.efficient_freq));
 }
 
 static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret;
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
-       mutex_lock(&dev_priv->rps.hw_lock);
-       ret = intel_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
-       mutex_unlock(&dev_priv->rps.hw_lock);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       intel_gpu_freq(dev_priv,
+                                      dev_priv->rps.max_freq_softlimit));
 }
 
 static ssize_t gt_max_freq_mhz_store(struct device *kdev,
                                     struct device_attribute *attr,
                                     const char *buf, size_t count)
 {
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
        u32 val;
        ssize_t ret;
 
@@ -360,8 +368,6 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
        if (ret)
                return ret;
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
        intel_runtime_pm_get(dev_priv);
 
        mutex_lock(&dev_priv->rps.hw_lock);
@@ -400,27 +406,18 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
 
 static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret;
-
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
 
-       mutex_lock(&dev_priv->rps.hw_lock);
-       ret = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
-       mutex_unlock(&dev_priv->rps.hw_lock);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", ret);
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       intel_gpu_freq(dev_priv,
+                                      dev_priv->rps.min_freq_softlimit));
 }
 
 static ssize_t gt_min_freq_mhz_store(struct device *kdev,
                                     struct device_attribute *attr,
                                     const char *buf, size_t count)
 {
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
        u32 val;
        ssize_t ret;
 
@@ -428,8 +425,6 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
        if (ret)
                return ret;
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
        intel_runtime_pm_get(dev_priv);
 
        mutex_lock(&dev_priv->rps.hw_lock);
@@ -465,6 +460,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
 
 static DEVICE_ATTR(gt_act_freq_mhz, S_IRUGO, gt_act_freq_mhz_show, NULL);
 static DEVICE_ATTR(gt_cur_freq_mhz, S_IRUGO, gt_cur_freq_mhz_show, NULL);
+static DEVICE_ATTR(gt_boost_freq_mhz, S_IRUGO, gt_boost_freq_mhz_show, gt_boost_freq_mhz_store);
 static DEVICE_ATTR(gt_max_freq_mhz, S_IRUGO | S_IWUSR, gt_max_freq_mhz_show, gt_max_freq_mhz_store);
 static DEVICE_ATTR(gt_min_freq_mhz, S_IRUGO | S_IWUSR, gt_min_freq_mhz_show, gt_min_freq_mhz_store);
 
@@ -478,9 +474,7 @@ static DEVICE_ATTR(gt_RPn_freq_mhz, S_IRUGO, gt_rp_mhz_show, NULL);
 /* For now we have a static number of RP states */
 static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
 {
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
        u32 val;
 
        if (attr == &dev_attr_gt_RP0_freq_mhz)
@@ -498,6 +492,7 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr
 static const struct attribute *gen6_attrs[] = {
        &dev_attr_gt_act_freq_mhz.attr,
        &dev_attr_gt_cur_freq_mhz.attr,
+       &dev_attr_gt_boost_freq_mhz.attr,
        &dev_attr_gt_max_freq_mhz.attr,
        &dev_attr_gt_min_freq_mhz.attr,
        &dev_attr_gt_RP0_freq_mhz.attr,
@@ -509,6 +504,7 @@ static const struct attribute *gen6_attrs[] = {
 static const struct attribute *vlv_attrs[] = {
        &dev_attr_gt_act_freq_mhz.attr,
        &dev_attr_gt_cur_freq_mhz.attr,
+       &dev_attr_gt_boost_freq_mhz.attr,
        &dev_attr_gt_max_freq_mhz.attr,
        &dev_attr_gt_min_freq_mhz.attr,
        &dev_attr_gt_RP0_freq_mhz.attr,
@@ -524,8 +520,8 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
 {
 
        struct device *kdev = kobj_to_dev(kobj);
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+       struct drm_device *dev = &dev_priv->drm;
        struct i915_error_state_file_priv error_priv;
        struct drm_i915_error_state_buf error_str;
        ssize_t ret_count = 0;
@@ -559,18 +555,10 @@ static ssize_t error_state_write(struct file *file, struct kobject *kobj,
                                 loff_t off, size_t count)
 {
        struct device *kdev = kobj_to_dev(kobj);
-       struct drm_minor *minor = dev_to_drm_minor(kdev);
-       struct drm_device *dev = minor->dev;
-       int ret;
+       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
 
        DRM_DEBUG_DRIVER("Resetting error state\n");
-
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
-
-       i915_destroy_error_state(dev);
-       mutex_unlock(&dev->struct_mutex);
+       i915_destroy_error_state(&dev_priv->drm);
 
        return count;
 }
@@ -583,37 +571,38 @@ static struct bin_attribute error_state_attr = {
        .write = error_state_write,
 };
 
-void i915_setup_sysfs(struct drm_device *dev)
+void i915_setup_sysfs(struct drm_i915_private *dev_priv)
 {
+       struct device *kdev = dev_priv->drm.primary->kdev;
        int ret;
 
 #ifdef CONFIG_PM
-       if (HAS_RC6(dev)) {
-               ret = sysfs_merge_group(&dev->primary->kdev->kobj,
+       if (HAS_RC6(dev_priv)) {
+               ret = sysfs_merge_group(&kdev->kobj,
                                        &rc6_attr_group);
                if (ret)
                        DRM_ERROR("RC6 residency sysfs setup failed\n");
        }
-       if (HAS_RC6p(dev)) {
-               ret = sysfs_merge_group(&dev->primary->kdev->kobj,
+       if (HAS_RC6p(dev_priv)) {
+               ret = sysfs_merge_group(&kdev->kobj,
                                        &rc6p_attr_group);
                if (ret)
                        DRM_ERROR("RC6p residency sysfs setup failed\n");
        }
-       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
-               ret = sysfs_merge_group(&dev->primary->kdev->kobj,
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               ret = sysfs_merge_group(&kdev->kobj,
                                        &media_rc6_attr_group);
                if (ret)
                        DRM_ERROR("Media RC6 residency sysfs setup failed\n");
        }
 #endif
-       if (HAS_L3_DPF(dev)) {
-               ret = device_create_bin_file(dev->primary->kdev, &dpf_attrs);
+       if (HAS_L3_DPF(dev_priv)) {
+               ret = device_create_bin_file(kdev, &dpf_attrs);
                if (ret)
                        DRM_ERROR("l3 parity sysfs setup failed\n");
 
-               if (NUM_L3_SLICES(dev) > 1) {
-                       ret = device_create_bin_file(dev->primary->kdev,
+               if (NUM_L3_SLICES(dev_priv) > 1) {
+                       ret = device_create_bin_file(kdev,
                                                     &dpf_attrs_1);
                        if (ret)
                                DRM_ERROR("l3 parity slice 1 setup failed\n");
@@ -621,30 +610,32 @@ void i915_setup_sysfs(struct drm_device *dev)
        }
 
        ret = 0;
-       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
-               ret = sysfs_create_files(&dev->primary->kdev->kobj, vlv_attrs);
-       else if (INTEL_INFO(dev)->gen >= 6)
-               ret = sysfs_create_files(&dev->primary->kdev->kobj, gen6_attrs);
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               ret = sysfs_create_files(&kdev->kobj, vlv_attrs);
+       else if (INTEL_GEN(dev_priv) >= 6)
+               ret = sysfs_create_files(&kdev->kobj, gen6_attrs);
        if (ret)
                DRM_ERROR("RPS sysfs setup failed\n");
 
-       ret = sysfs_create_bin_file(&dev->primary->kdev->kobj,
+       ret = sysfs_create_bin_file(&kdev->kobj,
                                    &error_state_attr);
        if (ret)
                DRM_ERROR("error_state sysfs setup failed\n");
 }
 
-void i915_teardown_sysfs(struct drm_device *dev)
+void i915_teardown_sysfs(struct drm_i915_private *dev_priv)
 {
-       sysfs_remove_bin_file(&dev->primary->kdev->kobj, &error_state_attr);
-       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
-               sysfs_remove_files(&dev->primary->kdev->kobj, vlv_attrs);
+       struct device *kdev = dev_priv->drm.primary->kdev;
+
+       sysfs_remove_bin_file(&kdev->kobj, &error_state_attr);
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               sysfs_remove_files(&kdev->kobj, vlv_attrs);
        else
-               sysfs_remove_files(&dev->primary->kdev->kobj, gen6_attrs);
-       device_remove_bin_file(dev->primary->kdev,  &dpf_attrs_1);
-       device_remove_bin_file(dev->primary->kdev,  &dpf_attrs);
+               sysfs_remove_files(&kdev->kobj, gen6_attrs);
+       device_remove_bin_file(kdev,  &dpf_attrs_1);
+       device_remove_bin_file(kdev,  &dpf_attrs);
 #ifdef CONFIG_PM
-       sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6_attr_group);
-       sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6p_attr_group);
+       sysfs_unmerge_group(&kdev->kobj, &rc6_attr_group);
+       sysfs_unmerge_group(&kdev->kobj, &rc6p_attr_group);
 #endif
 }
index 534154e..1787980 100644 (file)
@@ -394,25 +394,27 @@ DEFINE_EVENT(i915_gem_object, i915_gem_object_destroy,
 );
 
 TRACE_EVENT(i915_gem_evict,
-           TP_PROTO(struct drm_device *dev, u32 size, u32 align, unsigned flags),
-           TP_ARGS(dev, size, align, flags),
+           TP_PROTO(struct i915_address_space *vm, u32 size, u32 align, unsigned int flags),
+           TP_ARGS(vm, size, align, flags),
 
            TP_STRUCT__entry(
                             __field(u32, dev)
+                            __field(struct i915_address_space *, vm)
                             __field(u32, size)
                             __field(u32, align)
-                            __field(unsigned, flags)
+                            __field(unsigned int, flags)
                            ),
 
            TP_fast_assign(
-                          __entry->dev = dev->primary->index;
+                          __entry->dev = vm->dev->primary->index;
+                          __entry->vm = vm;
                           __entry->size = size;
                           __entry->align = align;
                           __entry->flags = flags;
                          ),
 
-           TP_printk("dev=%d, size=%d, align=%d %s",
-                     __entry->dev, __entry->size, __entry->align,
+           TP_printk("dev=%d, vm=%p, size=%d, align=%d %s",
+                     __entry->dev, __entry->vm, __entry->size, __entry->align,
                      __entry->flags & PIN_MAPPABLE ? ", mappable" : "")
 );
 
@@ -449,10 +451,9 @@ TRACE_EVENT(i915_gem_evict_vm,
 );
 
 TRACE_EVENT(i915_gem_ring_sync_to,
-           TP_PROTO(struct drm_i915_gem_request *to_req,
-                    struct intel_engine_cs *from,
-                    struct drm_i915_gem_request *req),
-           TP_ARGS(to_req, from, req),
+           TP_PROTO(struct drm_i915_gem_request *to,
+                    struct drm_i915_gem_request *from),
+           TP_ARGS(to, from),
 
            TP_STRUCT__entry(
                             __field(u32, dev)
@@ -463,9 +464,9 @@ TRACE_EVENT(i915_gem_ring_sync_to,
 
            TP_fast_assign(
                           __entry->dev = from->i915->drm.primary->index;
-                          __entry->sync_from = from->id;
-                          __entry->sync_to = to_req->engine->id;
-                          __entry->seqno = i915_gem_request_get_seqno(req);
+                          __entry->sync_from = from->engine->id;
+                          __entry->sync_to = to->engine->id;
+                          __entry->seqno = from->fence.seqno;
                           ),
 
            TP_printk("dev=%u, sync-from=%u, sync-to=%u, seqno=%u",
@@ -488,9 +489,9 @@ TRACE_EVENT(i915_gem_ring_dispatch,
            TP_fast_assign(
                           __entry->dev = req->i915->drm.primary->index;
                           __entry->ring = req->engine->id;
-                          __entry->seqno = req->seqno;
+                          __entry->seqno = req->fence.seqno;
                           __entry->flags = flags;
-                          intel_engine_enable_signaling(req);
+                          fence_enable_sw_signaling(&req->fence);
                           ),
 
            TP_printk("dev=%u, ring=%u, seqno=%u, flags=%x",
@@ -533,7 +534,7 @@ DECLARE_EVENT_CLASS(i915_gem_request,
            TP_fast_assign(
                           __entry->dev = req->i915->drm.primary->index;
                           __entry->ring = req->engine->id;
-                          __entry->seqno = req->seqno;
+                          __entry->seqno = req->fence.seqno;
                           ),
 
            TP_printk("dev=%u, ring=%u, seqno=%u",
@@ -595,7 +596,7 @@ TRACE_EVENT(i915_gem_request_wait_begin,
            TP_fast_assign(
                           __entry->dev = req->i915->drm.primary->index;
                           __entry->ring = req->engine->id;
-                          __entry->seqno = req->seqno;
+                          __entry->seqno = req->fence.seqno;
                           __entry->blocking =
                                     mutex_is_locked(&req->i915->drm.struct_mutex);
                           ),
index b81cfb3..dae340c 100644 (file)
@@ -94,6 +94,7 @@ static struct _balloon_info_ bl_info;
 
 /**
  * intel_vgt_deballoon - deballoon reserved graphics address trunks
+ * @dev_priv: i915 device private data
  *
  * This function is called to deallocate the ballooned-out graphic memory, when
  * driver is unloaded or when ballooning fails.
@@ -135,7 +136,7 @@ static int vgt_balloon_space(struct drm_mm *mm,
 
 /**
  * intel_vgt_balloon - balloon out reserved graphics address trunks
- * @dev: drm device
+ * @dev_priv: i915 device private data
  *
  * This function is called at the initialization stage, to balloon out the
  * graphic address space allocated to other vGPUs, by marking these spaces as
@@ -152,27 +153,27 @@ static int vgt_balloon_space(struct drm_mm *mm,
  * host point of view, the graphic address space is partitioned by multiple
  * vGPUs in different VMs. ::
  *
- *                        vGPU1 view         Host view
- *             0 ------> +-----------+     +-----------+
- *               ^       |###########|     |   vGPU3   |
- *               |       |###########|     +-----------+
- *               |       |###########|     |   vGPU2   |
- *               |       +-----------+     +-----------+
- *        mappable GM    | available | ==> |   vGPU1   |
- *               |       +-----------+     +-----------+
- *               |       |###########|     |           |
- *               v       |###########|     |   Host    |
- *               +=======+===========+     +===========+
- *               ^       |###########|     |   vGPU3   |
- *               |       |###########|     +-----------+
- *               |       |###########|     |   vGPU2   |
- *               |       +-----------+     +-----------+
- *      unmappable GM    | available | ==> |   vGPU1   |
- *               |       +-----------+     +-----------+
- *               |       |###########|     |           |
- *               |       |###########|     |   Host    |
- *               v       |###########|     |           |
- * total GM size ------> +-----------+     +-----------+
+ *                         vGPU1 view         Host view
+ *              0 ------> +-----------+     +-----------+
+ *                ^       |###########|     |   vGPU3   |
+ *                |       |###########|     +-----------+
+ *                |       |###########|     |   vGPU2   |
+ *                |       +-----------+     +-----------+
+ *         mappable GM    | available | ==> |   vGPU1   |
+ *                |       +-----------+     +-----------+
+ *                |       |###########|     |           |
+ *                v       |###########|     |   Host    |
+ *                +=======+===========+     +===========+
+ *                ^       |###########|     |   vGPU3   |
+ *                |       |###########|     +-----------+
+ *                |       |###########|     |   vGPU2   |
+ *                |       +-----------+     +-----------+
+ *       unmappable GM    | available | ==> |   vGPU1   |
+ *                |       +-----------+     +-----------+
+ *                |       |###########|     |           |
+ *                |       |###########|     |   Host    |
+ *                v       |###########|     |           |
+ *  total GM size ------> +-----------+     +-----------+
  *
  * Returns:
  * zero on success, non-zero if configuration invalid or ballooning failed
index 7de7721..b82de30 100644 (file)
@@ -55,7 +55,7 @@ intel_create_plane_state(struct drm_plane *plane)
                return NULL;
 
        state->base.plane = plane;
-       state->base.rotation = BIT(DRM_ROTATE_0);
+       state->base.rotation = DRM_ROTATE_0;
        state->ckey.flags = I915_SET_COLORKEY_NONE;
 
        return state;
@@ -134,20 +134,6 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
 
        crtc_state = to_intel_crtc_state(drm_crtc_state);
 
-       /*
-        * The original src/dest coordinates are stored in state->base, but
-        * we want to keep another copy internal to our driver that we can
-        * clip/modify ourselves.
-        */
-       intel_state->src.x1 = state->src_x;
-       intel_state->src.y1 = state->src_y;
-       intel_state->src.x2 = state->src_x + state->src_w;
-       intel_state->src.y2 = state->src_y + state->src_h;
-       intel_state->dst.x1 = state->crtc_x;
-       intel_state->dst.y1 = state->crtc_y;
-       intel_state->dst.x2 = state->crtc_x + state->crtc_w;
-       intel_state->dst.y2 = state->crtc_y + state->crtc_h;
-
        /* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
        intel_state->clip.x1 = 0;
        intel_state->clip.y1 = 0;
@@ -157,6 +143,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
                crtc_state->base.enable ? crtc_state->pipe_src_h : 0;
 
        if (state->fb && intel_rotation_90_or_270(state->rotation)) {
+               char *format_name;
                if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
                        state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) {
                        DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n");
@@ -171,8 +158,9 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
                switch (state->fb->pixel_format) {
                case DRM_FORMAT_C8:
                case DRM_FORMAT_RGB565:
-                       DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n",
-                                       drm_get_format_name(state->fb->pixel_format));
+                       format_name = drm_get_format_name(state->fb->pixel_format);
+                       DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n", format_name);
+                       kfree(format_name);
                        return -EINVAL;
 
                default:
@@ -180,7 +168,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
                }
        }
 
-       intel_state->visible = false;
+       intel_state->base.visible = false;
        ret = intel_plane->check_plane(plane, crtc_state, intel_state);
        if (ret)
                return ret;
@@ -196,7 +184,7 @@ static void intel_plane_atomic_update(struct drm_plane *plane,
                to_intel_plane_state(plane->state);
        struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
 
-       if (intel_state->visible)
+       if (intel_state->base.visible)
                intel_plane->update_plane(plane,
                                          to_intel_crtc_state(crtc->state),
                                          intel_state);
index d32f586..6c70a5b 100644 (file)
  * related registers. (The notable exception is the power management, not
  * covered here.)
  *
- * The struct i915_audio_component is used to interact between the graphics
- * and audio drivers. The struct i915_audio_component_ops *ops in it is
+ * The struct &i915_audio_component is used to interact between the graphics
+ * and audio drivers. The struct &i915_audio_component_ops @ops in it is
  * defined in graphics driver and called in audio driver. The
- * struct i915_audio_component_audio_ops *audio_ops is called from i915 driver.
+ * struct &i915_audio_component_audio_ops @audio_ops is called from i915 driver.
  */
 
 static const struct {
@@ -359,9 +359,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
-       struct intel_digital_port *intel_dig_port =
-               enc_to_dig_port(&encoder->base);
-       enum port port = intel_dig_port->port;
+       enum port port = enc_to_dig_port(&encoder->base)->port;
        enum pipe pipe = intel_crtc->pipe;
        uint32_t tmp, eldv;
        i915_reg_t aud_config, aud_cntrl_st2;
@@ -407,13 +405,10 @@ static void ilk_audio_codec_enable(struct drm_connector *connector,
 {
        struct drm_i915_private *dev_priv = to_i915(connector->dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
-       struct intel_digital_port *intel_dig_port =
-               enc_to_dig_port(&encoder->base);
-       enum port port = intel_dig_port->port;
+       enum port port = enc_to_dig_port(&encoder->base)->port;
        enum pipe pipe = intel_crtc->pipe;
        uint8_t *eld = connector->eld;
-       uint32_t eldv;
-       uint32_t tmp;
+       uint32_t tmp, eldv;
        int len, i;
        i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
 
@@ -581,26 +576,26 @@ void intel_init_audio_hooks(struct drm_i915_private *dev_priv)
        }
 }
 
-static void i915_audio_component_get_power(struct device *dev)
+static void i915_audio_component_get_power(struct device *kdev)
 {
-       intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
+       intel_display_power_get(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
 }
 
-static void i915_audio_component_put_power(struct device *dev)
+static void i915_audio_component_put_power(struct device *kdev)
 {
-       intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
+       intel_display_power_put(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
 }
 
-static void i915_audio_component_codec_wake_override(struct device *dev,
+static void i915_audio_component_codec_wake_override(struct device *kdev,
                                                     bool enable)
 {
-       struct drm_i915_private *dev_priv = dev_to_i915(dev);
+       struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
        u32 tmp;
 
        if (!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv))
                return;
 
-       i915_audio_component_get_power(dev);
+       i915_audio_component_get_power(kdev);
 
        /*
         * Enable/disable generating the codec wake signal, overriding the
@@ -618,13 +613,13 @@ static void i915_audio_component_codec_wake_override(struct device *dev,
                usleep_range(1000, 1500);
        }
 
-       i915_audio_component_put_power(dev);
+       i915_audio_component_put_power(kdev);
 }
 
 /* Get CDCLK in kHz  */
-static int i915_audio_component_get_cdclk_freq(struct device *dev)
+static int i915_audio_component_get_cdclk_freq(struct device *kdev)
 {
-       struct drm_i915_private *dev_priv = dev_to_i915(dev);
+       struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
 
        if (WARN_ON_ONCE(!HAS_DDI(dev_priv)))
                return -ENODEV;
@@ -632,10 +627,10 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
        return dev_priv->cdclk_freq;
 }
 
-static int i915_audio_component_sync_audio_rate(struct device *dev,
+static int i915_audio_component_sync_audio_rate(struct device *kdev,
                                                int port, int rate)
 {
-       struct drm_i915_private *dev_priv = dev_to_i915(dev);
+       struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
        struct intel_encoder *intel_encoder;
        struct intel_crtc *crtc;
        struct drm_display_mode *mode;
@@ -652,7 +647,7 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
            !IS_HASWELL(dev_priv))
                return 0;
 
-       i915_audio_component_get_power(dev);
+       i915_audio_component_get_power(kdev);
        mutex_lock(&dev_priv->av_mutex);
        /* 1. get the pipe */
        intel_encoder = dev_priv->dig_port_map[port];
@@ -703,15 +698,15 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
 
  unlock:
        mutex_unlock(&dev_priv->av_mutex);
-       i915_audio_component_put_power(dev);
+       i915_audio_component_put_power(kdev);
        return err;
 }
 
-static int i915_audio_component_get_eld(struct device *dev, int port,
+static int i915_audio_component_get_eld(struct device *kdev, int port,
                                        bool *enabled,
                                        unsigned char *buf, int max_bytes)
 {
-       struct drm_i915_private *dev_priv = dev_to_i915(dev);
+       struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
        struct intel_encoder *intel_encoder;
        struct intel_digital_port *intel_dig_port;
        const u8 *eld;
@@ -745,11 +740,11 @@ static const struct i915_audio_component_ops i915_audio_component_ops = {
        .get_eld        = i915_audio_component_get_eld,
 };
 
-static int i915_audio_component_bind(struct device *i915_dev,
-                                    struct device *hda_dev, void *data)
+static int i915_audio_component_bind(struct device *i915_kdev,
+                                    struct device *hda_kdev, void *data)
 {
        struct i915_audio_component *acomp = data;
-       struct drm_i915_private *dev_priv = dev_to_i915(i915_dev);
+       struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
        int i;
 
        if (WARN_ON(acomp->ops || acomp->dev))
@@ -757,7 +752,7 @@ static int i915_audio_component_bind(struct device *i915_dev,
 
        drm_modeset_lock_all(&dev_priv->drm);
        acomp->ops = &i915_audio_component_ops;
-       acomp->dev = i915_dev;
+       acomp->dev = i915_kdev;
        BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS);
        for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++)
                acomp->aud_sample_rate[i] = 0;
@@ -767,11 +762,11 @@ static int i915_audio_component_bind(struct device *i915_dev,
        return 0;
 }
 
-static void i915_audio_component_unbind(struct device *i915_dev,
-                                       struct device *hda_dev, void *data)
+static void i915_audio_component_unbind(struct device *i915_kdev,
+                                       struct device *hda_kdev, void *data)
 {
        struct i915_audio_component *acomp = data;
-       struct drm_i915_private *dev_priv = dev_to_i915(i915_dev);
+       struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
 
        drm_modeset_lock_all(&dev_priv->drm);
        acomp->ops = NULL;
index b074f3d..495611b 100644 (file)
 
 #include "i915_drv.h"
 
+static void intel_breadcrumbs_hangcheck(unsigned long data)
+{
+       struct intel_engine_cs *engine = (struct intel_engine_cs *)data;
+       struct intel_breadcrumbs *b = &engine->breadcrumbs;
+
+       if (!b->irq_enabled)
+               return;
+
+       if (time_before(jiffies, b->timeout)) {
+               mod_timer(&b->hangcheck, b->timeout);
+               return;
+       }
+
+       DRM_DEBUG("Hangcheck timer elapsed... %s idle\n", engine->name);
+       set_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings);
+       mod_timer(&engine->breadcrumbs.fake_irq, jiffies + 1);
+
+       /* Ensure that even if the GPU hangs, we get woken up.
+        *
+        * However, note that if no one is waiting, we never notice
+        * a gpu hang. Eventually, we will have to wait for a resource
+        * held by the GPU and so trigger a hangcheck. In the most
+        * pathological case, this will be upon memory starvation! To
+        * prevent this, we also queue the hangcheck from the retire
+        * worker.
+        */
+       i915_queue_hangcheck(engine->i915);
+}
+
+static unsigned long wait_timeout(void)
+{
+       return round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES);
+}
+
 static void intel_breadcrumbs_fake_irq(unsigned long data)
 {
        struct intel_engine_cs *engine = (struct intel_engine_cs *)data;
@@ -37,10 +71,8 @@ static void intel_breadcrumbs_fake_irq(unsigned long data)
         * every jiffie in order to kick the oldest waiter to do the
         * coherent seqno check.
         */
-       rcu_read_lock();
        if (intel_engine_wakeup(engine))
                mod_timer(&engine->breadcrumbs.fake_irq, jiffies + 1);
-       rcu_read_unlock();
 }
 
 static void irq_enable(struct intel_engine_cs *engine)
@@ -91,17 +123,13 @@ static void __intel_breadcrumbs_enable_irq(struct intel_breadcrumbs *b)
        }
 
        if (!b->irq_enabled ||
-           test_bit(engine->id, &i915->gpu_error.missed_irq_rings))
+           test_bit(engine->id, &i915->gpu_error.missed_irq_rings)) {
                mod_timer(&b->fake_irq, jiffies + 1);
-
-       /* Ensure that even if the GPU hangs, we get woken up.
-        *
-        * However, note that if no one is waiting, we never notice
-        * a gpu hang. Eventually, we will have to wait for a resource
-        * held by the GPU and so trigger a hangcheck. In the most
-        * pathological case, this will be upon memory starvation!
-        */
-       i915_queue_hangcheck(i915);
+       } else {
+               /* Ensure we never sleep indefinitely */
+               GEM_BUG_ON(!time_after(b->timeout, jiffies));
+               mod_timer(&b->hangcheck, b->timeout);
+       }
 }
 
 static void __intel_breadcrumbs_disable_irq(struct intel_breadcrumbs *b)
@@ -204,7 +232,7 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine,
        }
        rb_link_node(&wait->node, parent, p);
        rb_insert_color(&wait->node, &b->waiters);
-       GEM_BUG_ON(!first && !b->irq_seqno_bh);
+       GEM_BUG_ON(!first && !rcu_access_pointer(b->irq_seqno_bh));
 
        if (completed) {
                struct rb_node *next = rb_next(completed);
@@ -212,8 +240,9 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine,
                GEM_BUG_ON(!next && !first);
                if (next && next != &wait->node) {
                        GEM_BUG_ON(first);
+                       b->timeout = wait_timeout();
                        b->first_wait = to_wait(next);
-                       smp_store_mb(b->irq_seqno_bh, b->first_wait->tsk);
+                       rcu_assign_pointer(b->irq_seqno_bh, b->first_wait->tsk);
                        /* As there is a delay between reading the current
                         * seqno, processing the completed tasks and selecting
                         * the next waiter, we may have missed the interrupt
@@ -238,8 +267,9 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine,
 
        if (first) {
                GEM_BUG_ON(rb_first(&b->waiters) != &wait->node);
+               b->timeout = wait_timeout();
                b->first_wait = wait;
-               smp_store_mb(b->irq_seqno_bh, wait->tsk);
+               rcu_assign_pointer(b->irq_seqno_bh, wait->tsk);
                /* After assigning ourselves as the new bottom-half, we must
                 * perform a cursory check to prevent a missed interrupt.
                 * Either we miss the interrupt whilst programming the hardware,
@@ -250,7 +280,7 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine,
                 */
                __intel_breadcrumbs_enable_irq(b);
        }
-       GEM_BUG_ON(!b->irq_seqno_bh);
+       GEM_BUG_ON(!rcu_access_pointer(b->irq_seqno_bh));
        GEM_BUG_ON(!b->first_wait);
        GEM_BUG_ON(rb_first(&b->waiters) != &b->first_wait->node);
 
@@ -270,11 +300,6 @@ bool intel_engine_add_wait(struct intel_engine_cs *engine,
        return first;
 }
 
-void intel_engine_enable_fake_irq(struct intel_engine_cs *engine)
-{
-       mod_timer(&engine->breadcrumbs.fake_irq, jiffies + 1);
-}
-
 static inline bool chain_wakeup(struct rb_node *rb, int priority)
 {
        return rb && to_wait(rb)->tsk->prio <= priority;
@@ -310,7 +335,7 @@ void intel_engine_remove_wait(struct intel_engine_cs *engine,
                const int priority = wakeup_priority(b, wait->tsk);
                struct rb_node *next;
 
-               GEM_BUG_ON(b->irq_seqno_bh != wait->tsk);
+               GEM_BUG_ON(rcu_access_pointer(b->irq_seqno_bh) != wait->tsk);
 
                /* We are the current bottom-half. Find the next candidate,
                 * the first waiter in the queue on the remaining oldest
@@ -352,14 +377,15 @@ void intel_engine_remove_wait(struct intel_engine_cs *engine,
                         * the interrupt, or if we have to handle an
                         * exception rather than a seqno completion.
                         */
+                       b->timeout = wait_timeout();
                        b->first_wait = to_wait(next);
-                       smp_store_mb(b->irq_seqno_bh, b->first_wait->tsk);
+                       rcu_assign_pointer(b->irq_seqno_bh, b->first_wait->tsk);
                        if (b->first_wait->seqno != wait->seqno)
                                __intel_breadcrumbs_enable_irq(b);
-                       wake_up_process(b->irq_seqno_bh);
+                       wake_up_process(b->first_wait->tsk);
                } else {
                        b->first_wait = NULL;
-                       WRITE_ONCE(b->irq_seqno_bh, NULL);
+                       rcu_assign_pointer(b->irq_seqno_bh, NULL);
                        __intel_breadcrumbs_disable_irq(b);
                }
        } else {
@@ -373,7 +399,7 @@ out_unlock:
        GEM_BUG_ON(b->first_wait == wait);
        GEM_BUG_ON(rb_first(&b->waiters) !=
                   (b->first_wait ? &b->first_wait->node : NULL));
-       GEM_BUG_ON(!b->irq_seqno_bh ^ RB_EMPTY_ROOT(&b->waiters));
+       GEM_BUG_ON(!rcu_access_pointer(b->irq_seqno_bh) ^ RB_EMPTY_ROOT(&b->waiters));
        spin_unlock(&b->lock);
 }
 
@@ -437,6 +463,10 @@ static int intel_breadcrumbs_signaler(void *arg)
                        intel_engine_remove_wait(engine,
                                                 &request->signaling.wait);
 
+                       local_bh_disable();
+                       fence_signal(&request->fence);
+                       local_bh_enable(); /* kick start the tasklets */
+
                        /* Find the next oldest signal. Note that as we have
                         * not been holding the lock, another client may
                         * have installed an even older signal than the one
@@ -452,7 +482,7 @@ static int intel_breadcrumbs_signaler(void *arg)
                        rb_erase(&request->signaling.node, &b->signals);
                        spin_unlock(&b->lock);
 
-                       i915_gem_request_unreference(request);
+                       i915_gem_request_put(request);
                } else {
                        if (kthread_should_stop())
                                break;
@@ -472,18 +502,14 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request)
        struct rb_node *parent, **p;
        bool first, wakeup;
 
-       if (unlikely(READ_ONCE(request->signaling.wait.tsk)))
-               return;
-
-       spin_lock(&b->lock);
-       if (unlikely(request->signaling.wait.tsk)) {
-               wakeup = false;
-               goto unlock;
-       }
+       /* locked by fence_enable_sw_signaling() */
+       assert_spin_locked(&request->lock);
 
        request->signaling.wait.tsk = b->signaler;
-       request->signaling.wait.seqno = request->seqno;
-       i915_gem_request_reference(request);
+       request->signaling.wait.seqno = request->fence.seqno;
+       i915_gem_request_get(request);
+
+       spin_lock(&b->lock);
 
        /* First add ourselves into the list of waiters, but register our
         * bottom-half as the signaller thread. As per usual, only the oldest
@@ -504,8 +530,8 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request)
        p = &b->signals.rb_node;
        while (*p) {
                parent = *p;
-               if (i915_seqno_passed(request->seqno,
-                                     to_signaler(parent)->seqno)) {
+               if (i915_seqno_passed(request->fence.seqno,
+                                     to_signaler(parent)->fence.seqno)) {
                        p = &parent->rb_right;
                        first = false;
                } else {
@@ -517,7 +543,6 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request)
        if (first)
                smp_store_mb(b->first_signal, request);
 
-unlock:
        spin_unlock(&b->lock);
 
        if (wakeup)
@@ -533,6 +558,9 @@ int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine)
        setup_timer(&b->fake_irq,
                    intel_breadcrumbs_fake_irq,
                    (unsigned long)engine);
+       setup_timer(&b->hangcheck,
+                   intel_breadcrumbs_hangcheck,
+                   (unsigned long)engine);
 
        /* Spawn a thread to provide a common bottom-half for all signals.
         * As this is an asynchronous interface we cannot steal the current
@@ -550,6 +578,36 @@ int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine)
        return 0;
 }
 
+static void cancel_fake_irq(struct intel_engine_cs *engine)
+{
+       struct intel_breadcrumbs *b = &engine->breadcrumbs;
+
+       del_timer_sync(&b->hangcheck);
+       del_timer_sync(&b->fake_irq);
+       clear_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings);
+}
+
+void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine)
+{
+       struct intel_breadcrumbs *b = &engine->breadcrumbs;
+
+       cancel_fake_irq(engine);
+       spin_lock(&b->lock);
+
+       __intel_breadcrumbs_disable_irq(b);
+       if (intel_engine_has_waiter(engine)) {
+               b->timeout = wait_timeout();
+               __intel_breadcrumbs_enable_irq(b);
+               if (READ_ONCE(b->irq_posted))
+                       wake_up_process(b->first_wait->tsk);
+       } else {
+               /* sanitize the IMR and unmask any auxiliary interrupts */
+               irq_disable(engine);
+       }
+
+       spin_unlock(&b->lock);
+}
+
 void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine)
 {
        struct intel_breadcrumbs *b = &engine->breadcrumbs;
@@ -557,7 +615,7 @@ void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine)
        if (!IS_ERR_OR_NULL(b->signaler))
                kthread_stop(b->signaler);
 
-       del_timer_sync(&b->fake_irq);
+       cancel_fake_irq(engine);
 }
 
 unsigned int intel_kick_waiters(struct drm_i915_private *i915)
@@ -570,11 +628,9 @@ unsigned int intel_kick_waiters(struct drm_i915_private *i915)
         * RCU lock, i.e. as we call wake_up_process() we must be holding the
         * rcu_read_lock().
         */
-       rcu_read_lock();
        for_each_engine(engine, i915)
                if (unlikely(intel_engine_wakeup(engine)))
                        mask |= intel_engine_flag(engine);
-       rcu_read_unlock();
 
        return mask;
 }
index bc0fef3..95a7277 100644 (file)
@@ -100,13 +100,14 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int i, pipe = intel_crtc->pipe;
        uint16_t coeffs[9] = { 0, };
+       struct intel_crtc_state *intel_crtc_state = to_intel_crtc_state(crtc_state);
 
        if (crtc_state->ctm) {
                struct drm_color_ctm *ctm =
                        (struct drm_color_ctm *)crtc_state->ctm->data;
                uint64_t input[9] = { 0, };
 
-               if (intel_crtc->config->limited_color_range) {
+               if (intel_crtc_state->limited_color_range) {
                        ctm_mult_by_limited(input, ctm->matrix);
                } else {
                        for (i = 0; i < ARRAY_SIZE(input); i++)
@@ -158,7 +159,7 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
                 * into consideration.
                 */
                for (i = 0; i < 3; i++) {
-                       if (intel_crtc->config->limited_color_range)
+                       if (intel_crtc_state->limited_color_range)
                                coeffs[i * 3 + i] =
                                        I9XX_CSC_COEFF_LIMITED_RANGE;
                        else
@@ -182,7 +183,7 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
        if (INTEL_INFO(dev)->gen > 6) {
                uint16_t postoff = 0;
 
-               if (intel_crtc->config->limited_color_range)
+               if (intel_crtc_state->limited_color_range)
                        postoff = (16 * (1 << 12) / 255) & 0x1fff;
 
                I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
@@ -193,7 +194,7 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
        } else {
                uint32_t mode = CSC_MODE_YUV_TO_RGB;
 
-               if (intel_crtc->config->limited_color_range)
+               if (intel_crtc_state->limited_color_range)
                        mode |= CSC_BLACK_SCREEN_OFFSET;
 
                I915_WRITE(PIPE_CSC_MODE(pipe), mode);
@@ -263,7 +264,8 @@ void intel_color_set_csc(struct drm_crtc_state *crtc_state)
 
 /* Loads the legacy palette/gamma unit for the CRTC. */
 static void i9xx_load_luts_internal(struct drm_crtc *crtc,
-                                   struct drm_property_blob *blob)
+                                   struct drm_property_blob *blob,
+                                   struct intel_crtc_state *crtc_state)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -272,7 +274,7 @@ static void i9xx_load_luts_internal(struct drm_crtc *crtc,
        int i;
 
        if (HAS_GMCH_DISPLAY(dev)) {
-               if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DSI))
+               if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
                        assert_dsi_pll_enabled(dev_priv);
                else
                        assert_pll_enabled(dev_priv, pipe);
@@ -305,7 +307,8 @@ static void i9xx_load_luts_internal(struct drm_crtc *crtc,
 
 static void i9xx_load_luts(struct drm_crtc_state *crtc_state)
 {
-       i9xx_load_luts_internal(crtc_state->crtc, crtc_state->gamma_lut);
+       i9xx_load_luts_internal(crtc_state->crtc, crtc_state->gamma_lut,
+                               to_intel_crtc_state(crtc_state));
 }
 
 /* Loads the legacy palette/gamma unit for the CRTC on Haswell. */
@@ -323,7 +326,7 @@ static void haswell_load_luts(struct drm_crtc_state *crtc_state)
         * Workaround : Do not read or write the pipe palette/gamma data while
         * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
         */
-       if (IS_HASWELL(dev) && intel_crtc->config->ips_enabled &&
+       if (IS_HASWELL(dev) && intel_crtc_state->ips_enabled &&
            (intel_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)) {
                hsw_disable_ips(intel_crtc);
                reenable_ips = true;
@@ -436,7 +439,8 @@ static void cherryview_load_luts(struct drm_crtc_state *state)
                /* Turn off degamma/gamma on CGM block. */
                I915_WRITE(CGM_PIPE_MODE(pipe),
                           (state->ctm ? CGM_PIPE_MODE_CSC : 0));
-               i9xx_load_luts_internal(crtc, state->gamma_lut);
+               i9xx_load_luts_internal(crtc, state->gamma_lut,
+                                       to_intel_crtc_state(state));
                return;
        }
 
@@ -479,7 +483,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state)
         * Also program a linear LUT in the legacy block (behind the
         * CGM block).
         */
-       i9xx_load_luts_internal(crtc, NULL);
+       i9xx_load_luts_internal(crtc, NULL, to_intel_crtc_state(state));
 }
 
 void intel_color_load_luts(struct drm_crtc_state *crtc_state)
index 827b6ef..dfbcf16 100644 (file)
@@ -143,13 +143,15 @@ static void hsw_crt_get_config(struct intel_encoder *encoder,
 
 /* Note: The caller is required to filter out dpms modes not supported by the
  * platform. */
-static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
+static void intel_crt_set_dpms(struct intel_encoder *encoder,
+                              struct intel_crtc_state *crtc_state,
+                              int mode)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crt *crt = intel_encoder_to_crt(encoder);
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
        u32 adpa;
 
        if (INTEL_INFO(dev)->gen >= 5)
@@ -193,23 +195,45 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
        I915_WRITE(crt->adpa_reg, adpa);
 }
 
-static void intel_disable_crt(struct intel_encoder *encoder)
+static void intel_disable_crt(struct intel_encoder *encoder,
+                             struct intel_crtc_state *old_crtc_state,
+                             struct drm_connector_state *old_conn_state)
 {
-       intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF);
+       intel_crt_set_dpms(encoder, old_crtc_state, DRM_MODE_DPMS_OFF);
 }
 
-static void pch_disable_crt(struct intel_encoder *encoder)
+static void pch_disable_crt(struct intel_encoder *encoder,
+                           struct intel_crtc_state *old_crtc_state,
+                           struct drm_connector_state *old_conn_state)
 {
 }
 
-static void pch_post_disable_crt(struct intel_encoder *encoder)
+static void pch_post_disable_crt(struct intel_encoder *encoder,
+                                struct intel_crtc_state *old_crtc_state,
+                                struct drm_connector_state *old_conn_state)
 {
-       intel_disable_crt(encoder);
+       intel_disable_crt(encoder, old_crtc_state, old_conn_state);
 }
 
-static void intel_enable_crt(struct intel_encoder *encoder)
+static void hsw_post_disable_crt(struct intel_encoder *encoder,
+                                struct intel_crtc_state *old_crtc_state,
+                                struct drm_connector_state *old_conn_state)
 {
-       intel_crt_set_dpms(encoder, DRM_MODE_DPMS_ON);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+       pch_post_disable_crt(encoder, old_crtc_state, old_conn_state);
+
+       lpt_disable_pch_transcoder(dev_priv);
+       lpt_disable_iclkip(dev_priv);
+
+       intel_ddi_fdi_post_disable(encoder, old_crtc_state, old_conn_state);
+}
+
+static void intel_enable_crt(struct intel_encoder *encoder,
+                            struct intel_crtc_state *pipe_config,
+                            struct drm_connector_state *conn_state)
+{
+       intel_crt_set_dpms(encoder, pipe_config, DRM_MODE_DPMS_ON);
 }
 
 static enum drm_mode_status
@@ -253,7 +277,8 @@ intel_crt_mode_valid(struct drm_connector *connector,
 }
 
 static bool intel_crt_compute_config(struct intel_encoder *encoder,
-                                    struct intel_crtc_state *pipe_config)
+                                    struct intel_crtc_state *pipe_config,
+                                    struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
 
@@ -894,6 +919,7 @@ void intel_crt_init(struct drm_device *dev)
        if (HAS_DDI(dev)) {
                crt->base.get_config = hsw_crt_get_config;
                crt->base.get_hw_state = intel_ddi_get_hw_state;
+               crt->base.post_disable = hsw_post_disable_crt;
        } else {
                crt->base.get_config = intel_crt_get_config;
                crt->base.get_hw_state = intel_crt_get_hw_state;
index c3b33a1..1ea0e1f 100644 (file)
  * onwards to drive newly added DMC (Display microcontroller) in display
  * engine to save and restore the state of display engine when it enter into
  * low-power state and comes back to normal.
- *
- * Firmware loading status will be one of the below states: FW_UNINITIALIZED,
- * FW_LOADED, FW_FAILED.
- *
- * Once the firmware is written into the registers status will be moved from
- * FW_UNINITIALIZED to FW_LOADED and for any erroneous condition status will
- * be moved to FW_FAILED.
  */
 
 #define I915_CSR_KBL "i915/kbl_dmc_ver1_01.bin"
index 1a7efac..15d47c8 100644 (file)
@@ -301,45 +301,34 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = {
        { 154, 0x9A, 1, 128, true },    /* 9:   1200            0   */
 };
 
-static void bxt_ddi_vswing_sequence(struct drm_i915_private *dev_priv,
-                                   u32 level, enum port port, int type);
-
-static void ddi_get_encoder_port(struct intel_encoder *intel_encoder,
-                                struct intel_digital_port **dig_port,
-                                enum port *port)
+enum port intel_ddi_get_encoder_port(struct intel_encoder *encoder)
 {
-       struct drm_encoder *encoder = &intel_encoder->base;
-
-       switch (intel_encoder->type) {
+       switch (encoder->type) {
        case INTEL_OUTPUT_DP_MST:
-               *dig_port = enc_to_mst(encoder)->primary;
-               *port = (*dig_port)->port;
-               break;
-       default:
-               WARN(1, "Invalid DDI encoder type %d\n", intel_encoder->type);
-               /* fallthrough and treat as unknown */
+               return enc_to_mst(&encoder->base)->primary->port;
        case INTEL_OUTPUT_DP:
        case INTEL_OUTPUT_EDP:
        case INTEL_OUTPUT_HDMI:
        case INTEL_OUTPUT_UNKNOWN:
-               *dig_port = enc_to_dig_port(encoder);
-               *port = (*dig_port)->port;
-               break;
+               return enc_to_dig_port(&encoder->base)->port;
        case INTEL_OUTPUT_ANALOG:
-               *dig_port = NULL;
-               *port = PORT_E;
-               break;
+               return PORT_E;
+       default:
+               MISSING_CASE(encoder->type);
+               return PORT_A;
        }
 }
 
-enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
+static const struct ddi_buf_trans *
+bdw_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
 {
-       struct intel_digital_port *dig_port;
-       enum port port;
-
-       ddi_get_encoder_port(intel_encoder, &dig_port, &port);
-
-       return port;
+       if (dev_priv->vbt.edp.low_vswing) {
+               *n_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
+               return bdw_ddi_translations_edp;
+       } else {
+               *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
+               return bdw_ddi_translations_dp;
+       }
 }
 
 static const struct ddi_buf_trans *
@@ -424,37 +413,22 @@ static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port por
 
 /*
  * Starting with Haswell, DDI port buffers must be programmed with correct
- * values in advance. The buffer values are different for FDI and DP modes,
- * but the HDMI/DVI fields are shared among those. So we program the DDI
- * in either FDI or DP modes only, as HDMI connections will work with both
- * of those
+ * values in advance. This function programs the correct values for
+ * DP/eDP/FDI use cases.
  */
-void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
+void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        u32 iboost_bit = 0;
-       int i, n_hdmi_entries, n_dp_entries, n_edp_entries,
-           size;
-       int hdmi_level;
-       enum port port;
+       int i, n_dp_entries, n_edp_entries, size;
+       enum port port = intel_ddi_get_encoder_port(encoder);
        const struct ddi_buf_trans *ddi_translations_fdi;
        const struct ddi_buf_trans *ddi_translations_dp;
        const struct ddi_buf_trans *ddi_translations_edp;
-       const struct ddi_buf_trans *ddi_translations_hdmi;
        const struct ddi_buf_trans *ddi_translations;
 
-       port = intel_ddi_get_encoder_port(encoder);
-       hdmi_level = intel_ddi_hdmi_level(dev_priv, port);
-
-       if (IS_BROXTON(dev_priv)) {
-               if (encoder->type != INTEL_OUTPUT_HDMI)
-                       return;
-
-               /* Vswing programming for HDMI */
-               bxt_ddi_vswing_sequence(dev_priv, hdmi_level, port,
-                                       INTEL_OUTPUT_HDMI);
+       if (IS_BROXTON(dev_priv))
                return;
-       }
 
        if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
                ddi_translations_fdi = NULL;
@@ -462,12 +436,10 @@ void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
                                skl_get_buf_trans_dp(dev_priv, &n_dp_entries);
                ddi_translations_edp =
                                skl_get_buf_trans_edp(dev_priv, &n_edp_entries);
-               ddi_translations_hdmi =
-                               skl_get_buf_trans_hdmi(dev_priv, &n_hdmi_entries);
+
                /* If we're boosting the current, set bit 31 of trans1 */
-               if (dev_priv->vbt.ddi_port_info[port].hdmi_boost_level ||
-                   dev_priv->vbt.ddi_port_info[port].dp_boost_level)
-                       iboost_bit = 1<<31;
+               if (dev_priv->vbt.ddi_port_info[port].dp_boost_level)
+                       iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
 
                if (WARN_ON(encoder->type == INTEL_OUTPUT_EDP &&
                            port != PORT_A && port != PORT_E &&
@@ -476,35 +448,20 @@ void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
        } else if (IS_BROADWELL(dev_priv)) {
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
-
-               if (dev_priv->vbt.edp.low_vswing) {
-                       ddi_translations_edp = bdw_ddi_translations_edp;
-                       n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
-               } else {
-                       ddi_translations_edp = bdw_ddi_translations_dp;
-                       n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
-               }
-
-               ddi_translations_hdmi = bdw_ddi_translations_hdmi;
-
+               ddi_translations_edp = bdw_get_buf_trans_edp(dev_priv, &n_edp_entries);
                n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
-               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
        } else if (IS_HASWELL(dev_priv)) {
                ddi_translations_fdi = hsw_ddi_translations_fdi;
                ddi_translations_dp = hsw_ddi_translations_dp;
                ddi_translations_edp = hsw_ddi_translations_dp;
-               ddi_translations_hdmi = hsw_ddi_translations_hdmi;
                n_dp_entries = n_edp_entries = ARRAY_SIZE(hsw_ddi_translations_dp);
-               n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi);
        } else {
                WARN(1, "ddi translation table missing\n");
                ddi_translations_edp = bdw_ddi_translations_dp;
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
-               ddi_translations_hdmi = bdw_ddi_translations_hdmi;
                n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
                n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
-               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
        }
 
        switch (encoder->type) {
@@ -513,7 +470,6 @@ void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
                size = n_edp_entries;
                break;
        case INTEL_OUTPUT_DP:
-       case INTEL_OUTPUT_HDMI:
                ddi_translations = ddi_translations_dp;
                size = n_dp_entries;
                break;
@@ -531,14 +487,48 @@ void intel_prepare_ddi_buffer(struct intel_encoder *encoder)
                I915_WRITE(DDI_BUF_TRANS_HI(port, i),
                           ddi_translations[i].trans2);
        }
+}
+
+/*
+ * Starting with Haswell, DDI port buffers must be programmed with correct
+ * values in advance. This function programs the correct values for
+ * HDMI/DVI use cases.
+ */
+static void intel_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 iboost_bit = 0;
+       int n_hdmi_entries, hdmi_level;
+       enum port port = intel_ddi_get_encoder_port(encoder);
+       const struct ddi_buf_trans *ddi_translations_hdmi;
 
-       if (encoder->type != INTEL_OUTPUT_HDMI)
+       if (IS_BROXTON(dev_priv))
                return;
 
+       hdmi_level = intel_ddi_hdmi_level(dev_priv, port);
+
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+               ddi_translations_hdmi = skl_get_buf_trans_hdmi(dev_priv, &n_hdmi_entries);
+
+               /* If we're boosting the current, set bit 31 of trans1 */
+               if (dev_priv->vbt.ddi_port_info[port].hdmi_boost_level)
+                       iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
+       } else if (IS_BROADWELL(dev_priv)) {
+               ddi_translations_hdmi = bdw_ddi_translations_hdmi;
+               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
+       } else if (IS_HASWELL(dev_priv)) {
+               ddi_translations_hdmi = hsw_ddi_translations_hdmi;
+               n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi);
+       } else {
+               WARN(1, "ddi translation table missing\n");
+               ddi_translations_hdmi = bdw_ddi_translations_hdmi;
+               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
+       }
+
        /* Entry 9 is for HDMI: */
-       I915_WRITE(DDI_BUF_TRANS_LO(port, i),
+       I915_WRITE(DDI_BUF_TRANS_LO(port, 9),
                   ddi_translations_hdmi[hdmi_level].trans1 | iboost_bit);
-       I915_WRITE(DDI_BUF_TRANS_HI(port, i),
+       I915_WRITE(DDI_BUF_TRANS_HI(port, 9),
                   ddi_translations_hdmi[hdmi_level].trans2);
 }
 
@@ -556,6 +546,27 @@ static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
        DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port));
 }
 
+static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
+{
+       switch (pll->id) {
+       case DPLL_ID_WRPLL1:
+               return PORT_CLK_SEL_WRPLL1;
+       case DPLL_ID_WRPLL2:
+               return PORT_CLK_SEL_WRPLL2;
+       case DPLL_ID_SPLL:
+               return PORT_CLK_SEL_SPLL;
+       case DPLL_ID_LCPLL_810:
+               return PORT_CLK_SEL_LCPLL_810;
+       case DPLL_ID_LCPLL_1350:
+               return PORT_CLK_SEL_LCPLL_1350;
+       case DPLL_ID_LCPLL_2700:
+               return PORT_CLK_SEL_LCPLL_2700;
+       default:
+               MISSING_CASE(pll->id);
+               return PORT_CLK_SEL_NONE;
+       }
+}
+
 /* Starting with Haswell, different DDI ports can work in FDI mode for
  * connection to the PCH-located connectors. For this, it is necessary to train
  * both the DDI port and PCH receiver for the desired DDI buffer settings.
@@ -571,11 +582,11 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
-       u32 temp, i, rx_ctl_val;
+       u32 temp, i, rx_ctl_val, ddi_pll_sel;
 
        for_each_encoder_on_crtc(dev, crtc, encoder) {
                WARN_ON(encoder->type != INTEL_OUTPUT_ANALOG);
-               intel_prepare_ddi_buffer(encoder);
+               intel_prepare_dp_ddi_buffers(encoder);
        }
 
        /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the
@@ -602,8 +613,9 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
        I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
 
        /* Configure Port Clock Select */
-       I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel);
-       WARN_ON(intel_crtc->config->ddi_pll_sel != PORT_CLK_SEL_SPLL);
+       ddi_pll_sel = hsw_pll_to_ddi_pll_sel(intel_crtc->config->shared_dpll);
+       I915_WRITE(PORT_CLK_SEL(PORT_E), ddi_pll_sel);
+       WARN_ON(ddi_pll_sel != PORT_CLK_SEL_SPLL);
 
        /* Start the training iterating through available voltages and emphasis,
         * testing each value twice. */
@@ -880,7 +892,7 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder,
        int link_clock = 0;
        uint32_t dpll_ctl1, dpll;
 
-       dpll = pipe_config->ddi_pll_sel;
+       dpll = intel_get_shared_dpll_id(dev_priv, pipe_config->shared_dpll);
 
        dpll_ctl1 = I915_READ(DPLL_CTRL1);
 
@@ -928,7 +940,7 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder,
        int link_clock = 0;
        u32 val, pll;
 
-       val = pipe_config->ddi_pll_sel;
+       val = hsw_pll_to_ddi_pll_sel(pipe_config->shared_dpll);
        switch (val & PORT_CLK_SEL_MASK) {
        case PORT_CLK_SEL_LCPLL_810:
                link_clock = 81000;
@@ -1136,7 +1148,6 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
-       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        enum pipe pipe = intel_crtc->pipe;
@@ -1202,29 +1213,15 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
                        temp |= TRANS_DDI_MODE_SELECT_HDMI;
                else
                        temp |= TRANS_DDI_MODE_SELECT_DVI;
-
        } else if (type == INTEL_OUTPUT_ANALOG) {
                temp |= TRANS_DDI_MODE_SELECT_FDI;
                temp |= (intel_crtc->config->fdi_lanes - 1) << 1;
-
        } else if (type == INTEL_OUTPUT_DP ||
                   type == INTEL_OUTPUT_EDP) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
-               if (intel_dp->is_mst) {
-                       temp |= TRANS_DDI_MODE_SELECT_DP_MST;
-               } else
-                       temp |= TRANS_DDI_MODE_SELECT_DP_SST;
-
+               temp |= TRANS_DDI_MODE_SELECT_DP_SST;
                temp |= DDI_PORT_WIDTH(intel_crtc->config->lane_count);
        } else if (type == INTEL_OUTPUT_DP_MST) {
-               struct intel_dp *intel_dp = &enc_to_mst(encoder)->primary->dp;
-
-               if (intel_dp->is_mst) {
-                       temp |= TRANS_DDI_MODE_SELECT_DP_MST;
-               } else
-                       temp |= TRANS_DDI_MODE_SELECT_DP_SST;
-
+               temp |= TRANS_DDI_MODE_SELECT_DP_MST;
                temp |= DDI_PORT_WIDTH(intel_crtc->config->lane_count);
        } else {
                WARN(1, "Invalid encoder type %d for pipe %c\n",
@@ -1611,13 +1608,15 @@ uint32_t ddi_signal_levels(struct intel_dp *intel_dp)
 }
 
 void intel_ddi_clk_select(struct intel_encoder *encoder,
-                         const struct intel_crtc_state *pipe_config)
+                         struct intel_shared_dpll *pll)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum port port = intel_ddi_get_encoder_port(encoder);
 
+       if (WARN_ON(!pll))
+               return;
+
        if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
-               uint32_t dpll = pipe_config->ddi_pll_sel;
                uint32_t val;
 
                /* DDI -> PLL mapping  */
@@ -1625,65 +1624,91 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
 
                val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) |
                        DPLL_CTRL2_DDI_CLK_SEL_MASK(port));
-               val |= (DPLL_CTRL2_DDI_CLK_SEL(dpll, port) |
+               val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->id, port) |
                        DPLL_CTRL2_DDI_SEL_OVERRIDE(port));
 
                I915_WRITE(DPLL_CTRL2, val);
 
        } else if (INTEL_INFO(dev_priv)->gen < 9) {
-               WARN_ON(pipe_config->ddi_pll_sel == PORT_CLK_SEL_NONE);
-               I915_WRITE(PORT_CLK_SEL(port), pipe_config->ddi_pll_sel);
+               I915_WRITE(PORT_CLK_SEL(port), hsw_pll_to_ddi_pll_sel(pll));
        }
 }
 
-static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
+static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+                                   int link_rate, uint32_t lane_count,
+                                   struct intel_shared_dpll *pll,
+                                   bool link_mst)
 {
-       struct drm_encoder *encoder = &intel_encoder->base;
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-       struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
-       enum port port = intel_ddi_get_encoder_port(intel_encoder);
-       int type = intel_encoder->type;
-
-       if (type == INTEL_OUTPUT_HDMI) {
-               struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-
-               intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
-       }
-
-       intel_prepare_ddi_buffer(intel_encoder);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = intel_ddi_get_encoder_port(encoder);
 
-       if (type == INTEL_OUTPUT_EDP) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       intel_dp_set_link_params(intel_dp, link_rate, lane_count,
+                                link_mst);
+       if (encoder->type == INTEL_OUTPUT_EDP)
                intel_edp_panel_on(intel_dp);
-       }
-
-       intel_ddi_clk_select(intel_encoder, crtc->config);
 
-       if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       intel_ddi_clk_select(encoder, pll);
+       intel_prepare_dp_ddi_buffers(encoder);
+       intel_ddi_init_dp_buf_reg(encoder);
+       intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+       intel_dp_start_link_train(intel_dp);
+       if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
+               intel_dp_stop_link_train(intel_dp);
+}
 
-               intel_dp_set_link_params(intel_dp, crtc->config);
+static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
+                                     bool has_hdmi_sink,
+                                     struct drm_display_mode *adjusted_mode,
+                                     struct intel_shared_dpll *pll)
+{
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct drm_encoder *drm_encoder = &encoder->base;
+       enum port port = intel_ddi_get_encoder_port(encoder);
+       int level = intel_ddi_hdmi_level(dev_priv, port);
 
-               intel_ddi_init_dp_buf_reg(intel_encoder);
+       intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
+       intel_ddi_clk_select(encoder, pll);
+       intel_prepare_hdmi_ddi_buffers(encoder);
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+               skl_ddi_set_iboost(encoder, level);
+       else if (IS_BROXTON(dev_priv))
+               bxt_ddi_vswing_sequence(dev_priv, level, port,
+                                       INTEL_OUTPUT_HDMI);
 
-               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
-               intel_dp_start_link_train(intel_dp);
-               if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
-                       intel_dp_stop_link_train(intel_dp);
-       } else if (type == INTEL_OUTPUT_HDMI) {
-               struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-               int level = intel_ddi_hdmi_level(dev_priv, port);
+       intel_hdmi->set_infoframes(drm_encoder,
+                                  has_hdmi_sink,
+                                  adjusted_mode);
+}
 
-               if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
-                       skl_ddi_set_iboost(intel_encoder, level);
+static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
+                                struct intel_crtc_state *pipe_config,
+                                struct drm_connector_state *conn_state)
+{
+       struct drm_encoder *encoder = &intel_encoder->base;
+       struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
+       int type = intel_encoder->type;
 
-               intel_hdmi->set_infoframes(encoder,
-                                          crtc->config->has_hdmi_sink,
-                                          &crtc->config->base.adjusted_mode);
+       if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
+               intel_ddi_pre_enable_dp(intel_encoder,
+                                       crtc->config->port_clock,
+                                       crtc->config->lane_count,
+                                       crtc->config->shared_dpll,
+                                       intel_crtc_has_type(crtc->config,
+                                                           INTEL_OUTPUT_DP_MST));
+       }
+       if (type == INTEL_OUTPUT_HDMI) {
+               intel_ddi_pre_enable_hdmi(intel_encoder,
+                                         crtc->config->has_hdmi_sink,
+                                         &crtc->config->base.adjusted_mode,
+                                         crtc->config->shared_dpll);
        }
 }
 
-static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
+static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
+                                  struct intel_crtc_state *old_crtc_state,
+                                  struct drm_connector_state *old_conn_state)
 {
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = encoder->dev;
@@ -1693,6 +1718,8 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
        uint32_t val;
        bool wait = false;
 
+       /* old_crtc_state and old_conn_state are NULL when called from DP_MST */
+
        val = I915_READ(DDI_BUF_CTL(port));
        if (val & DDI_BUF_CTL_ENABLE) {
                val &= ~DDI_BUF_CTL_ENABLE;
@@ -1728,7 +1755,42 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
        }
 }
 
-static void intel_enable_ddi(struct intel_encoder *intel_encoder)
+void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder,
+                               struct intel_crtc_state *old_crtc_state,
+                               struct drm_connector_state *old_conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
+       uint32_t val;
+
+       /*
+        * Bspec lists this as both step 13 (before DDI_BUF_CTL disable)
+        * and step 18 (after clearing PORT_CLK_SEL). Based on a BUN,
+        * step 13 is the correct place for it. Step 18 is where it was
+        * originally before the BUN.
+        */
+       val = I915_READ(FDI_RX_CTL(PIPE_A));
+       val &= ~FDI_RX_ENABLE;
+       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
+
+       intel_ddi_post_disable(intel_encoder, old_crtc_state, old_conn_state);
+
+       val = I915_READ(FDI_RX_MISC(PIPE_A));
+       val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
+       val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
+       I915_WRITE(FDI_RX_MISC(PIPE_A), val);
+
+       val = I915_READ(FDI_RX_CTL(PIPE_A));
+       val &= ~FDI_PCDCLK;
+       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
+
+       val = I915_READ(FDI_RX_CTL(PIPE_A));
+       val &= ~FDI_RX_PLL_ENABLE;
+       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
+}
+
+static void intel_enable_ddi(struct intel_encoder *intel_encoder,
+                            struct intel_crtc_state *pipe_config,
+                            struct drm_connector_state *conn_state)
 {
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = encoder->crtc;
@@ -1757,7 +1819,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
 
                intel_edp_backlight_on(intel_dp);
                intel_psr_enable(intel_dp);
-               intel_edp_drrs_enable(intel_dp);
+               intel_edp_drrs_enable(intel_dp, pipe_config);
        }
 
        if (intel_crtc->config->has_audio) {
@@ -1766,7 +1828,9 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
        }
 }
 
-static void intel_disable_ddi(struct intel_encoder *intel_encoder)
+static void intel_disable_ddi(struct intel_encoder *intel_encoder,
+                             struct intel_crtc_state *old_crtc_state,
+                             struct drm_connector_state *old_conn_state)
 {
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = encoder->crtc;
@@ -1783,7 +1847,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
        if (type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
-               intel_edp_drrs_disable(intel_dp);
+               intel_edp_drrs_disable(intel_dp, old_crtc_state);
                intel_psr_disable(intel_dp);
                intel_edp_backlight_off(intel_dp);
        }
@@ -2072,7 +2136,9 @@ bxt_ddi_phy_calc_lane_lat_optim_mask(struct intel_encoder *encoder,
        }
 }
 
-static void bxt_ddi_pre_pll_enable(struct intel_encoder *encoder)
+static void bxt_ddi_pre_pll_enable(struct intel_encoder *encoder,
+                                  struct intel_crtc_state *pipe_config,
+                                  struct drm_connector_state *conn_state)
 {
        struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
        struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
@@ -2144,7 +2210,7 @@ void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
 
        val = DP_TP_CTL_ENABLE |
              DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE;
-       if (intel_dp->is_mst)
+       if (intel_dp->link_mst)
                val |= DP_TP_CTL_MODE_MST;
        else {
                val |= DP_TP_CTL_MODE_SST;
@@ -2161,38 +2227,6 @@ void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
        udelay(600);
 }
 
-void intel_ddi_fdi_disable(struct drm_crtc *crtc)
-{
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
-       uint32_t val;
-
-       /*
-        * Bspec lists this as both step 13 (before DDI_BUF_CTL disable)
-        * and step 18 (after clearing PORT_CLK_SEL). Based on a BUN,
-        * step 13 is the correct place for it. Step 18 is where it was
-        * originally before the BUN.
-        */
-       val = I915_READ(FDI_RX_CTL(PIPE_A));
-       val &= ~FDI_RX_ENABLE;
-       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
-
-       intel_ddi_post_disable(intel_encoder);
-
-       val = I915_READ(FDI_RX_MISC(PIPE_A));
-       val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
-       val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
-       I915_WRITE(FDI_RX_MISC(PIPE_A), val);
-
-       val = I915_READ(FDI_RX_CTL(PIPE_A));
-       val &= ~FDI_PCDCLK;
-       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
-
-       val = I915_READ(FDI_RX_CTL(PIPE_A));
-       val &= ~FDI_RX_PLL_ENABLE;
-       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
-}
-
 void intel_ddi_get_config(struct intel_encoder *encoder,
                          struct intel_crtc_state *pipe_config)
 {
@@ -2292,7 +2326,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 }
 
 static bool intel_ddi_compute_config(struct intel_encoder *encoder,
-                                    struct intel_crtc_state *pipe_config)
+                                    struct intel_crtc_state *pipe_config,
+                                    struct drm_connector_state *conn_state)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        int type = encoder->type;
@@ -2305,9 +2340,9 @@ static bool intel_ddi_compute_config(struct intel_encoder *encoder,
                pipe_config->cpu_transcoder = TRANSCODER_EDP;
 
        if (type == INTEL_OUTPUT_HDMI)
-               ret = intel_hdmi_compute_config(encoder, pipe_config);
+               ret = intel_hdmi_compute_config(encoder, pipe_config, conn_state);
        else
-               ret = intel_dp_compute_config(encoder, pipe_config);
+               ret = intel_dp_compute_config(encoder, pipe_config, conn_state);
 
        if (IS_BROXTON(dev_priv) && ret)
                pipe_config->lane_lat_optim_mask =
@@ -2358,6 +2393,45 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
        return connector;
 }
 
+struct intel_shared_dpll *
+intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
+{
+       struct intel_connector *connector = intel_dp->attached_connector;
+       struct intel_encoder *encoder = connector->encoder;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_shared_dpll *pll = NULL;
+       struct intel_shared_dpll_config tmp_pll_config;
+       enum intel_dpll_id dpll_id;
+
+       if (IS_BROXTON(dev_priv)) {
+               dpll_id =  (enum intel_dpll_id)dig_port->port;
+               /*
+                * Select the required PLL. This works for platforms where
+                * there is no shared DPLL.
+                */
+               pll = &dev_priv->shared_dplls[dpll_id];
+               if (WARN_ON(pll->active_mask)) {
+
+                       DRM_ERROR("Shared DPLL in use. active_mask:%x\n",
+                                 pll->active_mask);
+                       return NULL;
+               }
+               tmp_pll_config = pll->config;
+               if (!bxt_ddi_dp_set_dpll_hw_state(clock,
+                                                 &pll->config.hw_state)) {
+                       DRM_ERROR("Could not setup DPLL\n");
+                       pll->config = tmp_pll_config;
+                       return NULL;
+               }
+       } else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+               pll = skl_find_link_pll(dev_priv, clock);
+       } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
+               pll = hsw_ddi_dp_get_dpll(encoder, clock);
+       }
+       return pll;
+}
+
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
index cba137f..73b6858 100644 (file)
@@ -46,71 +46,70 @@ void intel_device_info_dump(struct drm_i915_private *dev_priv)
 
 static void cherryview_sseu_info_init(struct drm_i915_private *dev_priv)
 {
-       struct intel_device_info *info = mkwrite_device_info(dev_priv);
+       struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
        u32 fuse, eu_dis;
 
        fuse = I915_READ(CHV_FUSE_GT);
 
-       info->slice_total = 1;
+       sseu->slice_mask = BIT(0);
 
        if (!(fuse & CHV_FGT_DISABLE_SS0)) {
-               info->subslice_per_slice++;
+               sseu->subslice_mask |= BIT(0);
                eu_dis = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
                                 CHV_FGT_EU_DIS_SS0_R1_MASK);
-               info->eu_total += 8 - hweight32(eu_dis);
+               sseu->eu_total += 8 - hweight32(eu_dis);
        }
 
        if (!(fuse & CHV_FGT_DISABLE_SS1)) {
-               info->subslice_per_slice++;
+               sseu->subslice_mask |= BIT(1);
                eu_dis = fuse & (CHV_FGT_EU_DIS_SS1_R0_MASK |
                                 CHV_FGT_EU_DIS_SS1_R1_MASK);
-               info->eu_total += 8 - hweight32(eu_dis);
+               sseu->eu_total += 8 - hweight32(eu_dis);
        }
 
-       info->subslice_total = info->subslice_per_slice;
        /*
         * CHV expected to always have a uniform distribution of EU
         * across subslices.
        */
-       info->eu_per_subslice = info->subslice_total ?
-                               info->eu_total / info->subslice_total :
+       sseu->eu_per_subslice = sseu_subslice_total(sseu) ?
+                               sseu->eu_total / sseu_subslice_total(sseu) :
                                0;
        /*
         * CHV supports subslice power gating on devices with more than
         * one subslice, and supports EU power gating on devices with
         * more than one EU pair per subslice.
        */
-       info->has_slice_pg = 0;
-       info->has_subslice_pg = (info->subslice_total > 1);
-       info->has_eu_pg = (info->eu_per_subslice > 2);
+       sseu->has_slice_pg = 0;
+       sseu->has_subslice_pg = sseu_subslice_total(sseu) > 1;
+       sseu->has_eu_pg = (sseu->eu_per_subslice > 2);
 }
 
 static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
 {
        struct intel_device_info *info = mkwrite_device_info(dev_priv);
+       struct sseu_dev_info *sseu = &info->sseu;
        int s_max = 3, ss_max = 4, eu_max = 8;
        int s, ss;
-       u32 fuse2, s_enable, ss_disable, eu_disable;
+       u32 fuse2, eu_disable;
        u8 eu_mask = 0xff;
 
        fuse2 = I915_READ(GEN8_FUSE2);
-       s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
-       ss_disable = (fuse2 & GEN9_F2_SS_DIS_MASK) >> GEN9_F2_SS_DIS_SHIFT;
+       sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
 
-       info->slice_total = hweight32(s_enable);
        /*
         * The subslice disable field is global, i.e. it applies
         * to each of the enabled slices.
        */
-       info->subslice_per_slice = ss_max - hweight32(ss_disable);
-       info->subslice_total = info->slice_total * info->subslice_per_slice;
+       sseu->subslice_mask = (1 << ss_max) - 1;
+       sseu->subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>
+                                GEN9_F2_SS_DIS_SHIFT);
 
        /*
         * Iterate through enabled slices and subslices to
         * count the total enabled EU.
        */
        for (s = 0; s < s_max; s++) {
-               if (!(s_enable & BIT(s)))
+               if (!(sseu->slice_mask & BIT(s)))
                        /* skip disabled slice */
                        continue;
 
@@ -118,7 +117,7 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
                for (ss = 0; ss < ss_max; ss++) {
                        int eu_per_ss;
 
-                       if (ss_disable & BIT(ss))
+                       if (!(sseu->subslice_mask & BIT(ss)))
                                /* skip disabled subslice */
                                continue;
 
@@ -131,9 +130,9 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
                         * subslices if they are unbalanced.
                         */
                        if (eu_per_ss == 7)
-                               info->subslice_7eu[s] |= BIT(ss);
+                               sseu->subslice_7eu[s] |= BIT(ss);
 
-                       info->eu_total += eu_per_ss;
+                       sseu->eu_total += eu_per_ss;
                }
        }
 
@@ -144,9 +143,9 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
         * recovery. BXT is expected to be perfectly uniform in EU
         * distribution.
        */
-       info->eu_per_subslice = info->subslice_total ?
-                               DIV_ROUND_UP(info->eu_total,
-                                            info->subslice_total) : 0;
+       sseu->eu_per_subslice = sseu_subslice_total(sseu) ?
+                               DIV_ROUND_UP(sseu->eu_total,
+                                            sseu_subslice_total(sseu)) : 0;
        /*
         * SKL supports slice power gating on devices with more than
         * one slice, and supports EU power gating on devices with
@@ -155,15 +154,15 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
         * supports EU power gating on devices with more than one EU
         * pair per subslice.
        */
-       info->has_slice_pg =
+       sseu->has_slice_pg =
                (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) &&
-               info->slice_total > 1;
-       info->has_subslice_pg =
-               IS_BROXTON(dev_priv) && info->subslice_total > 1;
-       info->has_eu_pg = info->eu_per_subslice > 2;
+               hweight8(sseu->slice_mask) > 1;
+       sseu->has_subslice_pg =
+               IS_BROXTON(dev_priv) && sseu_subslice_total(sseu) > 1;
+       sseu->has_eu_pg = sseu->eu_per_subslice > 2;
 
        if (IS_BROXTON(dev_priv)) {
-#define IS_SS_DISABLED(_ss_disable, ss)    (_ss_disable & BIT(ss))
+#define IS_SS_DISABLED(ss)     (!(sseu->subslice_mask & BIT(ss)))
                /*
                 * There is a HW issue in 2x6 fused down parts that requires
                 * Pooled EU to be enabled as a WA. The pool configuration
@@ -171,19 +170,18 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
                 * doesn't affect if the device has all 3 subslices enabled.
                 */
                /* WaEnablePooledEuFor2x6:bxt */
-               info->has_pooled_eu = ((info->subslice_per_slice == 3) ||
-                                      (info->subslice_per_slice == 2 &&
+               info->has_pooled_eu = ((hweight8(sseu->subslice_mask) == 3) ||
+                                      (hweight8(sseu->subslice_mask) == 2 &&
                                        INTEL_REVID(dev_priv) < BXT_REVID_C0));
 
-               info->min_eu_in_pool = 0;
+               sseu->min_eu_in_pool = 0;
                if (info->has_pooled_eu) {
-                       if (IS_SS_DISABLED(ss_disable, 0) ||
-                           IS_SS_DISABLED(ss_disable, 2))
-                               info->min_eu_in_pool = 3;
-                       else if (IS_SS_DISABLED(ss_disable, 1))
-                               info->min_eu_in_pool = 6;
+                       if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0))
+                               sseu->min_eu_in_pool = 3;
+                       else if (IS_SS_DISABLED(1))
+                               sseu->min_eu_in_pool = 6;
                        else
-                               info->min_eu_in_pool = 9;
+                               sseu->min_eu_in_pool = 9;
                }
 #undef IS_SS_DISABLED
        }
@@ -191,14 +189,20 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
 
 static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
 {
-       struct intel_device_info *info = mkwrite_device_info(dev_priv);
+       struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
        const int s_max = 3, ss_max = 3, eu_max = 8;
        int s, ss;
-       u32 fuse2, eu_disable[s_max], s_enable, ss_disable;
+       u32 fuse2, eu_disable[s_max];
 
        fuse2 = I915_READ(GEN8_FUSE2);
-       s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
-       ss_disable = (fuse2 & GEN8_F2_SS_DIS_MASK) >> GEN8_F2_SS_DIS_SHIFT;
+       sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
+       /*
+        * The subslice disable field is global, i.e. it applies
+        * to each of the enabled slices.
+        */
+       sseu->subslice_mask = BIT(ss_max) - 1;
+       sseu->subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>
+                                GEN8_F2_SS_DIS_SHIFT);
 
        eu_disable[0] = I915_READ(GEN8_EU_DISABLE0) & GEN8_EU_DIS0_S0_MASK;
        eu_disable[1] = (I915_READ(GEN8_EU_DISABLE0) >> GEN8_EU_DIS0_S1_SHIFT) |
@@ -208,28 +212,19 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
                        ((I915_READ(GEN8_EU_DISABLE2) & GEN8_EU_DIS2_S2_MASK) <<
                         (32 - GEN8_EU_DIS1_S2_SHIFT));
 
-       info->slice_total = hweight32(s_enable);
-
-       /*
-        * The subslice disable field is global, i.e. it applies
-        * to each of the enabled slices.
-        */
-       info->subslice_per_slice = ss_max - hweight32(ss_disable);
-       info->subslice_total = info->slice_total * info->subslice_per_slice;
-
        /*
         * Iterate through enabled slices and subslices to
         * count the total enabled EU.
         */
        for (s = 0; s < s_max; s++) {
-               if (!(s_enable & (0x1 << s)))
+               if (!(sseu->slice_mask & BIT(s)))
                        /* skip disabled slice */
                        continue;
 
                for (ss = 0; ss < ss_max; ss++) {
                        u32 n_disabled;
 
-                       if (ss_disable & (0x1 << ss))
+                       if (!(sseu->subslice_mask & BIT(ss)))
                                /* skip disabled subslice */
                                continue;
 
@@ -239,9 +234,9 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
                         * Record which subslices have 7 EUs.
                         */
                        if (eu_max - n_disabled == 7)
-                               info->subslice_7eu[s] |= 1 << ss;
+                               sseu->subslice_7eu[s] |= 1 << ss;
 
-                       info->eu_total += eu_max - n_disabled;
+                       sseu->eu_total += eu_max - n_disabled;
                }
        }
 
@@ -250,16 +245,17 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
         * subslices with the exception that any one EU in any one subslice may
         * be fused off for die recovery.
         */
-       info->eu_per_subslice = info->subslice_total ?
-               DIV_ROUND_UP(info->eu_total, info->subslice_total) : 0;
+       sseu->eu_per_subslice = sseu_subslice_total(sseu) ?
+                               DIV_ROUND_UP(sseu->eu_total,
+                                            sseu_subslice_total(sseu)) : 0;
 
        /*
         * BDW supports slice power gating on devices with more than
         * one slice.
         */
-       info->has_slice_pg = (info->slice_total > 1);
-       info->has_subslice_pg = 0;
-       info->has_eu_pg = 0;
+       sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1;
+       sseu->has_subslice_pg = 0;
+       sseu->has_eu_pg = 0;
 }
 
 /*
@@ -374,15 +370,19 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
        if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
                info->has_snoop = false;
 
-       DRM_DEBUG_DRIVER("slice total: %u\n", info->slice_total);
-       DRM_DEBUG_DRIVER("subslice total: %u\n", info->subslice_total);
-       DRM_DEBUG_DRIVER("subslice per slice: %u\n", info->subslice_per_slice);
-       DRM_DEBUG_DRIVER("EU total: %u\n", info->eu_total);
-       DRM_DEBUG_DRIVER("EU per subslice: %u\n", info->eu_per_subslice);
+       DRM_DEBUG_DRIVER("slice mask: %04x\n", info->sseu.slice_mask);
+       DRM_DEBUG_DRIVER("slice total: %u\n", hweight8(info->sseu.slice_mask));
+       DRM_DEBUG_DRIVER("subslice total: %u\n",
+                        sseu_subslice_total(&info->sseu));
+       DRM_DEBUG_DRIVER("subslice mask %04x\n", info->sseu.subslice_mask);
+       DRM_DEBUG_DRIVER("subslice per slice: %u\n",
+                        hweight8(info->sseu.subslice_mask));
+       DRM_DEBUG_DRIVER("EU total: %u\n", info->sseu.eu_total);
+       DRM_DEBUG_DRIVER("EU per subslice: %u\n", info->sseu.eu_per_subslice);
        DRM_DEBUG_DRIVER("has slice power gating: %s\n",
-                        info->has_slice_pg ? "y" : "n");
+                        info->sseu.has_slice_pg ? "y" : "n");
        DRM_DEBUG_DRIVER("has subslice power gating: %s\n",
-                        info->has_subslice_pg ? "y" : "n");
+                        info->sseu.has_subslice_pg ? "y" : "n");
        DRM_DEBUG_DRIVER("has EU power gating: %s\n",
-                        info->has_eu_pg ? "y" : "n");
+                        info->sseu.has_eu_pg ? "y" : "n");
 }
index 175595f..fbcfed6 100644 (file)
@@ -34,6 +34,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drmP.h>
 #include "intel_drv.h"
+#include "intel_frontbuffer.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 #include "i915_gem_dmabuf.h"
@@ -1201,8 +1202,8 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv,
        if (HAS_PCH_SPLIT(dev)) {
                u32 port_sel;
 
-               pp_reg = PCH_PP_CONTROL;
-               port_sel = I915_READ(PCH_PP_ON_DELAYS) & PANEL_PORT_SELECT_MASK;
+               pp_reg = PP_CONTROL(0);
+               port_sel = I915_READ(PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK;
 
                if (port_sel == PANEL_PORT_SELECT_LVDS &&
                    I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT)
@@ -1210,10 +1211,10 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv,
                /* XXX: else fix for eDP */
        } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
                /* presumably write lock depends on pipe, not port select */
-               pp_reg = VLV_PIPE_PP_CONTROL(pipe);
+               pp_reg = PP_CONTROL(pipe);
                panel_pipe = pipe;
        } else {
-               pp_reg = PP_CONTROL;
+               pp_reg = PP_CONTROL(0);
                if (I915_READ(LVDS) & LVDS_PIPEB_SELECT)
                        panel_pipe = PIPE_B;
        }
@@ -1906,7 +1907,7 @@ static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv,
        }
 }
 
-static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv)
+void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv)
 {
        u32 val;
 
@@ -1958,12 +1959,12 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
         * a plane.  On ILK+ the pipe PLLs are integrated, so we don't
         * need the check.
         */
-       if (HAS_GMCH_DISPLAY(dev_priv))
+       if (HAS_GMCH_DISPLAY(dev_priv)) {
                if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DSI))
                        assert_dsi_pll_enabled(dev_priv);
                else
                        assert_pll_enabled(dev_priv, pipe);
-       else {
+       else {
                if (crtc->config->has_pch_encoder) {
                        /* if driving the PCH, we need FDI enabled */
                        assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder);
@@ -2146,33 +2147,6 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
        }
 }
 
-static void
-intel_fill_fb_info(struct drm_i915_private *dev_priv,
-                  struct drm_framebuffer *fb)
-{
-       struct intel_rotation_info *info = &to_intel_framebuffer(fb)->rot_info;
-       unsigned int tile_size, tile_width, tile_height, cpp;
-
-       tile_size = intel_tile_size(dev_priv);
-
-       cpp = drm_format_plane_cpp(fb->pixel_format, 0);
-       intel_tile_dims(dev_priv, &tile_width, &tile_height,
-                       fb->modifier[0], cpp);
-
-       info->plane[0].width = DIV_ROUND_UP(fb->pitches[0], tile_width * cpp);
-       info->plane[0].height = DIV_ROUND_UP(fb->height, tile_height);
-
-       if (info->pixel_format == DRM_FORMAT_NV12) {
-               cpp = drm_format_plane_cpp(fb->pixel_format, 1);
-               intel_tile_dims(dev_priv, &tile_width, &tile_height,
-                               fb->modifier[1], cpp);
-
-               info->uv_offset = fb->offsets[1];
-               info->plane[1].width = DIV_ROUND_UP(fb->pitches[1], tile_width * cpp);
-               info->plane[1].height = DIV_ROUND_UP(fb->height / 2, tile_height);
-       }
-}
-
 static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
 {
        if (INTEL_INFO(dev_priv)->gen >= 9)
@@ -2205,16 +2179,15 @@ static unsigned int intel_surf_alignment(const struct drm_i915_private *dev_priv
        }
 }
 
-int
-intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
-                          unsigned int rotation)
+struct i915_vma *
+intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
 {
        struct drm_device *dev = fb->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        struct i915_ggtt_view view;
+       struct i915_vma *vma;
        u32 alignment;
-       int ret;
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
@@ -2239,75 +2212,112 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
         */
        intel_runtime_pm_get(dev_priv);
 
-       ret = i915_gem_object_pin_to_display_plane(obj, alignment,
-                                                  &view);
-       if (ret)
-               goto err_pm;
-
-       /* Install a fence for tiled scan-out. Pre-i965 always needs a
-        * fence, whereas 965+ only requires a fence if using
-        * framebuffer compression.  For simplicity, we always install
-        * a fence as the cost is not that onerous.
-        */
-       if (view.type == I915_GGTT_VIEW_NORMAL) {
-               ret = i915_gem_object_get_fence(obj);
-               if (ret == -EDEADLK) {
-                       /*
-                        * -EDEADLK means there are no free fences
-                        * no pending flips.
-                        *
-                        * This is propagated to atomic, but it uses
-                        * -EDEADLK to force a locking recovery, so
-                        * change the returned error to -EBUSY.
-                        */
-                       ret = -EBUSY;
-                       goto err_unpin;
-               } else if (ret)
-                       goto err_unpin;
+       vma = i915_gem_object_pin_to_display_plane(obj, alignment, &view);
+       if (IS_ERR(vma))
+               goto err;
 
-               i915_gem_object_pin_fence(obj);
+       if (i915_vma_is_map_and_fenceable(vma)) {
+               /* Install a fence for tiled scan-out. Pre-i965 always needs a
+                * fence, whereas 965+ only requires a fence if using
+                * framebuffer compression.  For simplicity, we always, when
+                * possible, install a fence as the cost is not that onerous.
+                *
+                * If we fail to fence the tiled scanout, then either the
+                * modeset will reject the change (which is highly unlikely as
+                * the affected systems, all but one, do not have unmappable
+                * space) or we will not be able to enable full powersaving
+                * techniques (also likely not to apply due to various limits
+                * FBC and the like impose on the size of the buffer, which
+                * presumably we violated anyway with this unmappable buffer).
+                * Anyway, it is presumably better to stumble onwards with
+                * something and try to run the system in a "less than optimal"
+                * mode that matches the user configuration.
+                */
+               if (i915_vma_get_fence(vma) == 0)
+                       i915_vma_pin_fence(vma);
        }
 
+err:
        intel_runtime_pm_put(dev_priv);
-       return 0;
-
-err_unpin:
-       i915_gem_object_unpin_from_display_plane(obj, &view);
-err_pm:
-       intel_runtime_pm_put(dev_priv);
-       return ret;
+       return vma;
 }
 
 void intel_unpin_fb_obj(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;
 
        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);
 
-       if (view.type == I915_GGTT_VIEW_NORMAL)
-               i915_gem_object_unpin_fence(obj);
+       i915_vma_unpin_fence(vma);
+       i915_gem_object_unpin_from_display_plane(vma);
+}
 
-       i915_gem_object_unpin_from_display_plane(obj, &view);
+static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane,
+                         unsigned int rotation)
+{
+       if (intel_rotation_90_or_270(rotation))
+               return to_intel_framebuffer(fb)->rotated[plane].pitch;
+       else
+               return fb->pitches[plane];
+}
+
+/*
+ * Convert the x/y offsets into a linear offset.
+ * Only valid with 0/180 degree rotation, which is fine since linear
+ * offset is only used with linear buffers on pre-hsw and tiled buffers
+ * with gen2/3, and 90/270 degree rotations isn't supported on any of them.
+ */
+u32 intel_fb_xy_to_linear(int x, int y,
+                         const struct intel_plane_state *state,
+                         int plane)
+{
+       const struct drm_framebuffer *fb = state->base.fb;
+       unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
+       unsigned int pitch = fb->pitches[plane];
+
+       return y * pitch + x * cpp;
+}
+
+/*
+ * Add the x/y offsets derived from fb->offsets[] to the user
+ * specified plane src x/y offsets. The resulting x/y offsets
+ * specify the start of scanout from the beginning of the gtt mapping.
+ */
+void intel_add_fb_offsets(int *x, int *y,
+                         const struct intel_plane_state *state,
+                         int plane)
+
+{
+       const struct intel_framebuffer *intel_fb = to_intel_framebuffer(state->base.fb);
+       unsigned int rotation = state->base.rotation;
+
+       if (intel_rotation_90_or_270(rotation)) {
+               *x += intel_fb->rotated[plane].x;
+               *y += intel_fb->rotated[plane].y;
+       } else {
+               *x += intel_fb->normal[plane].x;
+               *y += intel_fb->normal[plane].y;
+       }
 }
 
 /*
- * Adjust the tile offset by moving the difference into
- * the x/y offsets.
- *
  * Input tile dimensions and pitch must already be
  * rotated to match x and y, and in pixel units.
  */
-static u32 intel_adjust_tile_offset(int *x, int *y,
-                                   unsigned int tile_width,
-                                   unsigned int tile_height,
-                                   unsigned int tile_size,
-                                   unsigned int pitch_tiles,
-                                   u32 old_offset,
-                                   u32 new_offset)
-{
+static u32 _intel_adjust_tile_offset(int *x, int *y,
+                                    unsigned int tile_width,
+                                    unsigned int tile_height,
+                                    unsigned int tile_size,
+                                    unsigned int pitch_tiles,
+                                    u32 old_offset,
+                                    u32 new_offset)
+{
+       unsigned int pitch_pixels = pitch_tiles * tile_width;
        unsigned int tiles;
 
        WARN_ON(old_offset & (tile_size - 1));
@@ -2319,6 +2329,54 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
        *y += tiles / pitch_tiles * tile_height;
        *x += tiles % pitch_tiles * tile_width;
 
+       /* minimize x in case it got needlessly big */
+       *y += *x / pitch_pixels * tile_height;
+       *x %= pitch_pixels;
+
+       return new_offset;
+}
+
+/*
+ * Adjust the tile offset by moving the difference into
+ * the x/y offsets.
+ */
+static u32 intel_adjust_tile_offset(int *x, int *y,
+                                   const struct intel_plane_state *state, int plane,
+                                   u32 old_offset, u32 new_offset)
+{
+       const struct drm_i915_private *dev_priv = to_i915(state->base.plane->dev);
+       const struct drm_framebuffer *fb = state->base.fb;
+       unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
+       unsigned int rotation = state->base.rotation;
+       unsigned int pitch = intel_fb_pitch(fb, plane, rotation);
+
+       WARN_ON(new_offset > old_offset);
+
+       if (fb->modifier[plane] != DRM_FORMAT_MOD_NONE) {
+               unsigned int tile_size, tile_width, tile_height;
+               unsigned int pitch_tiles;
+
+               tile_size = intel_tile_size(dev_priv);
+               intel_tile_dims(dev_priv, &tile_width, &tile_height,
+                               fb->modifier[plane], cpp);
+
+               if (intel_rotation_90_or_270(rotation)) {
+                       pitch_tiles = pitch / tile_height;
+                       swap(tile_width, tile_height);
+               } else {
+                       pitch_tiles = pitch / (tile_width * cpp);
+               }
+
+               _intel_adjust_tile_offset(x, y, tile_width, tile_height,
+                                         tile_size, pitch_tiles,
+                                         old_offset, new_offset);
+       } else {
+               old_offset += *y * pitch + *x * cpp;
+
+               *y = (old_offset - new_offset) / pitch;
+               *x = ((old_offset - new_offset) - *y * pitch) / cpp;
+       }
+
        return new_offset;
 }
 
@@ -2329,18 +2387,24 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
  * In the 90/270 rotated case, x and y are assumed
  * to be already rotated to match the rotated GTT view, and
  * pitch is the tile_height aligned framebuffer height.
+ *
+ * This function is used when computing the derived information
+ * under intel_framebuffer, so using any of that information
+ * here is not allowed. Anything under drm_framebuffer can be
+ * used. This is why the user has to pass in the pitch since it
+ * is specified in the rotated orientation.
  */
-u32 intel_compute_tile_offset(int *x, int *y,
-                             const struct drm_framebuffer *fb, int plane,
-                             unsigned int pitch,
-                             unsigned int rotation)
+static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
+                                     int *x, int *y,
+                                     const struct drm_framebuffer *fb, int plane,
+                                     unsigned int pitch,
+                                     unsigned int rotation,
+                                     u32 alignment)
 {
-       const struct drm_i915_private *dev_priv = to_i915(fb->dev);
        uint64_t fb_modifier = fb->modifier[plane];
        unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
-       u32 offset, offset_aligned, alignment;
+       u32 offset, offset_aligned;
 
-       alignment = intel_surf_alignment(dev_priv, fb_modifier);
        if (alignment)
                alignment--;
 
@@ -2368,9 +2432,9 @@ u32 intel_compute_tile_offset(int *x, int *y,
                offset = (tile_rows * pitch_tiles + tiles) * tile_size;
                offset_aligned = offset & ~alignment;
 
-               intel_adjust_tile_offset(x, y, tile_width, tile_height,
-                                        tile_size, pitch_tiles,
-                                        offset, offset_aligned);
+               _intel_adjust_tile_offset(x, y, tile_width, tile_height,
+                                         tile_size, pitch_tiles,
+                                         offset, offset_aligned);
        } else {
                offset = *y * pitch + *x * cpp;
                offset_aligned = offset & ~alignment;
@@ -2382,6 +2446,177 @@ u32 intel_compute_tile_offset(int *x, int *y,
        return offset_aligned;
 }
 
+u32 intel_compute_tile_offset(int *x, int *y,
+                             const struct intel_plane_state *state,
+                             int plane)
+{
+       const struct drm_i915_private *dev_priv = to_i915(state->base.plane->dev);
+       const struct drm_framebuffer *fb = state->base.fb;
+       unsigned int rotation = state->base.rotation;
+       int pitch = intel_fb_pitch(fb, plane, rotation);
+       u32 alignment;
+
+       /* AUX_DIST needs only 4K alignment */
+       if (fb->pixel_format == DRM_FORMAT_NV12 && plane == 1)
+               alignment = 4096;
+       else
+               alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]);
+
+       return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch,
+                                         rotation, alignment);
+}
+
+/* Convert the fb->offset[] linear offset into x/y offsets */
+static void intel_fb_offset_to_xy(int *x, int *y,
+                                 const struct drm_framebuffer *fb, int plane)
+{
+       unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
+       unsigned int pitch = fb->pitches[plane];
+       u32 linear_offset = fb->offsets[plane];
+
+       *y = linear_offset / pitch;
+       *x = linear_offset % pitch / cpp;
+}
+
+static unsigned int intel_fb_modifier_to_tiling(uint64_t fb_modifier)
+{
+       switch (fb_modifier) {
+       case I915_FORMAT_MOD_X_TILED:
+               return I915_TILING_X;
+       case I915_FORMAT_MOD_Y_TILED:
+               return I915_TILING_Y;
+       default:
+               return I915_TILING_NONE;
+       }
+}
+
+static int
+intel_fill_fb_info(struct drm_i915_private *dev_priv,
+                  struct drm_framebuffer *fb)
+{
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+       struct intel_rotation_info *rot_info = &intel_fb->rot_info;
+       u32 gtt_offset_rotated = 0;
+       unsigned int max_size = 0;
+       uint32_t format = fb->pixel_format;
+       int i, num_planes = drm_format_num_planes(format);
+       unsigned int tile_size = intel_tile_size(dev_priv);
+
+       for (i = 0; i < num_planes; i++) {
+               unsigned int width, height;
+               unsigned int cpp, size;
+               u32 offset;
+               int x, y;
+
+               cpp = drm_format_plane_cpp(format, i);
+               width = drm_format_plane_width(fb->width, format, i);
+               height = drm_format_plane_height(fb->height, format, i);
+
+               intel_fb_offset_to_xy(&x, &y, fb, i);
+
+               /*
+                * The fence (if used) is aligned to the start of the object
+                * so having the framebuffer wrap around across the edge of the
+                * fenced region doesn't really work. We have no API to configure
+                * the fence start offset within the object (nor could we probably
+                * on gen2/3). So it's just easier if we just require that the
+                * fb layout agrees with the fence layout. We already check that the
+                * fb stride matches the fence stride elsewhere.
+                */
+               if (i915_gem_object_is_tiled(intel_fb->obj) &&
+                   (x + width) * cpp > fb->pitches[i]) {
+                       DRM_DEBUG("bad fb plane %d offset: 0x%x\n",
+                                 i, fb->offsets[i]);
+                       return -EINVAL;
+               }
+
+               /*
+                * First pixel of the framebuffer from
+                * the start of the normal gtt mapping.
+                */
+               intel_fb->normal[i].x = x;
+               intel_fb->normal[i].y = y;
+
+               offset = _intel_compute_tile_offset(dev_priv, &x, &y,
+                                                   fb, 0, fb->pitches[i],
+                                                   DRM_ROTATE_0, tile_size);
+               offset /= tile_size;
+
+               if (fb->modifier[i] != DRM_FORMAT_MOD_NONE) {
+                       unsigned int tile_width, tile_height;
+                       unsigned int pitch_tiles;
+                       struct drm_rect r;
+
+                       intel_tile_dims(dev_priv, &tile_width, &tile_height,
+                                       fb->modifier[i], cpp);
+
+                       rot_info->plane[i].offset = offset;
+                       rot_info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i], tile_width * cpp);
+                       rot_info->plane[i].width = DIV_ROUND_UP(x + width, tile_width);
+                       rot_info->plane[i].height = DIV_ROUND_UP(y + height, tile_height);
+
+                       intel_fb->rotated[i].pitch =
+                               rot_info->plane[i].height * tile_height;
+
+                       /* how many tiles does this plane need */
+                       size = rot_info->plane[i].stride * rot_info->plane[i].height;
+                       /*
+                        * If the plane isn't horizontally tile aligned,
+                        * we need one more tile.
+                        */
+                       if (x != 0)
+                               size++;
+
+                       /* rotate the x/y offsets to match the GTT view */
+                       r.x1 = x;
+                       r.y1 = y;
+                       r.x2 = x + width;
+                       r.y2 = y + height;
+                       drm_rect_rotate(&r,
+                                       rot_info->plane[i].width * tile_width,
+                                       rot_info->plane[i].height * tile_height,
+                                       DRM_ROTATE_270);
+                       x = r.x1;
+                       y = r.y1;
+
+                       /* rotate the tile dimensions to match the GTT view */
+                       pitch_tiles = intel_fb->rotated[i].pitch / tile_height;
+                       swap(tile_width, tile_height);
+
+                       /*
+                        * We only keep the x/y offsets, so push all of the
+                        * gtt offset into the x/y offsets.
+                        */
+                       _intel_adjust_tile_offset(&x, &y, tile_size,
+                                                 tile_width, tile_height, pitch_tiles,
+                                                 gtt_offset_rotated * tile_size, 0);
+
+                       gtt_offset_rotated += rot_info->plane[i].width * rot_info->plane[i].height;
+
+                       /*
+                        * First pixel of the framebuffer from
+                        * the start of the rotated gtt mapping.
+                        */
+                       intel_fb->rotated[i].x = x;
+                       intel_fb->rotated[i].y = y;
+               } else {
+                       size = DIV_ROUND_UP((y + height) * fb->pitches[i] +
+                                           x * cpp, tile_size);
+               }
+
+               /* how many tiles in total needed in the bo */
+               max_size = max(max_size, offset + size);
+       }
+
+       if (max_size * tile_size > to_intel_framebuffer(fb)->obj->base.size) {
+               DRM_DEBUG("fb too big for bo (need %u bytes, have %zu bytes)\n",
+                         max_size * tile_size, to_intel_framebuffer(fb)->obj->base.size);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int i9xx_format_to_fourcc(int format)
 {
        switch (format) {
@@ -2465,9 +2700,8 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
                return false;
        }
 
-       obj->tiling_mode = plane_config->tiling;
-       if (obj->tiling_mode == I915_TILING_X)
-               obj->stride = fb->pitches[0];
+       if (plane_config->tiling == I915_TILING_X)
+               obj->tiling_and_stride = fb->pitches[0] | I915_TILING_X;
 
        mode_cmd.pixel_format = fb->pixel_format;
        mode_cmd.width = fb->width;
@@ -2488,7 +2722,7 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
        return true;
 
 out_unref_obj:
-       drm_gem_object_unreference(&obj->base);
+       i915_gem_object_put(obj);
        mutex_unlock(&dev->struct_mutex);
        return false;
 }
@@ -2552,7 +2786,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
                        continue;
 
                obj = intel_fb_obj(fb);
-               if (i915_gem_obj_ggtt_offset(obj) == plane_config->base) {
+               if (i915_gem_object_ggtt_offset(obj, NULL) == plane_config->base) {
                        drm_framebuffer_reference(fb);
                        goto valid_fb;
                }
@@ -2565,7 +2799,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)->visible = false;
+       to_intel_plane_state(plane_state)->base.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);
@@ -2583,24 +2817,188 @@ valid_fb:
        plane_state->crtc_w = fb->width;
        plane_state->crtc_h = fb->height;
 
-       intel_state->src.x1 = plane_state->src_x;
-       intel_state->src.y1 = plane_state->src_y;
-       intel_state->src.x2 = plane_state->src_x + plane_state->src_w;
-       intel_state->src.y2 = plane_state->src_y + plane_state->src_h;
-       intel_state->dst.x1 = plane_state->crtc_x;
-       intel_state->dst.y1 = plane_state->crtc_y;
-       intel_state->dst.x2 = plane_state->crtc_x + plane_state->crtc_w;
-       intel_state->dst.y2 = plane_state->crtc_y + plane_state->crtc_h;
+       intel_state->base.src.x1 = plane_state->src_x;
+       intel_state->base.src.y1 = plane_state->src_y;
+       intel_state->base.src.x2 = plane_state->src_x + plane_state->src_w;
+       intel_state->base.src.y2 = plane_state->src_y + plane_state->src_h;
+       intel_state->base.dst.x1 = plane_state->crtc_x;
+       intel_state->base.dst.y1 = plane_state->crtc_y;
+       intel_state->base.dst.x2 = plane_state->crtc_x + plane_state->crtc_w;
+       intel_state->base.dst.y2 = plane_state->crtc_y + plane_state->crtc_h;
 
        obj = intel_fb_obj(fb);
-       if (obj->tiling_mode != I915_TILING_NONE)
+       if (i915_gem_object_is_tiled(obj))
                dev_priv->preserve_bios_swizzle = true;
 
        drm_framebuffer_reference(fb);
        primary->fb = primary->state->fb = fb;
        primary->crtc = primary->state->crtc = &intel_crtc->base;
        intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary));
-       obj->frontbuffer_bits |= to_intel_plane(primary)->frontbuffer_bit;
+       atomic_or(to_intel_plane(primary)->frontbuffer_bit,
+                 &obj->frontbuffer_bits);
+}
+
+static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane,
+                              unsigned int rotation)
+{
+       int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
+
+       switch (fb->modifier[plane]) {
+       case DRM_FORMAT_MOD_NONE:
+       case I915_FORMAT_MOD_X_TILED:
+               switch (cpp) {
+               case 8:
+                       return 4096;
+               case 4:
+               case 2:
+               case 1:
+                       return 8192;
+               default:
+                       MISSING_CASE(cpp);
+                       break;
+               }
+               break;
+       case I915_FORMAT_MOD_Y_TILED:
+       case I915_FORMAT_MOD_Yf_TILED:
+               switch (cpp) {
+               case 8:
+                       return 2048;
+               case 4:
+                       return 4096;
+               case 2:
+               case 1:
+                       return 8192;
+               default:
+                       MISSING_CASE(cpp);
+                       break;
+               }
+               break;
+       default:
+               MISSING_CASE(fb->modifier[plane]);
+       }
+
+       return 2048;
+}
+
+static int skl_check_main_surface(struct intel_plane_state *plane_state)
+{
+       const struct drm_i915_private *dev_priv = to_i915(plane_state->base.plane->dev);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
+       int x = plane_state->base.src.x1 >> 16;
+       int y = plane_state->base.src.y1 >> 16;
+       int w = drm_rect_width(&plane_state->base.src) >> 16;
+       int h = drm_rect_height(&plane_state->base.src) >> 16;
+       int max_width = skl_max_plane_width(fb, 0, rotation);
+       int max_height = 4096;
+       u32 alignment, offset, aux_offset = plane_state->aux.offset;
+
+       if (w > max_width || h > max_height) {
+               DRM_DEBUG_KMS("requested Y/RGB source size %dx%d too big (limit %dx%d)\n",
+                             w, h, max_width, max_height);
+               return -EINVAL;
+       }
+
+       intel_add_fb_offsets(&x, &y, plane_state, 0);
+       offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
+
+       alignment = intel_surf_alignment(dev_priv, fb->modifier[0]);
+
+       /*
+        * AUX surface offset is specified as the distance from the
+        * main surface offset, and it must be non-negative. Make
+        * sure that is what we will get.
+        */
+       if (offset > aux_offset)
+               offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
+                                                 offset, aux_offset & ~(alignment - 1));
+
+       /*
+        * When using an X-tiled surface, the plane blows up
+        * if the x offset + width exceed the stride.
+        *
+        * TODO: linear and Y-tiled seem fine, Yf untested,
+        */
+       if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) {
+               int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+
+               while ((x + w) * cpp > fb->pitches[0]) {
+                       if (offset == 0) {
+                               DRM_DEBUG_KMS("Unable to find suitable display surface offset\n");
+                               return -EINVAL;
+                       }
+
+                       offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
+                                                         offset, offset - alignment);
+               }
+       }
+
+       plane_state->main.offset = offset;
+       plane_state->main.x = x;
+       plane_state->main.y = y;
+
+       return 0;
+}
+
+static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
+{
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
+       int max_width = skl_max_plane_width(fb, 1, rotation);
+       int max_height = 4096;
+       int x = plane_state->base.src.x1 >> 17;
+       int y = plane_state->base.src.y1 >> 17;
+       int w = drm_rect_width(&plane_state->base.src) >> 17;
+       int h = drm_rect_height(&plane_state->base.src) >> 17;
+       u32 offset;
+
+       intel_add_fb_offsets(&x, &y, plane_state, 1);
+       offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
+
+       /* FIXME not quite sure how/if these apply to the chroma plane */
+       if (w > max_width || h > max_height) {
+               DRM_DEBUG_KMS("CbCr source size %dx%d too big (limit %dx%d)\n",
+                             w, h, max_width, max_height);
+               return -EINVAL;
+       }
+
+       plane_state->aux.offset = offset;
+       plane_state->aux.x = x;
+       plane_state->aux.y = y;
+
+       return 0;
+}
+
+int skl_check_plane_surface(struct intel_plane_state *plane_state)
+{
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
+       int ret;
+
+       /* Rotate src coordinates to match rotated GTT view */
+       if (intel_rotation_90_or_270(rotation))
+               drm_rect_rotate(&plane_state->base.src,
+                               fb->width, fb->height, DRM_ROTATE_270);
+
+       /*
+        * Handle the AUX surface first since
+        * the main surface setup depends on it.
+        */
+       if (fb->pixel_format == DRM_FORMAT_NV12) {
+               ret = skl_check_nv12_aux_surface(plane_state);
+               if (ret)
+                       return ret;
+       } else {
+               plane_state->aux.offset = ~0xfff;
+               plane_state->aux.x = 0;
+               plane_state->aux.y = 0;
+       }
+
+       ret = skl_check_main_surface(plane_state);
+       if (ret)
+               return ret;
+
+       return 0;
 }
 
 static void i9xx_update_primary_plane(struct drm_plane *primary,
@@ -2617,9 +3015,8 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
        u32 dspcntr;
        i915_reg_t reg = DSPCNTR(plane);
        unsigned int rotation = plane_state->base.rotation;
-       int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
-       int x = plane_state->src.x1 >> 16;
-       int y = plane_state->src.y1 >> 16;
+       int x = plane_state->base.src.x1 >> 16;
+       int y = plane_state->base.src.y1 >> 16;
 
        dspcntr = DISPPLANE_GAMMA_ENABLE;
 
@@ -2670,37 +3067,31 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
                BUG();
        }
 
-       if (INTEL_INFO(dev)->gen >= 4 &&
-           obj->tiling_mode != I915_TILING_NONE)
+       if (INTEL_GEN(dev_priv) >= 4 &&
+           fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                dspcntr |= DISPPLANE_TILED;
 
        if (IS_G4X(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-       linear_offset = y * fb->pitches[0] + x * cpp;
+       intel_add_fb_offsets(&x, &y, plane_state, 0);
 
-       if (INTEL_INFO(dev)->gen >= 4) {
+       if (INTEL_INFO(dev)->gen >= 4)
                intel_crtc->dspaddr_offset =
-                       intel_compute_tile_offset(&x, &y, fb, 0,
-                                                 fb->pitches[0], rotation);
-               linear_offset -= intel_crtc->dspaddr_offset;
-       } else {
-               intel_crtc->dspaddr_offset = linear_offset;
-       }
+                       intel_compute_tile_offset(&x, &y, plane_state, 0);
 
-       if (rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == DRM_ROTATE_180) {
                dspcntr |= DISPPLANE_ROTATE_180;
 
                x += (crtc_state->pipe_src_w - 1);
                y += (crtc_state->pipe_src_h - 1);
-
-               /* Finding the last pixel of the last line of the display
-               data and adding to linear_offset*/
-               linear_offset +=
-                       (crtc_state->pipe_src_h - 1) * fb->pitches[0] +
-                       (crtc_state->pipe_src_w - 1) * cpp;
        }
 
+       linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
+
+       if (INTEL_INFO(dev)->gen < 4)
+               intel_crtc->dspaddr_offset = linear_offset;
+
        intel_crtc->adjusted_x = x;
        intel_crtc->adjusted_y = y;
 
@@ -2709,11 +3100,12 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        if (INTEL_INFO(dev)->gen >= 4) {
                I915_WRITE(DSPSURF(plane),
-                          i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
+                          intel_fb_gtt_offset(fb, rotation) +
+                          intel_crtc->dspaddr_offset);
                I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
                I915_WRITE(DSPLINOFF(plane), linear_offset);
        } else
-               I915_WRITE(DSPADDR(plane), i915_gem_obj_ggtt_offset(obj) + linear_offset);
+               I915_WRITE(DSPADDR(plane), i915_gem_object_ggtt_offset(obj, NULL) + linear_offset);
        POSTING_READ(reg);
 }
 
@@ -2741,15 +3133,13 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_framebuffer *fb = plane_state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int plane = intel_crtc->plane;
        u32 linear_offset;
        u32 dspcntr;
        i915_reg_t reg = DSPCNTR(plane);
        unsigned int rotation = plane_state->base.rotation;
-       int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
-       int x = plane_state->src.x1 >> 16;
-       int y = plane_state->src.y1 >> 16;
+       int x = plane_state->base.src.x1 >> 16;
+       int y = plane_state->base.src.y1 >> 16;
 
        dspcntr = DISPPLANE_GAMMA_ENABLE;
        dspcntr |= DISPLAY_PLANE_ENABLE;
@@ -2780,32 +3170,28 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
                BUG();
        }
 
-       if (obj->tiling_mode != I915_TILING_NONE)
+       if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                dspcntr |= DISPPLANE_TILED;
 
        if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-       linear_offset = y * fb->pitches[0] + x * cpp;
+       intel_add_fb_offsets(&x, &y, plane_state, 0);
+
        intel_crtc->dspaddr_offset =
-               intel_compute_tile_offset(&x, &y, fb, 0,
-                                         fb->pitches[0], rotation);
-       linear_offset -= intel_crtc->dspaddr_offset;
-       if (rotation == BIT(DRM_ROTATE_180)) {
+               intel_compute_tile_offset(&x, &y, plane_state, 0);
+
+       if (rotation == DRM_ROTATE_180) {
                dspcntr |= DISPPLANE_ROTATE_180;
 
                if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
                        x += (crtc_state->pipe_src_w - 1);
                        y += (crtc_state->pipe_src_h - 1);
-
-                       /* Finding the last pixel of the last line of the display
-                       data and adding to linear_offset*/
-                       linear_offset +=
-                               (crtc_state->pipe_src_h - 1) * fb->pitches[0] +
-                               (crtc_state->pipe_src_w - 1) * cpp;
                }
        }
 
+       linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
+
        intel_crtc->adjusted_x = x;
        intel_crtc->adjusted_y = y;
 
@@ -2813,7 +3199,8 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
 
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        I915_WRITE(DSPSURF(plane),
-                  i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
+                  intel_fb_gtt_offset(fb, rotation) +
+                  intel_crtc->dspaddr_offset);
        if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
        } else {
@@ -2835,32 +3222,21 @@ u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv,
        }
 }
 
-u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
-                          struct drm_i915_gem_object *obj,
-                          unsigned int plane)
+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;
-       u64 offset;
 
-       intel_fill_fb_ggtt_view(&view, intel_plane->base.state->fb,
-                               intel_plane->base.state->rotation);
+       intel_fill_fb_ggtt_view(&view, fb, rotation);
 
-       vma = i915_gem_obj_to_ggtt_view(obj, &view);
+       vma = i915_gem_object_to_ggtt(obj, &view);
        if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
-               view.type))
+                view.type))
                return -1;
 
-       offset = vma->node.start;
-
-       if (plane == 1) {
-               offset += vma->ggtt_view.params.rotated.uv_start_page *
-                         PAGE_SIZE;
-       }
-
-       WARN_ON(upper_32_bits(offset));
-
-       return lower_32_bits(offset);
+       return i915_ggtt_offset(vma);
 }
 
 static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
@@ -2890,6 +3266,28 @@ static void skl_detach_scalers(struct intel_crtc *intel_crtc)
        }
 }
 
+u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
+                    unsigned int rotation)
+{
+       const struct drm_i915_private *dev_priv = to_i915(fb->dev);
+       u32 stride = intel_fb_pitch(fb, plane, rotation);
+
+       /*
+        * The stride is either expressed as a multiple of 64 bytes chunks for
+        * linear buffers or in number of tiles for tiled buffers.
+        */
+       if (intel_rotation_90_or_270(rotation)) {
+               int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
+
+               stride /= intel_tile_height(dev_priv, fb->modifier[0], cpp);
+       } else {
+               stride /= intel_fb_stride_alignment(dev_priv, fb->modifier[0],
+                                                   fb->pixel_format);
+       }
+
+       return stride;
+}
+
 u32 skl_plane_ctl_format(uint32_t pixel_format)
 {
        switch (pixel_format) {
@@ -2952,17 +3350,17 @@ u32 skl_plane_ctl_tiling(uint64_t fb_modifier)
 u32 skl_plane_ctl_rotation(unsigned int rotation)
 {
        switch (rotation) {
-       case BIT(DRM_ROTATE_0):
+       case DRM_ROTATE_0:
                break;
        /*
         * DRM_ROTATE_ is counter clockwise to stay compatible with Xrandr
         * while i915 HW rotation is clockwise, thats why this swapping.
         */
-       case BIT(DRM_ROTATE_90):
+       case DRM_ROTATE_90:
                return PLANE_CTL_ROTATE_270;
-       case BIT(DRM_ROTATE_180):
+       case DRM_ROTATE_180:
                return PLANE_CTL_ROTATE_180;
-       case BIT(DRM_ROTATE_270):
+       case DRM_ROTATE_270:
                return PLANE_CTL_ROTATE_90;
        default:
                MISSING_CASE(rotation);
@@ -2979,22 +3377,21 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_framebuffer *fb = plane_state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
        int pipe = intel_crtc->pipe;
-       u32 plane_ctl, stride_div, stride;
-       u32 tile_height, plane_offset, plane_size;
+       u32 plane_ctl;
        unsigned int rotation = plane_state->base.rotation;
-       int x_offset, y_offset;
-       u32 surf_addr;
+       u32 stride = skl_plane_stride(fb, 0, rotation);
+       u32 surf_addr = plane_state->main.offset;
        int scaler_id = plane_state->scaler_id;
-       int src_x = plane_state->src.x1 >> 16;
-       int src_y = plane_state->src.y1 >> 16;
-       int src_w = drm_rect_width(&plane_state->src) >> 16;
-       int src_h = drm_rect_height(&plane_state->src) >> 16;
-       int dst_x = plane_state->dst.x1;
-       int dst_y = plane_state->dst.y1;
-       int dst_w = drm_rect_width(&plane_state->dst);
-       int dst_h = drm_rect_height(&plane_state->dst);
+       int src_x = plane_state->main.x;
+       int src_y = plane_state->main.y;
+       int src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       int src_h = drm_rect_height(&plane_state->base.src) >> 16;
+       int dst_x = plane_state->base.dst.x1;
+       int dst_y = plane_state->base.dst.y1;
+       int dst_w = drm_rect_width(&plane_state->base.dst);
+       int dst_h = drm_rect_height(&plane_state->base.dst);
 
        plane_ctl = PLANE_CTL_ENABLE |
                    PLANE_CTL_PIPE_GAMMA_ENABLE |
@@ -3005,36 +3402,24 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
        plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
        plane_ctl |= skl_plane_ctl_rotation(rotation);
 
-       stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
-                                              fb->pixel_format);
-       surf_addr = intel_plane_obj_offset(to_intel_plane(plane), obj, 0);
+       /* Sizes are 0 based */
+       src_w--;
+       src_h--;
+       dst_w--;
+       dst_h--;
 
-       WARN_ON(drm_rect_width(&plane_state->src) == 0);
+       intel_crtc->dspaddr_offset = surf_addr;
 
-       if (intel_rotation_90_or_270(rotation)) {
-               int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
-
-               /* stride = Surface height in tiles */
-               tile_height = intel_tile_height(dev_priv, fb->modifier[0], cpp);
-               stride = DIV_ROUND_UP(fb->height, tile_height);
-               x_offset = stride * tile_height - src_y - src_h;
-               y_offset = src_x;
-               plane_size = (src_w - 1) << 16 | (src_h - 1);
-       } else {
-               stride = fb->pitches[0] / stride_div;
-               x_offset = src_x;
-               y_offset = src_y;
-               plane_size = (src_h - 1) << 16 | (src_w - 1);
-       }
-       plane_offset = y_offset << 16 | x_offset;
+       intel_crtc->adjusted_x = src_x;
+       intel_crtc->adjusted_y = src_y;
 
-       intel_crtc->adjusted_x = x_offset;
-       intel_crtc->adjusted_y = y_offset;
+       if (wm->dirty_pipes & drm_crtc_mask(&intel_crtc->base))
+               skl_write_plane_wm(intel_crtc, wm, 0);
 
        I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
-       I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
-       I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
+       I915_WRITE(PLANE_OFFSET(pipe, 0), (src_y << 16) | src_x);
        I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
+       I915_WRITE(PLANE_SIZE(pipe, 0), (src_h << 16) | src_w);
 
        if (scaler_id >= 0) {
                uint32_t ps_ctrl = 0;
@@ -3051,7 +3436,8 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
                I915_WRITE(PLANE_POS(pipe, 0), (dst_y << 16) | dst_x);
        }
 
-       I915_WRITE(PLANE_SURF(pipe, 0), surf_addr);
+       I915_WRITE(PLANE_SURF(pipe, 0),
+                  intel_fb_gtt_offset(fb, rotation) + surf_addr);
 
        POSTING_READ(PLANE_SURF(pipe, 0));
 }
@@ -3061,7 +3447,15 @@ static void skylake_disable_primary_plane(struct drm_plane *primary,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       int pipe = to_intel_crtc(crtc)->pipe;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+
+       /*
+        * We only populate skl_results on watermark updates, and if the
+        * plane's visiblity isn't actually changing neither is its watermarks.
+        */
+       if (!crtc->primary->state->visible)
+               skl_write_plane_wm(intel_crtc, &dev_priv->wm.skl_results, 0);
 
        I915_WRITE(PLANE_CTL(pipe, 0), 0);
        I915_WRITE(PLANE_SURF(pipe, 0), 0);
@@ -3096,7 +3490,7 @@ static void intel_update_primary_planes(struct drm_device *dev)
                struct intel_plane_state *plane_state =
                        to_intel_plane_state(plane->base.state);
 
-               if (plane_state->visible)
+               if (plane_state->base.visible)
                        plane->update_plane(&plane->base,
                                            to_intel_crtc_state(crtc->state),
                                            plane_state);
@@ -3135,6 +3529,12 @@ __intel_display_resume(struct drm_device *dev,
        return ret;
 }
 
+static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv)
+{
+       return intel_has_gpu_reset(dev_priv) &&
+               INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv);
+}
+
 void intel_prepare_reset(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = &dev_priv->drm;
@@ -3142,10 +3542,6 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
        struct drm_atomic_state *state;
        int ret;
 
-       /* no reset support for gen2 */
-       if (IS_GEN2(dev_priv))
-               return;
-
        /*
         * Need mode_config.mutex so that we don't
         * trample ongoing ->detect() and whatnot.
@@ -3161,7 +3557,8 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
        }
 
        /* reset doesn't touch the display, but flips might get nuked anyway, */
-       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+       if (!i915.force_reset_modeset_test &&
+           !gpu_reset_clobbers_display(dev_priv))
                return;
 
        /*
@@ -3204,24 +3601,28 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
         */
        intel_complete_page_flips(dev_priv);
 
-       /* no reset support for gen2 */
-       if (IS_GEN2(dev_priv))
-               return;
+       dev_priv->modeset_restore_state = NULL;
 
        dev_priv->modeset_restore_state = NULL;
 
        /* reset doesn't touch the display */
-       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) {
-               /*
-                * Flips in the rings have been nuked by the reset,
-                * so update the base address of all primary
-                * planes to the the last fb to make sure we're
-                * showing the correct fb after a reset.
-                *
-                * FIXME: Atomic will make this obsolete since we won't schedule
-                * CS-based flips (which might get lost in gpu resets) any more.
-                */
-               intel_update_primary_planes(dev);
+       if (!gpu_reset_clobbers_display(dev_priv)) {
+               if (!state) {
+                       /*
+                        * Flips in the rings have been nuked by the reset,
+                        * so update the base address of all primary
+                        * planes to the the last fb to make sure we're
+                        * showing the correct fb after a reset.
+                        *
+                        * FIXME: Atomic will make this obsolete since we won't schedule
+                        * CS-based flips (which might get lost in gpu resets) any more.
+                        */
+                       intel_update_primary_planes(dev);
+               } else {
+                       ret = __intel_display_resume(dev, state);
+                       if (ret)
+                               DRM_ERROR("Restoring old state failed with %i\n", ret);
+               }
        } else {
                /*
                 * The display has been reset as well,
@@ -3230,6 +3631,7 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
                intel_runtime_pm_disable_interrupts(dev_priv);
                intel_runtime_pm_enable_interrupts(dev_priv);
 
+               intel_pps_unlock_regs_wa(dev_priv);
                intel_modeset_init_hw(dev);
 
                spin_lock_irq(&dev_priv->irq_lock);
@@ -3249,15 +3651,26 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
        mutex_unlock(&dev->mode_config.mutex);
 }
 
+static bool abort_flip_on_reset(struct intel_crtc *crtc)
+{
+       struct i915_gpu_error *error = &to_i915(crtc->base.dev)->gpu_error;
+
+       if (i915_reset_in_progress(error))
+               return true;
+
+       if (crtc->reset_count != i915_reset_count(error))
+               return true;
+
+       return false;
+}
+
 static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       unsigned reset_counter;
        bool pending;
 
-       reset_counter = i915_reset_counter(&to_i915(dev)->gpu_error);
-       if (intel_crtc->reset_counter != reset_counter)
+       if (abort_flip_on_reset(intel_crtc))
                return false;
 
        spin_lock_irq(&dev->event_lock);
@@ -3900,7 +4313,7 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
        return 0;
 }
 
-static void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
+void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
 {
        u32 temp;
 
@@ -4323,7 +4736,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state)
                      intel_crtc->pipe, SKL_CRTC_INDEX);
 
        return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX,
-               &state->scaler_state.scaler_id, BIT(DRM_ROTATE_0),
+               &state->scaler_state.scaler_id, DRM_ROTATE_0,
                state->pipe_src_w, state->pipe_src_h,
                adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay);
 }
@@ -4348,7 +4761,7 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
        struct drm_framebuffer *fb = plane_state->base.fb;
        int ret;
 
-       bool force_detach = !fb || !plane_state->visible;
+       bool force_detach = !fb || !plane_state->base.visible;
 
        DRM_DEBUG_KMS("Updating scaler for [PLANE:%d:%s] scaler_user index %u.%u\n",
                      intel_plane->base.base.id, intel_plane->base.name,
@@ -4358,10 +4771,10 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
                                drm_plane_index(&intel_plane->base),
                                &plane_state->scaler_id,
                                plane_state->base.rotation,
-                               drm_rect_width(&plane_state->src) >> 16,
-                               drm_rect_height(&plane_state->src) >> 16,
-                               drm_rect_width(&plane_state->dst),
-                               drm_rect_height(&plane_state->dst));
+                               drm_rect_width(&plane_state->base.src) >> 16,
+                               drm_rect_height(&plane_state->base.src) >> 16,
+                               drm_rect_width(&plane_state->base.dst),
+                               drm_rect_height(&plane_state->base.dst));
 
        if (ret || plane_state->scaler_id < 0)
                return ret;
@@ -4639,12 +5052,11 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
        struct drm_atomic_state *old_state = old_crtc_state->base.state;
        struct intel_crtc_state *pipe_config =
                to_intel_crtc_state(crtc->base.state);
-       struct drm_device *dev = crtc->base.dev;
        struct drm_plane *primary = crtc->base.primary;
        struct drm_plane_state *old_pri_state =
                drm_atomic_get_existing_plane_state(old_state, primary);
 
-       intel_frontbuffer_flip(dev, pipe_config->fb_bits);
+       intel_frontbuffer_flip(to_i915(crtc->base.dev), pipe_config->fb_bits);
 
        crtc->wm.cxsr_allowed = true;
 
@@ -4659,9 +5071,9 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
 
                intel_fbc_post_update(crtc);
 
-               if (primary_state->visible &&
+               if (primary_state->base.visible &&
                    (needs_modeset(&pipe_config->base) ||
-                    !old_primary_state->visible))
+                    !old_primary_state->base.visible))
                        intel_post_enable_primary(&crtc->base);
        }
 }
@@ -4687,8 +5099,8 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state)
 
                intel_fbc_pre_update(crtc, pipe_config, primary_state);
 
-               if (old_primary_state->visible &&
-                   (modeset || !primary_state->visible))
+               if (old_primary_state->base.visible &&
+                   (modeset || !primary_state->base.visible))
                        intel_pre_disable_primary(&crtc->base);
        }
 
@@ -4767,18 +5179,140 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask
         * to compute the mask of flip planes precisely. For the time being
         * consider this a flip to a NULL plane.
         */
-       intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe));
+       intel_frontbuffer_flip(to_i915(dev), INTEL_FRONTBUFFER_ALL_MASK(pipe));
 }
 
-static void ironlake_crtc_enable(struct drm_crtc *crtc)
+static void intel_encoders_pre_pll_enable(struct drm_crtc *crtc,
+                                         struct intel_crtc_state *crtc_state,
+                                         struct drm_atomic_state *old_state)
 {
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector *conn;
+       int i;
+
+       for_each_connector_in_state(old_state, conn, old_conn_state, i) {
+               struct drm_connector_state *conn_state = conn->state;
+               struct intel_encoder *encoder =
+                       to_intel_encoder(conn_state->best_encoder);
+
+               if (conn_state->crtc != crtc)
+                       continue;
+
+               if (encoder->pre_pll_enable)
+                       encoder->pre_pll_enable(encoder, crtc_state, conn_state);
+       }
+}
+
+static void intel_encoders_pre_enable(struct drm_crtc *crtc,
+                                     struct intel_crtc_state *crtc_state,
+                                     struct drm_atomic_state *old_state)
+{
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector *conn;
+       int i;
+
+       for_each_connector_in_state(old_state, conn, old_conn_state, i) {
+               struct drm_connector_state *conn_state = conn->state;
+               struct intel_encoder *encoder =
+                       to_intel_encoder(conn_state->best_encoder);
+
+               if (conn_state->crtc != crtc)
+                       continue;
+
+               if (encoder->pre_enable)
+                       encoder->pre_enable(encoder, crtc_state, conn_state);
+       }
+}
+
+static void intel_encoders_enable(struct drm_crtc *crtc,
+                                 struct intel_crtc_state *crtc_state,
+                                 struct drm_atomic_state *old_state)
+{
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector *conn;
+       int i;
+
+       for_each_connector_in_state(old_state, conn, old_conn_state, i) {
+               struct drm_connector_state *conn_state = conn->state;
+               struct intel_encoder *encoder =
+                       to_intel_encoder(conn_state->best_encoder);
+
+               if (conn_state->crtc != crtc)
+                       continue;
+
+               encoder->enable(encoder, crtc_state, conn_state);
+               intel_opregion_notify_encoder(encoder, true);
+       }
+}
+
+static void intel_encoders_disable(struct drm_crtc *crtc,
+                                  struct intel_crtc_state *old_crtc_state,
+                                  struct drm_atomic_state *old_state)
+{
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector *conn;
+       int i;
+
+       for_each_connector_in_state(old_state, conn, old_conn_state, i) {
+               struct intel_encoder *encoder =
+                       to_intel_encoder(old_conn_state->best_encoder);
+
+               if (old_conn_state->crtc != crtc)
+                       continue;
+
+               intel_opregion_notify_encoder(encoder, false);
+               encoder->disable(encoder, old_crtc_state, old_conn_state);
+       }
+}
+
+static void intel_encoders_post_disable(struct drm_crtc *crtc,
+                                       struct intel_crtc_state *old_crtc_state,
+                                       struct drm_atomic_state *old_state)
+{
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector *conn;
+       int i;
+
+       for_each_connector_in_state(old_state, conn, old_conn_state, i) {
+               struct intel_encoder *encoder =
+                       to_intel_encoder(old_conn_state->best_encoder);
+
+               if (old_conn_state->crtc != crtc)
+                       continue;
+
+               if (encoder->post_disable)
+                       encoder->post_disable(encoder, old_crtc_state, old_conn_state);
+       }
+}
+
+static void intel_encoders_post_pll_disable(struct drm_crtc *crtc,
+                                           struct intel_crtc_state *old_crtc_state,
+                                           struct drm_atomic_state *old_state)
+{
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector *conn;
+       int i;
+
+       for_each_connector_in_state(old_state, conn, old_conn_state, i) {
+               struct intel_encoder *encoder =
+                       to_intel_encoder(old_conn_state->best_encoder);
+
+               if (old_conn_state->crtc != crtc)
+                       continue;
+
+               if (encoder->post_pll_disable)
+                       encoder->post_pll_disable(encoder, old_crtc_state, old_conn_state);
+       }
+}
+
+static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
+                                struct drm_atomic_state *old_state)
+{
+       struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       struct intel_crtc_state *pipe_config =
-               to_intel_crtc_state(crtc->state);
 
        if (WARN_ON(intel_crtc->active))
                return;
@@ -4816,9 +5350,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
        intel_crtc->active = true;
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->pre_enable)
-                       encoder->pre_enable(encoder);
+       intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
        if (intel_crtc->config->has_pch_encoder) {
                /* Note: FDI PLL enabling _must_ be done before we enable the
@@ -4848,8 +5380,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        assert_vblank_disabled(crtc);
        drm_crtc_vblank_on(crtc);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               encoder->enable(encoder);
+       intel_encoders_enable(crtc, pipe_config, old_state);
 
        if (HAS_PCH_CPT(dev))
                cpt_verify_modeset(dev, intel_crtc->pipe);
@@ -4867,16 +5398,15 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
        return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A;
 }
 
-static void haswell_crtc_enable(struct drm_crtc *crtc)
+static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
+                               struct drm_atomic_state *old_state)
 {
+       struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe, hsw_workaround_pipe;
        enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
-       struct intel_crtc_state *pipe_config =
-               to_intel_crtc_state(crtc->state);
 
        if (WARN_ON(intel_crtc->active))
                return;
@@ -4885,9 +5415,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
                intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
                                                      false);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
+       intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
 
        if (intel_crtc->config->shared_dpll)
                intel_enable_shared_dpll(intel_crtc);
@@ -4925,10 +5453,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        else
                intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder) {
-               if (encoder->pre_enable)
-                       encoder->pre_enable(encoder);
-       }
+       intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
        if (intel_crtc->config->has_pch_encoder)
                dev_priv->display.fdi_link_train(crtc);
@@ -4969,10 +5494,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        assert_vblank_disabled(crtc);
        drm_crtc_vblank_on(crtc);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder) {
-               encoder->enable(encoder);
-               intel_opregion_notify_encoder(encoder, true);
-       }
+       intel_encoders_enable(crtc, pipe_config, old_state);
 
        if (intel_crtc->config->has_pch_encoder) {
                intel_wait_for_vblank(dev, pipe);
@@ -5006,12 +5528,13 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
        }
 }
 
-static void ironlake_crtc_disable(struct drm_crtc *crtc)
+static void ironlake_crtc_disable(struct intel_crtc_state *old_crtc_state,
+                                 struct drm_atomic_state *old_state)
 {
+       struct drm_crtc *crtc = old_crtc_state->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
 
        /*
@@ -5024,8 +5547,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
                intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
        }
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               encoder->disable(encoder);
+       intel_encoders_disable(crtc, old_crtc_state, old_state);
 
        drm_crtc_vblank_off(crtc);
        assert_vblank_disabled(crtc);
@@ -5037,9 +5559,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        if (intel_crtc->config->has_pch_encoder)
                ironlake_fdi_disable(crtc);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->post_disable)
-                       encoder->post_disable(encoder);
+       intel_encoders_post_disable(crtc, old_crtc_state, old_state);
 
        if (intel_crtc->config->has_pch_encoder) {
                ironlake_disable_pch_transcoder(dev_priv, pipe);
@@ -5069,22 +5589,20 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
 }
 
-static void haswell_crtc_disable(struct drm_crtc *crtc)
+static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state,
+                                struct drm_atomic_state *old_state)
 {
+       struct drm_crtc *crtc = old_crtc_state->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_encoder *encoder;
        enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 
        if (intel_crtc->config->has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
                                                      false);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder) {
-               intel_opregion_notify_encoder(encoder, false);
-               encoder->disable(encoder);
-       }
+       intel_encoders_disable(crtc, old_crtc_state, old_state);
 
        drm_crtc_vblank_off(crtc);
        assert_vblank_disabled(crtc);
@@ -5107,18 +5625,11 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
        if (!transcoder_is_dsi(cpu_transcoder))
                intel_ddi_disable_pipe_clock(intel_crtc);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->post_disable)
-                       encoder->post_disable(encoder);
-
-       if (intel_crtc->config->has_pch_encoder) {
-               lpt_disable_pch_transcoder(dev_priv);
-               lpt_disable_iclkip(dev_priv);
-               intel_ddi_fdi_disable(crtc);
+       intel_encoders_post_disable(crtc, old_crtc_state, old_state);
 
+       if (old_crtc_state->has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
                                                      true);
-       }
 }
 
 static void i9xx_pfit_enable(struct intel_crtc *crtc)
@@ -6174,14 +6685,13 @@ static void valleyview_modeset_commit_cdclk(struct drm_atomic_state *old_state)
        intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
 }
 
-static void valleyview_crtc_enable(struct drm_crtc *crtc)
+static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
+                                  struct drm_atomic_state *old_state)
 {
+       struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_encoder *encoder;
-       struct intel_crtc_state *pipe_config =
-               to_intel_crtc_state(crtc->state);
        int pipe = intel_crtc->pipe;
 
        if (WARN_ON(intel_crtc->active))
@@ -6206,9 +6716,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 
        intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
+       intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
 
        if (IS_CHERRYVIEW(dev)) {
                chv_prepare_pll(intel_crtc, intel_crtc->config);
@@ -6218,9 +6726,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
                vlv_enable_pll(intel_crtc, intel_crtc->config);
        }
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->pre_enable)
-                       encoder->pre_enable(encoder);
+       intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
        i9xx_pfit_enable(intel_crtc);
 
@@ -6232,8 +6738,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
        assert_vblank_disabled(crtc);
        drm_crtc_vblank_on(crtc);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               encoder->enable(encoder);
+       intel_encoders_enable(crtc, pipe_config, old_state);
 }
 
 static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
@@ -6245,14 +6750,13 @@ static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
        I915_WRITE(FP1(crtc->pipe), crtc->config->dpll_hw_state.fp1);
 }
 
-static void i9xx_crtc_enable(struct drm_crtc *crtc)
+static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
+                            struct drm_atomic_state *old_state)
 {
+       struct drm_crtc *crtc = pipe_config->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_encoder *encoder;
-       struct intel_crtc_state *pipe_config =
-               to_intel_crtc_state(crtc->state);
        enum pipe pipe = intel_crtc->pipe;
 
        if (WARN_ON(intel_crtc->active))
@@ -6273,9 +6777,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
        if (!IS_GEN2(dev))
                intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->pre_enable)
-                       encoder->pre_enable(encoder);
+       intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
        i9xx_enable_pll(intel_crtc);
 
@@ -6289,8 +6791,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
        assert_vblank_disabled(crtc);
        drm_crtc_vblank_on(crtc);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               encoder->enable(encoder);
+       intel_encoders_enable(crtc, pipe_config, old_state);
 }
 
 static void i9xx_pfit_disable(struct intel_crtc *crtc)
@@ -6308,12 +6809,13 @@ static void i9xx_pfit_disable(struct intel_crtc *crtc)
        I915_WRITE(PFIT_CONTROL, 0);
 }
 
-static void i9xx_crtc_disable(struct drm_crtc *crtc)
+static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state,
+                             struct drm_atomic_state *old_state)
 {
+       struct drm_crtc *crtc = old_crtc_state->base.crtc;
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
 
        /*
@@ -6323,8 +6825,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
        if (IS_GEN2(dev))
                intel_wait_for_vblank(dev, pipe);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               encoder->disable(encoder);
+       intel_encoders_disable(crtc, old_crtc_state, old_state);
 
        drm_crtc_vblank_off(crtc);
        assert_vblank_disabled(crtc);
@@ -6333,9 +6834,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
 
        i9xx_pfit_disable(intel_crtc);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->post_disable)
-                       encoder->post_disable(encoder);
+       intel_encoders_post_disable(crtc, old_crtc_state, old_state);
 
        if (!intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DSI)) {
                if (IS_CHERRYVIEW(dev))
@@ -6346,9 +6845,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
                        i9xx_disable_pll(intel_crtc);
        }
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->post_pll_disable)
-                       encoder->post_pll_disable(encoder);
+       intel_encoders_post_pll_disable(crtc, old_crtc_state, old_state);
 
        if (!IS_GEN2(dev))
                intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
@@ -6361,20 +6858,34 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
        enum intel_display_power_domain domain;
        unsigned long domains;
+       struct drm_atomic_state *state;
+       struct intel_crtc_state *crtc_state;
+       int ret;
 
        if (!intel_crtc->active)
                return;
 
-       if (to_intel_plane_state(crtc->primary->state)->visible) {
+       if (to_intel_plane_state(crtc->primary->state)->base.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)->visible = false;
+               to_intel_plane_state(crtc->primary->state)->base.visible = false;
        }
 
-       dev_priv->display.crtc_disable(crtc);
+       state = drm_atomic_state_alloc(crtc->dev);
+       state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
+
+       /* Everything's already locked, -EDEADLK can't happen. */
+       crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
+       ret = drm_atomic_add_affected_connectors(state, crtc);
+
+       WARN_ON(IS_ERR(crtc_state) || ret);
+
+       dev_priv->display.crtc_disable(crtc_state, state);
+
+       drm_atomic_state_free(state);
 
        DRM_DEBUG_KMS("[CRTC:%d:%s] hw state adjusted, was enabled, now disabled\n",
                      crtc->base.id, crtc->name);
@@ -6889,9 +7400,10 @@ static int i9xx_misc_get_display_clock_speed(struct drm_device *dev)
 
 static int pnv_get_display_clock_speed(struct drm_device *dev)
 {
+       struct pci_dev *pdev = dev->pdev;
        u16 gcfgc = 0;
 
-       pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
+       pci_read_config_word(pdev, GCFGC, &gcfgc);
 
        switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
        case GC_DISPLAY_CLOCK_267_MHZ_PNV:
@@ -6913,9 +7425,10 @@ static int pnv_get_display_clock_speed(struct drm_device *dev)
 
 static int i915gm_get_display_clock_speed(struct drm_device *dev)
 {
+       struct pci_dev *pdev = dev->pdev;
        u16 gcfgc = 0;
 
-       pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
+       pci_read_config_word(pdev, GCFGC, &gcfgc);
 
        if (gcfgc & GC_LOW_FREQUENCY_ENABLE)
                return 133333;
@@ -6937,6 +7450,7 @@ static int i865_get_display_clock_speed(struct drm_device *dev)
 
 static int i85x_get_display_clock_speed(struct drm_device *dev)
 {
+       struct pci_dev *pdev = dev->pdev;
        u16 hpllcc = 0;
 
        /*
@@ -6944,10 +7458,10 @@ static int i85x_get_display_clock_speed(struct drm_device *dev)
         * encoding is different :(
         * FIXME is this the right way to detect 852GM/852GMV?
         */
-       if (dev->pdev->revision == 0x1)
+       if (pdev->revision == 0x1)
                return 133333;
 
-       pci_bus_read_config_word(dev->pdev->bus,
+       pci_bus_read_config_word(pdev->bus,
                                 PCI_DEVFN(0, 3), HPLLCC, &hpllcc);
 
        /* Assume that the hardware is in the high speed state.  This
@@ -7048,10 +7562,11 @@ static unsigned int intel_hpll_vco(struct drm_device *dev)
 
 static int gm45_get_display_clock_speed(struct drm_device *dev)
 {
+       struct pci_dev *pdev = dev->pdev;
        unsigned int cdclk_sel, vco = intel_hpll_vco(dev);
        uint16_t tmp = 0;
 
-       pci_read_config_word(dev->pdev, GCFGC, &tmp);
+       pci_read_config_word(pdev, GCFGC, &tmp);
 
        cdclk_sel = (tmp >> 12) & 0x1;
 
@@ -7070,6 +7585,7 @@ static int gm45_get_display_clock_speed(struct drm_device *dev)
 
 static int i965gm_get_display_clock_speed(struct drm_device *dev)
 {
+       struct pci_dev *pdev = dev->pdev;
        static const uint8_t div_3200[] = { 16, 10,  8 };
        static const uint8_t div_4000[] = { 20, 12, 10 };
        static const uint8_t div_5333[] = { 24, 16, 14 };
@@ -7077,7 +7593,7 @@ static int i965gm_get_display_clock_speed(struct drm_device *dev)
        unsigned int cdclk_sel, vco = intel_hpll_vco(dev);
        uint16_t tmp = 0;
 
-       pci_read_config_word(dev->pdev, GCFGC, &tmp);
+       pci_read_config_word(pdev, GCFGC, &tmp);
 
        cdclk_sel = ((tmp >> 8) & 0x1f) - 1;
 
@@ -7107,6 +7623,7 @@ fail:
 
 static int g33_get_display_clock_speed(struct drm_device *dev)
 {
+       struct pci_dev *pdev = dev->pdev;
        static const uint8_t div_3200[] = { 12, 10,  8,  7, 5, 16 };
        static const uint8_t div_4000[] = { 14, 12, 10,  8, 6, 20 };
        static const uint8_t div_4800[] = { 20, 14, 12, 10, 8, 24 };
@@ -7115,7 +7632,7 @@ static int g33_get_display_clock_speed(struct drm_device *dev)
        unsigned int cdclk_sel, vco = intel_hpll_vco(dev);
        uint16_t tmp = 0;
 
-       pci_read_config_word(dev->pdev, GCFGC, &tmp);
+       pci_read_config_word(pdev, GCFGC, &tmp);
 
        cdclk_sel = (tmp >> 4) & 0x7;
 
@@ -8995,6 +9512,24 @@ static void ironlake_compute_dpll(struct intel_crtc *intel_crtc,
        if (intel_crtc_has_dp_encoder(crtc_state))
                dpll |= DPLL_SDVO_HIGH_SPEED;
 
+       /*
+        * The high speed IO clock is only really required for
+        * SDVO/HDMI/DP, but we also enable it for CRT to make it
+        * possible to share the DPLL between CRT and HDMI. Enabling
+        * the clock needlessly does no real harm, except use up a
+        * bit of power potentially.
+        *
+        * We'll limit this to IVB with 3 pipes, since it has only two
+        * DPLLs and so DPLL sharing is the only way to get three pipes
+        * driving PCH ports at the same time. On SNB we could do this,
+        * and potentially avoid enabling the second DPLL, but it's not
+        * clear if it''s a win or loss power wise. No point in doing
+        * this on ILK at all since it has a fixed DPLL<->pipe mapping.
+        */
+       if (INTEL_INFO(dev_priv)->num_pipes == 3 &&
+           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
+               dpll |= DPLL_SDVO_HIGH_SPEED;
+
        /* compute bitmask from p1 value */
        dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
        /* also FPA1 */
@@ -9281,7 +9816,7 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
        return;
 
 error:
-       kfree(fb);
+       kfree(intel_fb);
 }
 
 static void ironlake_get_pfit_config(struct intel_crtc *crtc,
@@ -9487,7 +10022,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
        I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
        I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
        I915_STATE_WARN(I915_READ(WRPLL_CTL(1)) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
-       I915_STATE_WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
+       I915_STATE_WARN(I915_READ(PP_STATUS(0)) & PP_ON, "Panel power on\n");
        I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
             "CPU PWM1 enabled\n");
        if (IS_HASWELL(dev))
@@ -9526,7 +10061,7 @@ static void hsw_write_dcomp(struct drm_i915_private *dev_priv, uint32_t val)
                mutex_lock(&dev_priv->rps.hw_lock);
                if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP,
                                            val))
-                       DRM_ERROR("Failed to write to D_COMP\n");
+                       DRM_DEBUG_KMS("Failed to write to D_COMP\n");
                mutex_unlock(&dev_priv->rps.hw_lock);
        } else {
                I915_WRITE(D_COMP_BDW, val);
@@ -9934,15 +10469,12 @@ static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
 
        switch (port) {
        case PORT_A:
-               pipe_config->ddi_pll_sel = SKL_DPLL0;
                id = DPLL_ID_SKL_DPLL0;
                break;
        case PORT_B:
-               pipe_config->ddi_pll_sel = SKL_DPLL1;
                id = DPLL_ID_SKL_DPLL1;
                break;
        case PORT_C:
-               pipe_config->ddi_pll_sel = SKL_DPLL2;
                id = DPLL_ID_SKL_DPLL2;
                break;
        default:
@@ -9961,25 +10493,10 @@ static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
        u32 temp;
 
        temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
-       pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
+       id = temp >> (port * 3 + 1);
 
-       switch (pipe_config->ddi_pll_sel) {
-       case SKL_DPLL0:
-               id = DPLL_ID_SKL_DPLL0;
-               break;
-       case SKL_DPLL1:
-               id = DPLL_ID_SKL_DPLL1;
-               break;
-       case SKL_DPLL2:
-               id = DPLL_ID_SKL_DPLL2;
-               break;
-       case SKL_DPLL3:
-               id = DPLL_ID_SKL_DPLL3;
-               break;
-       default:
-               MISSING_CASE(pipe_config->ddi_pll_sel);
+       if (WARN_ON(id < SKL_DPLL0 || id > SKL_DPLL3))
                return;
-       }
 
        pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
 }
@@ -9989,10 +10506,9 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
                                struct intel_crtc_state *pipe_config)
 {
        enum intel_dpll_id id;
+       uint32_t ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
 
-       pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
-
-       switch (pipe_config->ddi_pll_sel) {
+       switch (ddi_pll_sel) {
        case PORT_CLK_SEL_WRPLL1:
                id = DPLL_ID_WRPLL1;
                break;
@@ -10012,7 +10528,7 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
                id = DPLL_ID_LCPLL_2700;
                break;
        default:
-               MISSING_CASE(pipe_config->ddi_pll_sel);
+               MISSING_CASE(ddi_pll_sel);
                /* fall through */
        case PORT_CLK_SEL_NONE:
                return;
@@ -10245,7 +10761,7 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t cntl = 0, size = 0;
 
-       if (plane_state && plane_state->visible) {
+       if (plane_state && plane_state->base.visible) {
                unsigned int width = plane_state->base.crtc_w;
                unsigned int height = plane_state->base.crtc_h;
                unsigned int stride = roundup_pow_of_two(width) * 4;
@@ -10306,10 +10822,14 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
        int pipe = intel_crtc->pipe;
        uint32_t cntl = 0;
 
-       if (plane_state && plane_state->visible) {
+       if (INTEL_GEN(dev_priv) >= 9 && wm->dirty_pipes & drm_crtc_mask(crtc))
+               skl_write_cursor_wm(intel_crtc, wm);
+
+       if (plane_state && plane_state->base.visible) {
                cntl = MCURSOR_GAMMA_ENABLE;
                switch (plane_state->base.crtc_w) {
                        case 64:
@@ -10330,7 +10850,7 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
                if (HAS_DDI(dev))
                        cntl |= CURSOR_PIPE_CSC_ENABLE;
 
-               if (plane_state->base.rotation == BIT(DRM_ROTATE_180))
+               if (plane_state->base.rotation == DRM_ROTATE_180)
                        cntl |= CURSOR_ROTATE_180;
        }
 
@@ -10376,7 +10896,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 
                /* ILK+ do this automagically */
                if (HAS_GMCH_DISPLAY(dev) &&
-                   plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
+                   plane_state->base.rotation == DRM_ROTATE_180) {
                        base += (plane_state->base.crtc_h *
                                 plane_state->base.crtc_w - 1) * 4;
                }
@@ -10509,7 +11029,7 @@ intel_framebuffer_create_for_mode(struct drm_device *dev,
 
        fb = intel_framebuffer_create(dev, &mode_cmd, obj);
        if (IS_ERR(fb))
-               drm_gem_object_unreference_unlocked(&obj->base);
+               i915_gem_object_put_unlocked(obj);
 
        return fb;
 }
@@ -11020,13 +11540,13 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 
        mutex_lock(&dev->struct_mutex);
        intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
-       drm_gem_object_unreference(&work->pending_flip_obj->base);
-
-       if (work->flip_queued_req)
-               i915_gem_request_assign(&work->flip_queued_req, NULL);
+       i915_gem_object_put(work->pending_flip_obj);
        mutex_unlock(&dev->struct_mutex);
 
-       intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit);
+       i915_gem_request_put(work->flip_queued_req);
+
+       intel_frontbuffer_flip_complete(to_i915(dev),
+                                       to_intel_plane(primary)->frontbuffer_bit);
        intel_fbc_post_update(crtc);
        drm_framebuffer_unreference(work->old_fb);
 
@@ -11047,10 +11567,8 @@ static bool __pageflip_finished_cs(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       unsigned reset_counter;
 
-       reset_counter = i915_reset_counter(&dev_priv->gpu_error);
-       if (crtc->reset_counter != reset_counter)
+       if (abort_flip_on_reset(crtc))
                return true;
 
        /*
@@ -11191,7 +11709,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        u32 flip_mask;
        int ret;
@@ -11207,13 +11725,13 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
                flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
        else
                flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-       intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask);
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_emit(engine, MI_DISPLAY_FLIP |
+       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       intel_ring_emit(engine, fb->pitches[0]);
-       intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
-       intel_ring_emit(engine, 0); /* aux display base address, unused */
+       intel_ring_emit(ring, fb->pitches[0]);
+       intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset);
+       intel_ring_emit(ring, 0); /* aux display base address, unused */
 
        return 0;
 }
@@ -11225,7 +11743,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        u32 flip_mask;
        int ret;
@@ -11238,13 +11756,13 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
                flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
        else
                flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-       intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask);
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
+       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       intel_ring_emit(engine, fb->pitches[0]);
-       intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
-       intel_ring_emit(engine, MI_NOOP);
+       intel_ring_emit(ring, fb->pitches[0]);
+       intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset);
+       intel_ring_emit(ring, MI_NOOP);
 
        return 0;
 }
@@ -11256,7 +11774,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t pf, pipesrc;
@@ -11270,11 +11788,11 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
         * Display Registers (which do not change across a page-flip)
         * so we need only reprogram the base address.
         */
-       intel_ring_emit(engine, MI_DISPLAY_FLIP |
+       intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       intel_ring_emit(engine, fb->pitches[0]);
-       intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset |
-                       obj->tiling_mode);
+       intel_ring_emit(ring, fb->pitches[0]);
+       intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset |
+                       intel_fb_modifier_to_tiling(fb->modifier[0]));
 
        /* XXX Enabling the panel-fitter across page-flip is so far
         * untested on non-native modes, so ignore it for now.
@@ -11282,7 +11800,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
         */
        pf = 0;
        pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
-       intel_ring_emit(engine, pf | pipesrc);
+       intel_ring_emit(ring, pf | pipesrc);
 
        return 0;
 }
@@ -11294,7 +11812,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t pf, pipesrc;
@@ -11304,10 +11822,11 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, MI_DISPLAY_FLIP |
+       intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
-       intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
+       intel_ring_emit(ring, fb->pitches[0] |
+                       intel_fb_modifier_to_tiling(fb->modifier[0]));
+       intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset);
 
        /* Contrary to the suggestions in the documentation,
         * "Enable Panel Fitter" does not seem to be required when page
@@ -11317,7 +11836,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
         */
        pf = 0;
        pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
-       intel_ring_emit(engine, pf | pipesrc);
+       intel_ring_emit(ring, pf | pipesrc);
 
        return 0;
 }
@@ -11329,7 +11848,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
                                 struct drm_i915_gem_request *req,
                                 uint32_t flags)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t plane_bit = 0;
        int len, ret;
@@ -11350,7 +11869,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
        }
 
        len = 4;
-       if (engine->id == RCS) {
+       if (req->engine->id == RCS) {
                len += 6;
                /*
                 * On Gen 8, SRM is now taking an extra dword to accommodate
@@ -11388,30 +11907,32 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
         * for the RCS also doesn't appear to drop events. Setting the DERRMR
         * to zero does lead to lockups within MI_DISPLAY_FLIP.
         */
-       if (engine->id == RCS) {
-               intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(1));
-               intel_ring_emit_reg(engine, DERRMR);
-               intel_ring_emit(engine, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
+       if (req->engine->id == RCS) {
+               intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+               intel_ring_emit_reg(ring, DERRMR);
+               intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
                                          DERRMR_PIPEB_PRI_FLIP_DONE |
                                          DERRMR_PIPEC_PRI_FLIP_DONE));
                if (IS_GEN8(dev))
-                       intel_ring_emit(engine, MI_STORE_REGISTER_MEM_GEN8 |
+                       intel_ring_emit(ring, MI_STORE_REGISTER_MEM_GEN8 |
                                              MI_SRM_LRM_GLOBAL_GTT);
                else
-                       intel_ring_emit(engine, MI_STORE_REGISTER_MEM |
+                       intel_ring_emit(ring, MI_STORE_REGISTER_MEM |
                                              MI_SRM_LRM_GLOBAL_GTT);
-               intel_ring_emit_reg(engine, DERRMR);
-               intel_ring_emit(engine, engine->scratch.gtt_offset + 256);
+               intel_ring_emit_reg(ring, DERRMR);
+               intel_ring_emit(ring,
+                               i915_ggtt_offset(req->engine->scratch) + 256);
                if (IS_GEN8(dev)) {
-                       intel_ring_emit(engine, 0);
-                       intel_ring_emit(engine, MI_NOOP);
+                       intel_ring_emit(ring, 0);
+                       intel_ring_emit(ring, MI_NOOP);
                }
        }
 
-       intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
-       intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
-       intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
-       intel_ring_emit(engine, (MI_NOOP));
+       intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
+       intel_ring_emit(ring, fb->pitches[0] |
+                       intel_fb_modifier_to_tiling(fb->modifier[0]));
+       intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset);
+       intel_ring_emit(ring, (MI_NOOP));
 
        return 0;
 }
@@ -11446,7 +11967,8 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
        if (resv && !reservation_object_test_signaled_rcu(resv, false))
                return true;
 
-       return engine != i915_gem_request_get_engine(obj->last_write_req);
+       return engine != i915_gem_active_get_engine(&obj->last_write,
+                                                   &obj->base.dev->struct_mutex);
 }
 
 static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
@@ -11457,7 +11979,7 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
        const enum pipe pipe = intel_crtc->pipe;
-       u32 ctl, stride, tile_height;
+       u32 ctl, stride = skl_plane_stride(fb, 0, rotation);
 
        ctl = I915_READ(PLANE_CTL(pipe, 0));
        ctl &= ~PLANE_CTL_TILED_MASK;
@@ -11477,20 +11999,6 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
                MISSING_CASE(fb->modifier[0]);
        }
 
-       /*
-        * The stride is either expressed as a multiple of 64 bytes chunks for
-        * linear buffers or in number of tiles for tiled buffers.
-        */
-       if (intel_rotation_90_or_270(rotation)) {
-               /* stride = Surface height in tiles */
-               tile_height = intel_tile_height(dev_priv, fb->modifier[0], 0);
-               stride = DIV_ROUND_UP(fb->height, tile_height);
-       } else {
-               stride = fb->pitches[0] /
-                       intel_fb_stride_alignment(dev_priv, fb->modifier[0],
-                                                 fb->pixel_format);
-       }
-
        /*
         * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
         * PLANE_SURF updates, the update is then guaranteed to be atomic.
@@ -11507,15 +12015,13 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
 {
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_framebuffer *intel_fb =
-               to_intel_framebuffer(intel_crtc->base.primary->fb);
-       struct drm_i915_gem_object *obj = intel_fb->obj;
+       struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
        i915_reg_t reg = DSPCNTR(intel_crtc->plane);
        u32 dspcntr;
 
        dspcntr = I915_READ(reg);
 
-       if (obj->tiling_mode != I915_TILING_NONE)
+       if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                dspcntr |= DISPPLANE_TILED;
        else
                dspcntr &= ~DISPPLANE_TILED;
@@ -11538,9 +12044,8 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
        struct reservation_object *resv;
 
        if (work->flip_queued_req)
-               WARN_ON(__i915_wait_request(work->flip_queued_req,
-                                           false, NULL,
-                                           &dev_priv->rps.mmioflips));
+               WARN_ON(i915_wait_request(work->flip_queued_req,
+                                         0, NULL, NO_WAITBOOST));
 
        /* For framebuffer backed by dmabuf, wait for fence */
        resv = i915_gem_object_get_dmabuf_resv(obj);
@@ -11651,7 +12156,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        struct intel_flip_work *work;
        struct intel_engine_cs *engine;
        bool mmio_flip;
-       struct drm_i915_gem_request *request = NULL;
+       struct drm_i915_gem_request *request;
+       struct i915_vma *vma;
        int ret;
 
        /*
@@ -11717,22 +12223,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
        /* Reference the objects for the scheduled work. */
        drm_framebuffer_reference(work->old_fb);
-       drm_gem_object_reference(&obj->base);
 
        crtc->primary->fb = fb;
        update_state_fb(crtc->primary);
 
-       intel_fbc_pre_update(intel_crtc, intel_crtc->config,
-                            to_intel_plane_state(primary->state));
-
-       work->pending_flip_obj = obj;
+       work->pending_flip_obj = i915_gem_object_get(obj);
 
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                goto cleanup;
 
-       intel_crtc->reset_counter = i915_reset_counter(&dev_priv->gpu_error);
-       if (__i915_reset_in_progress_or_wedged(intel_crtc->reset_counter)) {
+       intel_crtc->reset_count = i915_reset_count(&dev_priv->gpu_error);
+       if (i915_reset_in_progress_or_wedged(&dev_priv->gpu_error)) {
                ret = -EIO;
                goto cleanup;
        }
@@ -11744,13 +12246,14 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
        if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
                engine = &dev_priv->engine[BCS];
-               if (obj->tiling_mode != intel_fb_obj(work->old_fb)->tiling_mode)
+               if (fb->modifier[0] != old_fb->modifier[0])
                        /* vlv: DISPLAY_FLIP fails to change tiling */
                        engine = NULL;
        } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
                engine = &dev_priv->engine[BCS];
        } else if (INTEL_INFO(dev)->gen >= 7) {
-               engine = i915_gem_request_get_engine(obj->last_write_req);
+               engine = i915_gem_active_get_engine(&obj->last_write,
+                                                   &obj->base.dev->struct_mutex);
                if (engine == NULL || engine->id != RCS)
                        engine = &dev_priv->engine[BCS];
        } else {
@@ -11759,47 +12262,52 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
        mmio_flip = use_mmio_flip(engine, obj);
 
-       /* When using CS flips, we want to emit semaphores between rings.
-        * However, when using mmio flips we will create a task to do the
-        * synchronisation, so all we want here is to pin the framebuffer
-        * into the display plane and skip any waits.
-        */
-       if (!mmio_flip) {
-               ret = i915_gem_object_sync(obj, engine, &request);
-               if (!ret && !request) {
-                       request = i915_gem_request_alloc(engine, NULL);
-                       ret = PTR_ERR_OR_ZERO(request);
-               }
-
-               if (ret)
-                       goto cleanup_pending;
-       }
-
-       ret = intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
-       if (ret)
+       vma = intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
                goto cleanup_pending;
+       }
 
-       work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
-                                                 obj, 0);
+       work->gtt_offset = intel_fb_gtt_offset(fb, primary->state->rotation);
        work->gtt_offset += intel_crtc->dspaddr_offset;
        work->rotation = crtc->primary->state->rotation;
 
+       /*
+        * There's the potential that the next frame will not be compatible with
+        * FBC, so we want to call pre_update() before the actual page flip.
+        * The problem is that pre_update() caches some information about the fb
+        * object, so we want to do this only after the object is pinned. Let's
+        * be on the safe side and do this immediately before scheduling the
+        * flip.
+        */
+       intel_fbc_pre_update(intel_crtc, intel_crtc->config,
+                            to_intel_plane_state(primary->state));
+
        if (mmio_flip) {
                INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
 
-               i915_gem_request_assign(&work->flip_queued_req,
-                                       obj->last_write_req);
-
+               work->flip_queued_req = i915_gem_active_get(&obj->last_write,
+                                                           &obj->base.dev->struct_mutex);
                schedule_work(&work->mmio_work);
        } else {
-               i915_gem_request_assign(&work->flip_queued_req, request);
+               request = i915_gem_request_alloc(engine, engine->last_context);
+               if (IS_ERR(request)) {
+                       ret = PTR_ERR(request);
+                       goto cleanup_unpin;
+               }
+
+               ret = i915_gem_request_await_object(request, obj, false);
+               if (ret)
+                       goto cleanup_request;
+
                ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
                                                   page_flip_flags);
                if (ret)
-                       goto cleanup_unpin;
+                       goto cleanup_request;
 
                intel_mark_page_flip_active(intel_crtc, work);
 
+               work->flip_queued_req = i915_gem_request_get(request);
                i915_add_request_no_flush(request);
        }
 
@@ -11807,25 +12315,25 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                          to_intel_plane(primary)->frontbuffer_bit);
        mutex_unlock(&dev->struct_mutex);
 
-       intel_frontbuffer_flip_prepare(dev,
+       intel_frontbuffer_flip_prepare(to_i915(dev),
                                       to_intel_plane(primary)->frontbuffer_bit);
 
        trace_i915_flip_request(intel_crtc->plane, obj);
 
        return 0;
 
+cleanup_request:
+       i915_add_request_no_flush(request);
 cleanup_unpin:
        intel_unpin_fb_obj(fb, crtc->primary->state->rotation);
 cleanup_pending:
-       if (!IS_ERR_OR_NULL(request))
-               i915_add_request_no_flush(request);
        atomic_dec(&intel_crtc->unpin_work_count);
        mutex_unlock(&dev->struct_mutex);
 cleanup:
        crtc->primary->fb = old_fb;
        update_state_fb(crtc->primary);
 
-       drm_gem_object_unreference_unlocked(&obj->base);
+       i915_gem_object_put_unlocked(obj);
        drm_framebuffer_unreference(work->old_fb);
 
        spin_lock_irq(&dev->event_lock);
@@ -11893,7 +12401,7 @@ static bool intel_wm_need_update(struct drm_plane *plane,
        struct intel_plane_state *cur = to_intel_plane_state(plane->state);
 
        /* Update watermarks on tiling or size changes. */
-       if (new->visible != cur->visible)
+       if (new->base.visible != cur->base.visible)
                return true;
 
        if (!cur->base.fb || !new->base.fb)
@@ -11901,10 +12409,10 @@ static bool intel_wm_need_update(struct drm_plane *plane,
 
        if (cur->base.fb->modifier[0] != new->base.fb->modifier[0] ||
            cur->base.rotation != new->base.rotation ||
-           drm_rect_width(&new->src) != drm_rect_width(&cur->src) ||
-           drm_rect_height(&new->src) != drm_rect_height(&cur->src) ||
-           drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) ||
-           drm_rect_height(&new->dst) != drm_rect_height(&cur->dst))
+           drm_rect_width(&new->base.src) != drm_rect_width(&cur->base.src) ||
+           drm_rect_height(&new->base.src) != drm_rect_height(&cur->base.src) ||
+           drm_rect_width(&new->base.dst) != drm_rect_width(&cur->base.dst) ||
+           drm_rect_height(&new->base.dst) != drm_rect_height(&cur->base.dst))
                return true;
 
        return false;
@@ -11912,10 +12420,10 @@ static bool intel_wm_need_update(struct drm_plane *plane,
 
 static bool needs_scaling(struct intel_plane_state *state)
 {
-       int src_w = drm_rect_width(&state->src) >> 16;
-       int src_h = drm_rect_height(&state->src) >> 16;
-       int dst_w = drm_rect_width(&state->dst);
-       int dst_h = drm_rect_height(&state->dst);
+       int src_w = drm_rect_width(&state->base.src) >> 16;
+       int src_h = drm_rect_height(&state->base.src) >> 16;
+       int dst_w = drm_rect_width(&state->base.dst);
+       int dst_h = drm_rect_height(&state->base.dst);
 
        return (src_w != dst_w || src_h != dst_h);
 }
@@ -11946,8 +12454,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
                        return ret;
        }
 
-       was_visible = old_plane_state->visible;
-       visible = to_intel_plane_state(plane_state)->visible;
+       was_visible = old_plane_state->base.visible;
+       visible = to_intel_plane_state(plane_state)->base.visible;
 
        if (!was_crtc_enabled && WARN_ON(was_visible))
                was_visible = false;
@@ -11963,7 +12471,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)->visible = visible = false;
+               to_intel_plane_state(plane_state)->base.visible = visible = false;
 
        if (!was_visible && !visible)
                return 0;
@@ -12167,22 +12675,22 @@ static void
 connected_sink_compute_bpp(struct intel_connector *connector,
                           struct intel_crtc_state *pipe_config)
 {
+       const struct drm_display_info *info = &connector->base.display_info;
        int bpp = pipe_config->pipe_bpp;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n",
-               connector->base.base.id,
-               connector->base.name);
+                     connector->base.base.id,
+                     connector->base.name);
 
        /* Don't use an invalid EDID bpc value */
-       if (connector->base.display_info.bpc &&
-           connector->base.display_info.bpc * 3 < bpp) {
+       if (info->bpc != 0 && info->bpc * 3 < bpp) {
                DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
-                             bpp, connector->base.display_info.bpc*3);
-               pipe_config->pipe_bpp = connector->base.display_info.bpc*3;
+                             bpp, info->bpc * 3);
+               pipe_config->pipe_bpp = info->bpc * 3;
        }
 
        /* Clamp bpp to 8 on screens without EDID 1.4 */
-       if (connector->base.display_info.bpc == 0 && bpp > 24) {
+       if (info->bpc == 0 && bpp > 24) {
                DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
                              bpp);
                pipe_config->pipe_bpp = 24;
@@ -12301,10 +12809,9 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
        DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide);
 
        if (IS_BROXTON(dev)) {
-               DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x,"
+               DRM_DEBUG_KMS("dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x,"
                              "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, "
                              "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pll10: 0x%x, pcsdw12: 0x%x\n",
-                             pipe_config->ddi_pll_sel,
                              pipe_config->dpll_hw_state.ebb0,
                              pipe_config->dpll_hw_state.ebb4,
                              pipe_config->dpll_hw_state.pll0,
@@ -12317,15 +12824,13 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                              pipe_config->dpll_hw_state.pll10,
                              pipe_config->dpll_hw_state.pcsdw12);
        } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
-               DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: "
+               DRM_DEBUG_KMS("dpll_hw_state: "
                              "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n",
-                             pipe_config->ddi_pll_sel,
                              pipe_config->dpll_hw_state.ctrl1,
                              pipe_config->dpll_hw_state.cfgcr1,
                              pipe_config->dpll_hw_state.cfgcr2);
        } else if (HAS_DDI(dev)) {
-               DRM_DEBUG_KMS("ddi_pll_sel: 0x%x; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
-                             pipe_config->ddi_pll_sel,
+               DRM_DEBUG_KMS("dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
                              pipe_config->dpll_hw_state.wrpll,
                              pipe_config->dpll_hw_state.spll);
        } else {
@@ -12339,6 +12844,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
 
        DRM_DEBUG_KMS("planes on this crtc\n");
        list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               char *format_name;
                intel_plane = to_intel_plane(plane);
                if (intel_plane->pipe != crtc->pipe)
                        continue;
@@ -12351,19 +12857,23 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                        continue;
                }
 
+               format_name = drm_get_format_name(fb->pixel_format);
+
                DRM_DEBUG_KMS("[PLANE:%d:%s] enabled",
                              plane->base.id, plane->name);
                DRM_DEBUG_KMS("\tFB:%d, fb = %ux%u format = %s",
-                             fb->base.id, fb->width, fb->height,
-                             drm_get_format_name(fb->pixel_format));
+                             fb->base.id, fb->width, fb->height, format_name);
                DRM_DEBUG_KMS("\tscaler:%d src %dx%d+%d+%d dst %dx%d+%d+%d\n",
                              state->scaler_id,
-                             state->src.x1 >> 16, state->src.y1 >> 16,
-                             drm_rect_width(&state->src) >> 16,
-                             drm_rect_height(&state->src) >> 16,
-                             state->dst.x1, state->dst.y1,
-                             drm_rect_width(&state->dst),
-                             drm_rect_height(&state->dst));
+                             state->base.src.x1 >> 16,
+                             state->base.src.y1 >> 16,
+                             drm_rect_width(&state->base.src) >> 16,
+                             drm_rect_height(&state->base.src) >> 16,
+                             state->base.dst.x1, state->base.dst.y1,
+                             drm_rect_width(&state->base.dst),
+                             drm_rect_height(&state->base.dst));
+
+               kfree(format_name);
        }
 }
 
@@ -12372,6 +12882,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
        struct drm_device *dev = state->dev;
        struct drm_connector *connector;
        unsigned int used_ports = 0;
+       unsigned int used_mst_ports = 0;
 
        /*
         * Walk the connector list instead of the encoder
@@ -12408,11 +12919,20 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
                                return false;
 
                        used_ports |= port_mask;
+                       break;
+               case INTEL_OUTPUT_DP_MST:
+                       used_mst_ports |=
+                               1 << enc_to_mst(&encoder->base)->primary->port;
+                       break;
                default:
                        break;
                }
        }
 
+       /* can't mix MST and SST/HDMI on the same port */
+       if (used_ports & used_mst_ports)
+               return false;
+
        return true;
 }
 
@@ -12423,7 +12943,6 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        struct intel_crtc_scaler_state scaler_state;
        struct intel_dpll_hw_state dpll_hw_state;
        struct intel_shared_dpll *shared_dpll;
-       uint32_t ddi_pll_sel;
        bool force_thru;
 
        /* FIXME: before the switch to atomic started, a new pipe_config was
@@ -12435,7 +12954,6 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        scaler_state = crtc_state->scaler_state;
        shared_dpll = crtc_state->shared_dpll;
        dpll_hw_state = crtc_state->dpll_hw_state;
-       ddi_pll_sel = crtc_state->ddi_pll_sel;
        force_thru = crtc_state->pch_pfit.force_thru;
 
        memset(crtc_state, 0, sizeof *crtc_state);
@@ -12444,7 +12962,6 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        crtc_state->scaler_state = scaler_state;
        crtc_state->shared_dpll = shared_dpll;
        crtc_state->dpll_hw_state = dpll_hw_state;
-       crtc_state->ddi_pll_sel = ddi_pll_sel;
        crtc_state->pch_pfit.force_thru = force_thru;
 }
 
@@ -12532,7 +13049,7 @@ encoder_retry:
 
                encoder = to_intel_encoder(connector_state->best_encoder);
 
-               if (!(encoder->compute_config(encoder, pipe_config))) {
+               if (!(encoder->compute_config(encoder, pipe_config, connector_state))) {
                        DRM_DEBUG_KMS("Encoder config failure\n");
                        goto fail;
                }
@@ -12620,12 +13137,6 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2)
        return false;
 }
 
-#define for_each_intel_crtc_masked(dev, mask, intel_crtc) \
-       list_for_each_entry((intel_crtc), \
-                           &(dev)->mode_config.crtc_list, \
-                           base.head) \
-               for_each_if (mask & (1 <<(intel_crtc)->pipe))
-
 static bool
 intel_compare_m_n(unsigned int m, unsigned int n,
                  unsigned int m2, unsigned int n2,
@@ -12873,8 +13384,6 @@ intel_pipe_config_compare(struct drm_device *dev,
 
        PIPE_CONF_CHECK_I(double_wide);
 
-       PIPE_CONF_CHECK_X(ddi_pll_sel);
-
        PIPE_CONF_CHECK_P(shared_dpll);
        PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
        PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
@@ -12956,16 +13465,23 @@ static void verify_wm_state(struct drm_crtc *crtc,
                          hw_entry->start, hw_entry->end);
        }
 
-       /* cursor */
-       hw_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
-       sw_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
-
-       if (!skl_ddb_entry_equal(hw_entry, sw_entry)) {
-               DRM_ERROR("mismatch in DDB state pipe %c cursor "
-                         "(expected (%u,%u), found (%u,%u))\n",
-                         pipe_name(pipe),
-                         sw_entry->start, sw_entry->end,
-                         hw_entry->start, hw_entry->end);
+       /*
+        * cursor
+        * If the cursor plane isn't active, we may not have updated it's ddb
+        * allocation. In that case since the ddb allocation will be updated
+        * once the plane becomes visible, we can skip this check
+        */
+       if (intel_crtc->cursor_addr) {
+               hw_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
+               sw_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
+
+               if (!skl_ddb_entry_equal(hw_entry, sw_entry)) {
+                       DRM_ERROR("mismatch in DDB state pipe %c cursor "
+                                 "(expected (%u,%u), found (%u,%u))\n",
+                                 pipe_name(pipe),
+                                 sw_entry->start, sw_entry->end,
+                                 hw_entry->start, hw_entry->end);
+               }
        }
 }
 
@@ -13580,8 +14096,9 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
                        if (!intel_plane_state->wait_req)
                                continue;
 
-                       ret = __i915_wait_request(intel_plane_state->wait_req,
-                                                 true, NULL, NULL);
+                       ret = i915_wait_request(intel_plane_state->wait_req,
+                                               I915_WAIT_INTERRUPTIBLE,
+                                               NULL, NULL);
                        if (ret) {
                                /* Any hang should be swallowed by the wait */
                                WARN_ON(ret == -EIO);
@@ -13671,6 +14188,111 @@ static bool needs_vblank_wait(struct intel_crtc_state *crtc_state)
        return false;
 }
 
+static void intel_update_crtc(struct drm_crtc *crtc,
+                             struct drm_atomic_state *state,
+                             struct drm_crtc_state *old_crtc_state,
+                             unsigned int *crtc_vblank_mask)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc->state);
+       bool modeset = needs_modeset(crtc->state);
+
+       if (modeset) {
+               update_scanline_offset(intel_crtc);
+               dev_priv->display.crtc_enable(pipe_config, state);
+       } else {
+               intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
+       }
+
+       if (drm_atomic_get_existing_plane_state(state, crtc->primary)) {
+               intel_fbc_enable(
+                   intel_crtc, pipe_config,
+                   to_intel_plane_state(crtc->primary->state));
+       }
+
+       drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
+
+       if (needs_vblank_wait(pipe_config))
+               *crtc_vblank_mask |= drm_crtc_mask(crtc);
+}
+
+static void intel_update_crtcs(struct drm_atomic_state *state,
+                              unsigned int *crtc_vblank_mask)
+{
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state;
+       int i;
+
+       for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
+               if (!crtc->state->active)
+                       continue;
+
+               intel_update_crtc(crtc, state, old_crtc_state,
+                                 crtc_vblank_mask);
+       }
+}
+
+static void skl_update_crtcs(struct drm_atomic_state *state,
+                            unsigned int *crtc_vblank_mask)
+{
+       struct drm_device *dev = state->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state;
+       struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
+       struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
+       unsigned int updated = 0;
+       bool progress;
+       enum pipe pipe;
+
+       /*
+        * Whenever the number of active pipes changes, we need to make sure we
+        * update the pipes in the right order so that their ddb allocations
+        * never overlap with eachother inbetween CRTC updates. Otherwise we'll
+        * cause pipe underruns and other bad stuff.
+        */
+       do {
+               int i;
+               progress = false;
+
+               for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
+                       bool vbl_wait = false;
+                       unsigned int cmask = drm_crtc_mask(crtc);
+                       pipe = to_intel_crtc(crtc)->pipe;
+
+                       if (updated & cmask || !crtc->state->active)
+                               continue;
+                       if (skl_ddb_allocation_overlaps(state, cur_ddb, new_ddb,
+                                                       pipe))
+                               continue;
+
+                       updated |= cmask;
+
+                       /*
+                        * If this is an already active pipe, it's DDB changed,
+                        * and this isn't the last pipe that needs updating
+                        * then we need to wait for a vblank to pass for the
+                        * new ddb allocation to take effect.
+                        */
+                       if (!skl_ddb_allocation_equals(cur_ddb, new_ddb, pipe) &&
+                           !crtc->state->active_changed &&
+                           intel_state->wm_results.dirty_pipes != updated)
+                               vbl_wait = true;
+
+                       intel_update_crtc(crtc, state, old_crtc_state,
+                                         crtc_vblank_mask);
+
+                       if (vbl_wait)
+                               intel_wait_for_vblank(dev, pipe);
+
+                       progress = true;
+               }
+       } while (progress);
+}
+
 static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
@@ -13693,8 +14315,8 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                if (!intel_plane_state->wait_req)
                        continue;
 
-               ret = __i915_wait_request(intel_plane_state->wait_req,
-                                         true, NULL, NULL);
+               ret = i915_wait_request(intel_plane_state->wait_req,
+                                       0, NULL, NULL);
                /* EIO should be eaten, and we can't get interrupted in the
                 * worker, and blocking commits have waited already. */
                WARN_ON(ret);
@@ -13730,7 +14352,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 
                if (old_crtc_state->active) {
                        intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask);
-                       dev_priv->display.crtc_disable(crtc);
+                       dev_priv->display.crtc_disable(to_intel_crtc_state(old_crtc_state), state);
                        intel_crtc->active = false;
                        intel_fbc_disable(intel_crtc);
                        intel_disable_shared_dpll(intel_crtc);
@@ -13763,23 +14385,15 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                 * SKL workaround: bspec recommends we disable the SAGV when we
                 * have more then one pipe enabled
                 */
-               if (IS_SKYLAKE(dev_priv) && !skl_can_enable_sagv(state))
-                       skl_disable_sagv(dev_priv);
+               if (!intel_can_enable_sagv(state))
+                       intel_disable_sagv(dev_priv);
 
                intel_modeset_verify_disabled(dev);
        }
 
-       /* Now enable the clocks, plane, pipe, and connectors that we set up. */
+       /* Complete the events for pipes that have now been disabled */
        for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
                bool modeset = needs_modeset(crtc->state);
-               struct intel_crtc_state *pipe_config =
-                       to_intel_crtc_state(crtc->state);
-
-               if (modeset && crtc->state->active) {
-                       update_scanline_offset(to_intel_crtc(crtc));
-                       dev_priv->display.crtc_enable(crtc);
-               }
 
                /* Complete events for now disable pipes here. */
                if (modeset && !crtc->state->active && crtc->state->event) {
@@ -13789,21 +14403,11 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 
                        crtc->state->event = NULL;
                }
-
-               if (!modeset)
-                       intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
-
-               if (crtc->state->active &&
-                   drm_atomic_get_existing_plane_state(state, crtc->primary))
-                       intel_fbc_enable(intel_crtc, pipe_config, to_intel_plane_state(crtc->primary->state));
-
-               if (crtc->state->active)
-                       drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
-
-               if (pipe_config->base.active && needs_vblank_wait(pipe_config))
-                       crtc_vblank_mask |= 1 << i;
        }
 
+       /* Now enable the clocks, plane, pipe, and connectors that we set up. */
+       dev_priv->display.update_crtcs(state, &crtc_vblank_mask);
+
        /* FIXME: We should call drm_atomic_helper_commit_hw_done() here
         * already, but still need the state for the delayed optimization. To
         * fix this:
@@ -13839,9 +14443,8 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                intel_modeset_verify_crtc(crtc, old_crtc_state, crtc->state);
        }
 
-       if (IS_SKYLAKE(dev_priv) && intel_state->modeset &&
-           skl_can_enable_sagv(state))
-               skl_enable_sagv(dev_priv);
+       if (intel_state->modeset && intel_can_enable_sagv(state))
+               intel_enable_sagv(dev_priv);
 
        drm_atomic_helper_commit_hw_done(state);
 
@@ -13882,19 +14485,12 @@ static void intel_atomic_track_fbs(struct drm_atomic_state *state)
 {
        struct drm_plane_state *old_plane_state;
        struct drm_plane *plane;
-       struct drm_i915_gem_object *obj, *old_obj;
-       struct intel_plane *intel_plane;
        int i;
 
-       mutex_lock(&state->dev->struct_mutex);
-       for_each_plane_in_state(state, plane, old_plane_state, i) {
-               obj = intel_fb_obj(plane->state->fb);
-               old_obj = intel_fb_obj(old_plane_state->fb);
-               intel_plane = to_intel_plane(plane);
-
-               i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
-       }
-       mutex_unlock(&state->dev->struct_mutex);
+       for_each_plane_in_state(state, plane, old_plane_state, i)
+               i915_gem_track_fb(intel_fb_obj(old_plane_state->fb),
+                                 intel_fb_obj(plane->state->fb),
+                                 to_intel_plane(plane)->frontbuffer_bit);
 }
 
 /**
@@ -13990,8 +14586,6 @@ out:
                drm_atomic_state_free(state);
 }
 
-#undef for_each_intel_crtc_masked
-
 /*
  * FIXME: Remove this once i915 is fully DRIVER_ATOMIC by calling
  *        drm_atomic_helper_legacy_gamma_set() directly.
@@ -14060,7 +14654,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
  */
 int
 intel_prepare_plane_fb(struct drm_plane *plane,
-                      const struct drm_plane_state *new_state)
+                      struct drm_plane_state *new_state)
 {
        struct drm_device *dev = plane->dev;
        struct drm_framebuffer *fb = new_state->fb;
@@ -14119,15 +14713,17 @@ intel_prepare_plane_fb(struct drm_plane *plane,
                if (ret)
                        DRM_DEBUG_KMS("failed to attach phys object\n");
        } else {
-               ret = intel_pin_and_fence_fb_obj(fb, new_state->rotation);
+               struct i915_vma *vma;
+
+               vma = intel_pin_and_fence_fb_obj(fb, new_state->rotation);
+               if (IS_ERR(vma))
+                       ret = PTR_ERR(vma);
        }
 
        if (ret == 0) {
-               struct intel_plane_state *plane_state =
-                       to_intel_plane_state(new_state);
-
-               i915_gem_request_assign(&plane_state->wait_req,
-                                       obj->last_write_req);
+               to_intel_plane_state(new_state)->wait_req =
+                       i915_gem_active_get(&obj->last_write,
+                                           &obj->base.dev->struct_mutex);
        }
 
        return ret;
@@ -14144,10 +14740,11 @@ intel_prepare_plane_fb(struct drm_plane *plane,
  */
 void
 intel_cleanup_plane_fb(struct drm_plane *plane,
-                      const struct drm_plane_state *old_state)
+                      struct drm_plane_state *old_state)
 {
        struct drm_device *dev = plane->dev;
        struct intel_plane_state *old_intel_state;
+       struct intel_plane_state *intel_state = to_intel_plane_state(plane->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);
 
@@ -14160,6 +14757,7 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
            !INTEL_INFO(dev)->cursor_needs_physical))
                intel_unpin_fb_obj(old_state->fb, old_state->rotation);
 
+       i915_gem_request_assign(&intel_state->wait_req, NULL);
        i915_gem_request_assign(&old_intel_state->wait_req, NULL);
 }
 
@@ -14194,13 +14792,14 @@ intel_check_primary_plane(struct drm_plane *plane,
                          struct intel_crtc_state *crtc_state,
                          struct intel_plane_state *state)
 {
+       struct drm_i915_private *dev_priv = to_i915(plane->dev);
        struct drm_crtc *crtc = state->base.crtc;
-       struct drm_framebuffer *fb = state->base.fb;
        int min_scale = DRM_PLANE_HELPER_NO_SCALING;
        int max_scale = DRM_PLANE_HELPER_NO_SCALING;
        bool can_position = false;
+       int ret;
 
-       if (INTEL_INFO(plane->dev)->gen >= 9) {
+       if (INTEL_GEN(dev_priv) >= 9) {
                /* use scaler when colorkey is not required */
                if (state->ckey.flags == I915_SET_COLORKEY_NONE) {
                        min_scale = 1;
@@ -14209,22 +14808,35 @@ intel_check_primary_plane(struct drm_plane *plane,
                can_position = true;
        }
 
-       return drm_plane_helper_check_update(plane, crtc, fb, &state->src,
-                                            &state->dst, &state->clip,
-                                            state->base.rotation,
-                                            min_scale, max_scale,
-                                            can_position, true,
-                                            &state->visible);
+       ret = drm_plane_helper_check_state(&state->base,
+                                          &state->clip,
+                                          min_scale, max_scale,
+                                          can_position, true);
+       if (ret)
+               return ret;
+
+       if (!state->base.fb)
+               return 0;
+
+       if (INTEL_GEN(dev_priv) >= 9) {
+               ret = skl_check_plane_surface(state);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static void intel_begin_crtc_commit(struct drm_crtc *crtc,
                                    struct drm_crtc_state *old_crtc_state)
 {
        struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_crtc_state *old_intel_state =
                to_intel_crtc_state(old_crtc_state);
        bool modeset = needs_modeset(crtc->state);
+       enum pipe pipe = intel_crtc->pipe;
 
        /* Perform vblank evasion around commit operation */
        intel_pipe_update_start(intel_crtc);
@@ -14239,8 +14851,12 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
 
        if (to_intel_crtc_state(crtc->state)->update_pipe)
                intel_update_pipe_config(intel_crtc, old_intel_state);
-       else if (INTEL_INFO(dev)->gen >= 9)
+       else if (INTEL_GEN(dev_priv) >= 9) {
                skl_detach_scalers(intel_crtc);
+
+               I915_WRITE(PIPE_WM_LINETIME(pipe),
+                          dev_priv->wm.skl_hw.wm_linetime[pipe]);
+       }
 }
 
 static void intel_finish_crtc_commit(struct drm_crtc *crtc,
@@ -14374,11 +14990,11 @@ fail:
 void intel_create_rotation_property(struct drm_device *dev, struct intel_plane *plane)
 {
        if (!dev->mode_config.rotation_property) {
-               unsigned long flags = BIT(DRM_ROTATE_0) |
-                       BIT(DRM_ROTATE_180);
+               unsigned long flags = DRM_ROTATE_0 |
+                       DRM_ROTATE_180;
 
                if (INTEL_INFO(dev)->gen >= 9)
-                       flags |= BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270);
+                       flags |= DRM_ROTATE_90 | DRM_ROTATE_270;
 
                dev->mode_config.rotation_property =
                        drm_mode_create_rotation_property(dev, flags);
@@ -14394,19 +15010,17 @@ intel_check_cursor_plane(struct drm_plane *plane,
                         struct intel_crtc_state *crtc_state,
                         struct intel_plane_state *state)
 {
-       struct drm_crtc *crtc = crtc_state->base.crtc;
        struct drm_framebuffer *fb = state->base.fb;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        enum pipe pipe = to_intel_plane(plane)->pipe;
        unsigned stride;
        int ret;
 
-       ret = drm_plane_helper_check_update(plane, crtc, fb, &state->src,
-                                           &state->dst, &state->clip,
-                                           state->base.rotation,
-                                           DRM_PLANE_HELPER_NO_SCALING,
-                                           DRM_PLANE_HELPER_NO_SCALING,
-                                           true, true, &state->visible);
+       ret = drm_plane_helper_check_state(&state->base,
+                                          &state->clip,
+                                          DRM_PLANE_HELPER_NO_SCALING,
+                                          DRM_PLANE_HELPER_NO_SCALING,
+                                          true, true);
        if (ret)
                return ret;
 
@@ -14443,7 +15057,7 @@ intel_check_cursor_plane(struct drm_plane *plane,
         * Refuse the put the cursor into that compromised position.
         */
        if (IS_CHERRYVIEW(plane->dev) && pipe == PIPE_C &&
-           state->visible && state->base.crtc_x < 0) {
+           state->base.visible && state->base.crtc_x < 0) {
                DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n");
                return -EINVAL;
        }
@@ -14475,7 +15089,7 @@ intel_update_cursor_plane(struct drm_plane *plane,
        if (!obj)
                addr = 0;
        else if (!INTEL_INFO(dev)->cursor_needs_physical)
-               addr = i915_gem_obj_ggtt_offset(obj);
+               addr = i915_gem_object_ggtt_offset(obj, NULL);
        else
                addr = obj->phys_handle->busaddr;
 
@@ -14521,8 +15135,8 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
                if (!dev->mode_config.rotation_property)
                        dev->mode_config.rotation_property =
                                drm_mode_create_rotation_property(dev,
-                                                       BIT(DRM_ROTATE_0) |
-                                                       BIT(DRM_ROTATE_180));
+                                                       DRM_ROTATE_0 |
+                                                       DRM_ROTATE_180);
                if (dev->mode_config.rotation_property)
                        drm_object_attach_property(&cursor->base.base,
                                dev->mode_config.rotation_property,
@@ -14728,12 +15342,50 @@ static bool intel_crt_present(struct drm_device *dev)
        return true;
 }
 
+void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv)
+{
+       int pps_num;
+       int pps_idx;
+
+       if (HAS_DDI(dev_priv))
+               return;
+       /*
+        * This w/a is needed at least on CPT/PPT, but to be sure apply it
+        * everywhere where registers can be write protected.
+        */
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               pps_num = 2;
+       else
+               pps_num = 1;
+
+       for (pps_idx = 0; pps_idx < pps_num; pps_idx++) {
+               u32 val = I915_READ(PP_CONTROL(pps_idx));
+
+               val = (val & ~PANEL_UNLOCK_MASK) | PANEL_UNLOCK_REGS;
+               I915_WRITE(PP_CONTROL(pps_idx), val);
+       }
+}
+
+static void intel_pps_init(struct drm_i915_private *dev_priv)
+{
+       if (HAS_PCH_SPLIT(dev_priv) || IS_BROXTON(dev_priv))
+               dev_priv->pps_mmio_base = PCH_PPS_BASE;
+       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               dev_priv->pps_mmio_base = VLV_PPS_BASE;
+       else
+               dev_priv->pps_mmio_base = PPS_BASE;
+
+       intel_pps_unlock_regs_wa(dev_priv);
+}
+
 static void intel_setup_outputs(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_encoder *encoder;
        bool dpd_is_edp = false;
 
+       intel_pps_init(dev_priv);
+
        /*
         * intel_edp_init_connector() depends on this completing first, to
         * prevent the registeration of both eDP and LVDS and the incorrect
@@ -14921,7 +15573,7 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
        drm_framebuffer_cleanup(fb);
        mutex_lock(&dev->struct_mutex);
        WARN_ON(!intel_fb->obj->framebuffer_references--);
-       drm_gem_object_unreference(&intel_fb->obj->base);
+       i915_gem_object_put(intel_fb->obj);
        mutex_unlock(&dev->struct_mutex);
        kfree(intel_fb);
 }
@@ -15001,24 +15653,27 @@ static int intel_framebuffer_init(struct drm_device *dev,
                                  struct drm_i915_gem_object *obj)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
-       unsigned int aligned_height;
+       unsigned int tiling = i915_gem_object_get_tiling(obj);
        int ret;
        u32 pitch_limit, stride_alignment;
+       char *format_name;
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
        if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
-               /* Enforce that fb modifier and tiling mode match, but only for
-                * X-tiled. This is needed for FBC. */
-               if (!!(obj->tiling_mode == I915_TILING_X) !=
-                   !!(mode_cmd->modifier[0] == I915_FORMAT_MOD_X_TILED)) {
+               /*
+                * If there's a fence, enforce that
+                * the fb modifier and tiling mode match.
+                */
+               if (tiling != I915_TILING_NONE &&
+                   tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
                        DRM_DEBUG("tiling_mode doesn't match fb modifier\n");
                        return -EINVAL;
                }
        } else {
-               if (obj->tiling_mode == I915_TILING_X)
+               if (tiling == I915_TILING_X) {
                        mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED;
-               else if (obj->tiling_mode == I915_TILING_Y) {
+               } else if (tiling == I915_TILING_Y) {
                        DRM_DEBUG("No Y tiling for legacy addfb\n");
                        return -EINVAL;
                }
@@ -15042,6 +15697,16 @@ static int intel_framebuffer_init(struct drm_device *dev,
                return -EINVAL;
        }
 
+       /*
+        * gen2/3 display engine uses the fence if present,
+        * so the tiling mode must match the fb modifier exactly.
+        */
+       if (INTEL_INFO(dev_priv)->gen < 4 &&
+           tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
+               DRM_DEBUG("tiling_mode must match fb modifier exactly on gen2/3\n");
+               return -EINVAL;
+       }
+
        stride_alignment = intel_fb_stride_alignment(dev_priv,
                                                     mode_cmd->modifier[0],
                                                     mode_cmd->pixel_format);
@@ -15061,10 +15726,15 @@ static int intel_framebuffer_init(struct drm_device *dev,
                return -EINVAL;
        }
 
-       if (mode_cmd->modifier[0] == I915_FORMAT_MOD_X_TILED &&
-           mode_cmd->pitches[0] != obj->stride) {
+       /*
+        * If there's a fence, enforce that
+        * the fb pitch and fence stride match.
+        */
+       if (tiling != I915_TILING_NONE &&
+           mode_cmd->pitches[0] != i915_gem_object_get_stride(obj)) {
                DRM_DEBUG("pitch (%d) must match tiling stride (%d)\n",
-                         mode_cmd->pitches[0], obj->stride);
+                         mode_cmd->pitches[0],
+                         i915_gem_object_get_stride(obj));
                return -EINVAL;
        }
 
@@ -15077,16 +15747,18 @@ static int intel_framebuffer_init(struct drm_device *dev,
                break;
        case DRM_FORMAT_XRGB1555:
                if (INTEL_INFO(dev)->gen > 3) {
-                       DRM_DEBUG("unsupported pixel format: %s\n",
-                                 drm_get_format_name(mode_cmd->pixel_format));
+                       format_name = drm_get_format_name(mode_cmd->pixel_format);
+                       DRM_DEBUG("unsupported pixel format: %s\n", format_name);
+                       kfree(format_name);
                        return -EINVAL;
                }
                break;
        case DRM_FORMAT_ABGR8888:
                if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) &&
                    INTEL_INFO(dev)->gen < 9) {
-                       DRM_DEBUG("unsupported pixel format: %s\n",
-                                 drm_get_format_name(mode_cmd->pixel_format));
+                       format_name = drm_get_format_name(mode_cmd->pixel_format);
+                       DRM_DEBUG("unsupported pixel format: %s\n", format_name);
+                       kfree(format_name);
                        return -EINVAL;
                }
                break;
@@ -15094,15 +15766,17 @@ static int intel_framebuffer_init(struct drm_device *dev,
        case DRM_FORMAT_XRGB2101010:
        case DRM_FORMAT_XBGR2101010:
                if (INTEL_INFO(dev)->gen < 4) {
-                       DRM_DEBUG("unsupported pixel format: %s\n",
-                                 drm_get_format_name(mode_cmd->pixel_format));
+                       format_name = drm_get_format_name(mode_cmd->pixel_format);
+                       DRM_DEBUG("unsupported pixel format: %s\n", format_name);
+                       kfree(format_name);
                        return -EINVAL;
                }
                break;
        case DRM_FORMAT_ABGR2101010:
                if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
-                       DRM_DEBUG("unsupported pixel format: %s\n",
-                                 drm_get_format_name(mode_cmd->pixel_format));
+                       format_name = drm_get_format_name(mode_cmd->pixel_format);
+                       DRM_DEBUG("unsupported pixel format: %s\n", format_name);
+                       kfree(format_name);
                        return -EINVAL;
                }
                break;
@@ -15111,14 +15785,16 @@ static int intel_framebuffer_init(struct drm_device *dev,
        case DRM_FORMAT_YVYU:
        case DRM_FORMAT_VYUY:
                if (INTEL_INFO(dev)->gen < 5) {
-                       DRM_DEBUG("unsupported pixel format: %s\n",
-                                 drm_get_format_name(mode_cmd->pixel_format));
+                       format_name = drm_get_format_name(mode_cmd->pixel_format);
+                       DRM_DEBUG("unsupported pixel format: %s\n", format_name);
+                       kfree(format_name);
                        return -EINVAL;
                }
                break;
        default:
-               DRM_DEBUG("unsupported pixel format: %s\n",
-                         drm_get_format_name(mode_cmd->pixel_format));
+               format_name = drm_get_format_name(mode_cmd->pixel_format);
+               DRM_DEBUG("unsupported pixel format: %s\n", format_name);
+               kfree(format_name);
                return -EINVAL;
        }
 
@@ -15126,17 +15802,12 @@ static int intel_framebuffer_init(struct drm_device *dev,
        if (mode_cmd->offsets[0] != 0)
                return -EINVAL;
 
-       aligned_height = intel_fb_align_height(dev, mode_cmd->height,
-                                              mode_cmd->pixel_format,
-                                              mode_cmd->modifier[0]);
-       /* FIXME drm helper for size checks (especially planar formats)? */
-       if (obj->base.size < aligned_height * mode_cmd->pitches[0])
-               return -EINVAL;
-
        drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
        intel_fb->obj = obj;
 
-       intel_fill_fb_info(dev_priv, &intel_fb->base);
+       ret = intel_fill_fb_info(dev_priv, &intel_fb->base);
+       if (ret)
+               return ret;
 
        ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
@@ -15158,13 +15829,13 @@ intel_user_framebuffer_create(struct drm_device *dev,
        struct drm_i915_gem_object *obj;
        struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
 
-       obj = to_intel_bo(drm_gem_object_lookup(filp, mode_cmd.handles[0]));
-       if (&obj->base == NULL)
+       obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]);
+       if (!obj)
                return ERR_PTR(-ENOENT);
 
        fb = intel_framebuffer_create(dev, &mode_cmd, obj);
        if (IS_ERR(fb))
-               drm_gem_object_unreference_unlocked(&obj->base);
+               i915_gem_object_put_unlocked(obj);
 
        return fb;
 }
@@ -15347,6 +16018,11 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
                        skl_modeset_calc_cdclk;
        }
 
+       if (dev_priv->info.gen >= 9)
+               dev_priv->display.update_crtcs = skl_update_crtcs;
+       else
+               dev_priv->display.update_crtcs = intel_update_crtcs;
+
        switch (INTEL_INFO(dev_priv)->gen) {
        case 2:
                dev_priv->display.queue_flip = intel_gen2_queue_flip;
@@ -15548,15 +16224,16 @@ static void intel_init_quirks(struct drm_device *dev)
 static void i915_disable_vga(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        u8 sr1;
        i915_reg_t vga_reg = i915_vgacntrl_reg(dev);
 
        /* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */
-       vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
+       vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO);
        outb(SR01, VGA_SR_INDEX);
        sr1 = inb(VGA_SR_DATA);
        outb(sr1 | 1<<5, VGA_SR_DATA);
-       vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
+       vga_put(pdev, VGA_RSRC_LEGACY_IO);
        udelay(300);
 
        I915_WRITE(vga_reg, VGA_DISP_DISABLE);
@@ -15572,7 +16249,6 @@ void intel_modeset_init_hw(struct drm_device *dev)
        dev_priv->atomic_cdclk_freq = dev_priv->cdclk_freq;
 
        intel_init_clock_gating(dev);
-       intel_enable_gt_powersave(dev_priv);
 }
 
 /*
@@ -15839,15 +16515,22 @@ static bool intel_crtc_has_encoders(struct intel_crtc *crtc)
        return false;
 }
 
-static bool intel_encoder_has_connectors(struct intel_encoder *encoder)
+static struct intel_connector *intel_encoder_find_connector(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
        struct intel_connector *connector;
 
        for_each_connector_on_encoder(dev, &encoder->base, connector)
-               return true;
+               return connector;
 
-       return false;
+       return NULL;
+}
+
+static bool has_pch_trancoder(struct drm_i915_private *dev_priv,
+                             enum transcoder pch_transcoder)
+{
+       return HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) ||
+               (HAS_PCH_LPT_H(dev_priv) && pch_transcoder == TRANSCODER_A);
 }
 
 static void intel_sanitize_crtc(struct intel_crtc *crtc)
@@ -15893,7 +16576,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)->visible = true;
+               to_intel_plane_state(crtc->base.primary->state)->base.visible = true;
                crtc->plane = !plane;
                intel_crtc_disable_noatomic(&crtc->base);
                crtc->plane = plane;
@@ -15928,14 +16611,23 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                 * worst a fifo underrun happens which also sets this to false.
                 */
                crtc->cpu_fifo_underrun_disabled = true;
-               crtc->pch_fifo_underrun_disabled = true;
+               /*
+                * We track the PCH trancoder underrun reporting state
+                * within the crtc. With crtc for pipe A housing the underrun
+                * reporting state for PCH transcoder A, crtc for pipe B housing
+                * it for PCH transcoder B, etc. LPT-H has only PCH transcoder A,
+                * and marking underrun reporting as disabled for the non-existing
+                * PCH transcoders B and C would prevent enabling the south
+                * error interrupt (see cpt_can_enable_serr_int()).
+                */
+               if (has_pch_trancoder(dev_priv, (enum transcoder)crtc->pipe))
+                       crtc->pch_fifo_underrun_disabled = true;
        }
 }
 
 static void intel_sanitize_encoder(struct intel_encoder *encoder)
 {
        struct intel_connector *connector;
-       struct drm_device *dev = encoder->base.dev;
 
        /* We need to check both for a crtc link (meaning that the
         * encoder is active and trying to read from a pipe) and the
@@ -15943,7 +16635,8 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
        bool has_active_crtc = encoder->base.crtc &&
                to_intel_crtc(encoder->base.crtc)->active;
 
-       if (intel_encoder_has_connectors(encoder) && !has_active_crtc) {
+       connector = intel_encoder_find_connector(encoder);
+       if (connector && !has_active_crtc) {
                DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n",
                              encoder->base.base.id,
                              encoder->base.name);
@@ -15952,12 +16645,14 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
                 * fallout from our resume register restoring. Disable
                 * the encoder manually again. */
                if (encoder->base.crtc) {
+                       struct drm_crtc_state *crtc_state = encoder->base.crtc->state;
+
                        DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n",
                                      encoder->base.base.id,
                                      encoder->base.name);
-                       encoder->disable(encoder);
+                       encoder->disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
                        if (encoder->post_disable)
-                               encoder->post_disable(encoder);
+                               encoder->post_disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
                }
                encoder->base.crtc = NULL;
 
@@ -15965,12 +16660,9 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
                 * a bug in one of the get_hw_state functions. Or someplace else
                 * in our code, like the register restore mess on resume. Clamp
                 * things to off as a safer default. */
-               for_each_intel_connector(dev, connector) {
-                       if (connector->encoder != encoder)
-                               continue;
-                       connector->base.dpms = DRM_MODE_DPMS_OFF;
-                       connector->base.encoder = NULL;
-               }
+
+               connector->base.dpms = DRM_MODE_DPMS_OFF;
+               connector->base.encoder = NULL;
        }
        /* Enabled encoders without active connectors will be fixed in
         * the crtc fixup. */
@@ -16020,10 +16712,10 @@ static void readout_plane_state(struct intel_crtc *crtc)
        struct intel_plane_state *plane_state =
                to_intel_plane_state(primary->state);
 
-       plane_state->visible = crtc->active &&
+       plane_state->base.visible = crtc->active &&
                primary_get_hw_state(to_intel_plane(primary));
 
-       if (plane_state->visible)
+       if (plane_state->base.visible)
                crtc->base.state->plane_mask |= 1 << drm_plane_index(primary);
 }
 
@@ -16282,7 +16974,6 @@ 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;
-       int ret;
 
        intel_init_gt_powersave(dev_priv);
 
@@ -16296,15 +16987,17 @@ void intel_modeset_gem_init(struct drm_device *dev)
         * 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);
-               ret = intel_pin_and_fence_fb_obj(c->primary->fb,
+               vma = intel_pin_and_fence_fb_obj(c->primary->fb,
                                                 c->primary->state->rotation);
                mutex_unlock(&dev->struct_mutex);
-               if (ret) {
+               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);
index 21b04c3..14a3cf0 100644 (file)
@@ -190,6 +190,29 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
        return (max_link_clock * max_lanes * 8) / 10;
 }
 
+static int
+intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &intel_dig_port->base;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       int max_dotclk = dev_priv->max_dotclk_freq;
+       int ds_max_dotclk;
+
+       int type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK;
+
+       if (type != DP_DS_PORT_TYPE_VGA)
+               return max_dotclk;
+
+       ds_max_dotclk = drm_dp_downstream_max_clock(intel_dp->dpcd,
+                                                   intel_dp->downstream_ports);
+
+       if (ds_max_dotclk != 0)
+               max_dotclk = min(max_dotclk, ds_max_dotclk);
+
+       return max_dotclk;
+}
+
 static enum drm_mode_status
 intel_dp_mode_valid(struct drm_connector *connector,
                    struct drm_display_mode *mode)
@@ -199,7 +222,9 @@ intel_dp_mode_valid(struct drm_connector *connector,
        struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
        int target_clock = mode->clock;
        int max_rate, mode_rate, max_lanes, max_link_clock;
-       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+       int max_dotclk;
+
+       max_dotclk = intel_dp_downstream_max_dotclock(intel_dp);
 
        if (is_edp(intel_dp) && fixed_mode) {
                if (mode->hdisplay > fixed_mode->hdisplay)
@@ -256,6 +281,8 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
 static void
 intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                                              struct intel_dp *intel_dp);
+static void
+intel_dp_pps_init(struct drm_device *dev, struct intel_dp *intel_dp);
 
 static void pps_lock(struct intel_dp *intel_dp)
 {
@@ -463,13 +490,13 @@ typedef bool (*vlv_pipe_check)(struct drm_i915_private *dev_priv,
 static bool vlv_pipe_has_pp_on(struct drm_i915_private *dev_priv,
                               enum pipe pipe)
 {
-       return I915_READ(VLV_PIPE_PP_STATUS(pipe)) & PP_ON;
+       return I915_READ(PP_STATUS(pipe)) & PP_ON;
 }
 
 static bool vlv_pipe_has_vdd_on(struct drm_i915_private *dev_priv,
                                enum pipe pipe)
 {
-       return I915_READ(VLV_PIPE_PP_CONTROL(pipe)) & EDP_FORCE_VDD;
+       return I915_READ(PP_CONTROL(pipe)) & EDP_FORCE_VDD;
 }
 
 static bool vlv_pipe_any(struct drm_i915_private *dev_priv,
@@ -486,7 +513,7 @@ vlv_initial_pps_pipe(struct drm_i915_private *dev_priv,
        enum pipe pipe;
 
        for (pipe = PIPE_A; pipe <= PIPE_B; pipe++) {
-               u32 port_sel = I915_READ(VLV_PIPE_PP_ON_DELAYS(pipe)) &
+               u32 port_sel = I915_READ(PP_ON_DELAYS(pipe)) &
                        PANEL_PORT_SELECT_MASK;
 
                if (port_sel != PANEL_PORT_SELECT_VLV(port))
@@ -583,30 +610,21 @@ static void intel_pps_get_registers(struct drm_i915_private *dev_priv,
                                    struct intel_dp *intel_dp,
                                    struct pps_registers *regs)
 {
+       int pps_idx = 0;
+
        memset(regs, 0, sizeof(*regs));
 
-       if (IS_BROXTON(dev_priv)) {
-               int idx = bxt_power_sequencer_idx(intel_dp);
-
-               regs->pp_ctrl = BXT_PP_CONTROL(idx);
-               regs->pp_stat = BXT_PP_STATUS(idx);
-               regs->pp_on = BXT_PP_ON_DELAYS(idx);
-               regs->pp_off = BXT_PP_OFF_DELAYS(idx);
-       } else if (HAS_PCH_SPLIT(dev_priv)) {
-               regs->pp_ctrl = PCH_PP_CONTROL;
-               regs->pp_stat = PCH_PP_STATUS;
-               regs->pp_on = PCH_PP_ON_DELAYS;
-               regs->pp_off = PCH_PP_OFF_DELAYS;
-               regs->pp_div = PCH_PP_DIVISOR;
-       } else {
-               enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
+       if (IS_BROXTON(dev_priv))
+               pps_idx = bxt_power_sequencer_idx(intel_dp);
+       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               pps_idx = vlv_power_sequencer_pipe(intel_dp);
 
-               regs->pp_ctrl = VLV_PIPE_PP_CONTROL(pipe);
-               regs->pp_stat = VLV_PIPE_PP_STATUS(pipe);
-               regs->pp_on = VLV_PIPE_PP_ON_DELAYS(pipe);
-               regs->pp_off = VLV_PIPE_PP_OFF_DELAYS(pipe);
-               regs->pp_div = VLV_PIPE_PP_DIVISOR(pipe);
-       }
+       regs->pp_ctrl = PP_CONTROL(pps_idx);
+       regs->pp_stat = PP_STATUS(pps_idx);
+       regs->pp_on = PP_ON_DELAYS(pps_idx);
+       regs->pp_off = PP_OFF_DELAYS(pps_idx);
+       if (!IS_BROXTON(dev_priv))
+               regs->pp_div = PP_DIVISOR(pps_idx);
 }
 
 static i915_reg_t
@@ -651,8 +669,8 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
                i915_reg_t pp_ctrl_reg, pp_div_reg;
                u32 pp_div;
 
-               pp_ctrl_reg = VLV_PIPE_PP_CONTROL(pipe);
-               pp_div_reg  = VLV_PIPE_PP_DIVISOR(pipe);
+               pp_ctrl_reg = PP_CONTROL(pipe);
+               pp_div_reg  = PP_DIVISOR(pipe);
                pp_div = I915_READ(pp_div_reg);
                pp_div &= PP_REFERENCE_DIVIDER_MASK;
 
@@ -1041,10 +1059,10 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                if (WARN_ON(txsize > 20))
                        return -E2BIG;
 
+               WARN_ON(!msg->buffer != !msg->size);
+
                if (msg->buffer)
                        memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
-               else
-                       WARN_ON(msg->size);
 
                ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize);
                if (ret > 0) {
@@ -1250,7 +1268,7 @@ intel_dp_aux_fini(struct intel_dp *intel_dp)
 }
 
 static void
-intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
+intel_dp_aux_init(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        enum port port = intel_dig_port->port;
@@ -1426,6 +1444,44 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
        DRM_DEBUG_KMS("common rates: %s\n", str);
 }
 
+static void intel_dp_print_hw_revision(struct intel_dp *intel_dp)
+{
+       uint8_t rev;
+       int len;
+
+       if ((drm_debug & DRM_UT_KMS) == 0)
+               return;
+
+       if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+             DP_DWN_STRM_PORT_PRESENT))
+               return;
+
+       len = drm_dp_dpcd_read(&intel_dp->aux, DP_BRANCH_HW_REV, &rev, 1);
+       if (len < 0)
+               return;
+
+       DRM_DEBUG_KMS("sink hw revision: %d.%d\n", (rev & 0xf0) >> 4, rev & 0xf);
+}
+
+static void intel_dp_print_sw_revision(struct intel_dp *intel_dp)
+{
+       uint8_t rev[2];
+       int len;
+
+       if ((drm_debug & DRM_UT_KMS) == 0)
+               return;
+
+       if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+             DP_DWN_STRM_PORT_PRESENT))
+               return;
+
+       len = drm_dp_dpcd_read(&intel_dp->aux, DP_BRANCH_SW_REV, &rev, 2);
+       if (len < 0)
+               return;
+
+       DRM_DEBUG_KMS("sink sw revision: %d.%d\n", rev[0], rev[1]);
+}
+
 static int rate_to_index(int find, const int *rates)
 {
        int i = 0;
@@ -1447,7 +1503,7 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
        if (WARN_ON(len <= 0))
                return 162000;
 
-       return rates[rate_to_index(0, rates) - 1];
+       return rates[len - 1];
 }
 
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
@@ -1468,9 +1524,24 @@ void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
        }
 }
 
+static int intel_dp_compute_bpp(struct intel_dp *intel_dp,
+                               struct intel_crtc_state *pipe_config)
+{
+       int bpp, bpc;
+
+       bpp = pipe_config->pipe_bpp;
+       bpc = drm_dp_downstream_max_bpc(intel_dp->dpcd, intel_dp->downstream_ports);
+
+       if (bpc > 0)
+               bpp = min(bpp, 3*bpc);
+
+       return bpp;
+}
+
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
-                       struct intel_crtc_state *pipe_config)
+                       struct intel_crtc_state *pipe_config,
+                       struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -1533,7 +1604,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 
        /* Walk through all bpp values. Luckily they're all nicely spaced with 2
         * bpc in between. */
-       bpp = pipe_config->pipe_bpp;
+       bpp = intel_dp_compute_bpp(intel_dp, pipe_config);
        if (is_edp(intel_dp)) {
 
                /* Get bpp from vbt only for panels that dont have bpp in edid */
@@ -1647,22 +1718,28 @@ found:
 }
 
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
-                             const struct intel_crtc_state *pipe_config)
+                             int link_rate, uint8_t lane_count,
+                             bool link_mst)
 {
-       intel_dp->link_rate = pipe_config->port_clock;
-       intel_dp->lane_count = pipe_config->lane_count;
+       intel_dp->link_rate = link_rate;
+       intel_dp->lane_count = lane_count;
+       intel_dp->link_mst = link_mst;
 }
 
-static void intel_dp_prepare(struct intel_encoder *encoder)
+static void intel_dp_prepare(struct intel_encoder *encoder,
+                            struct intel_crtc_state *pipe_config)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
        struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 
-       intel_dp_set_link_params(intel_dp, crtc->config);
+       intel_dp_set_link_params(intel_dp, pipe_config->port_clock,
+                                pipe_config->lane_count,
+                                intel_crtc_has_type(pipe_config,
+                                                    INTEL_OUTPUT_DP_MST));
 
        /*
         * There are four kinds of DP registers:
@@ -1688,7 +1765,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
 
        /* Handle DP bits in common between all three register formats */
        intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
-       intel_dp->DP |= DP_PORT_WIDTH(crtc->config->lane_count);
+       intel_dp->DP |= DP_PORT_WIDTH(pipe_config->lane_count);
 
        /* Split out the IBX/CPU vs CPT settings */
 
@@ -1716,7 +1793,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
                I915_WRITE(TRANS_DP_CTL(crtc->pipe), trans_dp);
        } else {
                if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev) &&
-                   !IS_CHERRYVIEW(dev) && crtc->config->limited_color_range)
+                   !IS_CHERRYVIEW(dev) && pipe_config->limited_color_range)
                        intel_dp->DP |= DP_COLOR_RANGE_16_235;
 
                if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
@@ -1835,7 +1912,8 @@ static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
        lockdep_assert_held(&dev_priv->pps_mutex);
 
        control = I915_READ(_pp_ctrl_reg(intel_dp));
-       if (!IS_BROXTON(dev)) {
+       if (WARN_ON(!HAS_DDI(dev_priv) &&
+                   (control & PANEL_UNLOCK_MASK) != PANEL_UNLOCK_REGS)) {
                control &= ~PANEL_UNLOCK_MASK;
                control |= PANEL_UNLOCK_REGS;
        }
@@ -1956,7 +2034,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
        DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
        I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
 
-       if ((pp & POWER_TARGET_ON) == 0)
+       if ((pp & PANEL_POWER_ON) == 0)
                intel_dp->panel_power_off_time = ktime_get_boottime();
 
        power_domain = intel_display_port_aux_power_domain(intel_encoder);
@@ -2043,7 +2121,7 @@ static void edp_panel_on(struct intel_dp *intel_dp)
                POSTING_READ(pp_ctrl_reg);
        }
 
-       pp |= POWER_TARGET_ON;
+       pp |= PANEL_POWER_ON;
        if (!IS_GEN5(dev))
                pp |= PANEL_POWER_RESET;
 
@@ -2095,7 +2173,7 @@ static void edp_panel_off(struct intel_dp *intel_dp)
        pp = ironlake_get_pp_control(intel_dp);
        /* We need to switch off panel power _and_ force vdd, for otherwise some
         * panels get very unhappy and cease to work. */
-       pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_FORCE_VDD |
+       pp &= ~(PANEL_POWER_ON | PANEL_POWER_RESET | EDP_FORCE_VDD |
                EDP_BLC_ENABLE);
 
        pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
@@ -2254,10 +2332,10 @@ static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
 #define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
 #define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
 
-static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
+static void ironlake_edp_pll_on(struct intel_dp *intel_dp,
+                               struct intel_crtc_state *pipe_config)
 {
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
        assert_pipe_disabled(dev_priv, crtc->pipe);
@@ -2265,11 +2343,11 @@ static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
        assert_edp_pll_disabled(dev_priv);
 
        DRM_DEBUG_KMS("enabling eDP PLL for clock %d\n",
-                     crtc->config->port_clock);
+                     pipe_config->port_clock);
 
        intel_dp->DP &= ~DP_PLL_FREQ_MASK;
 
-       if (crtc->config->port_clock == 162000)
+       if (pipe_config->port_clock == 162000)
                intel_dp->DP |= DP_PLL_FREQ_162MHZ;
        else
                intel_dp->DP |= DP_PLL_FREQ_270MHZ;
@@ -2478,16 +2556,17 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
        }
 }
 
-static void intel_disable_dp(struct intel_encoder *encoder)
+static void intel_disable_dp(struct intel_encoder *encoder,
+                            struct intel_crtc_state *old_crtc_state,
+                            struct drm_connector_state *old_conn_state)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct drm_device *dev = encoder->base.dev;
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 
-       if (crtc->config->has_audio)
+       if (old_crtc_state->has_audio)
                intel_audio_codec_disable(encoder);
 
-       if (HAS_PSR(dev) && !HAS_DDI(dev))
+       if (HAS_PSR(dev_priv) && !HAS_DDI(dev_priv))
                intel_psr_disable(intel_dp);
 
        /* Make sure the panel is off before trying to change the mode. But also
@@ -2498,11 +2577,13 @@ static void intel_disable_dp(struct intel_encoder *encoder)
        intel_edp_panel_off(intel_dp);
 
        /* disable the port before the pipe on g4x */
-       if (INTEL_INFO(dev)->gen < 5)
+       if (INTEL_GEN(dev_priv) < 5)
                intel_dp_link_down(intel_dp);
 }
 
-static void ilk_post_disable_dp(struct intel_encoder *encoder)
+static void ilk_post_disable_dp(struct intel_encoder *encoder,
+                               struct intel_crtc_state *old_crtc_state,
+                               struct drm_connector_state *old_conn_state)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
@@ -2514,14 +2595,18 @@ static void ilk_post_disable_dp(struct intel_encoder *encoder)
                ironlake_edp_pll_off(intel_dp);
 }
 
-static void vlv_post_disable_dp(struct intel_encoder *encoder)
+static void vlv_post_disable_dp(struct intel_encoder *encoder,
+                               struct intel_crtc_state *old_crtc_state,
+                               struct drm_connector_state *old_conn_state)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
        intel_dp_link_down(intel_dp);
 }
 
-static void chv_post_disable_dp(struct intel_encoder *encoder)
+static void chv_post_disable_dp(struct intel_encoder *encoder,
+                               struct intel_crtc_state *old_crtc_state,
+                               struct drm_connector_state *old_conn_state)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        struct drm_device *dev = encoder->base.dev;
@@ -2547,6 +2632,10 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp,
        struct drm_i915_private *dev_priv = to_i915(dev);
        enum port port = intel_dig_port->port;
 
+       if (dp_train_pat & DP_TRAINING_PATTERN_MASK)
+               DRM_DEBUG_KMS("Using DP training pattern TPS%d\n",
+                             dp_train_pat & DP_TRAINING_PATTERN_MASK);
+
        if (HAS_DDI(dev)) {
                uint32_t temp = I915_READ(DP_TP_CTL(port));
 
@@ -2588,7 +2677,7 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp,
                        *DP |= DP_LINK_TRAIN_PAT_2_CPT;
                        break;
                case DP_TRAINING_PATTERN_3:
-                       DRM_ERROR("DP training pattern 3 not supported\n");
+                       DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
                        *DP |= DP_LINK_TRAIN_PAT_2_CPT;
                        break;
                }
@@ -2613,7 +2702,7 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp,
                        if (IS_CHERRYVIEW(dev)) {
                                *DP |= DP_LINK_TRAIN_PAT_3_CHV;
                        } else {
-                               DRM_ERROR("DP training pattern 3 not supported\n");
+                               DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
                                *DP |= DP_LINK_TRAIN_PAT_2;
                        }
                        break;
@@ -2621,19 +2710,15 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp,
        }
 }
 
-static void intel_dp_enable_port(struct intel_dp *intel_dp)
+static void intel_dp_enable_port(struct intel_dp *intel_dp,
+                                struct intel_crtc_state *old_crtc_state)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *crtc =
-               to_intel_crtc(dp_to_dig_port(intel_dp)->base.base.crtc);
 
        /* enable with pattern 1 (as per spec) */
-       _intel_dp_set_link_train(intel_dp, &intel_dp->DP,
-                                DP_TRAINING_PATTERN_1);
 
-       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
-       POSTING_READ(intel_dp->output_reg);
+       intel_dp_program_link_training_pattern(intel_dp, DP_TRAINING_PATTERN_1);
 
        /*
         * Magic for VLV/CHV. We _must_ first set up the register
@@ -2642,14 +2727,15 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp)
         * fail when the power sequencer is freshly used for this port.
         */
        intel_dp->DP |= DP_PORT_EN;
-       if (crtc->config->has_audio)
+       if (old_crtc_state->has_audio)
                intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
 
        I915_WRITE(intel_dp->output_reg, intel_dp->DP);
        POSTING_READ(intel_dp->output_reg);
 }
 
-static void intel_enable_dp(struct intel_encoder *encoder)
+static void intel_enable_dp(struct intel_encoder *encoder,
+                           struct intel_crtc_state *pipe_config)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        struct drm_device *dev = encoder->base.dev;
@@ -2666,7 +2752,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
        if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
                vlv_init_panel_power_sequencer(intel_dp);
 
-       intel_dp_enable_port(intel_dp);
+       intel_dp_enable_port(intel_dp, pipe_config);
 
        edp_panel_vdd_on(intel_dp);
        edp_panel_on(intel_dp);
@@ -2678,7 +2764,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
                unsigned int lane_mask = 0x0;
 
                if (IS_CHERRYVIEW(dev))
-                       lane_mask = intel_dp_unused_lane_mask(crtc->config->lane_count);
+                       lane_mask = intel_dp_unused_lane_mask(pipe_config->lane_count);
 
                vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp),
                                    lane_mask);
@@ -2688,22 +2774,26 @@ static void intel_enable_dp(struct intel_encoder *encoder)
        intel_dp_start_link_train(intel_dp);
        intel_dp_stop_link_train(intel_dp);
 
-       if (crtc->config->has_audio) {
+       if (pipe_config->has_audio) {
                DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
                                 pipe_name(pipe));
                intel_audio_codec_enable(encoder);
        }
 }
 
-static void g4x_enable_dp(struct intel_encoder *encoder)
+static void g4x_enable_dp(struct intel_encoder *encoder,
+                         struct intel_crtc_state *pipe_config,
+                         struct drm_connector_state *conn_state)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
-       intel_enable_dp(encoder);
+       intel_enable_dp(encoder, pipe_config);
        intel_edp_backlight_on(intel_dp);
 }
 
-static void vlv_enable_dp(struct intel_encoder *encoder)
+static void vlv_enable_dp(struct intel_encoder *encoder,
+                         struct intel_crtc_state *pipe_config,
+                         struct drm_connector_state *conn_state)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
@@ -2711,16 +2801,18 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
        intel_psr_enable(intel_dp);
 }
 
-static void g4x_pre_enable_dp(struct intel_encoder *encoder)
+static void g4x_pre_enable_dp(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config,
+                             struct drm_connector_state *conn_state)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
 
-       intel_dp_prepare(encoder);
+       intel_dp_prepare(encoder, pipe_config);
 
        /* Only ilk+ has port A */
        if (port == PORT_A)
-               ironlake_edp_pll_on(intel_dp);
+               ironlake_edp_pll_on(intel_dp, pipe_config);
 }
 
 static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
@@ -2728,7 +2820,7 @@ static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
        enum pipe pipe = intel_dp->pps_pipe;
-       i915_reg_t pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe);
+       i915_reg_t pp_on_reg = PP_ON_DELAYS(pipe);
 
        edp_panel_vdd_off_sync(intel_dp);
 
@@ -2826,38 +2918,48 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp)
        intel_dp_init_panel_power_sequencer_registers(dev, intel_dp);
 }
 
-static void vlv_pre_enable_dp(struct intel_encoder *encoder)
+static void vlv_pre_enable_dp(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config,
+                             struct drm_connector_state *conn_state)
 {
        vlv_phy_pre_encoder_enable(encoder);
 
-       intel_enable_dp(encoder);
+       intel_enable_dp(encoder, pipe_config);
 }
 
-static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder)
+static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config,
+                                 struct drm_connector_state *conn_state)
 {
-       intel_dp_prepare(encoder);
+       intel_dp_prepare(encoder, pipe_config);
 
        vlv_phy_pre_pll_enable(encoder);
 }
 
-static void chv_pre_enable_dp(struct intel_encoder *encoder)
+static void chv_pre_enable_dp(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config,
+                             struct drm_connector_state *conn_state)
 {
        chv_phy_pre_encoder_enable(encoder);
 
-       intel_enable_dp(encoder);
+       intel_enable_dp(encoder, pipe_config);
 
        /* Second common lane will stay alive on its own now */
        chv_phy_release_cl2_override(encoder);
 }
 
-static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
+static void chv_dp_pre_pll_enable(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config,
+                                 struct drm_connector_state *conn_state)
 {
-       intel_dp_prepare(encoder);
+       intel_dp_prepare(encoder, pipe_config);
 
        chv_phy_pre_pll_enable(encoder);
 }
 
-static void chv_dp_post_pll_disable(struct intel_encoder *encoder)
+static void chv_dp_post_pll_disable(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config,
+                                   struct drm_connector_state *conn_state)
 {
        chv_phy_post_pll_disable(encoder);
 }
@@ -3395,84 +3497,67 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 }
 
 static bool
-intel_dp_get_dpcd(struct intel_dp *intel_dp)
+intel_dp_read_dpcd(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);
-
        if (drm_dp_dpcd_read(&intel_dp->aux, 0x000, intel_dp->dpcd,
                             sizeof(intel_dp->dpcd)) < 0)
                return false; /* aux transfer failed */
 
        DRM_DEBUG_KMS("DPCD: %*ph\n", (int) sizeof(intel_dp->dpcd), intel_dp->dpcd);
 
-       if (intel_dp->dpcd[DP_DPCD_REV] == 0)
-               return false; /* DPCD not present */
+       return intel_dp->dpcd[DP_DPCD_REV] != 0;
+}
 
-       if (drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT,
-                            &intel_dp->sink_count, 1) < 0)
-               return false;
+static bool
+intel_edp_init_dpcd(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv =
+               to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
 
-       /*
-        * Sink count can change between short pulse hpd hence
-        * a member variable in intel_dp will track any changes
-        * between short pulse interrupts.
-        */
-       intel_dp->sink_count = DP_GET_SINK_COUNT(intel_dp->sink_count);
+       /* this function is meant to be called only once */
+       WARN_ON(intel_dp->dpcd[DP_DPCD_REV] != 0);
 
-       /*
-        * SINK_COUNT == 0 and DOWNSTREAM_PORT_PRESENT == 1 implies that
-        * a dongle is present but no display. Unless we require to know
-        * if a dongle is present or not, we don't need to update
-        * downstream port information. So, an early return here saves
-        * time from performing other operations which are not required.
-        */
-       if (!is_edp(intel_dp) && !intel_dp->sink_count)
+       if (!intel_dp_read_dpcd(intel_dp))
                return false;
 
-       /* Check if the panel supports PSR */
-       memset(intel_dp->psr_dpcd, 0, sizeof(intel_dp->psr_dpcd));
-       if (is_edp(intel_dp)) {
-               drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT,
-                                intel_dp->psr_dpcd,
-                                sizeof(intel_dp->psr_dpcd));
-               if (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED) {
-                       dev_priv->psr.sink_support = true;
-                       DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
-               }
+       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
+               dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
+                       DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
 
-               if (INTEL_INFO(dev)->gen >= 9 &&
-                       (intel_dp->psr_dpcd[0] & DP_PSR2_IS_SUPPORTED)) {
-                       uint8_t frame_sync_cap;
-
-                       dev_priv->psr.sink_support = true;
-                       drm_dp_dpcd_read(&intel_dp->aux,
-                                        DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP,
-                                        &frame_sync_cap, 1);
-                       dev_priv->psr.aux_frame_sync = frame_sync_cap ? true : false;
-                       /* PSR2 needs frame sync as well */
-                       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");
-               }
-
-               /* Read the eDP Display control capabilities registers */
-               memset(intel_dp->edp_dpcd, 0, sizeof(intel_dp->edp_dpcd));
-               if ((intel_dp->dpcd[DP_EDP_CONFIGURATION_CAP] & DP_DPCD_DISPLAY_CONTROL_CAPABLE) &&
-                               (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV,
-                                               intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd)) ==
-                                                               sizeof(intel_dp->edp_dpcd)))
-                       DRM_DEBUG_KMS("EDP DPCD : %*ph\n", (int) sizeof(intel_dp->edp_dpcd),
-                                       intel_dp->edp_dpcd);
-       }
-
-       DRM_DEBUG_KMS("Display Port TPS3 support: source %s, sink %s\n",
-                     yesno(intel_dp_source_supports_hbr2(intel_dp)),
-                     yesno(drm_dp_tps3_supported(intel_dp->dpcd)));
+       /* Check if the panel supports PSR */
+       drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT,
+                        intel_dp->psr_dpcd,
+                        sizeof(intel_dp->psr_dpcd));
+       if (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED) {
+               dev_priv->psr.sink_support = true;
+               DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
+       }
+
+       if (INTEL_GEN(dev_priv) >= 9 &&
+           (intel_dp->psr_dpcd[0] & DP_PSR2_IS_SUPPORTED)) {
+               uint8_t frame_sync_cap;
+
+               dev_priv->psr.sink_support = true;
+               drm_dp_dpcd_read(&intel_dp->aux,
+                                DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP,
+                                &frame_sync_cap, 1);
+               dev_priv->psr.aux_frame_sync = frame_sync_cap ? true : false;
+               /* PSR2 needs frame sync as well */
+               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");
+       }
+
+       /* Read the eDP Display control capabilities registers */
+       if ((intel_dp->dpcd[DP_EDP_CONFIGURATION_CAP] & DP_DPCD_DISPLAY_CONTROL_CAPABLE) &&
+           drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV,
+                            intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd) ==
+                            sizeof(intel_dp->edp_dpcd)))
+               DRM_DEBUG_KMS("EDP DPCD : %*ph\n", (int) sizeof(intel_dp->edp_dpcd),
+                             intel_dp->edp_dpcd);
 
        /* Intermediate frequency support */
-       if (is_edp(intel_dp) && (intel_dp->edp_dpcd[0] >= 0x03)) { /* eDp v1.4 or higher */
+       if (intel_dp->edp_dpcd[0] >= 0x03) { /* eDp v1.4 or higher */
                __le16 sink_rates[DP_MAX_SUPPORTED_RATES];
                int i;
 
@@ -3491,7 +3576,36 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
                intel_dp->num_sink_rates = i;
        }
 
-       intel_dp_print_rates(intel_dp);
+       return true;
+}
+
+
+static bool
+intel_dp_get_dpcd(struct intel_dp *intel_dp)
+{
+       if (!intel_dp_read_dpcd(intel_dp))
+               return false;
+
+       if (drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT,
+                            &intel_dp->sink_count, 1) < 0)
+               return false;
+
+       /*
+        * Sink count can change between short pulse hpd hence
+        * a member variable in intel_dp will track any changes
+        * between short pulse interrupts.
+        */
+       intel_dp->sink_count = DP_GET_SINK_COUNT(intel_dp->sink_count);
+
+       /*
+        * SINK_COUNT == 0 and DOWNSTREAM_PORT_PRESENT == 1 implies that
+        * a dongle is present but no display. Unless we require to know
+        * if a dongle is present or not, we don't need to update
+        * downstream port information. So, an early return here saves
+        * time from performing other operations which are not required.
+        */
+       if (!is_edp(intel_dp) && !intel_dp->sink_count)
+               return false;
 
        if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
              DP_DWN_STRM_PORT_PRESENT))
@@ -3526,7 +3640,7 @@ intel_dp_probe_oui(struct intel_dp *intel_dp)
 }
 
 static bool
-intel_dp_probe_mst(struct intel_dp *intel_dp)
+intel_dp_can_mst(struct intel_dp *intel_dp)
 {
        u8 buf[1];
 
@@ -3539,18 +3653,30 @@ intel_dp_probe_mst(struct intel_dp *intel_dp)
        if (intel_dp->dpcd[DP_DPCD_REV] < 0x12)
                return false;
 
-       if (drm_dp_dpcd_read(&intel_dp->aux, DP_MSTM_CAP, buf, 1)) {
-               if (buf[0] & DP_MST_CAP) {
-                       DRM_DEBUG_KMS("Sink is MST capable\n");
-                       intel_dp->is_mst = true;
-               } else {
-                       DRM_DEBUG_KMS("Sink is not MST capable\n");
-                       intel_dp->is_mst = false;
-               }
-       }
+       if (drm_dp_dpcd_read(&intel_dp->aux, DP_MSTM_CAP, buf, 1) != 1)
+               return false;
+
+       return buf[0] & DP_MST_CAP;
+}
+
+static void
+intel_dp_configure_mst(struct intel_dp *intel_dp)
+{
+       if (!i915.enable_dp_mst)
+               return;
+
+       if (!intel_dp->can_mst)
+               return;
 
-       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
-       return intel_dp->is_mst;
+       intel_dp->is_mst = intel_dp_can_mst(intel_dp);
+
+       if (intel_dp->is_mst)
+               DRM_DEBUG_KMS("Sink is MST capable\n");
+       else
+               DRM_DEBUG_KMS("Sink is not MST capable\n");
+
+       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
+                                       intel_dp->is_mst);
 }
 
 static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
@@ -3909,7 +4035,7 @@ static bool
 intel_dp_short_pulse(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
-       u8 sink_irq_vector;
+       u8 sink_irq_vector = 0;
        u8 old_sink_count = intel_dp->sink_count;
        bool ret;
 
@@ -3936,7 +4062,8 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
 
        /* Try to read the source of the interrupt */
        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
-           intel_dp_get_sink_irq(intel_dp, &sink_irq_vector)) {
+           intel_dp_get_sink_irq(intel_dp, &sink_irq_vector) &&
+           sink_irq_vector != 0) {
                /* Clear interrupt source */
                drm_dp_dpcd_writeb(&intel_dp->aux,
                                   DP_DEVICE_SERVICE_IRQ_VECTOR,
@@ -3980,6 +4107,9 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp)
                connector_status_connected : connector_status_disconnected;
        }
 
+       if (intel_dp_can_mst(intel_dp))
+               return connector_status_connected;
+
        /* If no HPD, poke DDC gently */
        if (drm_probe_ddc(&intel_dp->aux.ddc))
                return connector_status_connected;
@@ -4148,7 +4278,7 @@ static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv,
  *
  * Return %true if @port is connected, %false otherwise.
  */
-bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
+static bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
                                         struct intel_digital_port *port)
 {
        if (HAS_PCH_IBX(dev_priv))
@@ -4207,7 +4337,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
        intel_dp->has_audio = false;
 }
 
-static void
+static enum drm_connector_status
 intel_dp_long_pulse(struct intel_connector *intel_connector)
 {
        struct drm_connector *connector = &intel_connector->base;
@@ -4217,8 +4347,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
        struct drm_device *dev = connector->dev;
        enum drm_connector_status status;
        enum intel_display_power_domain power_domain;
-       bool ret;
-       u8 sink_irq_vector;
+       u8 sink_irq_vector = 0;
 
        power_domain = intel_display_port_aux_power_domain(intel_encoder);
        intel_display_power_get(to_i915(dev), power_domain);
@@ -4232,7 +4361,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
        else
                status = connector_status_disconnected;
 
-       if (status != connector_status_connected) {
+       if (status == connector_status_disconnected) {
                intel_dp->compliance_test_active = 0;
                intel_dp->compliance_test_type = 0;
                intel_dp->compliance_test_data = 0;
@@ -4252,10 +4381,20 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
        if (intel_encoder->type != INTEL_OUTPUT_EDP)
                intel_encoder->type = INTEL_OUTPUT_DP;
 
+       DRM_DEBUG_KMS("Display Port TPS3 support: source %s, sink %s\n",
+                     yesno(intel_dp_source_supports_hbr2(intel_dp)),
+                     yesno(drm_dp_tps3_supported(intel_dp->dpcd)));
+
+       intel_dp_print_rates(intel_dp);
+
        intel_dp_probe_oui(intel_dp);
 
-       ret = intel_dp_probe_mst(intel_dp);
-       if (ret) {
+       intel_dp_print_hw_revision(intel_dp);
+       intel_dp_print_sw_revision(intel_dp);
+
+       intel_dp_configure_mst(intel_dp);
+
+       if (intel_dp->is_mst) {
                /*
                 * If we are in MST mode then this connector
                 * won't appear connected or have anything
@@ -4284,13 +4423,14 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
        intel_dp->aux.i2c_defer_count = 0;
 
        intel_dp_set_edid(intel_dp);
-
-       status = connector_status_connected;
+       if (is_edp(intel_dp) || intel_connector->detect_edid)
+               status = connector_status_connected;
        intel_dp->detect_done = true;
 
        /* Try to read the source of the interrupt */
        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
-           intel_dp_get_sink_irq(intel_dp, &sink_irq_vector)) {
+           intel_dp_get_sink_irq(intel_dp, &sink_irq_vector) &&
+           sink_irq_vector != 0) {
                /* Clear interrupt source */
                drm_dp_dpcd_writeb(&intel_dp->aux,
                                   DP_DEVICE_SERVICE_IRQ_VECTOR,
@@ -4303,12 +4443,11 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
        }
 
 out:
-       if ((status != connector_status_connected) &&
-           (intel_dp->is_mst == false))
+       if (status != connector_status_connected && !intel_dp->is_mst)
                intel_dp_unset_edid(intel_dp);
 
        intel_display_power_put(to_i915(dev), power_domain);
-       return;
+       return status;
 }
 
 static enum drm_connector_status
@@ -4317,7 +4456,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
        struct intel_dp *intel_dp = intel_attached_dp(connector);
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       struct intel_connector *intel_connector = to_intel_connector(connector);
+       enum drm_connector_status status = connector->status;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
@@ -4332,14 +4471,11 @@ intel_dp_detect(struct drm_connector *connector, bool force)
 
        /* If full detect is not performed yet, do a full detect */
        if (!intel_dp->detect_done)
-               intel_dp_long_pulse(intel_dp->attached_connector);
+               status = intel_dp_long_pulse(intel_dp->attached_connector);
 
        intel_dp->detect_done = false;
 
-       if (is_edp(intel_dp) || intel_connector->detect_edid)
-               return connector_status_connected;
-       else
-               return connector_status_disconnected;
+       return status;
 }
 
 static void
@@ -4630,13 +4766,8 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder)
 
        pps_lock(intel_dp);
 
-       /*
-        * Read out the current power sequencer assignment,
-        * in case the BIOS did something with it.
-        */
-       if (IS_VALLEYVIEW(encoder->dev) || IS_CHERRYVIEW(encoder->dev))
-               vlv_initial_power_sequencer_setup(intel_dp);
-
+       /* Reinit the power sequencer, in case BIOS did something with it. */
+       intel_dp_pps_init(encoder->dev, intel_dp);
        intel_edp_panel_vdd_sanitize(intel_dp);
 
        pps_unlock(intel_dp);
@@ -4696,36 +4827,34 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                      port_name(intel_dig_port->port),
                      long_hpd ? "long" : "short");
 
+       if (long_hpd) {
+               intel_dp->detect_done = false;
+               return IRQ_NONE;
+       }
+
        power_domain = intel_display_port_aux_power_domain(intel_encoder);
        intel_display_power_get(dev_priv, power_domain);
 
-       if (long_hpd) {
-               intel_dp_long_pulse(intel_dp->attached_connector);
-               if (intel_dp->is_mst)
-                       ret = IRQ_HANDLED;
-               goto put_power;
-
-       } else {
-               if (intel_dp->is_mst) {
-                       if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
-                               /*
-                                * If we were in MST mode, and device is not
-                                * there, get out of MST mode
-                                */
-                               DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n",
-                                             intel_dp->is_mst, intel_dp->mst_mgr.mst_state);
-                               intel_dp->is_mst = false;
-                               drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
-                                                               intel_dp->is_mst);
-                               goto put_power;
-                       }
+       if (intel_dp->is_mst) {
+               if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
+                       /*
+                        * If we were in MST mode, and device is not
+                        * there, get out of MST mode
+                        */
+                       DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n",
+                                     intel_dp->is_mst, intel_dp->mst_mgr.mst_state);
+                       intel_dp->is_mst = false;
+                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
+                                                       intel_dp->is_mst);
+                       intel_dp->detect_done = false;
+                       goto put_power;
                }
+       }
 
-               if (!intel_dp->is_mst) {
-                       if (!intel_dp_short_pulse(intel_dp)) {
-                               intel_dp_long_pulse(intel_dp->attached_connector);
-                               goto put_power;
-                       }
+       if (!intel_dp->is_mst) {
+               if (!intel_dp_short_pulse(intel_dp)) {
+                       intel_dp->detect_done = false;
+                       goto put_power;
                }
        }
 
@@ -4984,9 +5113,21 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                      I915_READ(regs.pp_div));
 }
 
+static void intel_dp_pps_init(struct drm_device *dev,
+                             struct intel_dp *intel_dp)
+{
+       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
+               vlv_initial_power_sequencer_setup(intel_dp);
+       } else {
+               intel_dp_init_panel_power_sequencer(dev, intel_dp);
+               intel_dp_init_panel_power_sequencer_registers(dev, intel_dp);
+       }
+}
+
 /**
  * intel_dp_set_drrs_state - program registers for RR switch to take effect
- * @dev: DRM device
+ * @dev_priv: i915 device
+ * @crtc_state: a pointer to the active intel_crtc_state
  * @refresh_rate: RR to be programmed
  *
  * This function gets called when refresh rate (RR) has to be changed from
@@ -4996,14 +5137,14 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
  *
  * The caller of this function needs to take a lock on dev_priv->drrs.
  */
-static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
+static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv,
+                                   struct intel_crtc_state *crtc_state,
+                                   int refresh_rate)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_encoder *encoder;
        struct intel_digital_port *dig_port = NULL;
        struct intel_dp *intel_dp = dev_priv->drrs.dp;
-       struct intel_crtc_state *config = NULL;
-       struct intel_crtc *intel_crtc = NULL;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
 
        if (refresh_rate <= 0) {
@@ -5030,8 +5171,6 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
                return;
        }
 
-       config = intel_crtc->config;
-
        if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
                DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
                return;
@@ -5047,12 +5186,12 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
                return;
        }
 
-       if (!intel_crtc->active) {
+       if (!crtc_state->base.active) {
                DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n");
                return;
        }
 
-       if (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev)) {
+       if (INTEL_GEN(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) {
                switch (index) {
                case DRRS_HIGH_RR:
                        intel_dp_set_m_n(intel_crtc, M1_N1);
@@ -5064,18 +5203,18 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
                default:
                        DRM_ERROR("Unsupported refreshrate type\n");
                }
-       } else if (INTEL_INFO(dev)->gen > 6) {
-               i915_reg_t reg = PIPECONF(intel_crtc->config->cpu_transcoder);
+       } else if (INTEL_GEN(dev_priv) > 6) {
+               i915_reg_t reg = PIPECONF(crtc_state->cpu_transcoder);
                u32 val;
 
                val = I915_READ(reg);
                if (index > DRRS_HIGH_RR) {
-                       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
+                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                                val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
                        else
                                val |= PIPECONF_EDP_RR_MODE_SWITCH;
                } else {
-                       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
+                       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                                val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
                        else
                                val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
@@ -5091,18 +5230,17 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
 /**
  * intel_edp_drrs_enable - init drrs struct if supported
  * @intel_dp: DP struct
+ * @crtc_state: A pointer to the active crtc state.
  *
  * Initializes frontbuffer_bits and drrs.dp
  */
-void intel_edp_drrs_enable(struct intel_dp *intel_dp)
+void intel_edp_drrs_enable(struct intel_dp *intel_dp,
+                          struct intel_crtc_state *crtc_state)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       struct drm_crtc *crtc = dig_port->base.base.crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       if (!intel_crtc->config->has_drrs) {
+       if (!crtc_state->has_drrs) {
                DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
                return;
        }
@@ -5124,17 +5262,16 @@ unlock:
 /**
  * intel_edp_drrs_disable - Disable DRRS
  * @intel_dp: DP struct
+ * @old_crtc_state: Pointer to old crtc_state.
  *
  */
-void intel_edp_drrs_disable(struct intel_dp *intel_dp)
+void intel_edp_drrs_disable(struct intel_dp *intel_dp,
+                           struct intel_crtc_state *old_crtc_state)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       struct drm_crtc *crtc = dig_port->base.base.crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       if (!intel_crtc->config->has_drrs)
+       if (!old_crtc_state->has_drrs)
                return;
 
        mutex_lock(&dev_priv->drrs.mutex);
@@ -5144,9 +5281,8 @@ void intel_edp_drrs_disable(struct intel_dp *intel_dp)
        }
 
        if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
-               intel_dp_set_drrs_state(&dev_priv->drm,
-                                       intel_dp->attached_connector->panel.
-                                       fixed_mode->vrefresh);
+               intel_dp_set_drrs_state(dev_priv, old_crtc_state,
+                       intel_dp->attached_connector->panel.fixed_mode->vrefresh);
 
        dev_priv->drrs.dp = NULL;
        mutex_unlock(&dev_priv->drrs.mutex);
@@ -5175,10 +5311,12 @@ static void intel_edp_drrs_downclock_work(struct work_struct *work)
        if (dev_priv->drrs.busy_frontbuffer_bits)
                goto unlock;
 
-       if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR)
-               intel_dp_set_drrs_state(&dev_priv->drm,
-                                       intel_dp->attached_connector->panel.
-                                       downclock_mode->vrefresh);
+       if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR) {
+               struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
+
+               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
+                       intel_dp->attached_connector->panel.downclock_mode->vrefresh);
+       }
 
 unlock:
        mutex_unlock(&dev_priv->drrs.mutex);
@@ -5186,7 +5324,7 @@ unlock:
 
 /**
  * intel_edp_drrs_invalidate - Disable Idleness DRRS
- * @dev: DRM device
+ * @dev_priv: i915 device
  * @frontbuffer_bits: frontbuffer plane tracking bits
  *
  * This function gets called everytime rendering on the given planes start.
@@ -5194,10 +5332,9 @@ unlock:
  *
  * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
  */
-void intel_edp_drrs_invalidate(struct drm_device *dev,
-               unsigned frontbuffer_bits)
+void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
+                              unsigned int frontbuffer_bits)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc *crtc;
        enum pipe pipe;
 
@@ -5220,16 +5357,15 @@ void intel_edp_drrs_invalidate(struct drm_device *dev,
 
        /* invalidate means busy screen hence upclock */
        if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
-               intel_dp_set_drrs_state(&dev_priv->drm,
-                                       dev_priv->drrs.dp->attached_connector->panel.
-                                       fixed_mode->vrefresh);
+               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
+                       dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
 
        mutex_unlock(&dev_priv->drrs.mutex);
 }
 
 /**
  * intel_edp_drrs_flush - Restart Idleness DRRS
- * @dev: DRM device
+ * @dev_priv: i915 device
  * @frontbuffer_bits: frontbuffer plane tracking bits
  *
  * This function gets called every time rendering on the given planes has
@@ -5239,10 +5375,9 @@ void intel_edp_drrs_invalidate(struct drm_device *dev,
  *
  * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
  */
-void intel_edp_drrs_flush(struct drm_device *dev,
-               unsigned frontbuffer_bits)
+void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
+                         unsigned int frontbuffer_bits)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc *crtc;
        enum pipe pipe;
 
@@ -5265,9 +5400,8 @@ void intel_edp_drrs_flush(struct drm_device *dev,
 
        /* flush means busy screen hence upclock */
        if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
-               intel_dp_set_drrs_state(&dev_priv->drm,
-                                       dev_priv->drrs.dp->attached_connector->panel.
-                                       fixed_mode->vrefresh);
+               intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
+                               dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
 
        /*
         * flush also means no more activity hence schedule downclock, if all
@@ -5400,27 +5534,15 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        pps_lock(intel_dp);
 
        intel_dp_init_panel_power_timestamps(intel_dp);
-
-       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
-               vlv_initial_power_sequencer_setup(intel_dp);
-       } else {
-               intel_dp_init_panel_power_sequencer(dev, intel_dp);
-               intel_dp_init_panel_power_sequencer_registers(dev, intel_dp);
-       }
-
+       intel_dp_pps_init(dev, intel_dp);
        intel_edp_panel_vdd_sanitize(intel_dp);
 
        pps_unlock(intel_dp);
 
        /* Cache DPCD and EDID for edp. */
-       has_dpcd = intel_dp_get_dpcd(intel_dp);
+       has_dpcd = intel_edp_init_dpcd(intel_dp);
 
-       if (has_dpcd) {
-               if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
-                       dev_priv->no_aux_handshake =
-                               intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
-                               DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
-       } else {
+       if (!has_dpcd) {
                /* if this fails, presume the device is a ghost */
                DRM_INFO("failed to retrieve link info, disabling eDP\n");
                goto out_vdd_off;
@@ -5576,7 +5698,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        connector->interlace_allowed = true;
        connector->doublescan_allowed = 0;
 
-       intel_dp_aux_init(intel_dp, intel_connector);
+       intel_dp_aux_init(intel_dp);
 
        INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
                          edp_panel_vdd_work);
index 60fb39c..c438b02 100644 (file)
 
 #include "intel_drv.h"
 
+static void
+intel_dp_dump_link_status(const uint8_t link_status[DP_LINK_STATUS_SIZE])
+{
+
+       DRM_DEBUG_KMS("ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x",
+                     link_status[0], link_status[1], link_status[2],
+                     link_status[3], link_status[4], link_status[5]);
+}
+
 static void
 intel_get_adjust_train(struct intel_dp *intel_dp,
                       const uint8_t link_status[DP_LINK_STATUS_SIZE])
@@ -103,13 +112,24 @@ intel_dp_update_link_train(struct intel_dp *intel_dp)
        return ret == intel_dp->lane_count;
 }
 
+static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
+{
+       int lane;
+
+       for (lane = 0; lane < intel_dp->lane_count; lane++)
+               if ((intel_dp->train_set[lane] &
+                    DP_TRAIN_MAX_SWING_REACHED) == 0)
+                       return false;
+
+       return true;
+}
+
 /* Enable corresponding port and start training pattern 1 */
-static void
+static bool
 intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 {
-       int i;
        uint8_t voltage;
-       int voltage_tries, loop_tries;
+       int voltage_tries, max_vswing_tries;
        uint8_t link_config[2];
        uint8_t link_bw, rate_select;
 
@@ -125,6 +145,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
        if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
                link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
        drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
+
        if (intel_dp->num_sink_rates)
                drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
                                  &rate_select, 1);
@@ -140,60 +161,54 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
                                       DP_TRAINING_PATTERN_1 |
                                       DP_LINK_SCRAMBLING_DISABLE)) {
                DRM_ERROR("failed to enable link training\n");
-               return;
+               return false;
        }
 
-       voltage = 0xff;
-       voltage_tries = 0;
-       loop_tries = 0;
+       voltage_tries = 1;
+       max_vswing_tries = 0;
        for (;;) {
                uint8_t link_status[DP_LINK_STATUS_SIZE];
 
                drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+
                if (!intel_dp_get_link_status(intel_dp, link_status)) {
                        DRM_ERROR("failed to get link status\n");
-                       break;
+                       return false;
                }
 
                if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
                        DRM_DEBUG_KMS("clock recovery OK\n");
-                       break;
+                       return true;
                }
 
-               /* Check to see if we've tried the max voltage */
-               for (i = 0; i < intel_dp->lane_count; i++)
-                       if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
-                               break;
-               if (i == intel_dp->lane_count) {
-                       ++loop_tries;
-                       if (loop_tries == 5) {
-                               DRM_ERROR("too many full retries, give up\n");
-                               break;
-                       }
-                       intel_dp_reset_link_train(intel_dp,
-                                                 DP_TRAINING_PATTERN_1 |
-                                                 DP_LINK_SCRAMBLING_DISABLE);
-                       voltage_tries = 0;
-                       continue;
+               if (voltage_tries == 5) {
+                       DRM_DEBUG_KMS("Same voltage tried 5 times\n");
+                       return false;
+               }
+
+               if (max_vswing_tries == 1) {
+                       DRM_DEBUG_KMS("Max Voltage Swing reached\n");
+                       return false;
                }
 
-               /* Check to see if we've tried the same voltage 5 times */
-               if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-                       ++voltage_tries;
-                       if (voltage_tries == 5) {
-                               DRM_ERROR("too many voltage retries, give up\n");
-                               break;
-                       }
-               } else
-                       voltage_tries = 0;
                voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
                /* Update training set as requested by target */
                intel_get_adjust_train(intel_dp, link_status);
                if (!intel_dp_update_link_train(intel_dp)) {
                        DRM_ERROR("failed to update link training\n");
-                       break;
+                       return false;
                }
+
+               if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
+                   voltage)
+                       ++voltage_tries;
+               else
+                       voltage_tries = 1;
+
+               if (intel_dp_link_max_vswing_reached(intel_dp))
+                       ++max_vswing_tries;
+
        }
 }
 
@@ -229,12 +244,12 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
        return training_pattern;
 }
 
-static void
+static bool
 intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 {
-       bool channel_eq = false;
-       int tries, cr_tries;
+       int tries;
        u32 training_pattern;
+       uint8_t link_status[DP_LINK_STATUS_SIZE];
 
        training_pattern = intel_dp_training_pattern(intel_dp);
 
@@ -243,19 +258,11 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
                                     training_pattern |
                                     DP_LINK_SCRAMBLING_DISABLE)) {
                DRM_ERROR("failed to start channel equalization\n");
-               return;
+               return false;
        }
 
-       tries = 0;
-       cr_tries = 0;
-       channel_eq = false;
-       for (;;) {
-               uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-               if (cr_tries > 5) {
-                       DRM_ERROR("failed to train DP, aborting\n");
-                       break;
-               }
+       intel_dp->channel_eq_status = false;
+       for (tries = 0; tries < 5; tries++) {
 
                drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
                if (!intel_dp_get_link_status(intel_dp, link_status)) {
@@ -266,44 +273,38 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
                /* Make sure clock is still ok */
                if (!drm_dp_clock_recovery_ok(link_status,
                                              intel_dp->lane_count)) {
-                       intel_dp_link_training_clock_recovery(intel_dp);
-                       intel_dp_set_link_train(intel_dp,
-                                               training_pattern |
-                                               DP_LINK_SCRAMBLING_DISABLE);
-                       cr_tries++;
-                       continue;
+                       intel_dp_dump_link_status(link_status);
+                       DRM_DEBUG_KMS("Clock recovery check failed, cannot "
+                                     "continue channel equalization\n");
+                       break;
                }
 
                if (drm_dp_channel_eq_ok(link_status,
                                         intel_dp->lane_count)) {
-                       channel_eq = true;
+                       intel_dp->channel_eq_status = true;
+                       DRM_DEBUG_KMS("Channel EQ done. DP Training "
+                                     "successful\n");
                        break;
                }
 
-               /* Try 5 times, then try clock recovery if that fails */
-               if (tries > 5) {
-                       intel_dp_link_training_clock_recovery(intel_dp);
-                       intel_dp_set_link_train(intel_dp,
-                                               training_pattern |
-                                               DP_LINK_SCRAMBLING_DISABLE);
-                       tries = 0;
-                       cr_tries++;
-                       continue;
-               }
-
                /* Update training set as requested by target */
                intel_get_adjust_train(intel_dp, link_status);
                if (!intel_dp_update_link_train(intel_dp)) {
                        DRM_ERROR("failed to update link training\n");
                        break;
                }
-               ++tries;
+       }
+
+       /* Try 5 times, else fail and try at lower BW */
+       if (tries == 5) {
+               intel_dp_dump_link_status(link_status);
+               DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
        }
 
        intel_dp_set_idle_link_train(intel_dp);
 
-       if (channel_eq)
-               DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
+       return intel_dp->channel_eq_status;
+
 }
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
index 68a005d..54a9d76 100644 (file)
 #include <drm/drm_edid.h>
 
 static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
-                                       struct intel_crtc_state *pipe_config)
+                                       struct intel_crtc_state *pipe_config,
+                                       struct drm_connector_state *conn_state)
 {
        struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
        struct intel_dp *intel_dp = &intel_dig_port->dp;
        struct drm_atomic_state *state;
-       int bpp, i;
+       int bpp;
        int lane_count, slots;
        const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       struct drm_connector *drm_connector;
-       struct intel_connector *connector, *found = NULL;
-       struct drm_connector_state *connector_state;
        int mst_pbn;
 
        pipe_config->dp_encoder_is_mst = true;
@@ -54,7 +52,6 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
         */
        lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
 
-
        pipe_config->lane_count = lane_count;
 
        pipe_config->pipe_bpp = 24;
@@ -62,20 +59,6 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 
        state = pipe_config->base.state;
 
-       for_each_connector_in_state(state, drm_connector, connector_state, i) {
-               connector = to_intel_connector(drm_connector);
-
-               if (connector_state->best_encoder == &encoder->base) {
-                       found = connector;
-                       break;
-               }
-       }
-
-       if (!found) {
-               DRM_ERROR("can't find connector\n");
-               return false;
-       }
-
        mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
 
        pipe_config->pbn = mst_pbn;
@@ -92,16 +75,20 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 
 }
 
-static void intel_mst_disable_dp(struct intel_encoder *encoder)
+static void intel_mst_disable_dp(struct intel_encoder *encoder,
+                                struct intel_crtc_state *old_crtc_state,
+                                struct drm_connector_state *old_conn_state)
 {
        struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
        struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct intel_connector *connector =
+               to_intel_connector(old_conn_state->connector);
        int ret;
 
        DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
 
-       drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, intel_mst->connector->port);
+       drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port);
 
        ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
        if (ret) {
@@ -109,11 +96,15 @@ static void intel_mst_disable_dp(struct intel_encoder *encoder)
        }
 }
 
-static void intel_mst_post_disable_dp(struct intel_encoder *encoder)
+static void intel_mst_post_disable_dp(struct intel_encoder *encoder,
+                                     struct intel_crtc_state *old_crtc_state,
+                                     struct drm_connector_state *old_conn_state)
 {
        struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
        struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct intel_connector *connector =
+               to_intel_connector(old_conn_state->connector);
 
        DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
 
@@ -122,59 +113,51 @@ static void intel_mst_post_disable_dp(struct intel_encoder *encoder)
        /* and this can also fail */
        drm_dp_update_payload_part2(&intel_dp->mst_mgr);
 
-       drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, intel_mst->connector->port);
+       drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
 
        intel_dp->active_mst_links--;
 
        intel_mst->connector = NULL;
        if (intel_dp->active_mst_links == 0) {
-               intel_dig_port->base.post_disable(&intel_dig_port->base);
+               intel_dig_port->base.post_disable(&intel_dig_port->base,
+                                                 NULL, NULL);
+
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
        }
 }
 
-static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
+static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config,
+                                   struct drm_connector_state *conn_state)
 {
        struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
        struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum port port = intel_dig_port->port;
+       struct intel_connector *connector =
+               to_intel_connector(conn_state->connector);
        int ret;
        uint32_t temp;
-       struct intel_connector *found = NULL, *connector;
        int slots;
-       struct drm_crtc *crtc = encoder->base.crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-       for_each_intel_connector(dev, connector) {
-               if (connector->base.state->best_encoder == &encoder->base) {
-                       found = connector;
-                       break;
-               }
-       }
-
-       if (!found) {
-               DRM_ERROR("can't find connector\n");
-               return;
-       }
 
        /* MST encoders are bound to a crtc, not to a connector,
         * force the mapping here for get_hw_state.
         */
-       found->encoder = encoder;
+       connector->encoder = encoder;
+       intel_mst->connector = connector;
 
        DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
 
-       intel_mst->connector = found;
-
        if (intel_dp->active_mst_links == 0) {
-               intel_prepare_ddi_buffer(&intel_dig_port->base);
-
-               intel_ddi_clk_select(&intel_dig_port->base, intel_crtc->config);
+               intel_ddi_clk_select(&intel_dig_port->base,
+                                    pipe_config->shared_dpll);
 
-               intel_dp_set_link_params(intel_dp, intel_crtc->config);
+               intel_prepare_dp_ddi_buffers(&intel_dig_port->base);
+               intel_dp_set_link_params(intel_dp,
+                                        pipe_config->port_clock,
+                                        pipe_config->lane_count,
+                                        true);
 
                intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
 
@@ -185,8 +168,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
        }
 
        ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
-                                      intel_mst->connector->port,
-                                      intel_crtc->config->pbn, &slots);
+                                      connector->port,
+                                      pipe_config->pbn, &slots);
        if (ret == false) {
                DRM_ERROR("failed to allocate vcpi\n");
                return;
@@ -200,13 +183,14 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
        ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
 }
 
-static void intel_mst_enable_dp(struct intel_encoder *encoder)
+static void intel_mst_enable_dp(struct intel_encoder *encoder,
+                               struct intel_crtc_state *pipe_config,
+                               struct drm_connector_state *conn_state)
 {
        struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
        struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_device *dev = intel_dig_port->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum port port = intel_dig_port->port;
        int ret;
 
@@ -239,9 +223,8 @@ static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
 {
        struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
        u32 temp, flags = 0;
 
index 5c1f2d2..1c59ca5 100644 (file)
 
 #include "intel_drv.h"
 
+struct intel_shared_dpll *
+skl_find_link_pll(struct drm_i915_private *dev_priv, int clock)
+{
+       struct intel_shared_dpll *pll = NULL;
+       struct intel_dpll_hw_state dpll_hw_state;
+       enum intel_dpll_id i;
+       bool found = false;
+
+       if (!skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
+               return pll;
+
+       for (i = DPLL_ID_SKL_DPLL1; i <= DPLL_ID_SKL_DPLL3; i++) {
+               pll = &dev_priv->shared_dplls[i];
+
+               /* Only want to check enabled timings first */
+               if (pll->config.crtc_mask == 0)
+                       continue;
+
+               if (memcmp(&dpll_hw_state, &pll->config.hw_state,
+                          sizeof(pll->config.hw_state)) == 0) {
+                       found = true;
+                       break;
+               }
+       }
+
+       /* Ok no matching timings, maybe there's a free one? */
+       for (i = DPLL_ID_SKL_DPLL1;
+            ((found == false) && (i <= DPLL_ID_SKL_DPLL3)); i++) {
+               pll = &dev_priv->shared_dplls[i];
+               if (pll->config.crtc_mask == 0) {
+                       pll->config.hw_state = dpll_hw_state;
+                       break;
+               }
+       }
+
+       return pll;
+}
+
 struct intel_shared_dpll *
 intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
                            enum intel_dpll_id id)
@@ -452,26 +490,6 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
        return val & SPLL_PLL_ENABLE;
 }
 
-static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
-{
-       switch (pll->id) {
-       case DPLL_ID_WRPLL1:
-               return PORT_CLK_SEL_WRPLL1;
-       case DPLL_ID_WRPLL2:
-               return PORT_CLK_SEL_WRPLL2;
-       case DPLL_ID_SPLL:
-               return PORT_CLK_SEL_SPLL;
-       case DPLL_ID_LCPLL_810:
-               return PORT_CLK_SEL_LCPLL_810;
-       case DPLL_ID_LCPLL_1350:
-               return PORT_CLK_SEL_LCPLL_1350;
-       case DPLL_ID_LCPLL_2700:
-               return PORT_CLK_SEL_LCPLL_2700;
-       default:
-               return PORT_CLK_SEL_NONE;
-       }
-}
-
 #define LC_FREQ 2700
 #define LC_FREQ_2K U64_C(LC_FREQ * 2000)
 
@@ -687,11 +705,65 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
        *r2_out = best.r2;
 }
 
+static struct intel_shared_dpll *hsw_ddi_hdmi_get_dpll(int clock,
+                                                      struct intel_crtc *crtc,
+                                                      struct intel_crtc_state *crtc_state)
+{
+       struct intel_shared_dpll *pll;
+       uint32_t val;
+       unsigned int p, n2, r2;
+
+       hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
+
+       val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
+             WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
+             WRPLL_DIVIDER_POST(p);
+
+       crtc_state->dpll_hw_state.wrpll = val;
+
+       pll = intel_find_shared_dpll(crtc, crtc_state,
+                                    DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
+
+       if (!pll)
+               return NULL;
+
+       return pll;
+}
+
+struct intel_shared_dpll *hsw_ddi_dp_get_dpll(struct intel_encoder *encoder,
+                                             int clock)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_shared_dpll *pll;
+       enum intel_dpll_id pll_id;
+
+       switch (clock / 2) {
+       case 81000:
+               pll_id = DPLL_ID_LCPLL_810;
+               break;
+       case 135000:
+               pll_id = DPLL_ID_LCPLL_1350;
+               break;
+       case 270000:
+               pll_id = DPLL_ID_LCPLL_2700;
+               break;
+       default:
+               DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
+               return NULL;
+       }
+
+       pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
+
+       if (!pll)
+               return NULL;
+
+       return pll;
+}
+
 static struct intel_shared_dpll *
 hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
             struct intel_encoder *encoder)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        struct intel_shared_dpll *pll;
        int clock = crtc_state->port_clock;
 
@@ -699,41 +771,12 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
               sizeof(crtc_state->dpll_hw_state));
 
        if (encoder->type == INTEL_OUTPUT_HDMI) {
-               uint32_t val;
-               unsigned p, n2, r2;
-
-               hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
-
-               val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
-                     WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
-                     WRPLL_DIVIDER_POST(p);
-
-               crtc_state->dpll_hw_state.wrpll = val;
-
-               pll = intel_find_shared_dpll(crtc, crtc_state,
-                                            DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
+               pll = hsw_ddi_hdmi_get_dpll(clock, crtc, crtc_state);
 
        } else if (encoder->type == INTEL_OUTPUT_DP ||
                   encoder->type == INTEL_OUTPUT_DP_MST ||
                   encoder->type == INTEL_OUTPUT_EDP) {
-               enum intel_dpll_id pll_id;
-
-               switch (clock / 2) {
-               case 81000:
-                       pll_id = DPLL_ID_LCPLL_810;
-                       break;
-               case 135000:
-                       pll_id = DPLL_ID_LCPLL_1350;
-                       break;
-               case 270000:
-                       pll_id = DPLL_ID_LCPLL_2700;
-                       break;
-               default:
-                       DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
-                       return NULL;
-               }
-
-               pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
+               pll = hsw_ddi_dp_get_dpll(encoder, clock);
 
        } else if (encoder->type == INTEL_OUTPUT_ANALOG) {
                if (WARN_ON(crtc_state->port_clock / 2 != 135000))
@@ -751,14 +794,11 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
        if (!pll)
                return NULL;
 
-       crtc_state->ddi_pll_sel = hsw_pll_to_ddi_pll_sel(pll);
-
        intel_reference_shared_dpll(pll, crtc_state);
 
        return pll;
 }
 
-
 static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
        .enable = hsw_ddi_wrpll_enable,
        .disable = hsw_ddi_wrpll_disable,
@@ -1194,75 +1234,110 @@ skip_remaining_dividers:
        return true;
 }
 
-static struct intel_shared_dpll *
-skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
-            struct intel_encoder *encoder)
+static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc *crtc,
+                                     struct intel_crtc_state *crtc_state,
+                                     int clock)
 {
-       struct intel_shared_dpll *pll;
        uint32_t ctrl1, cfgcr1, cfgcr2;
-       int clock = crtc_state->port_clock;
+       struct skl_wrpll_params wrpll_params = { 0, };
 
        /*
         * See comment in intel_dpll_hw_state to understand why we always use 0
         * as the DPLL id in this function.
         */
-
        ctrl1 = DPLL_CTRL1_OVERRIDE(0);
 
-       if (encoder->type == INTEL_OUTPUT_HDMI) {
-               struct skl_wrpll_params wrpll_params = { 0, };
+       ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
+
+       if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
+               return false;
 
-               ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
+       cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
+               DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
+               wrpll_params.dco_integer;
 
-               if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
-                       return NULL;
+       cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
+               DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
+               DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
+               DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
+               wrpll_params.central_freq;
+
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
+
+       crtc_state->dpll_hw_state.ctrl1 = ctrl1;
+       crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
+       crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
+       return true;
+}
+
+
+bool skl_ddi_dp_set_dpll_hw_state(int clock,
+                                 struct intel_dpll_hw_state *dpll_hw_state)
+{
+       uint32_t ctrl1;
+
+       /*
+        * See comment in intel_dpll_hw_state to understand why we always use 0
+        * as the DPLL id in this function.
+        */
+       ctrl1 = DPLL_CTRL1_OVERRIDE(0);
+       switch (clock / 2) {
+       case 81000:
+               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
+               break;
+       case 135000:
+               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
+               break;
+       case 270000:
+               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
+               break;
+               /* eDP 1.4 rates */
+       case 162000:
+               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
+               break;
+       case 108000:
+               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
+               break;
+       case 216000:
+               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
+               break;
+       }
+
+       dpll_hw_state->ctrl1 = ctrl1;
+       return true;
+}
+
+static struct intel_shared_dpll *
+skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
+            struct intel_encoder *encoder)
+{
+       struct intel_shared_dpll *pll;
+       int clock = crtc_state->port_clock;
+       bool bret;
+       struct intel_dpll_hw_state dpll_hw_state;
 
-               cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
-                        DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
-                        wrpll_params.dco_integer;
+       memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
 
-               cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
-                        DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
-                        DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
-                        DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
-                        wrpll_params.central_freq;
+       if (encoder->type == INTEL_OUTPUT_HDMI) {
+               bret = skl_ddi_hdmi_pll_dividers(crtc, crtc_state, clock);
+               if (!bret) {
+                       DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n");
+                       return NULL;
+               }
        } else if (encoder->type == INTEL_OUTPUT_DP ||
                   encoder->type == INTEL_OUTPUT_DP_MST ||
                   encoder->type == INTEL_OUTPUT_EDP) {
-               switch (crtc_state->port_clock / 2) {
-               case 81000:
-                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
-                       break;
-               case 135000:
-                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
-                       break;
-               case 270000:
-                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
-                       break;
-               /* eDP 1.4 rates */
-               case 162000:
-                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
-                       break;
-               case 108000:
-                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
-                       break;
-               case 216000:
-                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
-                       break;
+               bret = skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state);
+               if (!bret) {
+                       DRM_DEBUG_KMS("Could not set DP dpll HW state.\n");
+                       return NULL;
                }
-
-               cfgcr1 = cfgcr2 = 0;
+               crtc_state->dpll_hw_state = dpll_hw_state;
        } else {
                return NULL;
        }
 
-       memset(&crtc_state->dpll_hw_state, 0,
-              sizeof(crtc_state->dpll_hw_state));
-
-       crtc_state->dpll_hw_state.ctrl1 = ctrl1;
-       crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
-       crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
-
        if (encoder->type == INTEL_OUTPUT_EDP)
                pll = intel_find_shared_dpll(crtc, crtc_state,
                                             DPLL_ID_SKL_DPLL0,
@@ -1274,8 +1349,6 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
        if (!pll)
                return NULL;
 
-       crtc_state->ddi_pll_sel = pll->id;
-
        intel_reference_shared_dpll(pll, crtc_state);
 
        return pll;
@@ -1484,6 +1557,8 @@ struct bxt_clk_div {
        uint32_t m2_frac;
        bool m2_frac_en;
        uint32_t n;
+
+       int vco;
 };
 
 /* pre-calculated values for DP linkrates */
@@ -1497,57 +1572,60 @@ static const struct bxt_clk_div bxt_dp_clk_val[] = {
        {432000, 3, 1, 32, 1677722, 1, 1}
 };
 
-static struct intel_shared_dpll *
-bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
-            struct intel_encoder *encoder)
+static bool
+bxt_ddi_hdmi_pll_dividers(struct intel_crtc *intel_crtc,
+                         struct intel_crtc_state *crtc_state, int clock,
+                         struct bxt_clk_div *clk_div)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       struct intel_shared_dpll *pll;
-       enum intel_dpll_id i;
-       struct intel_digital_port *intel_dig_port;
-       struct bxt_clk_div clk_div = {0};
-       int vco = 0;
-       uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
-       uint32_t lanestagger;
-       int clock = crtc_state->port_clock;
+       struct dpll best_clock;
 
-       if (encoder->type == INTEL_OUTPUT_HDMI) {
-               struct dpll best_clock;
+       /* Calculate HDMI div */
+       /*
+        * FIXME: tie the following calculation into
+        * i9xx_crtc_compute_clock
+        */
+       if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
+               DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
+                                clock, pipe_name(intel_crtc->pipe));
+               return false;
+       }
 
-               /* Calculate HDMI div */
-               /*
-                * FIXME: tie the following calculation into
-                * i9xx_crtc_compute_clock
-                */
-               if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
-                       DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
-                                        clock, pipe_name(crtc->pipe));
-                       return NULL;
-               }
+       clk_div->p1 = best_clock.p1;
+       clk_div->p2 = best_clock.p2;
+       WARN_ON(best_clock.m1 != 2);
+       clk_div->n = best_clock.n;
+       clk_div->m2_int = best_clock.m2 >> 22;
+       clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1);
+       clk_div->m2_frac_en = clk_div->m2_frac != 0;
 
-               clk_div.p1 = best_clock.p1;
-               clk_div.p2 = best_clock.p2;
-               WARN_ON(best_clock.m1 != 2);
-               clk_div.n = best_clock.n;
-               clk_div.m2_int = best_clock.m2 >> 22;
-               clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1);
-               clk_div.m2_frac_en = clk_div.m2_frac != 0;
+       clk_div->vco = best_clock.vco;
 
-               vco = best_clock.vco;
-       } else if (encoder->type == INTEL_OUTPUT_DP ||
-                  encoder->type == INTEL_OUTPUT_EDP) {
-               int i;
+       return true;
+}
 
-               clk_div = bxt_dp_clk_val[0];
-               for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
-                       if (bxt_dp_clk_val[i].clock == clock) {
-                               clk_div = bxt_dp_clk_val[i];
-                               break;
-                       }
+static void bxt_ddi_dp_pll_dividers(int clock, struct bxt_clk_div *clk_div)
+{
+       int i;
+
+       *clk_div = bxt_dp_clk_val[0];
+       for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
+               if (bxt_dp_clk_val[i].clock == clock) {
+                       *clk_div = bxt_dp_clk_val[i];
+                       break;
                }
-               vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2;
        }
 
+       clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2;
+}
+
+static bool bxt_ddi_set_dpll_hw_state(int clock,
+                         struct bxt_clk_div *clk_div,
+                         struct intel_dpll_hw_state *dpll_hw_state)
+{
+       int vco = clk_div->vco;
+       uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
+       uint32_t lanestagger;
+
        if (vco >= 6200000 && vco <= 6700000) {
                prop_coef = 4;
                int_coef = 9;
@@ -1566,12 +1644,9 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
                targ_cnt = 9;
        } else {
                DRM_ERROR("Invalid VCO\n");
-               return NULL;
+               return false;
        }
 
-       memset(&crtc_state->dpll_hw_state, 0,
-              sizeof(crtc_state->dpll_hw_state));
-
        if (clock > 270000)
                lanestagger = 0x18;
        else if (clock > 135000)
@@ -1583,35 +1658,86 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
        else
                lanestagger = 0x02;
 
-       crtc_state->dpll_hw_state.ebb0 =
-               PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2);
-       crtc_state->dpll_hw_state.pll0 = clk_div.m2_int;
-       crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n);
-       crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac;
+       dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2);
+       dpll_hw_state->pll0 = clk_div->m2_int;
+       dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n);
+       dpll_hw_state->pll2 = clk_div->m2_frac;
 
-       if (clk_div.m2_frac_en)
-               crtc_state->dpll_hw_state.pll3 =
-                       PORT_PLL_M2_FRAC_ENABLE;
+       if (clk_div->m2_frac_en)
+               dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE;
 
-       crtc_state->dpll_hw_state.pll6 =
-               prop_coef | PORT_PLL_INT_COEFF(int_coef);
-       crtc_state->dpll_hw_state.pll6 |=
-               PORT_PLL_GAIN_CTL(gain_ctl);
+       dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef);
+       dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl);
 
-       crtc_state->dpll_hw_state.pll8 = targ_cnt;
+       dpll_hw_state->pll8 = targ_cnt;
 
-       crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
+       dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
 
-       crtc_state->dpll_hw_state.pll10 =
+       dpll_hw_state->pll10 =
                PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
                | PORT_PLL_DCO_AMP_OVR_EN_H;
 
-       crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
+       dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
+
+       dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
 
-       crtc_state->dpll_hw_state.pcsdw12 =
-               LANESTAGGER_STRAP_OVRD | lanestagger;
+       return true;
+}
 
-       intel_dig_port = enc_to_dig_port(&encoder->base);
+bool bxt_ddi_dp_set_dpll_hw_state(int clock,
+                         struct intel_dpll_hw_state *dpll_hw_state)
+{
+       struct bxt_clk_div clk_div = {0};
+
+       bxt_ddi_dp_pll_dividers(clock, &clk_div);
+
+       return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
+}
+
+static bool
+bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc *intel_crtc,
+                              struct intel_crtc_state *crtc_state, int clock,
+                              struct intel_dpll_hw_state *dpll_hw_state)
+{
+       struct bxt_clk_div clk_div = { };
+
+       bxt_ddi_hdmi_pll_dividers(intel_crtc, crtc_state, clock, &clk_div);
+
+       return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
+}
+
+static struct intel_shared_dpll *
+bxt_get_dpll(struct intel_crtc *crtc,
+               struct intel_crtc_state *crtc_state,
+               struct intel_encoder *encoder)
+{
+       struct intel_dpll_hw_state dpll_hw_state = { };
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct intel_digital_port *intel_dig_port;
+       struct intel_shared_dpll *pll;
+       int i, clock = crtc_state->port_clock;
+
+       if (encoder->type == INTEL_OUTPUT_HDMI &&
+           !bxt_ddi_hdmi_set_dpll_hw_state(crtc, crtc_state, clock,
+                                           &dpll_hw_state))
+               return NULL;
+
+       if ((encoder->type == INTEL_OUTPUT_DP ||
+            encoder->type == INTEL_OUTPUT_EDP) &&
+           !bxt_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
+               return NULL;
+
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
+
+       crtc_state->dpll_hw_state = dpll_hw_state;
+
+       if (encoder->type == INTEL_OUTPUT_DP_MST) {
+               struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+
+               intel_dig_port = intel_mst->primary;
+       } else
+               intel_dig_port = enc_to_dig_port(&encoder->base);
 
        /* 1:1 mapping between ports and PLLs */
        i = (enum intel_dpll_id) intel_dig_port->port;
@@ -1622,9 +1748,6 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 
        intel_reference_shared_dpll(pll, crtc_state);
 
-       /* shared DPLL id 0 is DPLL A */
-       crtc_state->ddi_pll_sel = pll->id;
-
        return pll;
 }
 
index 89c5ada..f438535 100644 (file)
@@ -160,5 +160,20 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc);
 void intel_shared_dpll_commit(struct drm_atomic_state *state);
 void intel_shared_dpll_init(struct drm_device *dev);
 
+/* BXT dpll related functions */
+bool bxt_ddi_dp_set_dpll_hw_state(int clock,
+                         struct intel_dpll_hw_state *dpll_hw_state);
+
+
+/* SKL dpll related functions */
+bool skl_ddi_dp_set_dpll_hw_state(int clock,
+                                 struct intel_dpll_hw_state *dpll_hw_state);
+struct intel_shared_dpll *skl_find_link_pll(struct drm_i915_private *dev_priv,
+                                           int clock);
+
+
+/* HSW dpll related functions */
+struct intel_shared_dpll *hsw_ddi_dp_get_dpll(struct intel_encoder *encoder,
+                                             int clock);
 
 #endif /* _INTEL_DPLL_MGR_H_ */
index ff399b9..a19ec06 100644 (file)
  */
 #define _wait_for(COND, US, W) ({ \
        unsigned long timeout__ = jiffies + usecs_to_jiffies(US) + 1;   \
-       int ret__ = 0;                                                  \
-       while (!(COND)) {                                               \
-               if (time_after(jiffies, timeout__)) {                   \
-                       if (!(COND))                                    \
-                               ret__ = -ETIMEDOUT;                     \
+       int ret__;                                                      \
+       for (;;) {                                                      \
+               bool expired__ = time_after(jiffies, timeout__);        \
+               if (COND) {                                             \
+                       ret__ = 0;                                      \
+                       break;                                          \
+               }                                                       \
+               if (expired__) {                                        \
+                       ret__ = -ETIMEDOUT;                             \
                        break;                                          \
                }                                                       \
                if ((W) && drm_can_sleep()) {                           \
@@ -178,11 +182,22 @@ struct intel_framebuffer {
        struct drm_framebuffer base;
        struct drm_i915_gem_object *obj;
        struct intel_rotation_info rot_info;
+
+       /* for each plane in the normal GTT view */
+       struct {
+               unsigned int x, y;
+       } normal[2];
+       /* for each plane in the rotated GTT view */
+       struct {
+               unsigned int x, y;
+               unsigned int pitch; /* pixels */
+       } rotated[2];
 };
 
 struct intel_fbdev {
        struct drm_fb_helper helper;
        struct intel_framebuffer *fb;
+       struct i915_vma *vma;
        async_cookie_t cookie;
        int preferred_bpp;
 };
@@ -194,14 +209,26 @@ struct intel_encoder {
        unsigned int cloneable;
        void (*hot_plug)(struct intel_encoder *);
        bool (*compute_config)(struct intel_encoder *,
-                              struct intel_crtc_state *);
-       void (*pre_pll_enable)(struct intel_encoder *);
-       void (*pre_enable)(struct intel_encoder *);
-       void (*enable)(struct intel_encoder *);
-       void (*mode_set)(struct intel_encoder *intel_encoder);
-       void (*disable)(struct intel_encoder *);
-       void (*post_disable)(struct intel_encoder *);
-       void (*post_pll_disable)(struct intel_encoder *);
+                              struct intel_crtc_state *,
+                              struct drm_connector_state *);
+       void (*pre_pll_enable)(struct intel_encoder *,
+                              struct intel_crtc_state *,
+                              struct drm_connector_state *);
+       void (*pre_enable)(struct intel_encoder *,
+                          struct intel_crtc_state *,
+                          struct drm_connector_state *);
+       void (*enable)(struct intel_encoder *,
+                      struct intel_crtc_state *,
+                      struct drm_connector_state *);
+       void (*disable)(struct intel_encoder *,
+                       struct intel_crtc_state *,
+                       struct drm_connector_state *);
+       void (*post_disable)(struct intel_encoder *,
+                            struct intel_crtc_state *,
+                            struct drm_connector_state *);
+       void (*post_pll_disable)(struct intel_encoder *,
+                                struct intel_crtc_state *,
+                                struct drm_connector_state *);
        /* Read out the current hw state of this connector, returning true if
         * the encoder is active. If the encoder is enabled it also set the pipe
         * it is connected to in the pipe parameter. */
@@ -236,6 +263,7 @@ struct intel_panel {
                bool enabled;
                bool combination_mode;  /* gen 2/4 only */
                bool active_low_pwm;
+               bool alternate_pwm_increment;   /* lpt+ */
 
                /* PWM chip */
                bool util_pin_active_low;       /* bxt+ */
@@ -338,10 +366,16 @@ struct intel_atomic_state {
 
 struct intel_plane_state {
        struct drm_plane_state base;
-       struct drm_rect src;
-       struct drm_rect dst;
        struct drm_rect clip;
-       bool visible;
+
+       struct {
+               u32 offset;
+               int x, y;
+       } main;
+       struct {
+               u32 offset;
+               int x, y;
+       } aux;
 
        /*
         * scaler_id
@@ -561,12 +595,6 @@ struct intel_crtc_state {
        /* Selected dpll when shared or NULL. */
        struct intel_shared_dpll *shared_dpll;
 
-       /*
-        * - PORT_CLK_SEL for DDI ports on HSW/BDW.
-        * - enum skl_dpll on SKL
-        */
-       uint32_t ddi_pll_sel;
-
        /* Actual register state of the dpll, for shared dpll cross-checking. */
        struct intel_dpll_hw_state dpll_hw_state;
 
@@ -683,8 +711,8 @@ struct intel_crtc {
 
        struct intel_crtc_state *config;
 
-       /* reset counter value when the last flip was submitted */
-       unsigned int reset_counter;
+       /* global reset count when the last flip was submitted */
+       unsigned int reset_count;
 
        /* Access to these should be protected by dev_priv->irq_lock. */
        bool cpu_fifo_underrun_disabled;
@@ -852,8 +880,10 @@ struct intel_dp {
        int link_rate;
        uint8_t lane_count;
        uint8_t sink_count;
+       bool link_mst;
        bool has_audio;
        bool detect_done;
+       bool channel_eq_status;
        enum hdmi_force_audio force_audio;
        bool limited_color_range;
        bool color_range_auto;
@@ -1106,8 +1136,11 @@ void intel_crt_reset(struct drm_encoder *encoder);
 
 /* intel_ddi.c */
 void intel_ddi_clk_select(struct intel_encoder *encoder,
-                         const struct intel_crtc_state *pipe_config);
-void intel_prepare_ddi_buffer(struct intel_encoder *encoder);
+                         struct intel_shared_dpll *pll);
+void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder,
+                               struct intel_crtc_state *old_crtc_state,
+                               struct drm_connector_state *old_conn_state);
+void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder);
 void hsw_fdi_link_train(struct drm_crtc *crtc);
 void intel_ddi_init(struct drm_device *dev, enum port port);
 enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder);
@@ -1122,7 +1155,6 @@ bool intel_ddi_pll_select(struct intel_crtc *crtc,
 void intel_ddi_set_pipe_settings(struct drm_crtc *crtc);
 void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp);
 bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
-void intel_ddi_fdi_disable(struct drm_crtc *crtc);
 void intel_ddi_get_config(struct intel_encoder *encoder,
                          struct intel_crtc_state *pipe_config);
 struct intel_encoder *
@@ -1133,22 +1165,12 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
                         struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
-
-/* intel_frontbuffer.c */
-void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
-                            enum fb_op_origin origin);
-void intel_frontbuffer_flip_prepare(struct drm_device *dev,
-                                   unsigned frontbuffer_bits);
-void intel_frontbuffer_flip_complete(struct drm_device *dev,
-                                    unsigned frontbuffer_bits);
-void intel_frontbuffer_flip(struct drm_device *dev,
-                           unsigned frontbuffer_bits);
+struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
+                                                 int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
                                   unsigned int height,
                                   uint32_t pixel_format,
                                   uint64_t fb_format_modifier);
-void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire,
-                       enum fb_op_origin origin);
 u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv,
                              uint64_t fb_modifier, uint32_t pixel_format);
 
@@ -1164,14 +1186,22 @@ void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, int vco);
 void intel_update_rawclk(struct drm_i915_private *dev_priv);
 int vlv_get_cck_clock(struct drm_i915_private *dev_priv,
                      const char *name, u32 reg, int ref_freq);
+void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv);
+void lpt_disable_iclkip(struct drm_i915_private *dev_priv);
 extern const struct drm_plane_funcs intel_plane_funcs;
 void intel_init_display_hooks(struct drm_i915_private *dev_priv);
+unsigned int intel_fb_xy_to_linear(int x, int y,
+                                  const struct intel_plane_state *state,
+                                  int plane);
+void intel_add_fb_offsets(int *x, int *y,
+                         const struct intel_plane_state *state, int plane);
 unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info);
 bool intel_has_pending_fb_unpin(struct drm_device *dev);
 void intel_mark_busy(struct drm_i915_private *dev_priv);
 void intel_mark_idle(struct drm_i915_private *dev_priv);
 void intel_crtc_restore_mode(struct drm_crtc *crtc);
 int intel_display_suspend(struct drm_device *dev);
+void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv);
 void intel_encoder_destroy(struct drm_encoder *encoder);
 int intel_connector_init(struct intel_connector *);
 struct intel_connector *intel_connector_alloc(void);
@@ -1227,8 +1257,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 void intel_release_load_detect_pipe(struct drm_connector *connector,
                                    struct intel_load_detect_pipe *old,
                                    struct drm_modeset_acquire_ctx *ctx);
-int intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
-                              unsigned int rotation);
+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);
 struct drm_framebuffer *
 __intel_framebuffer_create(struct drm_device *dev,
@@ -1238,9 +1268,9 @@ void intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, int pipe);
 void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe);
 void intel_check_page_flip(struct drm_i915_private *dev_priv, int pipe);
 int intel_prepare_plane_fb(struct drm_plane *plane,
-                          const struct drm_plane_state *new_state);
+                          struct drm_plane_state *new_state);
 void intel_cleanup_plane_fb(struct drm_plane *plane,
-                           const struct drm_plane_state *old_state);
+                           struct drm_plane_state *old_state);
 int intel_plane_atomic_get_property(struct drm_plane *plane,
                                    const struct drm_plane_state *state,
                                    struct drm_property *property,
@@ -1258,7 +1288,7 @@ unsigned int intel_tile_height(const struct drm_i915_private *dev_priv,
 static inline bool
 intel_rotation_90_or_270(unsigned int rotation)
 {
-       return rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270));
+       return rotation & (DRM_ROTATE_90 | DRM_ROTATE_270);
 }
 
 void intel_create_rotation_property(struct drm_device *dev,
@@ -1290,9 +1320,7 @@ void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state);
 #define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
 #define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
 u32 intel_compute_tile_offset(int *x, int *y,
-                             const struct drm_framebuffer *fb, int plane,
-                             unsigned int pitch,
-                             unsigned int rotation);
+                             const struct intel_plane_state *state, int plane);
 void intel_prepare_reset(struct drm_i915_private *dev_priv);
 void intel_finish_reset(struct drm_i915_private *dev_priv);
 void hsw_enable_pc8(struct drm_i915_private *dev_priv);
@@ -1335,13 +1363,14 @@ 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_plane_obj_offset(struct intel_plane *intel_plane,
-                          struct drm_i915_gem_object *obj,
-                          unsigned int plane);
+u32 intel_fb_gtt_offset(struct drm_framebuffer *fb, unsigned int rotation);
 
 u32 skl_plane_ctl_format(uint32_t pixel_format);
 u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
 u32 skl_plane_ctl_rotation(unsigned int rotation);
+u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
+                    unsigned int rotation);
+int skl_check_plane_surface(struct intel_plane_state *plane_state);
 
 /* intel_csr.c */
 void intel_csr_ucode_init(struct drm_i915_private *);
@@ -1355,7 +1384,8 @@ bool intel_dp_init(struct drm_device *dev, i915_reg_t output_reg, enum port port
 bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                             struct intel_connector *intel_connector);
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
-                             const struct intel_crtc_state *pipe_config);
+                             int link_rate, uint8_t lane_count,
+                             bool link_mst);
 void intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
@@ -1364,7 +1394,8 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
 void intel_dp_encoder_destroy(struct drm_encoder *encoder);
 int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc);
 bool intel_dp_compute_config(struct intel_encoder *encoder,
-                            struct intel_crtc_state *pipe_config);
+                            struct intel_crtc_state *pipe_config,
+                            struct drm_connector_state *conn_state);
 bool intel_dp_is_edp(struct drm_device *dev, enum port port);
 enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
                                  bool long_hpd);
@@ -1382,13 +1413,14 @@ void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
 void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
 uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
 void intel_plane_destroy(struct drm_plane *plane);
-void intel_edp_drrs_enable(struct intel_dp *intel_dp);
-void intel_edp_drrs_disable(struct intel_dp *intel_dp);
-void intel_edp_drrs_invalidate(struct drm_device *dev,
-               unsigned frontbuffer_bits);
-void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
-bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
-                                        struct intel_digital_port *port);
+void intel_edp_drrs_enable(struct intel_dp *intel_dp,
+                          struct intel_crtc_state *crtc_state);
+void intel_edp_drrs_disable(struct intel_dp *intel_dp,
+                          struct intel_crtc_state *crtc_state);
+void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
+                              unsigned int frontbuffer_bits);
+void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
+                         unsigned int frontbuffer_bits);
 
 void
 intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
@@ -1488,7 +1520,8 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
                               struct intel_connector *intel_connector);
 struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
 bool intel_hdmi_compute_config(struct intel_encoder *encoder,
-                              struct intel_crtc_state *pipe_config);
+                              struct intel_crtc_state *pipe_config,
+                              struct drm_connector_state *conn_state);
 void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
 
 
@@ -1561,13 +1594,13 @@ static inline void intel_backlight_device_unregister(struct intel_connector *con
 /* intel_psr.c */
 void intel_psr_enable(struct intel_dp *intel_dp);
 void intel_psr_disable(struct intel_dp *intel_dp);
-void intel_psr_invalidate(struct drm_device *dev,
+void intel_psr_invalidate(struct drm_i915_private *dev_priv,
                          unsigned frontbuffer_bits);
-void intel_psr_flush(struct drm_device *dev,
+void intel_psr_flush(struct drm_i915_private *dev_priv,
                     unsigned frontbuffer_bits,
                     enum fb_op_origin origin);
 void intel_psr_init(struct drm_device *dev);
-void intel_psr_single_frame_update(struct drm_device *dev,
+void intel_psr_single_frame_update(struct drm_i915_private *dev_priv,
                                   unsigned frontbuffer_bits);
 
 /* intel_runtime_pm.c */
@@ -1667,13 +1700,6 @@ enable_rpm_wakeref_asserts(struct drm_i915_private *dev_priv)
        atomic_dec(&dev_priv->pm.wakeref_count);
 }
 
-/* TODO: convert users of these to rely instead on proper RPM refcounting */
-#define DISABLE_RPM_WAKEREF_ASSERTS(dev_priv)  \
-       disable_rpm_wakeref_asserts(dev_priv)
-
-#define ENABLE_RPM_WAKEREF_ASSERTS(dev_priv)   \
-       enable_rpm_wakeref_asserts(dev_priv)
-
 void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
 bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
@@ -1699,11 +1725,11 @@ void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
 void intel_gpu_ips_teardown(void);
 void intel_init_gt_powersave(struct drm_i915_private *dev_priv);
 void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv);
+void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv);
 void intel_enable_gt_powersave(struct drm_i915_private *dev_priv);
+void intel_autoenable_gt_powersave(struct drm_i915_private *dev_priv);
 void intel_disable_gt_powersave(struct drm_i915_private *dev_priv);
 void intel_suspend_gt_powersave(struct drm_i915_private *dev_priv);
-void intel_reset_gt_powersave(struct drm_i915_private *dev_priv);
-void gen6_update_ring_freq(struct drm_i915_private *dev_priv);
 void gen6_rps_busy(struct drm_i915_private *dev_priv);
 void gen6_rps_reset_ei(struct drm_i915_private *dev_priv);
 void gen6_rps_idle(struct drm_i915_private *dev_priv);
@@ -1716,9 +1742,21 @@ void ilk_wm_get_hw_state(struct drm_device *dev);
 void skl_wm_get_hw_state(struct drm_device *dev);
 void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
                          struct skl_ddb_allocation *ddb /* out */);
-bool skl_can_enable_sagv(struct drm_atomic_state *state);
-int skl_enable_sagv(struct drm_i915_private *dev_priv);
-int skl_disable_sagv(struct drm_i915_private *dev_priv);
+bool intel_can_enable_sagv(struct drm_atomic_state *state);
+int intel_enable_sagv(struct drm_i915_private *dev_priv);
+int intel_disable_sagv(struct drm_i915_private *dev_priv);
+bool skl_ddb_allocation_equals(const struct skl_ddb_allocation *old,
+                              const struct skl_ddb_allocation *new,
+                              enum pipe pipe);
+bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
+                                const struct skl_ddb_allocation *old,
+                                const struct skl_ddb_allocation *new,
+                                enum pipe pipe);
+void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
+                        const struct skl_wm_values *wm);
+void skl_write_plane_wm(struct intel_crtc *intel_crtc,
+                       const struct skl_wm_values *wm,
+                       int plane);
 uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
 bool ilk_disable_lp_wm(struct drm_device *dev);
 int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
index de8e9fb..b2e3d3a 100644 (file)
@@ -312,7 +312,8 @@ static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
 }
 
 static bool intel_dsi_compute_config(struct intel_encoder *encoder,
-                                    struct intel_crtc_state *pipe_config)
+                                    struct intel_crtc_state *pipe_config,
+                                    struct drm_connector_state *conn_state)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
@@ -533,14 +534,15 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
        intel_panel_enable_backlight(intel_dsi->attached_connector);
 }
 
-static void intel_dsi_prepare(struct intel_encoder *intel_encoder);
+static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
+                             struct intel_crtc_state *pipe_config);
 
-static void intel_dsi_pre_enable(struct intel_encoder *encoder)
+static void intel_dsi_pre_enable(struct intel_encoder *encoder,
+                                struct intel_crtc_state *pipe_config,
+                                struct drm_connector_state *conn_state)
 {
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
        enum port port;
 
        DRM_DEBUG_KMS("\n");
@@ -550,9 +552,9 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
         * lock. It needs to be fully powered down to fix it.
         */
        intel_disable_dsi_pll(encoder);
-       intel_enable_dsi_pll(encoder, crtc->config);
+       intel_enable_dsi_pll(encoder, pipe_config);
 
-       intel_dsi_prepare(encoder);
+       intel_dsi_prepare(encoder, pipe_config);
 
        /* Panel Enable over CRC PMIC */
        if (intel_dsi->gpio_panel)
@@ -582,7 +584,9 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
        intel_dsi_enable(encoder);
 }
 
-static void intel_dsi_enable_nop(struct intel_encoder *encoder)
+static void intel_dsi_enable_nop(struct intel_encoder *encoder,
+                                struct intel_crtc_state *pipe_config,
+                                struct drm_connector_state *conn_state)
 {
        DRM_DEBUG_KMS("\n");
 
@@ -592,7 +596,9 @@ static void intel_dsi_enable_nop(struct intel_encoder *encoder)
         */
 }
 
-static void intel_dsi_pre_disable(struct intel_encoder *encoder)
+static void intel_dsi_pre_disable(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *old_crtc_state,
+                                 struct drm_connector_state *old_conn_state)
 {
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
        enum port port;
@@ -694,7 +700,9 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
        intel_disable_dsi_pll(encoder);
 }
 
-static void intel_dsi_post_disable(struct intel_encoder *encoder)
+static void intel_dsi_post_disable(struct intel_encoder *encoder,
+                                  struct intel_crtc_state *pipe_config,
+                                  struct drm_connector_state *conn_state)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
@@ -819,6 +827,7 @@ static void bxt_dsi_get_pipe_config(struct intel_encoder *encoder,
        u16 crtc_htotal_sw, crtc_hsync_start_sw, crtc_hsync_end_sw,
                                crtc_hblank_start_sw, crtc_hblank_end_sw;
 
+       /* FIXME: hw readout should not depend on SW state */
        intel_crtc = to_intel_crtc(encoder->base.crtc);
        adjusted_mode_sw = &intel_crtc->config->base.adjusted_mode;
 
@@ -1104,14 +1113,15 @@ static u32 pixel_format_to_reg(enum mipi_dsi_pixel_format fmt)
        }
 }
 
-static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
+static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
+                             struct intel_crtc_state *pipe_config)
 {
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
-       const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        enum port port;
        unsigned int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
        u32 val, tmp;
@@ -1348,7 +1358,7 @@ static int intel_dsi_set_property(struct drm_connector *connector,
                intel_connector->panel.fitting_mode = val;
        }
 
-       crtc = intel_attached_encoder(connector)->base.crtc;
+       crtc = connector->state->crtc;
        if (crtc && crtc->state->enable) {
                /*
                 * If the CRTC is enabled, the display will be changed
index b9e5a63..2e452c5 100644 (file)
@@ -174,7 +174,9 @@ static void intel_dvo_get_config(struct intel_encoder *encoder,
        pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
 }
 
-static void intel_disable_dvo(struct intel_encoder *encoder)
+static void intel_disable_dvo(struct intel_encoder *encoder,
+                             struct intel_crtc_state *old_crtc_state,
+                             struct drm_connector_state *old_conn_state)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
@@ -186,17 +188,18 @@ static void intel_disable_dvo(struct intel_encoder *encoder)
        I915_READ(dvo_reg);
 }
 
-static void intel_enable_dvo(struct intel_encoder *encoder)
+static void intel_enable_dvo(struct intel_encoder *encoder,
+                            struct intel_crtc_state *pipe_config,
+                            struct drm_connector_state *conn_state)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
        i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
        u32 temp = I915_READ(dvo_reg);
 
        intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
-                                        &crtc->config->base.mode,
-                                        &crtc->config->base.adjusted_mode);
+                                        &pipe_config->base.mode,
+                                        &pipe_config->base.adjusted_mode);
 
        I915_WRITE(dvo_reg, temp | DVO_ENABLE);
        I915_READ(dvo_reg);
@@ -235,7 +238,8 @@ intel_dvo_mode_valid(struct drm_connector *connector,
 }
 
 static bool intel_dvo_compute_config(struct intel_encoder *encoder,
-                                    struct intel_crtc_state *pipe_config)
+                                    struct intel_crtc_state *pipe_config,
+                                    struct drm_connector_state *conn_state)
 {
        struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
        const struct drm_display_mode *fixed_mode =
@@ -253,12 +257,13 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
        return true;
 }
 
-static void intel_dvo_pre_enable(struct intel_encoder *encoder)
+static void intel_dvo_pre_enable(struct intel_encoder *encoder,
+                                struct intel_crtc_state *pipe_config,
+                                struct drm_connector_state *conn_state)
 {
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
        int pipe = crtc->pipe;
        u32 dvo_val;
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
new file mode 100644 (file)
index 0000000..025e232
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Copyright © 2016 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 "i915_drv.h"
+#include "intel_ringbuffer.h"
+#include "intel_lrc.h"
+
+static const struct engine_info {
+       const char *name;
+       unsigned exec_id;
+       enum intel_engine_hw_id hw_id;
+       u32 mmio_base;
+       unsigned irq_shift;
+       int (*init_legacy)(struct intel_engine_cs *engine);
+       int (*init_execlists)(struct intel_engine_cs *engine);
+} intel_engines[] = {
+       [RCS] = {
+               .name = "render ring",
+               .exec_id = I915_EXEC_RENDER,
+               .hw_id = RCS_HW,
+               .mmio_base = RENDER_RING_BASE,
+               .irq_shift = GEN8_RCS_IRQ_SHIFT,
+               .init_execlists = logical_render_ring_init,
+               .init_legacy = intel_init_render_ring_buffer,
+       },
+       [BCS] = {
+               .name = "blitter ring",
+               .exec_id = I915_EXEC_BLT,
+               .hw_id = BCS_HW,
+               .mmio_base = BLT_RING_BASE,
+               .irq_shift = GEN8_BCS_IRQ_SHIFT,
+               .init_execlists = logical_xcs_ring_init,
+               .init_legacy = intel_init_blt_ring_buffer,
+       },
+       [VCS] = {
+               .name = "bsd ring",
+               .exec_id = I915_EXEC_BSD,
+               .hw_id = VCS_HW,
+               .mmio_base = GEN6_BSD_RING_BASE,
+               .irq_shift = GEN8_VCS1_IRQ_SHIFT,
+               .init_execlists = logical_xcs_ring_init,
+               .init_legacy = intel_init_bsd_ring_buffer,
+       },
+       [VCS2] = {
+               .name = "bsd2 ring",
+               .exec_id = I915_EXEC_BSD,
+               .hw_id = VCS2_HW,
+               .mmio_base = GEN8_BSD2_RING_BASE,
+               .irq_shift = GEN8_VCS2_IRQ_SHIFT,
+               .init_execlists = logical_xcs_ring_init,
+               .init_legacy = intel_init_bsd2_ring_buffer,
+       },
+       [VECS] = {
+               .name = "video enhancement ring",
+               .exec_id = I915_EXEC_VEBOX,
+               .hw_id = VECS_HW,
+               .mmio_base = VEBOX_RING_BASE,
+               .irq_shift = GEN8_VECS_IRQ_SHIFT,
+               .init_execlists = logical_xcs_ring_init,
+               .init_legacy = intel_init_vebox_ring_buffer,
+       },
+};
+
+static struct intel_engine_cs *
+intel_engine_setup(struct drm_i915_private *dev_priv,
+                  enum intel_engine_id id)
+{
+       const struct engine_info *info = &intel_engines[id];
+       struct intel_engine_cs *engine = &dev_priv->engine[id];
+
+       engine->id = id;
+       engine->i915 = dev_priv;
+       engine->name = info->name;
+       engine->exec_id = info->exec_id;
+       engine->hw_id = engine->guc_id = info->hw_id;
+       engine->mmio_base = info->mmio_base;
+       engine->irq_shift = info->irq_shift;
+
+       return engine;
+}
+
+/**
+ * intel_engines_init() - allocate, populate and init the Engine Command Streamers
+ * @dev: DRM device.
+ *
+ * Return: non-zero if the initialization failed.
+ */
+int intel_engines_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_device_info *device_info = mkwrite_device_info(dev_priv);
+       unsigned int mask = 0;
+       int (*init)(struct intel_engine_cs *engine);
+       unsigned int i;
+       int ret;
+
+       WARN_ON(INTEL_INFO(dev_priv)->ring_mask == 0);
+       WARN_ON(INTEL_INFO(dev_priv)->ring_mask &
+               GENMASK(sizeof(mask) * BITS_PER_BYTE - 1, I915_NUM_ENGINES));
+
+       for (i = 0; i < ARRAY_SIZE(intel_engines); i++) {
+               if (!HAS_ENGINE(dev_priv, i))
+                       continue;
+
+               if (i915.enable_execlists)
+                       init = intel_engines[i].init_execlists;
+               else
+                       init = intel_engines[i].init_legacy;
+
+               if (!init)
+                       continue;
+
+               ret = init(intel_engine_setup(dev_priv, i));
+               if (ret)
+                       goto cleanup;
+
+               mask |= ENGINE_MASK(i);
+       }
+
+       /*
+        * Catch failures to update intel_engines table when the new engines
+        * are added to the driver by a warning and disabling the forgotten
+        * engines.
+        */
+       if (WARN_ON(mask != INTEL_INFO(dev_priv)->ring_mask))
+               device_info->ring_mask = mask;
+
+       device_info->num_rings = hweight32(mask);
+
+       return 0;
+
+cleanup:
+       for (i = 0; i < I915_NUM_ENGINES; i++) {
+               if (i915.enable_execlists)
+                       intel_logical_ring_cleanup(&dev_priv->engine[i]);
+               else
+                       intel_engine_cleanup(&dev_priv->engine[i]);
+       }
+
+       return ret;
+}
+
+void intel_engine_init_seqno(struct intel_engine_cs *engine, u32 seqno)
+{
+       struct drm_i915_private *dev_priv = engine->i915;
+
+       /* Our semaphore implementation is strictly monotonic (i.e. we proceed
+        * so long as the semaphore value in the register/page is greater
+        * than the sync value), so whenever we reset the seqno,
+        * so long as we reset the tracking semaphore value to 0, it will
+        * always be before the next request's seqno. If we don't reset
+        * the semaphore value, then when the seqno moves backwards all
+        * future waits will complete instantly (causing rendering corruption).
+        */
+       if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) {
+               I915_WRITE(RING_SYNC_0(engine->mmio_base), 0);
+               I915_WRITE(RING_SYNC_1(engine->mmio_base), 0);
+               if (HAS_VEBOX(dev_priv))
+                       I915_WRITE(RING_SYNC_2(engine->mmio_base), 0);
+       }
+       if (dev_priv->semaphore) {
+               struct page *page = i915_vma_first_page(dev_priv->semaphore);
+               void *semaphores;
+
+               /* Semaphores are in noncoherent memory, flush to be safe */
+               semaphores = kmap(page);
+               memset(semaphores + GEN8_SEMAPHORE_OFFSET(engine->id, 0),
+                      0, I915_NUM_ENGINES * gen8_semaphore_seqno_size);
+               drm_clflush_virt_range(semaphores + GEN8_SEMAPHORE_OFFSET(engine->id, 0),
+                                      I915_NUM_ENGINES * gen8_semaphore_seqno_size);
+               kunmap(page);
+       }
+       memset(engine->semaphore.sync_seqno, 0,
+              sizeof(engine->semaphore.sync_seqno));
+
+       intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno);
+       if (engine->irq_seqno_barrier)
+               engine->irq_seqno_barrier(engine);
+       engine->last_submitted_seqno = seqno;
+
+       engine->hangcheck.seqno = seqno;
+
+       /* After manually advancing the seqno, fake the interrupt in case
+        * there are any waiters for that seqno.
+        */
+       intel_engine_wakeup(engine);
+}
+
+void intel_engine_init_hangcheck(struct intel_engine_cs *engine)
+{
+       memset(&engine->hangcheck, 0, sizeof(engine->hangcheck));
+}
+
+static void intel_engine_init_requests(struct intel_engine_cs *engine)
+{
+       init_request_active(&engine->last_request, NULL);
+       INIT_LIST_HEAD(&engine->request_list);
+}
+
+/**
+ * intel_engines_setup_common - setup engine state not requiring hw access
+ * @engine: Engine to setup.
+ *
+ * Initializes @engine@ structure members shared between legacy and execlists
+ * submission modes which do not require hardware access.
+ *
+ * Typically done early in the submission mode specific engine setup stage.
+ */
+void intel_engine_setup_common(struct intel_engine_cs *engine)
+{
+       INIT_LIST_HEAD(&engine->execlist_queue);
+       spin_lock_init(&engine->execlist_lock);
+
+       engine->fence_context = fence_context_alloc(1);
+
+       intel_engine_init_requests(engine);
+       intel_engine_init_hangcheck(engine);
+       i915_gem_batch_pool_init(engine, &engine->batch_pool);
+
+       intel_engine_init_cmd_parser(engine);
+}
+
+int intel_engine_create_scratch(struct intel_engine_cs *engine, int size)
+{
+       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
+       int ret;
+
+       WARN_ON(engine->scratch);
+
+       obj = i915_gem_object_create_stolen(&engine->i915->drm, size);
+       if (!obj)
+               obj = i915_gem_object_create(&engine->i915->drm, size);
+       if (IS_ERR(obj)) {
+               DRM_ERROR("Failed to allocate scratch page\n");
+               return PTR_ERR(obj);
+       }
+
+       vma = i915_vma_create(obj, &engine->i915->ggtt.base, NULL);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
+               goto err_unref;
+       }
+
+       ret = i915_vma_pin(vma, 0, 4096, PIN_GLOBAL | PIN_HIGH);
+       if (ret)
+               goto err_unref;
+
+       engine->scratch = vma;
+       DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
+                        engine->name, i915_ggtt_offset(vma));
+       return 0;
+
+err_unref:
+       i915_gem_object_put(obj);
+       return ret;
+}
+
+static void intel_engine_cleanup_scratch(struct intel_engine_cs *engine)
+{
+       i915_vma_unpin_and_release(&engine->scratch);
+}
+
+/**
+ * intel_engines_init_common - initialize cengine state which might require hw access
+ * @engine: Engine to initialize.
+ *
+ * Initializes @engine@ structure members shared between legacy and execlists
+ * submission modes which do require hardware access.
+ *
+ * Typcally done at later stages of submission mode specific engine setup.
+ *
+ * Returns zero on success or an error code on failure.
+ */
+int intel_engine_init_common(struct intel_engine_cs *engine)
+{
+       int ret;
+
+       ret = intel_engine_init_breadcrumbs(engine);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+/**
+ * intel_engines_cleanup_common - cleans up the engine state created by
+ *                                the common initiailizers.
+ * @engine: Engine to cleanup.
+ *
+ * This cleans up everything created by the common helpers.
+ */
+void intel_engine_cleanup_common(struct intel_engine_cs *engine)
+{
+       intel_engine_cleanup_scratch(engine);
+
+       intel_engine_fini_breadcrumbs(engine);
+       intel_engine_cleanup_cmd_parser(engine);
+       i915_gem_batch_pool_fini(&engine->batch_pool);
+}
index 3836a1c..faa6762 100644 (file)
@@ -190,9 +190,13 @@ static void g4x_fbc_activate(struct drm_i915_private *dev_priv)
                dpfc_ctl |= DPFC_CTL_LIMIT_2X;
        else
                dpfc_ctl |= DPFC_CTL_LIMIT_1X;
-       dpfc_ctl |= DPFC_CTL_FENCE_EN | params->fb.fence_reg;
 
-       I915_WRITE(DPFC_FENCE_YOFF, params->crtc.fence_y_offset);
+       if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
+               dpfc_ctl |= DPFC_CTL_FENCE_EN | params->fb.fence_reg;
+               I915_WRITE(DPFC_FENCE_YOFF, params->crtc.fence_y_offset);
+       } else {
+               I915_WRITE(DPFC_FENCE_YOFF, 0);
+       }
 
        /* enable it... */
        I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
@@ -244,21 +248,29 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv)
                dpfc_ctl |= DPFC_CTL_LIMIT_1X;
                break;
        }
-       dpfc_ctl |= DPFC_CTL_FENCE_EN;
-       if (IS_GEN5(dev_priv))
-               dpfc_ctl |= params->fb.fence_reg;
+
+       if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
+               dpfc_ctl |= DPFC_CTL_FENCE_EN;
+               if (IS_GEN5(dev_priv))
+                       dpfc_ctl |= params->fb.fence_reg;
+               if (IS_GEN6(dev_priv)) {
+                       I915_WRITE(SNB_DPFC_CTL_SA,
+                                  SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
+                       I915_WRITE(DPFC_CPU_FENCE_OFFSET,
+                                  params->crtc.fence_y_offset);
+               }
+       } else {
+               if (IS_GEN6(dev_priv)) {
+                       I915_WRITE(SNB_DPFC_CTL_SA, 0);
+                       I915_WRITE(DPFC_CPU_FENCE_OFFSET, 0);
+               }
+       }
 
        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);
        /* enable it... */
        I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
-       if (IS_GEN6(dev_priv)) {
-               I915_WRITE(SNB_DPFC_CTL_SA,
-                          SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
-               I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset);
-       }
-
        intel_fbc_recompress(dev_priv);
 }
 
@@ -305,7 +317,15 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv)
                break;
        }
 
-       dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
+       if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
+               dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
+               I915_WRITE(SNB_DPFC_CTL_SA,
+                          SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
+               I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset);
+       } else {
+               I915_WRITE(SNB_DPFC_CTL_SA,0);
+               I915_WRITE(DPFC_CPU_FENCE_OFFSET, 0);
+       }
 
        if (dev_priv->fbc.false_color)
                dpfc_ctl |= FBC_CTL_FALSE_COLOR;
@@ -324,10 +344,6 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv)
 
        I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
-       I915_WRITE(SNB_DPFC_CTL_SA,
-                  SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
-       I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset);
-
        intel_fbc_recompress(dev_priv);
 }
 
@@ -494,7 +510,7 @@ static bool multiple_pipes_ok(struct intel_crtc *crtc,
        if (!no_fbc_on_multiple_pipes(dev_priv))
                return true;
 
-       if (plane_state->visible)
+       if (plane_state->base.visible)
                fbc->visible_pipes_mask |= (1 << pipe);
        else
                fbc->visible_pipes_mask &= ~(1 << pipe);
@@ -709,6 +725,14 @@ 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)
@@ -725,9 +749,9 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
                        ilk_pipe_pixel_rate(crtc_state);
 
        cache->plane.rotation = plane_state->base.rotation;
-       cache->plane.src_w = drm_rect_width(&plane_state->src) >> 16;
-       cache->plane.src_h = drm_rect_height(&plane_state->src) >> 16;
-       cache->plane.visible = plane_state->visible;
+       cache->plane.src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       cache->plane.src_h = drm_rect_height(&plane_state->base.src) >> 16;
+       cache->plane.visible = plane_state->base.visible;
 
        if (!cache->plane.visible)
                return;
@@ -737,11 +761,11 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
        /* 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_obj_ggtt_offset(obj);
+               cache->fb.ilk_ggtt_offset = i915_gem_object_ggtt_offset(obj, NULL);
        cache->fb.pixel_format = fb->pixel_format;
        cache->fb.stride = fb->pitches[0];
-       cache->fb.fence_reg = obj->fence_reg;
-       cache->fb.tiling_mode = obj->tiling_mode;
+       cache->fb.fence_reg = get_fence_id(fb);
+       cache->fb.tiling_mode = i915_gem_object_get_tiling(obj);
 }
 
 static bool intel_fbc_can_activate(struct intel_crtc *crtc)
@@ -768,6 +792,10 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
 
        /* The use of a CPU fence is mandatory in order to detect writes
         * by the CPU to the scanout and trigger updates to the FBC.
+        *
+        * Note that is possible for a tiled surface to be unmappable (and
+        * 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) {
@@ -775,7 +803,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
                return false;
        }
        if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) &&
-           cache->plane.rotation != BIT(DRM_ROTATE_0)) {
+           cache->plane.rotation != DRM_ROTATE_0) {
                fbc->no_fbc_reason = "rotation unsupported";
                return false;
        }
@@ -1050,7 +1078,7 @@ void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
                struct intel_plane_state *intel_plane_state =
                        to_intel_plane_state(plane_state);
 
-               if (!intel_plane_state->visible)
+               if (!intel_plane_state->base.visible)
                        continue;
 
                for_each_crtc_in_state(state, crtc, crtc_state, j) {
@@ -1075,6 +1103,8 @@ out:
 /**
  * intel_fbc_enable: tries to enable FBC on the CRTC
  * @crtc: the CRTC
+ * @crtc_state: corresponding &drm_crtc_state for @crtc
+ * @plane_state: corresponding &drm_plane_state for the primary plane of @crtc
  *
  * This function checks if the given CRTC was chosen for FBC, then enables it if
  * possible. Notice that it doesn't activate FBC. It is valid to call
@@ -1163,11 +1193,8 @@ void intel_fbc_disable(struct intel_crtc *crtc)
                return;
 
        mutex_lock(&fbc->lock);
-       if (fbc->crtc == crtc) {
-               WARN_ON(!fbc->enabled);
-               WARN_ON(fbc->active);
+       if (fbc->crtc == crtc)
                __intel_fbc_disable(dev_priv);
-       }
        mutex_unlock(&fbc->lock);
 
        cancel_work_sync(&fbc->work.work);
@@ -1212,7 +1239,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->base) &&
-                   to_intel_plane_state(crtc->base.primary->state)->visible)
+                   to_intel_plane_state(crtc->base.primary->state)->base.visible)
                        dev_priv->fbc.visible_pipes_mask |= (1 << crtc->pipe);
 }
 
index 3e3632c..b7098f9 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/tty.h>
 #include <linux/sysrq.h>
 #include <linux/delay.h>
-#include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/vga_switcheroo.h>
 
@@ -42,6 +41,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_fb_helper.h>
 #include "intel_drv.h"
+#include "intel_frontbuffer.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
@@ -159,7 +159,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
 
        fb = __intel_framebuffer_create(dev, &mode_cmd, obj);
        if (IS_ERR(fb)) {
-               drm_gem_object_unreference(&obj->base);
+               i915_gem_object_put(obj);
                ret = PTR_ERR(fb);
                goto out;
        }
@@ -183,13 +183,13 @@ static int intelfb_create(struct drm_fb_helper *helper,
        struct intel_framebuffer *intel_fb = ifbdev->fb;
        struct drm_device *dev = helper->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
        struct fb_info *info;
        struct drm_framebuffer *fb;
        struct i915_vma *vma;
-       struct drm_i915_gem_object *obj;
        bool prealloc = false;
-       void *vaddr;
+       void __iomem *vaddr;
        int ret;
 
        if (intel_fb &&
@@ -215,17 +215,17 @@ static int intelfb_create(struct drm_fb_helper *helper,
                sizes->fb_height = intel_fb->base.height;
        }
 
-       obj = intel_fb->obj;
-
        mutex_lock(&dev->struct_mutex);
 
        /* Pin the GGTT vma for our access via info->screen_base.
         * This also validates that any existing fb inherited from the
         * BIOS is suitable for own access.
         */
-       ret = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, BIT(DRM_ROTATE_0));
-       if (ret)
+       vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
                goto out_unlock;
+       }
 
        info = drm_fb_helper_alloc_fbi(helper);
        if (IS_ERR(info)) {
@@ -245,13 +245,11 @@ static int intelfb_create(struct drm_fb_helper *helper,
        info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
        info->fbops = &intelfb_ops;
 
-       vma = i915_gem_obj_to_ggtt(obj);
-
        /* setup aperture base/size for vesafb takeover */
        info->apertures->ranges[0].base = dev->mode_config.fb_base;
        info->apertures->ranges[0].size = ggtt->mappable_end;
 
-       info->fix.smem_start = dev->mode_config.fb_base + vma->node.start;
+       info->fix.smem_start = dev->mode_config.fb_base + i915_ggtt_offset(vma);
        info->fix.smem_len = vma->node.size;
 
        vaddr = i915_vma_pin_iomap(vma);
@@ -273,23 +271,23 @@ static int intelfb_create(struct drm_fb_helper *helper,
         * If the object is stolen however, it will be full of whatever
         * garbage was left in there.
         */
-       if (ifbdev->fb->obj->stolen && !prealloc)
+       if (intel_fb->obj->stolen && !prealloc)
                memset_io(info->screen_base, 0, info->screen_size);
 
        /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
 
-       DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08llx, bo %p\n",
-                     fb->width, fb->height,
-                     i915_gem_obj_ggtt_offset(obj), obj);
+       DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x\n",
+                     fb->width, fb->height, i915_ggtt_offset(vma));
+       ifbdev->vma = vma;
 
        mutex_unlock(&dev->struct_mutex);
-       vga_switcheroo_client_fb_set(dev->pdev, info);
+       vga_switcheroo_client_fb_set(pdev, info);
        return 0;
 
 out_destroy_fbi:
        drm_fb_helper_release_fbi(helper);
 out_unpin:
-       intel_unpin_fb_obj(&ifbdev->fb->base, BIT(DRM_ROTATE_0));
+       intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0);
 out_unlock:
        mutex_unlock(&dev->struct_mutex);
        return ret;
@@ -554,7 +552,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, BIT(DRM_ROTATE_0));
+               intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0);
                mutex_unlock(&ifbdev->helper.dev->struct_mutex);
 
                drm_framebuffer_remove(&ifbdev->fb->base);
@@ -768,7 +766,7 @@ void intel_fbdev_fini(struct drm_device *dev)
        if (!ifbdev)
                return;
 
-       flush_work(&dev_priv->fbdev_suspend_work);
+       cancel_work_sync(&dev_priv->fbdev_suspend_work);
        if (!current_is_async())
                intel_fbdev_sync(ifbdev);
 
index ac85357..966de4c 100644 (file)
 #include <drm/drmP.h>
 
 #include "intel_drv.h"
+#include "intel_frontbuffer.h"
 #include "i915_drv.h"
 
-/**
- * intel_fb_obj_invalidate - invalidate frontbuffer object
- * @obj: GEM object to invalidate
- * @origin: which operation caused the invalidation
- *
- * This function gets called every time rendering on the given object starts and
- * frontbuffer caching (fbc, low refresh rate for DRRS, panel self refresh) must
- * be invalidated. For ORIGIN_CS any subsequent invalidation will be delayed
- * until the rendering completes or a flip on this frontbuffer plane is
- * scheduled.
- */
-void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
-                            enum fb_op_origin origin)
+void __intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
+                              enum fb_op_origin origin,
+                              unsigned int frontbuffer_bits)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
-       if (!obj->frontbuffer_bits)
-               return;
+       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
 
        if (origin == ORIGIN_CS) {
-               mutex_lock(&dev_priv->fb_tracking.lock);
-               dev_priv->fb_tracking.busy_bits
-                       |= obj->frontbuffer_bits;
-               dev_priv->fb_tracking.flip_bits
-                       &= ~obj->frontbuffer_bits;
-               mutex_unlock(&dev_priv->fb_tracking.lock);
+               spin_lock(&dev_priv->fb_tracking.lock);
+               dev_priv->fb_tracking.busy_bits |= frontbuffer_bits;
+               dev_priv->fb_tracking.flip_bits &= ~frontbuffer_bits;
+               spin_unlock(&dev_priv->fb_tracking.lock);
        }
 
-       intel_psr_invalidate(dev, obj->frontbuffer_bits);
-       intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits);
-       intel_fbc_invalidate(dev_priv, obj->frontbuffer_bits, origin);
+       intel_psr_invalidate(dev_priv, frontbuffer_bits);
+       intel_edp_drrs_invalidate(dev_priv, frontbuffer_bits);
+       intel_fbc_invalidate(dev_priv, frontbuffer_bits, origin);
 }
 
 /**
  * intel_frontbuffer_flush - flush frontbuffer
- * @dev: DRM device
+ * @dev_priv: i915 device
  * @frontbuffer_bits: frontbuffer plane tracking bits
  * @origin: which operation caused the flush
  *
@@ -113,64 +96,45 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
  *
  * Can be called without any locks held.
  */
-static void intel_frontbuffer_flush(struct drm_device *dev,
+static void intel_frontbuffer_flush(struct drm_i915_private *dev_priv,
                                    unsigned frontbuffer_bits,
                                    enum fb_op_origin origin)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        /* Delay flushing when rings are still busy.*/
-       mutex_lock(&dev_priv->fb_tracking.lock);
+       spin_lock(&dev_priv->fb_tracking.lock);
        frontbuffer_bits &= ~dev_priv->fb_tracking.busy_bits;
-       mutex_unlock(&dev_priv->fb_tracking.lock);
+       spin_unlock(&dev_priv->fb_tracking.lock);
 
        if (!frontbuffer_bits)
                return;
 
-       intel_edp_drrs_flush(dev, frontbuffer_bits);
-       intel_psr_flush(dev, frontbuffer_bits, origin);
+       intel_edp_drrs_flush(dev_priv, frontbuffer_bits);
+       intel_psr_flush(dev_priv, frontbuffer_bits, origin);
        intel_fbc_flush(dev_priv, frontbuffer_bits, origin);
 }
 
-/**
- * intel_fb_obj_flush - flush frontbuffer object
- * @obj: GEM object to flush
- * @retire: set when retiring asynchronous rendering
- * @origin: which operation caused the flush
- *
- * This function gets called every time rendering on the given object has
- * completed and frontbuffer caching can be started again. If @retire is true
- * then any delayed flushes will be unblocked.
- */
-void intel_fb_obj_flush(struct drm_i915_gem_object *obj,
-                       bool retire, enum fb_op_origin origin)
+void __intel_fb_obj_flush(struct drm_i915_gem_object *obj,
+                         bool retire,
+                         enum fb_op_origin origin,
+                         unsigned int frontbuffer_bits)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       unsigned frontbuffer_bits;
-
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
-       if (!obj->frontbuffer_bits)
-               return;
-
-       frontbuffer_bits = obj->frontbuffer_bits;
+       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
 
        if (retire) {
-               mutex_lock(&dev_priv->fb_tracking.lock);
+               spin_lock(&dev_priv->fb_tracking.lock);
                /* Filter out new bits since rendering started. */
                frontbuffer_bits &= dev_priv->fb_tracking.busy_bits;
-
                dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits;
-               mutex_unlock(&dev_priv->fb_tracking.lock);
+               spin_unlock(&dev_priv->fb_tracking.lock);
        }
 
-       intel_frontbuffer_flush(dev, frontbuffer_bits, origin);
+       if (frontbuffer_bits)
+               intel_frontbuffer_flush(dev_priv, frontbuffer_bits, origin);
 }
 
 /**
  * intel_frontbuffer_flip_prepare - prepare asynchronous frontbuffer flip
- * @dev: DRM device
+ * @dev_priv: i915 device
  * @frontbuffer_bits: frontbuffer plane tracking bits
  *
  * This function gets called after scheduling a flip on @obj. The actual
@@ -180,23 +144,21 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj,
  *
  * Can be called without any locks held.
  */
-void intel_frontbuffer_flip_prepare(struct drm_device *dev,
+void intel_frontbuffer_flip_prepare(struct drm_i915_private *dev_priv,
                                    unsigned frontbuffer_bits)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       mutex_lock(&dev_priv->fb_tracking.lock);
+       spin_lock(&dev_priv->fb_tracking.lock);
        dev_priv->fb_tracking.flip_bits |= frontbuffer_bits;
        /* Remove stale busy bits due to the old buffer. */
        dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits;
-       mutex_unlock(&dev_priv->fb_tracking.lock);
+       spin_unlock(&dev_priv->fb_tracking.lock);
 
-       intel_psr_single_frame_update(dev, frontbuffer_bits);
+       intel_psr_single_frame_update(dev_priv, frontbuffer_bits);
 }
 
 /**
  * intel_frontbuffer_flip_complete - complete asynchronous frontbuffer flip
- * @dev: DRM device
+ * @dev_priv: i915 device
  * @frontbuffer_bits: frontbuffer plane tracking bits
  *
  * This function gets called after the flip has been latched and will complete
@@ -204,23 +166,23 @@ void intel_frontbuffer_flip_prepare(struct drm_device *dev,
  *
  * Can be called without any locks held.
  */
-void intel_frontbuffer_flip_complete(struct drm_device *dev,
+void intel_frontbuffer_flip_complete(struct drm_i915_private *dev_priv,
                                     unsigned frontbuffer_bits)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       mutex_lock(&dev_priv->fb_tracking.lock);
+       spin_lock(&dev_priv->fb_tracking.lock);
        /* Mask any cancelled flips. */
        frontbuffer_bits &= dev_priv->fb_tracking.flip_bits;
        dev_priv->fb_tracking.flip_bits &= ~frontbuffer_bits;
-       mutex_unlock(&dev_priv->fb_tracking.lock);
+       spin_unlock(&dev_priv->fb_tracking.lock);
 
-       intel_frontbuffer_flush(dev, frontbuffer_bits, ORIGIN_FLIP);
+       if (frontbuffer_bits)
+               intel_frontbuffer_flush(dev_priv,
+                                       frontbuffer_bits, ORIGIN_FLIP);
 }
 
 /**
  * intel_frontbuffer_flip - synchronous frontbuffer flip
- * @dev: DRM device
+ * @dev_priv: i915 device
  * @frontbuffer_bits: frontbuffer plane tracking bits
  *
  * This function gets called after scheduling a flip on @obj. This is for
@@ -229,15 +191,13 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev,
  *
  * Can be called without any locks held.
  */
-void intel_frontbuffer_flip(struct drm_device *dev,
+void intel_frontbuffer_flip(struct drm_i915_private *dev_priv,
                            unsigned frontbuffer_bits)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       mutex_lock(&dev_priv->fb_tracking.lock);
+       spin_lock(&dev_priv->fb_tracking.lock);
        /* Remove stale busy bits due to the old buffer. */
        dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits;
-       mutex_unlock(&dev_priv->fb_tracking.lock);
+       spin_unlock(&dev_priv->fb_tracking.lock);
 
-       intel_frontbuffer_flush(dev, frontbuffer_bits, ORIGIN_FLIP);
+       intel_frontbuffer_flush(dev_priv, frontbuffer_bits, ORIGIN_FLIP);
 }
diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.h b/drivers/gpu/drm/i915/intel_frontbuffer.h
new file mode 100644 (file)
index 0000000..76ceb53
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014-2016 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.
+ */
+
+#ifndef __INTEL_FRONTBUFFER_H__
+#define __INTEL_FRONTBUFFER_H__
+
+struct drm_i915_private;
+struct drm_i915_gem_object;
+
+void intel_frontbuffer_flip_prepare(struct drm_i915_private *dev_priv,
+                                   unsigned frontbuffer_bits);
+void intel_frontbuffer_flip_complete(struct drm_i915_private *dev_priv,
+                                    unsigned frontbuffer_bits);
+void intel_frontbuffer_flip(struct drm_i915_private *dev_priv,
+                           unsigned frontbuffer_bits);
+
+void __intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
+                              enum fb_op_origin origin,
+                              unsigned int frontbuffer_bits);
+void __intel_fb_obj_flush(struct drm_i915_gem_object *obj,
+                         bool retire,
+                         enum fb_op_origin origin,
+                         unsigned int frontbuffer_bits);
+
+/**
+ * intel_fb_obj_invalidate - invalidate frontbuffer object
+ * @obj: GEM object to invalidate
+ * @origin: which operation caused the invalidation
+ *
+ * This function gets called every time rendering on the given object starts and
+ * frontbuffer caching (fbc, low refresh rate for DRRS, panel self refresh) must
+ * be invalidated. For ORIGIN_CS any subsequent invalidation will be delayed
+ * until the rendering completes or a flip on this frontbuffer plane is
+ * scheduled.
+ */
+static inline void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
+                                          enum fb_op_origin origin)
+{
+       unsigned int frontbuffer_bits;
+
+       frontbuffer_bits = atomic_read(&obj->frontbuffer_bits);
+       if (!frontbuffer_bits)
+               return;
+
+       __intel_fb_obj_invalidate(obj, origin, frontbuffer_bits);
+}
+
+/**
+ * intel_fb_obj_flush - flush frontbuffer object
+ * @obj: GEM object to flush
+ * @retire: set when retiring asynchronous rendering
+ * @origin: which operation caused the flush
+ *
+ * This function gets called every time rendering on the given object has
+ * completed and frontbuffer caching can be started again. If @retire is true
+ * then any delayed flushes will be unblocked.
+ */
+static inline void intel_fb_obj_flush(struct drm_i915_gem_object *obj,
+                                     bool retire,
+                                     enum fb_op_origin origin)
+{
+       unsigned int frontbuffer_bits;
+
+       frontbuffer_bits = atomic_read(&obj->frontbuffer_bits);
+       if (!frontbuffer_bits)
+               return;
+
+       __intel_fb_obj_flush(obj, retire, origin, frontbuffer_bits);
+}
+
+#endif /* __INTEL_FRONTBUFFER_H__ */
index 3e3e743..5cdf7aa 100644 (file)
@@ -63,26 +63,27 @@ struct drm_i915_gem_request;
  *   retcode: errno from last guc_submit()
  */
 struct i915_guc_client {
-       struct drm_i915_gem_object *client_obj;
+       struct i915_vma *vma;
        void *client_base;              /* first page (only) of above   */
        struct i915_gem_context *owner;
        struct intel_guc *guc;
+
+       uint32_t engines;               /* bitmap of (host) engine ids  */
        uint32_t priority;
        uint32_t ctx_index;
-
        uint32_t proc_desc_offset;
+
        uint32_t doorbell_offset;
        uint32_t cookie;
        uint16_t doorbell_id;
-       uint16_t padding;               /* Maintain alignment           */
+       uint16_t padding[3];            /* Maintain alignment           */
 
+       spinlock_t wq_lock;
        uint32_t wq_offset;
        uint32_t wq_size;
        uint32_t wq_tail;
-       uint32_t unused;                /* Was 'wq_head'                */
-
+       uint32_t wq_rsvd;
        uint32_t no_wq_space;
-       uint32_t q_fail;                /* No longer used               */
        uint32_t b_fail;
        int retcode;
 
@@ -125,11 +126,10 @@ struct intel_guc_fw {
 struct intel_guc {
        struct intel_guc_fw guc_fw;
        uint32_t log_flags;
-       struct drm_i915_gem_object *log_obj;
-
-       struct drm_i915_gem_object *ads_obj;
+       struct i915_vma *log_vma;
 
-       struct drm_i915_gem_object *ctx_pool_obj;
+       struct i915_vma *ads_vma;
+       struct i915_vma *ctx_pool_vma;
        struct ida ctx_ids;
 
        struct i915_guc_client *execbuf_client;
@@ -159,8 +159,8 @@ extern int intel_guc_resume(struct drm_device *dev);
 /* i915_guc_submission.c */
 int i915_guc_submission_init(struct drm_i915_private *dev_priv);
 int i915_guc_submission_enable(struct drm_i915_private *dev_priv);
-int i915_guc_wq_check_space(struct drm_i915_gem_request *rq);
-int i915_guc_submit(struct drm_i915_gem_request *rq);
+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);
 
index 944786d..e40db2d 100644 (file)
  *
  *     +-------------------------------+
  *     |        guc_css_header         |
+ *     |                               |
  *     | contains major/minor version  |
  *     +-------------------------------+
  *     |             uCode             |
  *
  * 1. Header, uCode and RSA are must-have components.
  * 2. All firmware components, if they present, are in the sequence illustrated
- * in the layout table above.
+ *    in the layout table above.
  * 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.
+ *    in fw. So driver will load a truncated firmware in this case.
  */
 
 struct guc_css_header {
index 605c696..6fd39ef 100644 (file)
  *
  */
 
-#define I915_SKL_GUC_UCODE "i915/skl_guc_ver6_1.bin"
+#define SKL_FW_MAJOR 6
+#define SKL_FW_MINOR 1
+
+#define BXT_FW_MAJOR 8
+#define BXT_FW_MINOR 7
+
+#define KBL_FW_MAJOR 9
+#define KBL_FW_MINOR 14
+
+#define GUC_FW_PATH(platform, major, minor) \
+       "i915/" __stringify(platform) "_guc_ver" __stringify(major) "_" __stringify(minor) ".bin"
+
+#define I915_SKL_GUC_UCODE GUC_FW_PATH(skl, SKL_FW_MAJOR, SKL_FW_MINOR)
 MODULE_FIRMWARE(I915_SKL_GUC_UCODE);
 
-#define I915_BXT_GUC_UCODE "i915/bxt_guc_ver8_7.bin"
+#define I915_BXT_GUC_UCODE GUC_FW_PATH(bxt, BXT_FW_MAJOR, BXT_FW_MINOR)
 MODULE_FIRMWARE(I915_BXT_GUC_UCODE);
 
-#define I915_KBL_GUC_UCODE "i915/kbl_guc_ver9_14.bin"
+#define I915_KBL_GUC_UCODE GUC_FW_PATH(kbl, KBL_FW_MAJOR, KBL_FW_MINOR)
 MODULE_FIRMWARE(I915_KBL_GUC_UCODE);
 
 /* User-friendly representation of an enum */
@@ -85,7 +97,7 @@ const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status)
        }
 };
 
-static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
+static void guc_interrupts_release(struct drm_i915_private *dev_priv)
 {
        struct intel_engine_cs *engine;
        int irqs;
@@ -102,7 +114,7 @@ static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
        I915_WRITE(GUC_WD_VECS_IER, 0);
 }
 
-static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
+static void guc_interrupts_capture(struct drm_i915_private *dev_priv)
 {
        struct intel_engine_cs *engine;
        int irqs;
@@ -122,13 +134,28 @@ static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
        I915_WRITE(GUC_WD_VECS_IER, ~irqs);
 
        /*
-        * If GuC has routed PM interrupts to itself, don't keep it.
-        * and keep other interrupts those are unmasked by GuC.
-       */
+        * The REDIRECT_TO_GUC bit of the PMINTRMSK register directs all
+        * (unmasked) PM interrupts to the GuC. All other bits of this
+        * register *disable* generation of a specific interrupt.
+        *
+        * 'pm_intr_keep' indicates bits that are NOT to be set when
+        * writing to the PM interrupt mask register, i.e. interrupts
+        * that must not be disabled.
+        *
+        * If the GuC is handling these interrupts, then we must not let
+        * the PM code disable ANY interrupt that the GuC is expecting.
+        * So for each ENABLED (0) bit in this register, we must SET the
+        * bit in pm_intr_keep so that it's left enabled for the GuC.
+        *
+        * OTOH the REDIRECT_TO_GUC bit is initially SET in pm_intr_keep
+        * (so interrupts go to the DISPLAY unit at first); but here we
+        * need to CLEAR that bit, which will result in the register bit
+        * being left SET!
+        */
        tmp = I915_READ(GEN6_PMINTRMSK);
-       if (tmp & GEN8_PMINTR_REDIRECT_TO_NON_DISP) {
-               dev_priv->rps.pm_intr_keep |= ~(tmp & ~GEN8_PMINTR_REDIRECT_TO_NON_DISP);
-               dev_priv->rps.pm_intr_keep &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP;
+       if (tmp & GEN8_PMINTR_REDIRECT_TO_GUC) {
+               dev_priv->rps.pm_intr_keep |= ~tmp;
+               dev_priv->rps.pm_intr_keep &= ~GEN8_PMINTR_REDIRECT_TO_GUC;
        }
 }
 
@@ -140,17 +167,24 @@ static u32 get_gttype(struct drm_i915_private *dev_priv)
 
 static u32 get_core_family(struct drm_i915_private *dev_priv)
 {
-       switch (INTEL_INFO(dev_priv)->gen) {
+       u32 gen = INTEL_GEN(dev_priv);
+
+       switch (gen) {
        case 9:
                return GFXCORE_FAMILY_GEN9;
 
        default:
-               DRM_ERROR("GUC: unsupported core family\n");
+               WARN(1, "GEN%d does not support GuC operation!\n", gen);
                return GFXCORE_FAMILY_UNKNOWN;
        }
 }
 
-static void set_guc_init_params(struct drm_i915_private *dev_priv)
+/*
+ * Initialise the GuC parameter block before starting the firmware
+ * transfer. These parameters are read by the firmware on startup
+ * and cannot be changed thereafter.
+ */
+static void guc_params_init(struct drm_i915_private *dev_priv)
 {
        struct intel_guc *guc = &dev_priv->guc;
        u32 params[GUC_CTL_MAX_DWORDS];
@@ -181,16 +215,15 @@ static void set_guc_init_params(struct drm_i915_private *dev_priv)
                        i915.guc_log_level << GUC_LOG_VERBOSITY_SHIFT;
        }
 
-       if (guc->ads_obj) {
-               u32 ads = (u32)i915_gem_obj_ggtt_offset(guc->ads_obj)
-                               >> PAGE_SHIFT;
+       if (guc->ads_vma) {
+               u32 ads = i915_ggtt_offset(guc->ads_vma) >> PAGE_SHIFT;
                params[GUC_CTL_DEBUG] |= ads << GUC_ADS_ADDR_SHIFT;
                params[GUC_CTL_DEBUG] |= GUC_ADS_ENABLED;
        }
 
        /* If GuC submission is enabled, set up additional parameters here */
        if (i915.enable_guc_submission) {
-               u32 pgs = i915_gem_obj_ggtt_offset(dev_priv->guc.ctx_pool_obj);
+               u32 pgs = i915_ggtt_offset(dev_priv->guc.ctx_pool_vma);
                u32 ctx_in_16 = GUC_MAX_GPU_CONTEXTS / 16;
 
                pgs >>= PAGE_SHIFT;
@@ -238,12 +271,12 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
  * Note that GuC needs the CSS header plus uKernel code to be copied by the
  * DMA engine in one operation, whereas the RSA signature is loaded via MMIO.
  */
-static int guc_ucode_xfer_dma(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 drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
        unsigned long offset;
-       struct sg_table *sg = fw_obj->pages;
+       struct sg_table *sg = vma->pages;
        u32 status, rsa[UOS_RSA_SCRATCH_MAX_COUNT];
        int i, ret = 0;
 
@@ -260,7 +293,7 @@ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
        I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size);
 
        /* Set the source address for the new blob */
-       offset = i915_gem_obj_ggtt_offset(fw_obj) + guc_fw->header_offset;
+       offset = i915_ggtt_offset(vma) + guc_fw->header_offset;
        I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
        I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
 
@@ -315,6 +348,7 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
 {
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
        struct drm_device *dev = &dev_priv->drm;
+       struct i915_vma *vma;
        int ret;
 
        ret = i915_gem_object_set_to_gtt_domain(guc_fw->guc_fw_obj, false);
@@ -323,10 +357,10 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
                return ret;
        }
 
-       ret = i915_gem_obj_ggtt_pin(guc_fw->guc_fw_obj, 0, 0);
-       if (ret) {
-               DRM_DEBUG_DRIVER("pin failed %d\n", ret);
-               return ret;
+       vma = i915_gem_object_ggtt_pin(guc_fw->guc_fw_obj, NULL, 0, 0, 0);
+       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. */
@@ -349,7 +383,9 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
        }
 
        /* WaC6DisallowByGfxPause*/
-       I915_WRITE(GEN6_GFXPAUSE, 0x30FFF);
+       if (IS_SKL_REVID(dev, 0, SKL_REVID_C0) ||
+           IS_BXT_REVID(dev, 0, BXT_REVID_B0))
+               I915_WRITE(GEN6_GFXPAUSE, 0x30FFF);
 
        if (IS_BROXTON(dev))
                I915_WRITE(GEN9LP_GT_PM_CONFIG, GT_DOORBELL_ENABLE);
@@ -361,13 +397,13 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
                I915_WRITE(GEN7_MISCCPCTL, (GEN8_DOP_CLOCK_GATE_GUC_ENABLE |
                                            I915_READ(GEN7_MISCCPCTL)));
 
-               /* allows for 5us before GT can go to RC6 */
+               /* allows for 5us (in 10ns units) before GT can go to RC6 */
                I915_WRITE(GUC_ARAT_C6DIS, 0x1FF);
        }
 
-       set_guc_init_params(dev_priv);
+       guc_params_init(dev_priv);
 
-       ret = guc_ucode_xfer_dma(dev_priv);
+       ret = guc_ucode_xfer_dma(dev_priv, vma);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 
@@ -375,12 +411,12 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
         * 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_gem_object_ggtt_unpin(guc_fw->guc_fw_obj);
+       i915_vma_unpin(vma);
 
        return ret;
 }
 
-static int i915_reset_guc(struct drm_i915_private *dev_priv)
+static int guc_hw_reset(struct drm_i915_private *dev_priv)
 {
        int ret;
        u32 guc_status;
@@ -433,7 +469,7 @@ int intel_guc_setup(struct drm_device *dev)
                goto fail;
        } else if (*fw_path == '\0') {
                /* Device has a GuC but we don't know what f/w to load? */
-               DRM_INFO("No GuC firmware known for this platform\n");
+               WARN(1, "No GuC firmware known for this platform!\n");
                err = -ENODEV;
                goto fail;
        }
@@ -447,7 +483,7 @@ int intel_guc_setup(struct drm_device *dev)
                goto fail;
        }
 
-       direct_interrupts_to_host(dev_priv);
+       guc_interrupts_release(dev_priv);
 
        guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
 
@@ -470,11 +506,9 @@ int intel_guc_setup(struct drm_device *dev)
                 * Always reset the GuC just before (re)loading, so
                 * that the state and timing are fairly predictable
                 */
-               err = i915_reset_guc(dev_priv);
-               if (err) {
-                       DRM_ERROR("GuC reset failed: %d\n", err);
+               err = guc_hw_reset(dev_priv);
+               if (err)
                        goto fail;
-               }
 
                err = guc_ucode_xfer(dev_priv);
                if (!err)
@@ -497,7 +531,7 @@ int intel_guc_setup(struct drm_device *dev)
                err = i915_guc_submission_enable(dev_priv);
                if (err)
                        goto fail;
-               direct_interrupts_to_guc(dev_priv);
+               guc_interrupts_capture(dev_priv);
        }
 
        return 0;
@@ -506,7 +540,7 @@ fail:
        if (guc_fw->guc_fw_load_status == GUC_FIRMWARE_PENDING)
                guc_fw->guc_fw_load_status = GUC_FIRMWARE_FAIL;
 
-       direct_interrupts_to_host(dev_priv);
+       guc_interrupts_release(dev_priv);
        i915_guc_submission_disable(dev_priv);
        i915_guc_submission_fini(dev_priv);
 
@@ -532,15 +566,15 @@ fail:
        else if (err == 0)
                DRM_INFO("GuC firmware load skipped\n");
        else if (ret != -EIO)
-               DRM_INFO("GuC firmware load failed: %d\n", err);
+               DRM_NOTE("GuC firmware load failed: %d\n", err);
        else
-               DRM_ERROR("GuC firmware load failed: %d\n", err);
+               DRM_WARN("GuC firmware load failed: %d\n", err);
 
        if (i915.enable_guc_submission) {
                if (fw_path == NULL)
                        DRM_INFO("GuC submission without firmware not supported\n");
                if (ret == 0)
-                       DRM_INFO("Falling back from GuC submission to execlist mode\n");
+                       DRM_NOTE("Falling back from GuC submission to execlist mode\n");
                else
                        DRM_ERROR("GuC init failed: %d\n", ret);
        }
@@ -551,6 +585,7 @@ fail:
 
 static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
 {
+       struct pci_dev *pdev = dev->pdev;
        struct drm_i915_gem_object *obj;
        const struct firmware *fw;
        struct guc_css_header *css;
@@ -560,7 +595,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
        DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
                intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status));
 
-       err = request_firmware(&fw, guc_fw->guc_fw_path, &dev->pdev->dev);
+       err = request_firmware(&fw, guc_fw->guc_fw_path, &pdev->dev);
        if (err)
                goto fail;
        if (!fw)
@@ -571,7 +606,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
 
        /* Check the size of the blob before examining buffer contents */
        if (fw->size < sizeof(struct guc_css_header)) {
-               DRM_ERROR("Firmware header is missing\n");
+               DRM_NOTE("Firmware header is missing\n");
                goto fail;
        }
 
@@ -583,7 +618,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
                css->key_size_dw - css->exponent_size_dw) * sizeof(u32);
 
        if (guc_fw->header_size != sizeof(struct guc_css_header)) {
-               DRM_ERROR("CSS header definition mismatch\n");
+               DRM_NOTE("CSS header definition mismatch\n");
                goto fail;
        }
 
@@ -593,7 +628,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
 
        /* now RSA */
        if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) {
-               DRM_ERROR("RSA key size is bad\n");
+               DRM_NOTE("RSA key size is bad\n");
                goto fail;
        }
        guc_fw->rsa_offset = guc_fw->ucode_offset + guc_fw->ucode_size;
@@ -602,14 +637,14 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
        /* 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;
        if (fw->size < size) {
-               DRM_ERROR("Missing firmware components\n");
+               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(to_i915(dev))) {
-               DRM_ERROR("Firmware is too large to fit in WOPCM\n");
+               DRM_NOTE("Firmware is too large to fit in WOPCM\n");
                goto fail;
        }
 
@@ -624,7 +659,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
 
        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_ERROR("GuC firmware version %d.%d, required %d.%d\n",
+               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);
                err = -ENOEXEC;
@@ -654,15 +689,15 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
        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_ERROR("Failed to fetch GuC firmware from %s (error %d)\n",
-                 guc_fw->guc_fw_path, err);
 
        mutex_lock(&dev->struct_mutex);
        obj = guc_fw->guc_fw_obj;
        if (obj)
-               drm_gem_object_unreference(&obj->base);
+               i915_gem_object_put(obj);
        guc_fw->guc_fw_obj = NULL;
        mutex_unlock(&dev->struct_mutex);
 
@@ -695,16 +730,16 @@ void intel_guc_init(struct drm_device *dev)
                fw_path = NULL;
        } else if (IS_SKYLAKE(dev)) {
                fw_path = I915_SKL_GUC_UCODE;
-               guc_fw->guc_fw_major_wanted = 6;
-               guc_fw->guc_fw_minor_wanted = 1;
+               guc_fw->guc_fw_major_wanted = SKL_FW_MAJOR;
+               guc_fw->guc_fw_minor_wanted = SKL_FW_MINOR;
        } else if (IS_BROXTON(dev)) {
                fw_path = I915_BXT_GUC_UCODE;
-               guc_fw->guc_fw_major_wanted = 8;
-               guc_fw->guc_fw_minor_wanted = 7;
+               guc_fw->guc_fw_major_wanted = BXT_FW_MAJOR;
+               guc_fw->guc_fw_minor_wanted = BXT_FW_MINOR;
        } else if (IS_KABYLAKE(dev)) {
                fw_path = I915_KBL_GUC_UCODE;
-               guc_fw->guc_fw_major_wanted = 9;
-               guc_fw->guc_fw_minor_wanted = 14;
+               guc_fw->guc_fw_major_wanted = KBL_FW_MAJOR;
+               guc_fw->guc_fw_minor_wanted = KBL_FW_MINOR;
        } else {
                fw_path = "";   /* unknown device */
        }
@@ -738,12 +773,12 @@ void intel_guc_fini(struct drm_device *dev)
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
 
        mutex_lock(&dev->struct_mutex);
-       direct_interrupts_to_host(dev_priv);
+       guc_interrupts_release(dev_priv);
        i915_guc_submission_disable(dev_priv);
        i915_guc_submission_fini(dev_priv);
 
        if (guc_fw->guc_fw_obj)
-               drm_gem_object_unreference(&guc_fw->guc_fw_obj->base);
+               i915_gem_object_put(guc_fw->guc_fw_obj);
        guc_fw->guc_fw_obj = NULL;
        mutex_unlock(&dev->struct_mutex);
 
index 4df9f38..f40a35f 100644 (file)
@@ -985,7 +985,9 @@ static void intel_enable_hdmi_audio(struct intel_encoder *encoder)
        intel_audio_codec_enable(encoder);
 }
 
-static void g4x_enable_hdmi(struct intel_encoder *encoder)
+static void g4x_enable_hdmi(struct intel_encoder *encoder,
+                           struct intel_crtc_state *pipe_config,
+                           struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -1006,7 +1008,9 @@ static void g4x_enable_hdmi(struct intel_encoder *encoder)
                intel_enable_hdmi_audio(encoder);
 }
 
-static void ibx_enable_hdmi(struct intel_encoder *encoder)
+static void ibx_enable_hdmi(struct intel_encoder *encoder,
+                           struct intel_crtc_state *pipe_config,
+                           struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -1055,7 +1059,9 @@ static void ibx_enable_hdmi(struct intel_encoder *encoder)
                intel_enable_hdmi_audio(encoder);
 }
 
-static void cpt_enable_hdmi(struct intel_encoder *encoder)
+static void cpt_enable_hdmi(struct intel_encoder *encoder,
+                           struct intel_crtc_state *pipe_config,
+                           struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -1108,11 +1114,15 @@ static void cpt_enable_hdmi(struct intel_encoder *encoder)
                intel_enable_hdmi_audio(encoder);
 }
 
-static void vlv_enable_hdmi(struct intel_encoder *encoder)
+static void vlv_enable_hdmi(struct intel_encoder *encoder,
+                           struct intel_crtc_state *pipe_config,
+                           struct drm_connector_state *conn_state)
 {
 }
 
-static void intel_disable_hdmi(struct intel_encoder *encoder)
+static void intel_disable_hdmi(struct intel_encoder *encoder,
+                              struct intel_crtc_state *old_crtc_state,
+                              struct drm_connector_state *old_conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -1164,17 +1174,21 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
        intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
 }
 
-static void g4x_disable_hdmi(struct intel_encoder *encoder)
+static void g4x_disable_hdmi(struct intel_encoder *encoder,
+                            struct intel_crtc_state *old_crtc_state,
+                            struct drm_connector_state *old_conn_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 
        if (crtc->config->has_audio)
                intel_audio_codec_disable(encoder);
 
-       intel_disable_hdmi(encoder);
+       intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
 }
 
-static void pch_disable_hdmi(struct intel_encoder *encoder)
+static void pch_disable_hdmi(struct intel_encoder *encoder,
+                            struct intel_crtc_state *old_crtc_state,
+                            struct drm_connector_state *old_conn_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 
@@ -1182,9 +1196,11 @@ static void pch_disable_hdmi(struct intel_encoder *encoder)
                intel_audio_codec_disable(encoder);
 }
 
-static void pch_post_disable_hdmi(struct intel_encoder *encoder)
+static void pch_post_disable_hdmi(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *old_crtc_state,
+                                 struct drm_connector_state *old_conn_state)
 {
-       intel_disable_hdmi(encoder);
+       intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
 }
 
 static int intel_hdmi_source_max_tmds_clock(struct drm_i915_private *dev_priv)
@@ -1204,10 +1220,17 @@ static int hdmi_port_clock_limit(struct intel_hdmi *hdmi,
        int max_tmds_clock = intel_hdmi_source_max_tmds_clock(to_i915(dev));
 
        if (respect_downstream_limits) {
+               struct intel_connector *connector = hdmi->attached_connector;
+               const struct drm_display_info *info = &connector->base.display_info;
+
                if (hdmi->dp_dual_mode.max_tmds_clock)
                        max_tmds_clock = min(max_tmds_clock,
                                             hdmi->dp_dual_mode.max_tmds_clock);
-               if (!hdmi->has_hdmi_sink)
+
+               if (info->max_tmds_clock)
+                       max_tmds_clock = min(max_tmds_clock,
+                                            info->max_tmds_clock);
+               else if (!hdmi->has_hdmi_sink)
                        max_tmds_clock = min(max_tmds_clock, 165000);
        }
 
@@ -1285,7 +1308,8 @@ static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state)
 }
 
 bool intel_hdmi_compute_config(struct intel_encoder *encoder,
-                              struct intel_crtc_state *pipe_config)
+                              struct intel_crtc_state *pipe_config,
+                              struct drm_connector_state *conn_state)
 {
        struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        struct drm_device *dev = encoder->base.dev;
@@ -1422,24 +1446,22 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
 }
 
 static bool
-intel_hdmi_set_edid(struct drm_connector *connector, bool force)
+intel_hdmi_set_edid(struct drm_connector *connector)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->dev);
        struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-       struct edid *edid = NULL;
+       struct edid *edid;
        bool connected = false;
 
-       if (force) {
-               intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+       intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
-               edid = drm_get_edid(connector,
-                                   intel_gmbus_get_adapter(dev_priv,
-                                   intel_hdmi->ddc_bus));
+       edid = drm_get_edid(connector,
+                           intel_gmbus_get_adapter(dev_priv,
+                           intel_hdmi->ddc_bus));
 
-               intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
+       intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
 
-               intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
-       }
+       intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
 
        to_intel_connector(connector)->detect_edid = edid;
        if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -1465,37 +1487,16 @@ static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
        enum drm_connector_status status;
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
        struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       bool live_status = false;
-       unsigned int try;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
 
        intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
-       for (try = 0; !live_status && try < 9; try++) {
-               if (try)
-                       msleep(10);
-               live_status = intel_digital_port_connected(dev_priv,
-                               hdmi_to_dig_port(intel_hdmi));
-       }
-
-       if (!live_status) {
-               DRM_DEBUG_KMS("HDMI live status down\n");
-               /*
-                * Live status register is not reliable on all intel platforms.
-                * So consider live_status only for certain platforms, for
-                * others, read EDID to determine presence of sink.
-                */
-               if (INTEL_INFO(dev_priv)->gen < 7 || IS_IVYBRIDGE(dev_priv))
-                       live_status = true;
-       }
-
        intel_hdmi_unset_edid(connector);
 
-       if (intel_hdmi_set_edid(connector, live_status)) {
+       if (intel_hdmi_set_edid(connector)) {
                struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 
                hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
@@ -1521,7 +1522,7 @@ intel_hdmi_force(struct drm_connector *connector)
        if (connector->status != connector_status_connected)
                return;
 
-       intel_hdmi_set_edid(connector, true);
+       intel_hdmi_set_edid(connector);
        hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
 }
 
@@ -1638,7 +1639,9 @@ done:
        return 0;
 }
 
-static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
+static void intel_hdmi_pre_enable(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config,
+                                 struct drm_connector_state *conn_state)
 {
        struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
@@ -1651,7 +1654,9 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
                                   adjusted_mode);
 }
 
-static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
+static void vlv_hdmi_pre_enable(struct intel_encoder *encoder,
+                               struct intel_crtc_state *pipe_config,
+                               struct drm_connector_state *conn_state)
 {
        struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
        struct intel_hdmi *intel_hdmi = &dport->hdmi;
@@ -1671,37 +1676,47 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
                                   intel_crtc->config->has_hdmi_sink,
                                   adjusted_mode);
 
-       g4x_enable_hdmi(encoder);
+       g4x_enable_hdmi(encoder, pipe_config, conn_state);
 
        vlv_wait_port_ready(dev_priv, dport, 0x0);
 }
 
-static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
+static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config,
+                                   struct drm_connector_state *conn_state)
 {
        intel_hdmi_prepare(encoder);
 
        vlv_phy_pre_pll_enable(encoder);
 }
 
-static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
+static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
+                                   struct intel_crtc_state *pipe_config,
+                                   struct drm_connector_state *conn_state)
 {
        intel_hdmi_prepare(encoder);
 
        chv_phy_pre_pll_enable(encoder);
 }
 
-static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder)
+static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder,
+                                     struct intel_crtc_state *old_crtc_state,
+                                     struct drm_connector_state *old_conn_state)
 {
        chv_phy_post_pll_disable(encoder);
 }
 
-static void vlv_hdmi_post_disable(struct intel_encoder *encoder)
+static void vlv_hdmi_post_disable(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *old_crtc_state,
+                                 struct drm_connector_state *old_conn_state)
 {
        /* Reset lanes to avoid HDMI flicker (VLV w/a) */
        vlv_phy_reset_lanes(encoder);
 }
 
-static void chv_hdmi_post_disable(struct intel_encoder *encoder)
+static void chv_hdmi_post_disable(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *old_crtc_state,
+                                 struct drm_connector_state *old_conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -1714,7 +1729,9 @@ static void chv_hdmi_post_disable(struct intel_encoder *encoder)
        mutex_unlock(&dev_priv->sb_lock);
 }
 
-static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
+static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
+                               struct intel_crtc_state *pipe_config,
+                               struct drm_connector_state *conn_state)
 {
        struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
        struct intel_hdmi *intel_hdmi = &dport->hdmi;
@@ -1734,7 +1751,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
                                   intel_crtc->config->has_hdmi_sink,
                                   adjusted_mode);
 
-       g4x_enable_hdmi(encoder);
+       g4x_enable_hdmi(encoder, pipe_config, conn_state);
 
        vlv_wait_port_ready(dev_priv, dport, 0x0);
 
index f48957e..334d47b 100644 (file)
@@ -477,7 +477,8 @@ void intel_hpd_init(struct drm_i915_private *dev_priv)
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
-void i915_hpd_poll_init_work(struct work_struct *work) {
+static void i915_hpd_poll_init_work(struct work_struct *work)
+{
        struct drm_i915_private *dev_priv =
                container_of(work, struct drm_i915_private,
                             hotplug.poll_init_work);
@@ -525,7 +526,6 @@ void i915_hpd_poll_init_work(struct work_struct *work) {
 /**
  * intel_hpd_poll_init - enables/disables polling for connectors with hpd
  * @dev_priv: i915 device instance
- * @enabled: Whether to enable or disable polling
  *
  * This function enables polling for all connectors, regardless of whether or
  * not they support hotplug detection. Under certain conditions HPD may not be
index 1f266d7..79aab9a 100644 (file)
@@ -255,67 +255,59 @@ intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin)
        algo->data = bus;
 }
 
-static int
-gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
-                    u32 gmbus2_status,
-                    u32 gmbus4_irq_en)
+static int gmbus_wait(struct drm_i915_private *dev_priv, u32 status, u32 irq_en)
 {
-       int i;
-       u32 gmbus2 = 0;
        DEFINE_WAIT(wait);
-
-       if (!HAS_GMBUS_IRQ(dev_priv))
-               gmbus4_irq_en = 0;
+       u32 gmbus2;
+       int ret;
 
        /* Important: The hw handles only the first bit, so set only one! Since
         * we also need to check for NAKs besides the hw ready/idle signal, we
-        * need to wake up periodically and check that ourselves. */
-       I915_WRITE(GMBUS4, gmbus4_irq_en);
-
-       for (i = 0; i < msecs_to_jiffies_timeout(50); i++) {
-               prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait,
-                               TASK_UNINTERRUPTIBLE);
+        * need to wake up periodically and check that ourselves.
+        */
+       if (!HAS_GMBUS_IRQ(dev_priv))
+               irq_en = 0;
 
-               gmbus2 = I915_READ_NOTRACE(GMBUS2);
-               if (gmbus2 & (GMBUS_SATOER | gmbus2_status))
-                       break;
+       add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+       I915_WRITE_FW(GMBUS4, irq_en);
 
-               schedule_timeout(1);
-       }
-       finish_wait(&dev_priv->gmbus_wait_queue, &wait);
+       status |= GMBUS_SATOER;
+       ret = wait_for_us((gmbus2 = I915_READ_FW(GMBUS2)) & status, 2);
+       if (ret)
+               ret = wait_for((gmbus2 = I915_READ_FW(GMBUS2)) & status, 50);
 
-       I915_WRITE(GMBUS4, 0);
+       I915_WRITE_FW(GMBUS4, 0);
+       remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
 
        if (gmbus2 & GMBUS_SATOER)
                return -ENXIO;
-       if (gmbus2 & gmbus2_status)
-               return 0;
-       return -ETIMEDOUT;
+
+       return ret;
 }
 
 static int
 gmbus_wait_idle(struct drm_i915_private *dev_priv)
 {
+       DEFINE_WAIT(wait);
+       u32 irq_enable;
        int ret;
 
-       if (!HAS_GMBUS_IRQ(dev_priv))
-               return intel_wait_for_register(dev_priv,
-                                              GMBUS2, GMBUS_ACTIVE, 0,
-                                              10);
-
        /* Important: The hw handles only the first bit, so set only one! */
-       I915_WRITE(GMBUS4, GMBUS_IDLE_EN);
+       irq_enable = 0;
+       if (HAS_GMBUS_IRQ(dev_priv))
+               irq_enable = GMBUS_IDLE_EN;
 
-       ret = wait_event_timeout(dev_priv->gmbus_wait_queue,
-                                (I915_READ_NOTRACE(GMBUS2) & GMBUS_ACTIVE) == 0,
-                                msecs_to_jiffies_timeout(10));
+       add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+       I915_WRITE_FW(GMBUS4, irq_enable);
 
-       I915_WRITE(GMBUS4, 0);
+       ret = intel_wait_for_register_fw(dev_priv,
+                                        GMBUS2, GMBUS_ACTIVE, 0,
+                                        10);
 
-       if (ret)
-               return 0;
-       else
-               return -ETIMEDOUT;
+       I915_WRITE_FW(GMBUS4, 0);
+       remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
+
+       return ret;
 }
 
 static int
@@ -323,22 +315,21 @@ gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
                      unsigned short addr, u8 *buf, unsigned int len,
                      u32 gmbus1_index)
 {
-       I915_WRITE(GMBUS1,
-                  gmbus1_index |
-                  GMBUS_CYCLE_WAIT |
-                  (len << GMBUS_BYTE_COUNT_SHIFT) |
-                  (addr << GMBUS_SLAVE_ADDR_SHIFT) |
-                  GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+       I915_WRITE_FW(GMBUS1,
+                     gmbus1_index |
+                     GMBUS_CYCLE_WAIT |
+                     (len << GMBUS_BYTE_COUNT_SHIFT) |
+                     (addr << GMBUS_SLAVE_ADDR_SHIFT) |
+                     GMBUS_SLAVE_READ | GMBUS_SW_RDY);
        while (len) {
                int ret;
                u32 val, loop = 0;
 
-               ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
-                                          GMBUS_HW_RDY_EN);
+               ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
                if (ret)
                        return ret;
 
-               val = I915_READ(GMBUS3);
+               val = I915_READ_FW(GMBUS3);
                do {
                        *buf++ = val & 0xff;
                        val >>= 8;
@@ -385,12 +376,12 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
                len -= 1;
        }
 
-       I915_WRITE(GMBUS3, val);
-       I915_WRITE(GMBUS1,
-                  GMBUS_CYCLE_WAIT |
-                  (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
-                  (addr << GMBUS_SLAVE_ADDR_SHIFT) |
-                  GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
+       I915_WRITE_FW(GMBUS3, val);
+       I915_WRITE_FW(GMBUS1,
+                     GMBUS_CYCLE_WAIT |
+                     (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
+                     (addr << GMBUS_SLAVE_ADDR_SHIFT) |
+                     GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
        while (len) {
                int ret;
 
@@ -399,10 +390,9 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
                        val |= *buf++ << (8 * loop);
                } while (--len && ++loop < 4);
 
-               I915_WRITE(GMBUS3, val);
+               I915_WRITE_FW(GMBUS3, val);
 
-               ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
-                                          GMBUS_HW_RDY_EN);
+               ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
                if (ret)
                        return ret;
        }
@@ -460,13 +450,13 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
 
        /* GMBUS5 holds 16-bit index */
        if (gmbus5)
-               I915_WRITE(GMBUS5, gmbus5);
+               I915_WRITE_FW(GMBUS5, gmbus5);
 
        ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
 
        /* Clear GMBUS5 after each index transfer */
        if (gmbus5)
-               I915_WRITE(GMBUS5, 0);
+               I915_WRITE_FW(GMBUS5, 0);
 
        return ret;
 }
@@ -478,11 +468,15 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
                                               struct intel_gmbus,
                                               adapter);
        struct drm_i915_private *dev_priv = bus->dev_priv;
+       const unsigned int fw =
+               intel_uncore_forcewake_for_reg(dev_priv, GMBUS0,
+                                              FW_REG_READ | FW_REG_WRITE);
        int i = 0, inc, try = 0;
        int ret = 0;
 
+       intel_uncore_forcewake_get(dev_priv, fw);
 retry:
-       I915_WRITE(GMBUS0, bus->reg0);
+       I915_WRITE_FW(GMBUS0, bus->reg0);
 
        for (; i < num; i += inc) {
                inc = 1;
@@ -496,8 +490,8 @@ retry:
                }
 
                if (!ret)
-                       ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE,
-                                                  GMBUS_HW_WAIT_EN);
+                       ret = gmbus_wait(dev_priv,
+                                        GMBUS_HW_WAIT_PHASE, GMBUS_HW_WAIT_EN);
                if (ret == -ETIMEDOUT)
                        goto timeout;
                else if (ret)
@@ -508,7 +502,7 @@ retry:
         * a STOP on the very first cycle. To simplify the code we
         * unconditionally generate the STOP condition with an additional gmbus
         * cycle. */
-       I915_WRITE(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
+       I915_WRITE_FW(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
 
        /* Mark the GMBUS interface as disabled after waiting for idle.
         * We will re-enable it at the start of the next xfer,
@@ -519,7 +513,7 @@ retry:
                         adapter->name);
                ret = -ETIMEDOUT;
        }
-       I915_WRITE(GMBUS0, 0);
+       I915_WRITE_FW(GMBUS0, 0);
        ret = ret ?: i;
        goto out;
 
@@ -548,9 +542,9 @@ clear_err:
         * of resetting the GMBUS controller and so clearing the
         * BUS_ERROR raised by the slave's NAK.
         */
-       I915_WRITE(GMBUS1, GMBUS_SW_CLR_INT);
-       I915_WRITE(GMBUS1, 0);
-       I915_WRITE(GMBUS0, 0);
+       I915_WRITE_FW(GMBUS1, GMBUS_SW_CLR_INT);
+       I915_WRITE_FW(GMBUS1, 0);
+       I915_WRITE_FW(GMBUS0, 0);
 
        DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
                         adapter->name, msgs[i].addr,
@@ -573,7 +567,7 @@ clear_err:
 timeout:
        DRM_DEBUG_KMS("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
                      bus->adapter.name, bus->reg0 & 0xff);
-       I915_WRITE(GMBUS0, 0);
+       I915_WRITE_FW(GMBUS0, 0);
 
        /*
         * Hardware may not support GMBUS over these pins? Try GPIO bitbanging
@@ -582,6 +576,7 @@ timeout:
        ret = -EAGAIN;
 
 out:
+       intel_uncore_forcewake_put(dev_priv, fw);
        return ret;
 }
 
@@ -633,6 +628,7 @@ static const struct i2c_algorithm gmbus_algorithm = {
 int intel_setup_gmbus(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        struct intel_gmbus *bus;
        unsigned int pin;
        int ret;
@@ -663,7 +659,7 @@ int intel_setup_gmbus(struct drm_device *dev)
                         "i915 gmbus %s",
                         get_gmbus_pin(dev_priv, pin)->name);
 
-               bus->adapter.dev.parent = &dev->pdev->dev;
+               bus->adapter.dev.parent = &pdev->dev;
                bus->dev_priv = dev_priv;
 
                bus->adapter.algo = &gmbus_algorithm;
index 414ddda..0adb879 100644 (file)
 #define GEN8_CTX_STATUS_COMPLETE       (1 << 4)
 #define GEN8_CTX_STATUS_LITE_RESTORE   (1 << 15)
 
+#define GEN8_CTX_STATUS_COMPLETED_MASK \
+        (GEN8_CTX_STATUS_ACTIVE_IDLE | \
+         GEN8_CTX_STATUS_PREEMPTED | \
+         GEN8_CTX_STATUS_ELEMENT_SWITCH)
+
 #define CTX_LRI_HEADER_0               0x01
 #define CTX_CONTEXT_CONTROL            0x02
 #define CTX_RING_HEAD                  0x04
@@ -221,10 +226,16 @@ enum {
 /* Typical size of the average request (2 pipecontrols and a MI_BB) */
 #define EXECLISTS_REQUEST_SIZE 64 /* bytes */
 
+#define WA_TAIL_DWORDS 2
+
 static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
                                            struct intel_engine_cs *engine);
 static int intel_lr_context_pin(struct i915_gem_context *ctx,
                                struct intel_engine_cs *engine);
+static void execlists_init_reg_state(u32 *reg_state,
+                                    struct i915_gem_context *ctx,
+                                    struct intel_engine_cs *engine,
+                                    struct intel_ring *ring);
 
 /**
  * intel_sanitize_enable_execlists() - sanitize i915.enable_execlists
@@ -263,12 +274,10 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv = engine->i915;
 
-       if (IS_GEN8(dev_priv) || IS_GEN9(dev_priv))
-               engine->idle_lite_restore_wa = ~0;
-
-       engine->disable_lite_restore_wa = (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) ||
-                                       IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) &&
-                                       (engine->id == VCS || engine->id == VCS2);
+       engine->disable_lite_restore_wa =
+               (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) ||
+                IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) &&
+               (engine->id == VCS || engine->id == VCS2);
 
        engine->ctx_desc_template = GEN8_CTX_VALID;
        if (IS_GEN8(dev_priv))
@@ -288,7 +297,6 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *engine)
 /**
  * intel_lr_context_descriptor_update() - calculate & cache the descriptor
  *                                       descriptor for a pinned context
- *
  * @ctx: Context to work on
  * @engine: Engine the descriptor will be used with
  *
@@ -297,12 +305,13 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *engine)
  * expensive to calculate, we'll just do it once and cache the result,
  * which remains valid until the context is unpinned.
  *
- * This is what a descriptor looks like, from LSB to MSB:
- *    bits  0-11:    flags, GEN8_CTX_* (cached in ctx_desc_template)
- *    bits 12-31:    LRCA, GTT address of (the HWSP of) this context
- *    bits 32-52:    ctx ID, a globally unique tag
- *    bits 53-54:    mbz, reserved for use by hardware
- *    bits 55-63:    group ID, currently unused and set to 0
+ * This is what a descriptor looks like, from LSB to MSB::
+ *
+ *      bits  0-11:    flags, GEN8_CTX_* (cached in ctx_desc_template)
+ *      bits 12-31:    LRCA, GTT address of (the HWSP of) this context
+ *      bits 32-52:    ctx ID, a globally unique tag
+ *      bits 53-54:    mbz, reserved for use by hardware
+ *      bits 55-63:    group ID, currently unused and set to 0
  */
 static void
 intel_lr_context_descriptor_update(struct i915_gem_context *ctx,
@@ -315,7 +324,7 @@ intel_lr_context_descriptor_update(struct i915_gem_context *ctx,
 
        desc = ctx->desc_template;                              /* bits  3-4  */
        desc |= engine->ctx_desc_template;                      /* bits  0-11 */
-       desc |= ce->lrc_vma->node.start + LRC_PPHWSP_PN * PAGE_SIZE;
+       desc |= i915_ggtt_offset(ce->state) + LRC_PPHWSP_PN * PAGE_SIZE;
                                                                /* bits 12-31 */
        desc |= (u64)ctx->hw_id << GEN8_CTX_ID_SHIFT;           /* bits 32-52 */
 
@@ -328,34 +337,18 @@ uint64_t intel_lr_context_descriptor(struct i915_gem_context *ctx,
        return ctx->engine[engine->id].lrc_desc;
 }
 
-static void execlists_elsp_write(struct drm_i915_gem_request *rq0,
-                                struct drm_i915_gem_request *rq1)
+static inline void
+execlists_context_status_change(struct drm_i915_gem_request *rq,
+                               unsigned long status)
 {
+       /*
+        * Only used when GVT-g is enabled now. When GVT-g is disabled,
+        * The compiler should eliminate this function as dead-code.
+        */
+       if (!IS_ENABLED(CONFIG_DRM_I915_GVT))
+               return;
 
-       struct intel_engine_cs *engine = rq0->engine;
-       struct drm_i915_private *dev_priv = rq0->i915;
-       uint64_t desc[2];
-
-       if (rq1) {
-               desc[1] = intel_lr_context_descriptor(rq1->ctx, rq1->engine);
-               rq1->elsp_submitted++;
-       } else {
-               desc[1] = 0;
-       }
-
-       desc[0] = intel_lr_context_descriptor(rq0->ctx, rq0->engine);
-       rq0->elsp_submitted++;
-
-       /* You must always write both descriptors in the order below. */
-       I915_WRITE_FW(RING_ELSP(engine), upper_32_bits(desc[1]));
-       I915_WRITE_FW(RING_ELSP(engine), lower_32_bits(desc[1]));
-
-       I915_WRITE_FW(RING_ELSP(engine), upper_32_bits(desc[0]));
-       /* The context is automatically loaded after the following */
-       I915_WRITE_FW(RING_ELSP(engine), lower_32_bits(desc[0]));
-
-       /* ELSP is a wo register, use another nearby reg for posting */
-       POSTING_READ_FW(RING_EXECLIST_STATUS_LO(engine));
+       atomic_notifier_call_chain(&rq->ctx->status_notifier, status, rq);
 }
 
 static void
@@ -367,13 +360,13 @@ execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state)
        ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
 }
 
-static void execlists_update_context(struct drm_i915_gem_request *rq)
+static u64 execlists_update_context(struct drm_i915_gem_request *rq)
 {
-       struct intel_engine_cs *engine = rq->engine;
+       struct intel_context *ce = &rq->ctx->engine[rq->engine->id];
        struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt;
-       uint32_t *reg_state = rq->ctx->engine[engine->id].lrc_reg_state;
+       u32 *reg_state = ce->lrc_reg_state;
 
-       reg_state[CTX_RING_TAIL+1] = rq->tail;
+       reg_state[CTX_RING_TAIL+1] = intel_ring_offset(rq->ring, rq->tail);
 
        /* True 32b PPGTT with dynamic page allocation: update PDP
         * registers and point the unallocated PDPs to scratch page.
@@ -382,321 +375,236 @@ static void execlists_update_context(struct drm_i915_gem_request *rq)
         */
        if (ppgtt && !USES_FULL_48BIT_PPGTT(ppgtt->base.dev))
                execlists_update_context_pdps(ppgtt, reg_state);
+
+       return ce->lrc_desc;
 }
 
-static void execlists_submit_requests(struct drm_i915_gem_request *rq0,
-                                     struct drm_i915_gem_request *rq1)
+static void execlists_submit_ports(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = rq0->i915;
-       unsigned int fw_domains = rq0->engine->fw_domains;
-
-       execlists_update_context(rq0);
+       struct drm_i915_private *dev_priv = engine->i915;
+       struct execlist_port *port = engine->execlist_port;
+       u32 __iomem *elsp =
+               dev_priv->regs + i915_mmio_reg_offset(RING_ELSP(engine));
+       u64 desc[2];
 
-       if (rq1)
-               execlists_update_context(rq1);
+       if (!port[0].count)
+               execlists_context_status_change(port[0].request,
+                                               INTEL_CONTEXT_SCHEDULE_IN);
+       desc[0] = execlists_update_context(port[0].request);
+       engine->preempt_wa = port[0].count++; /* bdw only? fixed on skl? */
 
-       spin_lock_irq(&dev_priv->uncore.lock);
-       intel_uncore_forcewake_get__locked(dev_priv, fw_domains);
+       if (port[1].request) {
+               GEM_BUG_ON(port[1].count);
+               execlists_context_status_change(port[1].request,
+                                               INTEL_CONTEXT_SCHEDULE_IN);
+               desc[1] = execlists_update_context(port[1].request);
+               port[1].count = 1;
+       } else {
+               desc[1] = 0;
+       }
+       GEM_BUG_ON(desc[0] == desc[1]);
 
-       execlists_elsp_write(rq0, rq1);
+       /* You must always write both descriptors in the order below. */
+       writel(upper_32_bits(desc[1]), elsp);
+       writel(lower_32_bits(desc[1]), elsp);
 
-       intel_uncore_forcewake_put__locked(dev_priv, fw_domains);
-       spin_unlock_irq(&dev_priv->uncore.lock);
+       writel(upper_32_bits(desc[0]), elsp);
+       /* The context is automatically loaded after the following */
+       writel(lower_32_bits(desc[0]), elsp);
 }
 
-static inline void execlists_context_status_change(
-               struct drm_i915_gem_request *rq,
-               unsigned long status)
+static bool ctx_single_port_submission(const struct i915_gem_context *ctx)
 {
-       /*
-        * Only used when GVT-g is enabled now. When GVT-g is disabled,
-        * The compiler should eliminate this function as dead-code.
-        */
-       if (!IS_ENABLED(CONFIG_DRM_I915_GVT))
-               return;
-
-       atomic_notifier_call_chain(&rq->ctx->status_notifier, status, rq);
+       return (IS_ENABLED(CONFIG_DRM_I915_GVT) &&
+               ctx->execlists_force_single_submission);
 }
 
-static void execlists_context_unqueue(struct intel_engine_cs *engine)
+static bool can_merge_ctx(const struct i915_gem_context *prev,
+                         const struct i915_gem_context *next)
 {
-       struct drm_i915_gem_request *req0 = NULL, *req1 = NULL;
-       struct drm_i915_gem_request *cursor, *tmp;
+       if (prev != next)
+               return false;
 
-       assert_spin_locked(&engine->execlist_lock);
+       if (ctx_single_port_submission(prev))
+               return false;
 
-       /*
-        * If irqs are not active generate a warning as batches that finish
-        * without the irqs may get lost and a GPU Hang may occur.
-        */
-       WARN_ON(!intel_irqs_enabled(engine->i915));
-
-       /* Try to read in pairs */
-       list_for_each_entry_safe(cursor, tmp, &engine->execlist_queue,
-                                execlist_link) {
-               if (!req0) {
-                       req0 = cursor;
-               } else if (req0->ctx == cursor->ctx) {
-                       /* Same ctx: ignore first request, as second request
-                        * will update tail past first request's workload */
-                       cursor->elsp_submitted = req0->elsp_submitted;
-                       list_del(&req0->execlist_link);
-                       i915_gem_request_unreference(req0);
-                       req0 = cursor;
-               } else {
-                       if (IS_ENABLED(CONFIG_DRM_I915_GVT)) {
-                               /*
-                                * req0 (after merged) ctx requires single
-                                * submission, stop picking
-                                */
-                               if (req0->ctx->execlists_force_single_submission)
-                                       break;
-                               /*
-                                * req0 ctx doesn't require single submission,
-                                * but next req ctx requires, stop picking
-                                */
-                               if (cursor->ctx->execlists_force_single_submission)
-                                       break;
-                       }
-                       req1 = cursor;
-                       WARN_ON(req1->elsp_submitted);
-                       break;
-               }
-       }
+       return true;
+}
 
-       if (unlikely(!req0))
-               return;
+static void execlists_dequeue(struct intel_engine_cs *engine)
+{
+       struct drm_i915_gem_request *cursor, *last;
+       struct execlist_port *port = engine->execlist_port;
+       bool submit = false;
+
+       last = port->request;
+       if (last)
+               /* WaIdleLiteRestore:bdw,skl
+                * Apply the wa NOOPs to prevent ring:HEAD == req:TAIL
+                * as we resubmit the request. See gen8_emit_request()
+                * for where we prepare the padding after the end of the
+                * request.
+                */
+               last->tail = last->wa_tail;
 
-       execlists_context_status_change(req0, INTEL_CONTEXT_SCHEDULE_IN);
+       GEM_BUG_ON(port[1].request);
 
-       if (req1)
-               execlists_context_status_change(req1,
-                                               INTEL_CONTEXT_SCHEDULE_IN);
+       /* Hardware submission is through 2 ports. Conceptually each port
+        * has a (RING_START, RING_HEAD, RING_TAIL) tuple. RING_START is
+        * static for a context, and unique to each, so we only execute
+        * requests belonging to a single context from each ring. RING_HEAD
+        * is maintained by the CS in the context image, it marks the place
+        * where it got up to last time, and through RING_TAIL we tell the CS
+        * where we want to execute up to this time.
+        *
+        * In this list the requests are in order of execution. Consecutive
+        * requests from the same context are adjacent in the ringbuffer. We
+        * can combine these requests into a single RING_TAIL update:
+        *
+        *              RING_HEAD...req1...req2
+        *                                    ^- RING_TAIL
+        * since to execute req2 the CS must first execute req1.
+        *
+        * Our goal then is to point each port to the end of a consecutive
+        * sequence of requests as being the most optimal (fewest wake ups
+        * and context switches) submission.
+        */
 
-       if (req0->elsp_submitted & engine->idle_lite_restore_wa) {
-               /*
-                * WaIdleLiteRestore: make sure we never cause a lite restore
-                * with HEAD==TAIL.
+       spin_lock(&engine->execlist_lock);
+       list_for_each_entry(cursor, &engine->execlist_queue, execlist_link) {
+               /* Can we combine this request with the current port? It has to
+                * be the same context/ringbuffer and not have any exceptions
+                * (e.g. GVT saying never to combine contexts).
                 *
-                * Apply the wa NOOPS to prevent ring:HEAD == req:TAIL as we
-                * resubmit the request. See gen8_emit_request() for where we
-                * prepare the padding after the end of the request.
+                * If we can combine the requests, we can execute both by
+                * updating the RING_TAIL to point to the end of the second
+                * request, and so we never need to tell the hardware about
+                * the first.
                 */
-               struct intel_ringbuffer *ringbuf;
+               if (last && !can_merge_ctx(cursor->ctx, last->ctx)) {
+                       /* If we are on the second port and cannot combine
+                        * this request with the last, then we are done.
+                        */
+                       if (port != engine->execlist_port)
+                               break;
+
+                       /* If GVT overrides us we only ever submit port[0],
+                        * leaving port[1] empty. Note that we also have
+                        * to be careful that we don't queue the same
+                        * context (even though a different request) to
+                        * the second port.
+                        */
+                       if (ctx_single_port_submission(cursor->ctx))
+                               break;
+
+                       GEM_BUG_ON(last->ctx == cursor->ctx);
+
+                       i915_gem_request_assign(&port->request, last);
+                       port++;
+               }
+               last = cursor;
+               submit = true;
+       }
+       if (submit) {
+               /* Decouple all the requests submitted from the queue */
+               engine->execlist_queue.next = &cursor->execlist_link;
+               cursor->execlist_link.prev = &engine->execlist_queue;
 
-               ringbuf = req0->ctx->engine[engine->id].ringbuf;
-               req0->tail += 8;
-               req0->tail &= ringbuf->size - 1;
+               i915_gem_request_assign(&port->request, last);
        }
+       spin_unlock(&engine->execlist_lock);
 
-       execlists_submit_requests(req0, req1);
+       if (submit)
+               execlists_submit_ports(engine);
 }
 
-static unsigned int
-execlists_check_remove_request(struct intel_engine_cs *engine, u32 ctx_id)
+static bool execlists_elsp_idle(struct intel_engine_cs *engine)
 {
-       struct drm_i915_gem_request *head_req;
-
-       assert_spin_locked(&engine->execlist_lock);
-
-       head_req = list_first_entry_or_null(&engine->execlist_queue,
-                                           struct drm_i915_gem_request,
-                                           execlist_link);
-
-       if (WARN_ON(!head_req || (head_req->ctx_hw_id != ctx_id)))
-               return 0;
-
-       WARN(head_req->elsp_submitted == 0, "Never submitted head request\n");
-
-       if (--head_req->elsp_submitted > 0)
-               return 0;
-
-       execlists_context_status_change(head_req, INTEL_CONTEXT_SCHEDULE_OUT);
-
-       list_del(&head_req->execlist_link);
-       i915_gem_request_unreference(head_req);
-
-       return 1;
+       return !engine->execlist_port[0].request;
 }
 
-static u32
-get_context_status(struct intel_engine_cs *engine, unsigned int read_pointer,
-                  u32 *context_id)
+static bool execlists_elsp_ready(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = engine->i915;
-       u32 status;
+       int port;
 
-       read_pointer %= GEN8_CSB_ENTRIES;
+       port = 1; /* wait for a free slot */
+       if (engine->disable_lite_restore_wa || engine->preempt_wa)
+               port = 0; /* wait for GPU to be idle before continuing */
 
-       status = I915_READ_FW(RING_CONTEXT_STATUS_BUF_LO(engine, read_pointer));
-
-       if (status & GEN8_CTX_STATUS_IDLE_ACTIVE)
-               return 0;
-
-       *context_id = I915_READ_FW(RING_CONTEXT_STATUS_BUF_HI(engine,
-                                                             read_pointer));
-
-       return status;
+       return !engine->execlist_port[port].request;
 }
 
-/**
- * intel_lrc_irq_handler() - handle Context Switch interrupts
- * @data: tasklet handler passed in unsigned long
- *
+/*
  * Check the unread Context Status Buffers and manage the submission of new
  * contexts to the ELSP accordingly.
  */
 static void intel_lrc_irq_handler(unsigned long data)
 {
        struct intel_engine_cs *engine = (struct intel_engine_cs *)data;
+       struct execlist_port *port = engine->execlist_port;
        struct drm_i915_private *dev_priv = engine->i915;
-       u32 status_pointer;
-       unsigned int read_pointer, write_pointer;
-       u32 csb[GEN8_CSB_ENTRIES][2];
-       unsigned int csb_read = 0, i;
-       unsigned int submit_contexts = 0;
 
        intel_uncore_forcewake_get(dev_priv, engine->fw_domains);
 
-       status_pointer = I915_READ_FW(RING_CONTEXT_STATUS_PTR(engine));
-
-       read_pointer = engine->next_context_status_buffer;
-       write_pointer = GEN8_CSB_WRITE_PTR(status_pointer);
-       if (read_pointer > write_pointer)
-               write_pointer += GEN8_CSB_ENTRIES;
-
-       while (read_pointer < write_pointer) {
-               if (WARN_ON_ONCE(csb_read == GEN8_CSB_ENTRIES))
-                       break;
-               csb[csb_read][0] = get_context_status(engine, ++read_pointer,
-                                                     &csb[csb_read][1]);
-               csb_read++;
-       }
-
-       engine->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES;
-
-       /* Update the read pointer to the old write pointer. Manual ringbuffer
-        * management ftw </sarcasm> */
-       I915_WRITE_FW(RING_CONTEXT_STATUS_PTR(engine),
-                     _MASKED_FIELD(GEN8_CSB_READ_PTR_MASK,
-                                   engine->next_context_status_buffer << 8));
-
-       intel_uncore_forcewake_put(dev_priv, engine->fw_domains);
-
-       spin_lock(&engine->execlist_lock);
+       if (!execlists_elsp_idle(engine)) {
+               u32 __iomem *csb_mmio =
+                       dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine));
+               u32 __iomem *buf =
+                       dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0));
+               unsigned int csb, head, tail;
+
+               csb = readl(csb_mmio);
+               head = GEN8_CSB_READ_PTR(csb);
+               tail = GEN8_CSB_WRITE_PTR(csb);
+               if (tail < head)
+                       tail += GEN8_CSB_ENTRIES;
+               while (head < tail) {
+                       unsigned int idx = ++head % GEN8_CSB_ENTRIES;
+                       unsigned int status = readl(buf + 2 * idx);
+
+                       if (!(status & GEN8_CTX_STATUS_COMPLETED_MASK))
+                               continue;
+
+                       GEM_BUG_ON(port[0].count == 0);
+                       if (--port[0].count == 0) {
+                               GEM_BUG_ON(status & GEN8_CTX_STATUS_PREEMPTED);
+                               execlists_context_status_change(port[0].request,
+                                                               INTEL_CONTEXT_SCHEDULE_OUT);
+
+                               i915_gem_request_put(port[0].request);
+                               port[0] = port[1];
+                               memset(&port[1], 0, sizeof(port[1]));
+
+                               engine->preempt_wa = false;
+                       }
 
-       for (i = 0; i < csb_read; i++) {
-               if (unlikely(csb[i][0] & GEN8_CTX_STATUS_PREEMPTED)) {
-                       if (csb[i][0] & GEN8_CTX_STATUS_LITE_RESTORE) {
-                               if (execlists_check_remove_request(engine, csb[i][1]))
-                                       WARN(1, "Lite Restored request removed from queue\n");
-                       } else
-                               WARN(1, "Preemption without Lite Restore\n");
+                       GEM_BUG_ON(port[0].count == 0 &&
+                                  !(status & GEN8_CTX_STATUS_ACTIVE_IDLE));
                }
 
-               if (csb[i][0] & (GEN8_CTX_STATUS_ACTIVE_IDLE |
-                   GEN8_CTX_STATUS_ELEMENT_SWITCH))
-                       submit_contexts +=
-                               execlists_check_remove_request(engine, csb[i][1]);
-       }
-
-       if (submit_contexts) {
-               if (!engine->disable_lite_restore_wa ||
-                   (csb[i][0] & GEN8_CTX_STATUS_ACTIVE_IDLE))
-                       execlists_context_unqueue(engine);
+               writel(_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK,
+                                    GEN8_CSB_WRITE_PTR(csb) << 8),
+                      csb_mmio);
        }
 
-       spin_unlock(&engine->execlist_lock);
+       if (execlists_elsp_ready(engine))
+               execlists_dequeue(engine);
 
-       if (unlikely(submit_contexts > 2))
-               DRM_ERROR("More than two context complete events?\n");
+       intel_uncore_forcewake_put(dev_priv, engine->fw_domains);
 }
 
-static void execlists_context_queue(struct drm_i915_gem_request *request)
+static void execlists_submit_request(struct drm_i915_gem_request *request)
 {
        struct intel_engine_cs *engine = request->engine;
-       struct drm_i915_gem_request *cursor;
-       int num_elements = 0;
-
-       spin_lock_bh(&engine->execlist_lock);
+       unsigned long flags;
 
-       list_for_each_entry(cursor, &engine->execlist_queue, execlist_link)
-               if (++num_elements > 2)
-                       break;
+       spin_lock_irqsave(&engine->execlist_lock, flags);
 
-       if (num_elements > 2) {
-               struct drm_i915_gem_request *tail_req;
-
-               tail_req = list_last_entry(&engine->execlist_queue,
-                                          struct drm_i915_gem_request,
-                                          execlist_link);
-
-               if (request->ctx == tail_req->ctx) {
-                       WARN(tail_req->elsp_submitted != 0,
-                               "More than 2 already-submitted reqs queued\n");
-                       list_del(&tail_req->execlist_link);
-                       i915_gem_request_unreference(tail_req);
-               }
-       }
-
-       i915_gem_request_reference(request);
        list_add_tail(&request->execlist_link, &engine->execlist_queue);
-       request->ctx_hw_id = request->ctx->hw_id;
-       if (num_elements == 0)
-               execlists_context_unqueue(engine);
+       if (execlists_elsp_idle(engine))
+               tasklet_hi_schedule(&engine->irq_tasklet);
 
-       spin_unlock_bh(&engine->execlist_lock);
-}
-
-static int logical_ring_invalidate_all_caches(struct drm_i915_gem_request *req)
-{
-       struct intel_engine_cs *engine = req->engine;
-       uint32_t flush_domains;
-       int ret;
-
-       flush_domains = 0;
-       if (engine->gpu_caches_dirty)
-               flush_domains = I915_GEM_GPU_DOMAINS;
-
-       ret = engine->emit_flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
-       if (ret)
-               return ret;
-
-       engine->gpu_caches_dirty = false;
-       return 0;
-}
-
-static int execlists_move_to_gpu(struct drm_i915_gem_request *req,
-                                struct list_head *vmas)
-{
-       const unsigned other_rings = ~intel_engine_flag(req->engine);
-       struct i915_vma *vma;
-       uint32_t flush_domains = 0;
-       bool flush_chipset = false;
-       int ret;
-
-       list_for_each_entry(vma, vmas, exec_list) {
-               struct drm_i915_gem_object *obj = vma->obj;
-
-               if (obj->active & other_rings) {
-                       ret = i915_gem_object_sync(obj, req->engine, &req);
-                       if (ret)
-                               return ret;
-               }
-
-               if (obj->base.write_domain & I915_GEM_DOMAIN_CPU)
-                       flush_chipset |= i915_gem_clflush_object(obj, false);
-
-               flush_domains |= obj->base.write_domain;
-       }
-
-       if (flush_domains & I915_GEM_DOMAIN_GTT)
-               wmb();
-
-       /* Unconditionally invalidate gpu caches and ensure that we do flush
-        * any residual writes from the previous batch.
-        */
-       return logical_ring_invalidate_all_caches(req);
+       spin_unlock_irqrestore(&engine->execlist_lock, flags);
 }
 
 int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request)
@@ -717,7 +625,11 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request
                        return ret;
        }
 
-       request->ringbuf = ce->ringbuf;
+       request->ring = ce->ring;
+
+       ret = intel_lr_context_pin(request->ctx, engine);
+       if (ret)
+               return ret;
 
        if (i915.enable_guc_submission) {
                /*
@@ -725,23 +637,19 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request
                 * going any further, as the i915_add_request() call
                 * later on mustn't fail ...
                 */
-               ret = i915_guc_wq_check_space(request);
+               ret = i915_guc_wq_reserve(request);
                if (ret)
-                       return ret;
+                       goto err_unpin;
        }
 
-       ret = intel_lr_context_pin(request->ctx, engine);
-       if (ret)
-               return ret;
-
        ret = intel_ring_begin(request, 0);
        if (ret)
-               goto err_unpin;
+               goto err_unreserve;
 
        if (!ce->initialised) {
                ret = engine->init_context(request);
                if (ret)
-                       goto err_unpin;
+                       goto err_unreserve;
 
                ce->initialised = true;
        }
@@ -756,13 +664,16 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request
        request->reserved_space -= EXECLISTS_REQUEST_SIZE;
        return 0;
 
+err_unreserve:
+       if (i915.enable_guc_submission)
+               i915_guc_wq_unreserve(request);
 err_unpin:
        intel_lr_context_unpin(request->ctx, engine);
        return ret;
 }
 
 /*
- * intel_logical_ring_advance_and_submit() - advance the tail and submit the workload
+ * intel_logical_ring_advance() - advance the tail and prepare for submission
  * @request: Request to advance the logical ringbuffer of.
  *
  * The tail is updated in our logical ringbuffer struct, not in the actual context. What
@@ -771,13 +682,13 @@ err_unpin:
  * point, the tail *inside* the context is updated and the ELSP written to.
  */
 static int
-intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request)
+intel_logical_ring_advance(struct drm_i915_gem_request *request)
 {
-       struct intel_ringbuffer *ringbuf = request->ringbuf;
+       struct intel_ring *ring = request->ring;
        struct intel_engine_cs *engine = request->engine;
 
-       intel_logical_ring_advance(ringbuf);
-       request->tail = ringbuf->tail;
+       intel_ring_advance(ring);
+       request->tail = ring->tail;
 
        /*
         * Here we add two extra NOOPs as padding to avoid
@@ -785,9 +696,10 @@ intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request)
         *
         * Caller must reserve WA_TAIL_DWORDS for us!
         */
-       intel_logical_ring_emit(ringbuf, MI_NOOP);
-       intel_logical_ring_emit(ringbuf, MI_NOOP);
-       intel_logical_ring_advance(ringbuf);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
+       request->wa_tail = ring->tail;
 
        /* We keep the previous context alive until we retire the following
         * request. This ensures that any the context object is still pinned
@@ -797,168 +709,14 @@ intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request)
         */
        request->previous_context = engine->last_context;
        engine->last_context = request->ctx;
-
-       if (i915.enable_guc_submission)
-               i915_guc_submit(request);
-       else
-               execlists_context_queue(request);
-
-       return 0;
-}
-
-/**
- * execlists_submission() - submit a batchbuffer for execution, Execlists style
- * @params: execbuffer call parameters.
- * @args: execbuffer call arguments.
- * @vmas: list of vmas.
- *
- * This is the evil twin version of i915_gem_ringbuffer_submission. It abstracts
- * away the submission details of the execbuffer ioctl call.
- *
- * Return: non-zero if the submission fails.
- */
-int intel_execlists_submission(struct i915_execbuffer_params *params,
-                              struct drm_i915_gem_execbuffer2 *args,
-                              struct list_head *vmas)
-{
-       struct drm_device       *dev = params->dev;
-       struct intel_engine_cs *engine = params->engine;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_ringbuffer *ringbuf = params->ctx->engine[engine->id].ringbuf;
-       u64 exec_start;
-       int instp_mode;
-       u32 instp_mask;
-       int ret;
-
-       instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
-       instp_mask = I915_EXEC_CONSTANTS_MASK;
-       switch (instp_mode) {
-       case I915_EXEC_CONSTANTS_REL_GENERAL:
-       case I915_EXEC_CONSTANTS_ABSOLUTE:
-       case I915_EXEC_CONSTANTS_REL_SURFACE:
-               if (instp_mode != 0 && engine != &dev_priv->engine[RCS]) {
-                       DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
-                       return -EINVAL;
-               }
-
-               if (instp_mode != dev_priv->relative_constants_mode) {
-                       if (instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
-                               DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
-                               return -EINVAL;
-                       }
-
-                       /* The HW changed the meaning on this bit on gen6 */
-                       instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE;
-               }
-               break;
-       default:
-               DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
-               return -EINVAL;
-       }
-
-       if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
-               DRM_DEBUG("sol reset is gen7 only\n");
-               return -EINVAL;
-       }
-
-       ret = execlists_move_to_gpu(params->request, vmas);
-       if (ret)
-               return ret;
-
-       if (engine == &dev_priv->engine[RCS] &&
-           instp_mode != dev_priv->relative_constants_mode) {
-               ret = intel_ring_begin(params->request, 4);
-               if (ret)
-                       return ret;
-
-               intel_logical_ring_emit(ringbuf, MI_NOOP);
-               intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1));
-               intel_logical_ring_emit_reg(ringbuf, INSTPM);
-               intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode);
-               intel_logical_ring_advance(ringbuf);
-
-               dev_priv->relative_constants_mode = instp_mode;
-       }
-
-       exec_start = params->batch_obj_vm_offset +
-                    args->batch_start_offset;
-
-       ret = engine->emit_bb_start(params->request, exec_start, params->dispatch_flags);
-       if (ret)
-               return ret;
-
-       trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags);
-
-       i915_gem_execbuffer_move_to_active(vmas, params->request);
-
-       return 0;
-}
-
-void intel_execlists_cancel_requests(struct intel_engine_cs *engine)
-{
-       struct drm_i915_gem_request *req, *tmp;
-       LIST_HEAD(cancel_list);
-
-       WARN_ON(!mutex_is_locked(&engine->i915->drm.struct_mutex));
-
-       spin_lock_bh(&engine->execlist_lock);
-       list_replace_init(&engine->execlist_queue, &cancel_list);
-       spin_unlock_bh(&engine->execlist_lock);
-
-       list_for_each_entry_safe(req, tmp, &cancel_list, execlist_link) {
-               list_del(&req->execlist_link);
-               i915_gem_request_unreference(req);
-       }
-}
-
-void intel_logical_ring_stop(struct intel_engine_cs *engine)
-{
-       struct drm_i915_private *dev_priv = engine->i915;
-       int ret;
-
-       if (!intel_engine_initialized(engine))
-               return;
-
-       ret = intel_engine_idle(engine);
-       if (ret)
-               DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
-                         engine->name, ret);
-
-       /* TODO: Is this correct with Execlists enabled? */
-       I915_WRITE_MODE(engine, _MASKED_BIT_ENABLE(STOP_RING));
-       if (intel_wait_for_register(dev_priv,
-                                   RING_MI_MODE(engine->mmio_base),
-                                   MODE_IDLE, MODE_IDLE,
-                                   1000)) {
-               DRM_ERROR("%s :timed out trying to stop ring\n", engine->name);
-               return;
-       }
-       I915_WRITE_MODE(engine, _MASKED_BIT_DISABLE(STOP_RING));
-}
-
-int logical_ring_flush_all_caches(struct drm_i915_gem_request *req)
-{
-       struct intel_engine_cs *engine = req->engine;
-       int ret;
-
-       if (!engine->gpu_caches_dirty)
-               return 0;
-
-       ret = engine->emit_flush(req, 0, I915_GEM_GPU_DOMAINS);
-       if (ret)
-               return ret;
-
-       engine->gpu_caches_dirty = false;
        return 0;
 }
 
 static int intel_lr_context_pin(struct i915_gem_context *ctx,
                                struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = ctx->i915;
        struct intel_context *ce = &ctx->engine[engine->id];
        void *vaddr;
-       u32 *lrc_reg_state;
        int ret;
 
        lockdep_assert_held(&ctx->i915->drm.struct_mutex);
@@ -966,41 +724,42 @@ static int intel_lr_context_pin(struct i915_gem_context *ctx,
        if (ce->pin_count++)
                return 0;
 
-       ret = i915_gem_obj_ggtt_pin(ce->state, GEN8_LR_CONTEXT_ALIGN,
-                                   PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
+       ret = i915_vma_pin(ce->state, 0, GEN8_LR_CONTEXT_ALIGN,
+                          PIN_OFFSET_BIAS | GUC_WOPCM_TOP | PIN_GLOBAL);
        if (ret)
                goto err;
 
-       vaddr = i915_gem_object_pin_map(ce->state);
+       vaddr = i915_gem_object_pin_map(ce->state->obj, I915_MAP_WB);
        if (IS_ERR(vaddr)) {
                ret = PTR_ERR(vaddr);
-               goto unpin_ctx_obj;
+               goto unpin_vma;
        }
 
-       lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE;
-
-       ret = intel_pin_and_map_ringbuffer_obj(dev_priv, ce->ringbuf);
+       ret = intel_ring_pin(ce->ring);
        if (ret)
                goto unpin_map;
 
-       i915_gem_context_reference(ctx);
-       ce->lrc_vma = i915_gem_obj_to_ggtt(ce->state);
        intel_lr_context_descriptor_update(ctx, engine);
 
-       lrc_reg_state[CTX_RING_BUFFER_START+1] = ce->ringbuf->vma->node.start;
-       ce->lrc_reg_state = lrc_reg_state;
-       ce->state->dirty = true;
+       ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE;
+       ce->lrc_reg_state[CTX_RING_BUFFER_START+1] =
+               i915_ggtt_offset(ce->ring->vma);
+
+       ce->state->obj->dirty = true;
 
        /* Invalidate GuC TLB. */
-       if (i915.enable_guc_submission)
+       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;
 
 unpin_map:
-       i915_gem_object_unpin_map(ce->state);
-unpin_ctx_obj:
-       i915_gem_object_ggtt_unpin(ce->state);
+       i915_gem_object_unpin_map(ce->state->obj);
+unpin_vma:
+       __i915_vma_unpin(ce->state);
 err:
        ce->pin_count = 0;
        return ret;
@@ -1017,30 +776,24 @@ void intel_lr_context_unpin(struct i915_gem_context *ctx,
        if (--ce->pin_count)
                return;
 
-       intel_unpin_ringbuffer_obj(ce->ringbuf);
+       intel_ring_unpin(ce->ring);
 
-       i915_gem_object_unpin_map(ce->state);
-       i915_gem_object_ggtt_unpin(ce->state);
+       i915_gem_object_unpin_map(ce->state->obj);
+       i915_vma_unpin(ce->state);
 
-       ce->lrc_vma = NULL;
-       ce->lrc_desc = 0;
-       ce->lrc_reg_state = NULL;
-
-       i915_gem_context_unreference(ctx);
+       i915_gem_context_put(ctx);
 }
 
 static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req)
 {
        int ret, i;
-       struct intel_engine_cs *engine = req->engine;
-       struct intel_ringbuffer *ringbuf = req->ringbuf;
+       struct intel_ring *ring = req->ring;
        struct i915_workarounds *w = &req->i915->workarounds;
 
        if (w->count == 0)
                return 0;
 
-       engine->gpu_caches_dirty = true;
-       ret = logical_ring_flush_all_caches(req);
+       ret = req->engine->emit_flush(req, EMIT_BARRIER);
        if (ret)
                return ret;
 
@@ -1048,17 +801,16 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req)
        if (ret)
                return ret;
 
-       intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(w->count));
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(w->count));
        for (i = 0; i < w->count; i++) {
-               intel_logical_ring_emit_reg(ringbuf, w->reg[i].addr);
-               intel_logical_ring_emit(ringbuf, w->reg[i].value);
+               intel_ring_emit_reg(ring, w->reg[i].addr);
+               intel_ring_emit(ring, w->reg[i].value);
        }
-       intel_logical_ring_emit(ringbuf, MI_NOOP);
+       intel_ring_emit(ring, MI_NOOP);
 
-       intel_logical_ring_advance(ringbuf);
+       intel_ring_advance(ring);
 
-       engine->gpu_caches_dirty = true;
-       ret = logical_ring_flush_all_caches(req);
+       ret = req->engine->emit_flush(req, EMIT_BARRIER);
        if (ret)
                return ret;
 
@@ -1094,7 +846,7 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req)
  * code duplication.
  */
 static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine,
-                                               uint32_t *const batch,
+                                               uint32_t *batch,
                                                uint32_t index)
 {
        struct drm_i915_private *dev_priv = engine->i915;
@@ -1113,7 +865,7 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine,
        wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 |
                                   MI_SRM_LRM_GLOBAL_GTT));
        wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
-       wa_ctx_emit(batch, index, engine->scratch.gtt_offset + 256);
+       wa_ctx_emit(batch, index, i915_ggtt_offset(engine->scratch) + 256);
        wa_ctx_emit(batch, index, 0);
 
        wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1));
@@ -1131,7 +883,7 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine,
        wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8 |
                                   MI_SRM_LRM_GLOBAL_GTT));
        wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
-       wa_ctx_emit(batch, index, engine->scratch.gtt_offset + 256);
+       wa_ctx_emit(batch, index, i915_ggtt_offset(engine->scratch) + 256);
        wa_ctx_emit(batch, index, 0);
 
        return index;
@@ -1156,37 +908,24 @@ static inline int wa_ctx_end(struct i915_wa_ctx_bb *wa_ctx,
        return 0;
 }
 
-/**
- * gen8_init_indirectctx_bb() - initialize indirect ctx batch with WA
- *
- * @engine: only applicable for RCS
- * @wa_ctx: structure representing wa_ctx
- *  offset: specifies start of the batch, should be cache-aligned. This is updated
- *    with the offset value received as input.
- *  size: size of the batch in DWORDS but HW expects in terms of cachelines
- * @batch: page in which WA are loaded
- * @offset: This field specifies the start of the batch, it should be
- *  cache-aligned otherwise it is adjusted accordingly.
- *  Typically we only have one indirect_ctx and per_ctx batch buffer which are
- *  initialized at the beginning and shared across all contexts but this field
- *  helps us to have multiple batches at different offsets and select them based
- *  on a criteria. At the moment this batch always start at the beginning of the page
- *  and at this point we don't have multiple wa_ctx batch buffers.
- *
- *  The number of WA applied are not known at the beginning; we use this field
- *  to return the no of DWORDS written.
+/*
+ * Typically we only have one indirect_ctx and per_ctx batch buffer which are
+ * initialized at the beginning and shared across all contexts but this field
+ * helps us to have multiple batches at different offsets and select them based
+ * on a criteria. At the moment this batch always start at the beginning of the page
+ * and at this point we don't have multiple wa_ctx batch buffers.
  *
- *  It is to be noted that this batch does not contain MI_BATCH_BUFFER_END
- *  so it adds NOOPs as padding to make it cacheline aligned.
- *  MI_BATCH_BUFFER_END will be added to perctx batch and both of them together
- *  makes a complete batch buffer.
+ * The number of WA applied are not known at the beginning; we use this field
+ * to return the no of DWORDS written.
  *
- * Return: non-zero if we exceed the PAGE_SIZE limit.
+ * It is to be noted that this batch does not contain MI_BATCH_BUFFER_END
+ * so it adds NOOPs as padding to make it cacheline aligned.
+ * MI_BATCH_BUFFER_END will be added to perctx batch and both of them together
+ * makes a complete batch buffer.
  */
-
 static int gen8_init_indirectctx_bb(struct intel_engine_cs *engine,
                                    struct i915_wa_ctx_bb *wa_ctx,
-                                   uint32_t *const batch,
+                                   uint32_t *batch,
                                    uint32_t *offset)
 {
        uint32_t scratch_addr;
@@ -1205,7 +944,7 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *engine,
 
        /* WaClearSlmSpaceAtContextSwitch:bdw,chv */
        /* Actual scratch location is at 128 bytes offset */
-       scratch_addr = engine->scratch.gtt_offset + 2*CACHELINE_BYTES;
+       scratch_addr = i915_ggtt_offset(engine->scratch) + 2 * CACHELINE_BYTES;
 
        wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6));
        wa_ctx_emit(batch, index, (PIPE_CONTROL_FLUSH_L3 |
@@ -1230,26 +969,18 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *engine,
        return wa_ctx_end(wa_ctx, *offset = index, CACHELINE_DWORDS);
 }
 
-/**
- * gen8_init_perctx_bb() - initialize per ctx batch with WA
- *
- * @engine: only applicable for RCS
- * @wa_ctx: structure representing wa_ctx
- *  offset: specifies start of the batch, should be cache-aligned.
- *  size: size of the batch in DWORDS but HW expects in terms of cachelines
- * @batch: page in which WA are loaded
- * @offset: This field specifies the start of this batch.
- *   This batch is started immediately after indirect_ctx batch. Since we ensure
- *   that indirect_ctx ends on a cacheline this batch is aligned automatically.
+/*
+ *  This batch is started immediately after indirect_ctx batch. Since we ensure
+ *  that indirect_ctx ends on a cacheline this batch is aligned automatically.
  *
- *   The number of DWORDS written are returned using this field.
+ *  The number of DWORDS written are returned using this field.
  *
  *  This batch is terminated with MI_BATCH_BUFFER_END and so we need not add padding
  *  to align it with cacheline as padding after MI_BATCH_BUFFER_END is redundant.
  */
 static int gen8_init_perctx_bb(struct intel_engine_cs *engine,
                               struct i915_wa_ctx_bb *wa_ctx,
-                              uint32_t *const batch,
+                              uint32_t *batch,
                               uint32_t *offset)
 {
        uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS);
@@ -1264,7 +995,7 @@ static int gen8_init_perctx_bb(struct intel_engine_cs *engine,
 
 static int gen9_init_indirectctx_bb(struct intel_engine_cs *engine,
                                    struct i915_wa_ctx_bb *wa_ctx,
-                                   uint32_t *const batch,
+                                   uint32_t *batch,
                                    uint32_t *offset)
 {
        int ret;
@@ -1282,11 +1013,18 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *engine,
                return ret;
        index = ret;
 
+       /* WaDisableGatherAtSetShaderCommonSlice:skl,bxt,kbl */
+       wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1));
+       wa_ctx_emit_reg(batch, index, COMMON_SLICE_CHICKEN2);
+       wa_ctx_emit(batch, index, _MASKED_BIT_DISABLE(
+                           GEN9_DISABLE_GATHER_AT_SET_SHADER_COMMON_SLICE));
+       wa_ctx_emit(batch, index, MI_NOOP);
+
        /* WaClearSlmSpaceAtContextSwitch:kbl */
        /* Actual scratch location is at 128 bytes offset */
        if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_A0)) {
-               uint32_t scratch_addr
-                       = engine->scratch.gtt_offset + 2*CACHELINE_BYTES;
+               u32 scratch_addr =
+                       i915_ggtt_offset(engine->scratch) + 2 * CACHELINE_BYTES;
 
                wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6));
                wa_ctx_emit(batch, index, (PIPE_CONTROL_FLUSH_L3 |
@@ -1332,7 +1070,7 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *engine,
 
 static int gen9_init_perctx_bb(struct intel_engine_cs *engine,
                               struct i915_wa_ctx_bb *wa_ctx,
-                              uint32_t *const batch,
+                              uint32_t *batch,
                               uint32_t *offset)
 {
        uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS);
@@ -1378,44 +1116,44 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *engine,
 
 static int lrc_setup_wa_ctx_obj(struct intel_engine_cs *engine, u32 size)
 {
-       int ret;
+       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
+       int err;
 
-       engine->wa_ctx.obj = i915_gem_object_create(&engine->i915->drm,
-                                                   PAGE_ALIGN(size));
-       if (IS_ERR(engine->wa_ctx.obj)) {
-               DRM_DEBUG_DRIVER("alloc LRC WA ctx backing obj failed.\n");
-               ret = PTR_ERR(engine->wa_ctx.obj);
-               engine->wa_ctx.obj = NULL;
-               return ret;
-       }
+       obj = i915_gem_object_create(&engine->i915->drm, PAGE_ALIGN(size));
+       if (IS_ERR(obj))
+               return PTR_ERR(obj);
 
-       ret = i915_gem_obj_ggtt_pin(engine->wa_ctx.obj, PAGE_SIZE, 0);
-       if (ret) {
-               DRM_DEBUG_DRIVER("pin LRC WA ctx backing obj failed: %d\n",
-                                ret);
-               drm_gem_object_unreference(&engine->wa_ctx.obj->base);
-               return ret;
+       vma = i915_vma_create(obj, &engine->i915->ggtt.base, NULL);
+       if (IS_ERR(vma)) {
+               err = PTR_ERR(vma);
+               goto err;
        }
 
+       err = i915_vma_pin(vma, 0, PAGE_SIZE, PIN_GLOBAL | PIN_HIGH);
+       if (err)
+               goto err;
+
+       engine->wa_ctx.vma = vma;
        return 0;
+
+err:
+       i915_gem_object_put(obj);
+       return err;
 }
 
 static void lrc_destroy_wa_ctx_obj(struct intel_engine_cs *engine)
 {
-       if (engine->wa_ctx.obj) {
-               i915_gem_object_ggtt_unpin(engine->wa_ctx.obj);
-               drm_gem_object_unreference(&engine->wa_ctx.obj->base);
-               engine->wa_ctx.obj = NULL;
-       }
+       i915_vma_unpin_and_release(&engine->wa_ctx.vma);
 }
 
 static int intel_init_workaround_bb(struct intel_engine_cs *engine)
 {
-       int ret;
+       struct i915_ctx_workarounds *wa_ctx = &engine->wa_ctx;
        uint32_t *batch;
        uint32_t offset;
        struct page *page;
-       struct i915_ctx_workarounds *wa_ctx = &engine->wa_ctx;
+       int ret;
 
        WARN_ON(engine->id != RCS);
 
@@ -1427,7 +1165,7 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine)
        }
 
        /* some WA perform writes to scratch page, ensure it is valid */
-       if (engine->scratch.obj == NULL) {
+       if (!engine->scratch) {
                DRM_ERROR("scratch page not allocated for %s\n", engine->name);
                return -EINVAL;
        }
@@ -1438,7 +1176,7 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine)
                return ret;
        }
 
-       page = i915_gem_object_get_dirty_page(wa_ctx->obj, 0);
+       page = i915_gem_object_get_dirty_page(wa_ctx->vma->obj, 0);
        batch = kmap_atomic(page);
        offset = 0;
 
@@ -1485,55 +1223,37 @@ static void lrc_init_hws(struct intel_engine_cs *engine)
        struct drm_i915_private *dev_priv = engine->i915;
 
        I915_WRITE(RING_HWS_PGA(engine->mmio_base),
-                  (u32)engine->status_page.gfx_addr);
+                  engine->status_page.ggtt_offset);
        POSTING_READ(RING_HWS_PGA(engine->mmio_base));
 }
 
 static int gen8_init_common_ring(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv = engine->i915;
-       unsigned int next_context_status_buffer_hw;
+       int ret;
+
+       ret = intel_mocs_init_engine(engine);
+       if (ret)
+               return ret;
 
        lrc_init_hws(engine);
 
-       I915_WRITE_IMR(engine,
-                      ~(engine->irq_enable_mask | engine->irq_keep_mask));
+       intel_engine_reset_breadcrumbs(engine);
+
        I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff);
 
        I915_WRITE(RING_MODE_GEN7(engine),
                   _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
                   _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
-       POSTING_READ(RING_MODE_GEN7(engine));
-
-       /*
-        * Instead of resetting the Context Status Buffer (CSB) read pointer to
-        * zero, we need to read the write pointer from hardware and use its
-        * value because "this register is power context save restored".
-        * Effectively, these states have been observed:
-        *
-        *      | Suspend-to-idle (freeze) | Suspend-to-RAM (mem) |
-        * BDW  | CSB regs not reset       | CSB regs reset       |
-        * CHT  | CSB regs not reset       | CSB regs not reset   |
-        * SKL  |         ?                |         ?            |
-        * BXT  |         ?                |         ?            |
-        */
-       next_context_status_buffer_hw =
-               GEN8_CSB_WRITE_PTR(I915_READ(RING_CONTEXT_STATUS_PTR(engine)));
-
-       /*
-        * When the CSB registers are reset (also after power-up / gpu reset),
-        * CSB write pointer is set to all 1's, which is not valid, use '5' in
-        * this special case, so the first element read is CSB[0].
-        */
-       if (next_context_status_buffer_hw == GEN8_CSB_PTR_MASK)
-               next_context_status_buffer_hw = (GEN8_CSB_ENTRIES - 1);
 
-       engine->next_context_status_buffer = next_context_status_buffer_hw;
        DRM_DEBUG_DRIVER("Execlists enabled for %s\n", engine->name);
 
        intel_engine_init_hangcheck(engine);
 
-       return intel_mocs_init_engine(engine);
+       if (!execlists_elsp_idle(engine))
+               execlists_submit_ports(engine);
+
+       return 0;
 }
 
 static int gen8_init_render_ring(struct intel_engine_cs *engine)
@@ -1569,11 +1289,57 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine)
        return init_workarounds_ring(engine);
 }
 
+static void reset_common_ring(struct intel_engine_cs *engine,
+                             struct drm_i915_gem_request *request)
+{
+       struct drm_i915_private *dev_priv = engine->i915;
+       struct execlist_port *port = engine->execlist_port;
+       struct intel_context *ce = &request->ctx->engine[engine->id];
+
+       /* We want a simple context + ring to execute the breadcrumb update.
+        * We cannot rely on the context being intact across the GPU hang,
+        * so clear it and rebuild just what we need for the breadcrumb.
+        * All pending requests for this context will be zapped, and any
+        * future request will be after userspace has had the opportunity
+        * to recreate its own state.
+        */
+       execlists_init_reg_state(ce->lrc_reg_state,
+                                request->ctx, engine, ce->ring);
+
+       /* Move the RING_HEAD onto the breadcrumb, past the hanging batch */
+       ce->lrc_reg_state[CTX_RING_BUFFER_START+1] =
+               i915_ggtt_offset(ce->ring->vma);
+       ce->lrc_reg_state[CTX_RING_HEAD+1] = request->postfix;
+
+       request->ring->head = request->postfix;
+       request->ring->last_retired_head = -1;
+       intel_ring_update_space(request->ring);
+
+       if (i915.enable_guc_submission)
+               return;
+
+       /* Catch up with any missed context-switch interrupts */
+       I915_WRITE(RING_CONTEXT_STATUS_PTR(engine), _MASKED_FIELD(0xffff, 0));
+       if (request->ctx != port[0].request->ctx) {
+               i915_gem_request_put(port[0].request);
+               port[0] = port[1];
+               memset(&port[1], 0, sizeof(port[1]));
+       }
+
+       /* CS is stopped, and we will resubmit both ports on resume */
+       GEM_BUG_ON(request->ctx != port[0].request->ctx);
+       port[0].count = 0;
+       port[1].count = 0;
+
+       /* Reset WaIdleLiteRestore:bdw,skl as well */
+       request->tail = request->wa_tail - WA_TAIL_DWORDS * sizeof(u32);
+}
+
 static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req)
 {
        struct i915_hw_ppgtt *ppgtt = req->ctx->ppgtt;
+       struct intel_ring *ring = req->ring;
        struct intel_engine_cs *engine = req->engine;
-       struct intel_ringbuffer *ringbuf = req->ringbuf;
        const int num_lri_cmds = GEN8_LEGACY_PDPES * 2;
        int i, ret;
 
@@ -1581,28 +1347,27 @@ static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req)
        if (ret)
                return ret;
 
-       intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(num_lri_cmds));
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_lri_cmds));
        for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) {
                const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
 
-               intel_logical_ring_emit_reg(ringbuf,
-                                           GEN8_RING_PDP_UDW(engine, i));
-               intel_logical_ring_emit(ringbuf, upper_32_bits(pd_daddr));
-               intel_logical_ring_emit_reg(ringbuf,
-                                           GEN8_RING_PDP_LDW(engine, i));
-               intel_logical_ring_emit(ringbuf, lower_32_bits(pd_daddr));
+               intel_ring_emit_reg(ring, GEN8_RING_PDP_UDW(engine, i));
+               intel_ring_emit(ring, upper_32_bits(pd_daddr));
+               intel_ring_emit_reg(ring, GEN8_RING_PDP_LDW(engine, i));
+               intel_ring_emit(ring, lower_32_bits(pd_daddr));
        }
 
-       intel_logical_ring_emit(ringbuf, MI_NOOP);
-       intel_logical_ring_advance(ringbuf);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static int gen8_emit_bb_start(struct drm_i915_gem_request *req,
-                             u64 offset, unsigned dispatch_flags)
+                             u64 offset, u32 len,
+                             unsigned int dispatch_flags)
 {
-       struct intel_ringbuffer *ringbuf = req->ringbuf;
+       struct intel_ring *ring = req->ring;
        bool ppgtt = !(dispatch_flags & I915_DISPATCH_SECURE);
        int ret;
 
@@ -1629,14 +1394,14 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req,
                return ret;
 
        /* FIXME(BDW): Address space and security selectors. */
-       intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 |
-                               (ppgtt<<8) |
-                               (dispatch_flags & I915_DISPATCH_RS ?
-                                MI_BATCH_RESOURCE_STREAMER : 0));
-       intel_logical_ring_emit(ringbuf, lower_32_bits(offset));
-       intel_logical_ring_emit(ringbuf, upper_32_bits(offset));
-       intel_logical_ring_emit(ringbuf, MI_NOOP);
-       intel_logical_ring_advance(ringbuf);
+       intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 |
+                       (ppgtt<<8) |
+                       (dispatch_flags & I915_DISPATCH_RS ?
+                        MI_BATCH_RESOURCE_STREAMER : 0));
+       intel_ring_emit(ring, lower_32_bits(offset));
+       intel_ring_emit(ring, upper_32_bits(offset));
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -1655,14 +1420,10 @@ static void gen8_logical_ring_disable_irq(struct intel_engine_cs *engine)
        I915_WRITE_IMR(engine, ~engine->irq_keep_mask);
 }
 
-static int gen8_emit_flush(struct drm_i915_gem_request *request,
-                          u32 invalidate_domains,
-                          u32 unused)
+static int gen8_emit_flush(struct drm_i915_gem_request *request, u32 mode)
 {
-       struct intel_ringbuffer *ringbuf = request->ringbuf;
-       struct intel_engine_cs *engine = ringbuf->engine;
-       struct drm_i915_private *dev_priv = request->i915;
-       uint32_t cmd;
+       struct intel_ring *ring = request->ring;
+       u32 cmd;
        int ret;
 
        ret = intel_ring_begin(request, 4);
@@ -1678,30 +1439,30 @@ static int gen8_emit_flush(struct drm_i915_gem_request *request,
         */
        cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
 
-       if (invalidate_domains & I915_GEM_GPU_DOMAINS) {
+       if (mode & EMIT_INVALIDATE) {
                cmd |= MI_INVALIDATE_TLB;
-               if (engine == &dev_priv->engine[VCS])
+               if (request->engine->id == VCS)
                        cmd |= MI_INVALIDATE_BSD;
        }
 
-       intel_logical_ring_emit(ringbuf, cmd);
-       intel_logical_ring_emit(ringbuf,
-                               I915_GEM_HWS_SCRATCH_ADDR |
-                               MI_FLUSH_DW_USE_GTT);
-       intel_logical_ring_emit(ringbuf, 0); /* upper addr */
-       intel_logical_ring_emit(ringbuf, 0); /* value */
-       intel_logical_ring_advance(ringbuf);
+       intel_ring_emit(ring, cmd);
+       intel_ring_emit(ring,
+                       I915_GEM_HWS_SCRATCH_ADDR |
+                       MI_FLUSH_DW_USE_GTT);
+       intel_ring_emit(ring, 0); /* upper addr */
+       intel_ring_emit(ring, 0); /* value */
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static int gen8_emit_flush_render(struct drm_i915_gem_request *request,
-                                 u32 invalidate_domains,
-                                 u32 flush_domains)
+                                 u32 mode)
 {
-       struct intel_ringbuffer *ringbuf = request->ringbuf;
-       struct intel_engine_cs *engine = ringbuf->engine;
-       u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
+       struct intel_ring *ring = request->ring;
+       struct intel_engine_cs *engine = request->engine;
+       u32 scratch_addr =
+               i915_ggtt_offset(engine->scratch) + 2 * CACHELINE_BYTES;
        bool vf_flush_wa = false, dc_flush_wa = false;
        u32 flags = 0;
        int ret;
@@ -1709,14 +1470,14 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request,
 
        flags |= PIPE_CONTROL_CS_STALL;
 
-       if (flush_domains) {
+       if (mode & EMIT_FLUSH) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
                flags |= PIPE_CONTROL_FLUSH_ENABLE;
        }
 
-       if (invalidate_domains) {
+       if (mode & EMIT_INVALIDATE) {
                flags |= PIPE_CONTROL_TLB_INVALIDATE;
                flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
                flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
@@ -1751,40 +1512,40 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request,
                return ret;
 
        if (vf_flush_wa) {
-               intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6));
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
+               intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
        }
 
        if (dc_flush_wa) {
-               intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6));
-               intel_logical_ring_emit(ringbuf, PIPE_CONTROL_DC_FLUSH_ENABLE);
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
+               intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
+               intel_ring_emit(ring, PIPE_CONTROL_DC_FLUSH_ENABLE);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
        }
 
-       intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6));
-       intel_logical_ring_emit(ringbuf, flags);
-       intel_logical_ring_emit(ringbuf, scratch_addr);
-       intel_logical_ring_emit(ringbuf, 0);
-       intel_logical_ring_emit(ringbuf, 0);
-       intel_logical_ring_emit(ringbuf, 0);
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
+       intel_ring_emit(ring, flags);
+       intel_ring_emit(ring, scratch_addr);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, 0);
 
        if (dc_flush_wa) {
-               intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6));
-               intel_logical_ring_emit(ringbuf, PIPE_CONTROL_CS_STALL);
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
-               intel_logical_ring_emit(ringbuf, 0);
+               intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
+               intel_ring_emit(ring, PIPE_CONTROL_CS_STALL);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 0);
        }
 
-       intel_logical_ring_advance(ringbuf);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -1809,11 +1570,10 @@ static void bxt_a_seqno_barrier(struct intel_engine_cs *engine)
  * used as a workaround for not being allowed to do lite
  * restore with HEAD==TAIL (WaIdleLiteRestore).
  */
-#define WA_TAIL_DWORDS 2
 
 static int gen8_emit_request(struct drm_i915_gem_request *request)
 {
-       struct intel_ringbuffer *ringbuf = request->ringbuf;
+       struct intel_ring *ring = request->ring;
        int ret;
 
        ret = intel_ring_begin(request, 6 + WA_TAIL_DWORDS);
@@ -1823,21 +1583,20 @@ static int gen8_emit_request(struct drm_i915_gem_request *request)
        /* w/a: bit 5 needs to be zero for MI_FLUSH_DW address. */
        BUILD_BUG_ON(I915_GEM_HWS_INDEX_ADDR & (1 << 5));
 
-       intel_logical_ring_emit(ringbuf,
-                               (MI_FLUSH_DW + 1) | MI_FLUSH_DW_OP_STOREDW);
-       intel_logical_ring_emit(ringbuf,
-                               intel_hws_seqno_address(request->engine) |
-                               MI_FLUSH_DW_USE_GTT);
-       intel_logical_ring_emit(ringbuf, 0);
-       intel_logical_ring_emit(ringbuf, request->seqno);
-       intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT);
-       intel_logical_ring_emit(ringbuf, MI_NOOP);
-       return intel_logical_ring_advance_and_submit(request);
+       intel_ring_emit(ring, (MI_FLUSH_DW + 1) | MI_FLUSH_DW_OP_STOREDW);
+       intel_ring_emit(ring,
+                       intel_hws_seqno_address(request->engine) |
+                       MI_FLUSH_DW_USE_GTT);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, request->fence.seqno);
+       intel_ring_emit(ring, MI_USER_INTERRUPT);
+       intel_ring_emit(ring, MI_NOOP);
+       return intel_logical_ring_advance(request);
 }
 
 static int gen8_emit_request_render(struct drm_i915_gem_request *request)
 {
-       struct intel_ringbuffer *ringbuf = request->ringbuf;
+       struct intel_ring *ring = request->ring;
        int ret;
 
        ret = intel_ring_begin(request, 8 + WA_TAIL_DWORDS);
@@ -1851,50 +1610,19 @@ static int gen8_emit_request_render(struct drm_i915_gem_request *request)
         * need a prior CS_STALL, which is emitted by the flush
         * following the batch.
         */
-       intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6));
-       intel_logical_ring_emit(ringbuf,
-                               (PIPE_CONTROL_GLOBAL_GTT_IVB |
-                                PIPE_CONTROL_CS_STALL |
-                                PIPE_CONTROL_QW_WRITE));
-       intel_logical_ring_emit(ringbuf,
-                               intel_hws_seqno_address(request->engine));
-       intel_logical_ring_emit(ringbuf, 0);
-       intel_logical_ring_emit(ringbuf, i915_gem_request_get_seqno(request));
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
+       intel_ring_emit(ring,
+                       (PIPE_CONTROL_GLOBAL_GTT_IVB |
+                        PIPE_CONTROL_CS_STALL |
+                        PIPE_CONTROL_QW_WRITE));
+       intel_ring_emit(ring, intel_hws_seqno_address(request->engine));
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, i915_gem_request_get_seqno(request));
        /* We're thrashing one dword of HWS. */
-       intel_logical_ring_emit(ringbuf, 0);
-       intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT);
-       intel_logical_ring_emit(ringbuf, MI_NOOP);
-       return intel_logical_ring_advance_and_submit(request);
-}
-
-static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req)
-{
-       struct render_state so;
-       int ret;
-
-       ret = i915_gem_render_state_prepare(req->engine, &so);
-       if (ret)
-               return ret;
-
-       if (so.rodata == NULL)
-               return 0;
-
-       ret = req->engine->emit_bb_start(req, so.ggtt_offset,
-                                      I915_DISPATCH_SECURE);
-       if (ret)
-               goto out;
-
-       ret = req->engine->emit_bb_start(req,
-                                      (so.ggtt_offset + so.aux_batch_offset),
-                                      I915_DISPATCH_SECURE);
-       if (ret)
-               goto out;
-
-       i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req);
-
-out:
-       i915_gem_render_state_fini(&so);
-       return ret;
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_USER_INTERRUPT);
+       intel_ring_emit(ring, MI_NOOP);
+       return intel_logical_ring_advance(request);
 }
 
 static int gen8_init_rcs_context(struct drm_i915_gem_request *req)
@@ -1913,14 +1641,12 @@ static int gen8_init_rcs_context(struct drm_i915_gem_request *req)
        if (ret)
                DRM_ERROR("MOCS failed to program: expect performance issues.\n");
 
-       return intel_lr_context_render_state_init(req);
+       return i915_gem_render_state_init(req);
 }
 
 /**
  * intel_logical_ring_cleanup() - deallocate the Engine Command Streamer
- *
  * @engine: Engine Command Streamer.
- *
  */
 void intel_logical_ring_cleanup(struct intel_engine_cs *engine)
 {
@@ -1939,39 +1665,42 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *engine)
        dev_priv = engine->i915;
 
        if (engine->buffer) {
-               intel_logical_ring_stop(engine);
                WARN_ON((I915_READ_MODE(engine) & MODE_IDLE) == 0);
        }
 
        if (engine->cleanup)
                engine->cleanup(engine);
 
-       i915_cmd_parser_fini_ring(engine);
-       i915_gem_batch_pool_fini(&engine->batch_pool);
-
-       intel_engine_fini_breadcrumbs(engine);
+       intel_engine_cleanup_common(engine);
 
-       if (engine->status_page.obj) {
-               i915_gem_object_unpin_map(engine->status_page.obj);
-               engine->status_page.obj = NULL;
+       if (engine->status_page.vma) {
+               i915_gem_object_unpin_map(engine->status_page.vma->obj);
+               engine->status_page.vma = NULL;
        }
        intel_lr_context_unpin(dev_priv->kernel_context, engine);
 
-       engine->idle_lite_restore_wa = 0;
-       engine->disable_lite_restore_wa = false;
-       engine->ctx_desc_template = 0;
-
        lrc_destroy_wa_ctx_obj(engine);
        engine->i915 = NULL;
 }
 
+void intel_execlists_enable_submission(struct drm_i915_private *dev_priv)
+{
+       struct intel_engine_cs *engine;
+
+       for_each_engine(engine, dev_priv)
+               engine->submit_request = execlists_submit_request;
+}
+
 static void
 logical_ring_default_vfuncs(struct intel_engine_cs *engine)
 {
        /* Default vfuncs which can be overriden by each engine. */
        engine->init_hw = gen8_init_common_ring;
-       engine->emit_request = gen8_emit_request;
+       engine->reset_hw = reset_common_ring;
        engine->emit_flush = gen8_emit_flush;
+       engine->emit_request = gen8_emit_request;
+       engine->submit_request = execlists_submit_request;
+
        engine->irq_enable = gen8_logical_ring_enable_irq;
        engine->irq_disable = gen8_logical_ring_disable_irq;
        engine->emit_bb_start = gen8_emit_bb_start;
@@ -1980,41 +1709,71 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine)
 }
 
 static inline void
-logical_ring_default_irqs(struct intel_engine_cs *engine, unsigned shift)
+logical_ring_default_irqs(struct intel_engine_cs *engine)
 {
+       unsigned shift = engine->irq_shift;
        engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT << shift;
        engine->irq_keep_mask = GT_CONTEXT_SWITCH_INTERRUPT << shift;
 }
 
 static int
-lrc_setup_hws(struct intel_engine_cs *engine,
-             struct drm_i915_gem_object *dctx_obj)
+lrc_setup_hws(struct intel_engine_cs *engine, struct i915_vma *vma)
 {
+       const int hws_offset = LRC_PPHWSP_PN * PAGE_SIZE;
        void *hws;
 
        /* The HWSP is part of the default context object in LRC mode. */
-       engine->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj) +
-                                      LRC_PPHWSP_PN * PAGE_SIZE;
-       hws = i915_gem_object_pin_map(dctx_obj);
+       hws = i915_gem_object_pin_map(vma->obj, I915_MAP_WB);
        if (IS_ERR(hws))
                return PTR_ERR(hws);
-       engine->status_page.page_addr = hws + LRC_PPHWSP_PN * PAGE_SIZE;
-       engine->status_page.obj = dctx_obj;
+
+       engine->status_page.page_addr = hws + hws_offset;
+       engine->status_page.ggtt_offset = i915_ggtt_offset(vma) + hws_offset;
+       engine->status_page.vma = vma;
 
        return 0;
 }
 
+static void
+logical_ring_setup(struct intel_engine_cs *engine)
+{
+       struct drm_i915_private *dev_priv = engine->i915;
+       enum forcewake_domains fw_domains;
+
+       intel_engine_setup_common(engine);
+
+       /* Intentionally left blank. */
+       engine->buffer = NULL;
+
+       fw_domains = intel_uncore_forcewake_for_reg(dev_priv,
+                                                   RING_ELSP(engine),
+                                                   FW_REG_WRITE);
+
+       fw_domains |= intel_uncore_forcewake_for_reg(dev_priv,
+                                                    RING_CONTEXT_STATUS_PTR(engine),
+                                                    FW_REG_READ | FW_REG_WRITE);
+
+       fw_domains |= intel_uncore_forcewake_for_reg(dev_priv,
+                                                    RING_CONTEXT_STATUS_BUF_BASE(engine),
+                                                    FW_REG_READ);
+
+       engine->fw_domains = fw_domains;
+
+       tasklet_init(&engine->irq_tasklet,
+                    intel_lrc_irq_handler, (unsigned long)engine);
+
+       logical_ring_init_platform_invariants(engine);
+       logical_ring_default_vfuncs(engine);
+       logical_ring_default_irqs(engine);
+}
+
 static int
 logical_ring_init(struct intel_engine_cs *engine)
 {
        struct i915_gem_context *dctx = engine->i915->kernel_context;
        int ret;
 
-       ret = intel_engine_init_breadcrumbs(engine);
-       if (ret)
-               goto error;
-
-       ret = i915_cmd_parser_init_ring(engine);
+       ret = intel_engine_init_common(engine);
        if (ret)
                goto error;
 
@@ -2044,11 +1803,13 @@ error:
        return ret;
 }
 
-static int logical_render_ring_init(struct intel_engine_cs *engine)
+int logical_render_ring_init(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv = engine->i915;
        int ret;
 
+       logical_ring_setup(engine);
+
        if (HAS_L3_DPF(dev_priv))
                engine->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 
@@ -2058,11 +1819,10 @@ static int logical_render_ring_init(struct intel_engine_cs *engine)
        else
                engine->init_hw = gen8_init_render_ring;
        engine->init_context = gen8_init_rcs_context;
-       engine->cleanup = intel_fini_pipe_control;
        engine->emit_flush = gen8_emit_flush_render;
        engine->emit_request = gen8_emit_request_render;
 
-       ret = intel_init_pipe_control(engine, 4096);
+       ret = intel_engine_create_scratch(engine, 4096);
        if (ret)
                return ret;
 
@@ -2085,160 +1845,11 @@ static int logical_render_ring_init(struct intel_engine_cs *engine)
        return ret;
 }
 
-static const struct logical_ring_info {
-       const char *name;
-       unsigned exec_id;
-       unsigned guc_id;
-       u32 mmio_base;
-       unsigned irq_shift;
-       int (*init)(struct intel_engine_cs *engine);
-} logical_rings[] = {
-       [RCS] = {
-               .name = "render ring",
-               .exec_id = I915_EXEC_RENDER,
-               .guc_id = GUC_RENDER_ENGINE,
-               .mmio_base = RENDER_RING_BASE,
-               .irq_shift = GEN8_RCS_IRQ_SHIFT,
-               .init = logical_render_ring_init,
-       },
-       [BCS] = {
-               .name = "blitter ring",
-               .exec_id = I915_EXEC_BLT,
-               .guc_id = GUC_BLITTER_ENGINE,
-               .mmio_base = BLT_RING_BASE,
-               .irq_shift = GEN8_BCS_IRQ_SHIFT,
-               .init = logical_ring_init,
-       },
-       [VCS] = {
-               .name = "bsd ring",
-               .exec_id = I915_EXEC_BSD,
-               .guc_id = GUC_VIDEO_ENGINE,
-               .mmio_base = GEN6_BSD_RING_BASE,
-               .irq_shift = GEN8_VCS1_IRQ_SHIFT,
-               .init = logical_ring_init,
-       },
-       [VCS2] = {
-               .name = "bsd2 ring",
-               .exec_id = I915_EXEC_BSD,
-               .guc_id = GUC_VIDEO_ENGINE2,
-               .mmio_base = GEN8_BSD2_RING_BASE,
-               .irq_shift = GEN8_VCS2_IRQ_SHIFT,
-               .init = logical_ring_init,
-       },
-       [VECS] = {
-               .name = "video enhancement ring",
-               .exec_id = I915_EXEC_VEBOX,
-               .guc_id = GUC_VIDEOENHANCE_ENGINE,
-               .mmio_base = VEBOX_RING_BASE,
-               .irq_shift = GEN8_VECS_IRQ_SHIFT,
-               .init = logical_ring_init,
-       },
-};
-
-static struct intel_engine_cs *
-logical_ring_setup(struct drm_i915_private *dev_priv, enum intel_engine_id id)
-{
-       const struct logical_ring_info *info = &logical_rings[id];
-       struct intel_engine_cs *engine = &dev_priv->engine[id];
-       enum forcewake_domains fw_domains;
-
-       engine->id = id;
-       engine->name = info->name;
-       engine->exec_id = info->exec_id;
-       engine->guc_id = info->guc_id;
-       engine->mmio_base = info->mmio_base;
-
-       engine->i915 = dev_priv;
-
-       /* Intentionally left blank. */
-       engine->buffer = NULL;
-
-       fw_domains = intel_uncore_forcewake_for_reg(dev_priv,
-                                                   RING_ELSP(engine),
-                                                   FW_REG_WRITE);
-
-       fw_domains |= intel_uncore_forcewake_for_reg(dev_priv,
-                                                    RING_CONTEXT_STATUS_PTR(engine),
-                                                    FW_REG_READ | FW_REG_WRITE);
-
-       fw_domains |= intel_uncore_forcewake_for_reg(dev_priv,
-                                                    RING_CONTEXT_STATUS_BUF_BASE(engine),
-                                                    FW_REG_READ);
-
-       engine->fw_domains = fw_domains;
-
-       INIT_LIST_HEAD(&engine->active_list);
-       INIT_LIST_HEAD(&engine->request_list);
-       INIT_LIST_HEAD(&engine->buffers);
-       INIT_LIST_HEAD(&engine->execlist_queue);
-       spin_lock_init(&engine->execlist_lock);
-
-       tasklet_init(&engine->irq_tasklet,
-                    intel_lrc_irq_handler, (unsigned long)engine);
-
-       logical_ring_init_platform_invariants(engine);
-       logical_ring_default_vfuncs(engine);
-       logical_ring_default_irqs(engine, info->irq_shift);
-
-       intel_engine_init_hangcheck(engine);
-       i915_gem_batch_pool_init(&dev_priv->drm, &engine->batch_pool);
-
-       return engine;
-}
-
-/**
- * intel_logical_rings_init() - allocate, populate and init the Engine Command Streamers
- * @dev: DRM device.
- *
- * This function inits the engines for an Execlists submission style (the
- * equivalent in the legacy ringbuffer submission world would be
- * i915_gem_init_engines). It does it only for those engines that are present in
- * the hardware.
- *
- * Return: non-zero if the initialization failed.
- */
-int intel_logical_rings_init(struct drm_device *dev)
+int logical_xcs_ring_init(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       unsigned int mask = 0;
-       unsigned int i;
-       int ret;
-
-       WARN_ON(INTEL_INFO(dev_priv)->ring_mask &
-               GENMASK(sizeof(mask) * BITS_PER_BYTE - 1, I915_NUM_ENGINES));
-
-       for (i = 0; i < ARRAY_SIZE(logical_rings); i++) {
-               if (!HAS_ENGINE(dev_priv, i))
-                       continue;
-
-               if (!logical_rings[i].init)
-                       continue;
+       logical_ring_setup(engine);
 
-               ret = logical_rings[i].init(logical_ring_setup(dev_priv, i));
-               if (ret)
-                       goto cleanup;
-
-               mask |= ENGINE_MASK(i);
-       }
-
-       /*
-        * Catch failures to update logical_rings table when the new engines
-        * are added to the driver by a warning and disabling the forgotten
-        * engines.
-        */
-       if (WARN_ON(mask != INTEL_INFO(dev_priv)->ring_mask)) {
-               struct intel_device_info *info =
-                       (struct intel_device_info *)&dev_priv->info;
-               info->ring_mask = mask;
-       }
-
-       return 0;
-
-cleanup:
-       for (i = 0; i < I915_NUM_ENGINES; i++)
-               intel_logical_ring_cleanup(&dev_priv->engine[i]);
-
-       return ret;
+       return logical_ring_init(engine);
 }
 
 static u32
@@ -2259,24 +1870,24 @@ make_rpcs(struct drm_i915_private *dev_priv)
         * must make an explicit request through RPCS for full
         * enablement.
        */
-       if (INTEL_INFO(dev_priv)->has_slice_pg) {
+       if (INTEL_INFO(dev_priv)->sseu.has_slice_pg) {
                rpcs |= GEN8_RPCS_S_CNT_ENABLE;
-               rpcs |= INTEL_INFO(dev_priv)->slice_total <<
+               rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.slice_mask) <<
                        GEN8_RPCS_S_CNT_SHIFT;
                rpcs |= GEN8_RPCS_ENABLE;
        }
 
-       if (INTEL_INFO(dev_priv)->has_subslice_pg) {
+       if (INTEL_INFO(dev_priv)->sseu.has_subslice_pg) {
                rpcs |= GEN8_RPCS_SS_CNT_ENABLE;
-               rpcs |= INTEL_INFO(dev_priv)->subslice_per_slice <<
+               rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.subslice_mask) <<
                        GEN8_RPCS_SS_CNT_SHIFT;
                rpcs |= GEN8_RPCS_ENABLE;
        }
 
-       if (INTEL_INFO(dev_priv)->has_eu_pg) {
-               rpcs |= INTEL_INFO(dev_priv)->eu_per_subslice <<
+       if (INTEL_INFO(dev_priv)->sseu.has_eu_pg) {
+               rpcs |= INTEL_INFO(dev_priv)->sseu.eu_per_subslice <<
                        GEN8_RPCS_EU_MIN_SHIFT;
-               rpcs |= INTEL_INFO(dev_priv)->eu_per_subslice <<
+               rpcs |= INTEL_INFO(dev_priv)->sseu.eu_per_subslice <<
                        GEN8_RPCS_EU_MAX_SHIFT;
                rpcs |= GEN8_RPCS_ENABLE;
        }
@@ -2305,38 +1916,13 @@ static u32 intel_lr_indirect_ctx_offset(struct intel_engine_cs *engine)
        return indirect_ctx_offset;
 }
 
-static int
-populate_lr_context(struct i915_gem_context *ctx,
-                   struct drm_i915_gem_object *ctx_obj,
-                   struct intel_engine_cs *engine,
-                   struct intel_ringbuffer *ringbuf)
+static void execlists_init_reg_state(u32 *reg_state,
+                                    struct i915_gem_context *ctx,
+                                    struct intel_engine_cs *engine,
+                                    struct intel_ring *ring)
 {
-       struct drm_i915_private *dev_priv = ctx->i915;
-       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;
-       void *vaddr;
-       u32 *reg_state;
-       int ret;
-
-       if (!ppgtt)
-               ppgtt = dev_priv->mm.aliasing_ppgtt;
-
-       ret = i915_gem_object_set_to_cpu_domain(ctx_obj, true);
-       if (ret) {
-               DRM_DEBUG_DRIVER("Could not set to CPU domain\n");
-               return ret;
-       }
-
-       vaddr = i915_gem_object_pin_map(ctx_obj);
-       if (IS_ERR(vaddr)) {
-               ret = PTR_ERR(vaddr);
-               DRM_DEBUG_DRIVER("Could not map object pages! (%d)\n", ret);
-               return ret;
-       }
-       ctx_obj->dirty = true;
-
-       /* The second page of the context object contains some fields which must
-        * be set up prior to the first execution. */
-       reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE;
+       struct drm_i915_private *dev_priv = engine->i915;
+       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt ?: dev_priv->mm.aliasing_ppgtt;
 
        /* A context is actually a big batch buffer with several MI_LOAD_REGISTER_IMM
         * commands followed by (reg, value) pairs. The values we are setting here are
@@ -2350,19 +1936,16 @@ populate_lr_context(struct i915_gem_context *ctx,
                       _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
                                          CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
                                          (HAS_RESOURCE_STREAMER(dev_priv) ?
-                                           CTX_CTRL_RS_CTX_ENABLE : 0)));
+                                          CTX_CTRL_RS_CTX_ENABLE : 0)));
        ASSIGN_CTX_REG(reg_state, CTX_RING_HEAD, RING_HEAD(engine->mmio_base),
                       0);
        ASSIGN_CTX_REG(reg_state, CTX_RING_TAIL, RING_TAIL(engine->mmio_base),
                       0);
-       /* Ring buffer start address is not known until the buffer is pinned.
-        * It is written to the context image in execlists_update_context()
-        */
        ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_START,
                       RING_START(engine->mmio_base), 0);
        ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_CONTROL,
                       RING_CTL(engine->mmio_base),
-                      ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID);
+                      ((ring->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID);
        ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_U,
                       RING_BBADDR_UDW(engine->mmio_base), 0);
        ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_L,
@@ -2383,9 +1966,9 @@ populate_lr_context(struct i915_gem_context *ctx,
                               RING_INDIRECT_CTX(engine->mmio_base), 0);
                ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX_OFFSET,
                               RING_INDIRECT_CTX_OFFSET(engine->mmio_base), 0);
-               if (engine->wa_ctx.obj) {
+               if (engine->wa_ctx.vma) {
                        struct i915_ctx_workarounds *wa_ctx = &engine->wa_ctx;
-                       uint32_t ggtt_offset = i915_gem_obj_ggtt_offset(wa_ctx->obj);
+                       u32 ggtt_offset = i915_ggtt_offset(wa_ctx->vma);
 
                        reg_state[CTX_RCS_INDIRECT_CTX+1] =
                                (ggtt_offset + wa_ctx->indirect_ctx.offset * sizeof(uint32_t)) |
@@ -2440,6 +2023,36 @@ populate_lr_context(struct i915_gem_context *ctx,
                ASSIGN_CTX_REG(reg_state, CTX_R_PWR_CLK_STATE, GEN8_R_PWR_CLK_STATE,
                               make_rpcs(dev_priv));
        }
+}
+
+static int
+populate_lr_context(struct i915_gem_context *ctx,
+                   struct drm_i915_gem_object *ctx_obj,
+                   struct intel_engine_cs *engine,
+                   struct intel_ring *ring)
+{
+       void *vaddr;
+       int ret;
+
+       ret = i915_gem_object_set_to_cpu_domain(ctx_obj, true);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Could not set to CPU domain\n");
+               return ret;
+       }
+
+       vaddr = i915_gem_object_pin_map(ctx_obj, I915_MAP_WB);
+       if (IS_ERR(vaddr)) {
+               ret = PTR_ERR(vaddr);
+               DRM_DEBUG_DRIVER("Could not map object pages! (%d)\n", ret);
+               return ret;
+       }
+       ctx_obj->dirty = true;
+
+       /* The second page of the context object contains some fields which must
+        * be set up prior to the first execution. */
+
+       execlists_init_reg_state(vaddr + LRC_STATE_PN * PAGE_SIZE,
+                                ctx, engine, ring);
 
        i915_gem_object_unpin_map(ctx_obj);
 
@@ -2484,26 +2097,14 @@ uint32_t intel_lr_context_size(struct intel_engine_cs *engine)
        return ret;
 }
 
-/**
- * execlists_context_deferred_alloc() - create the LRC specific bits of a context
- * @ctx: LR context to create.
- * @engine: engine to be used with the context.
- *
- * This function can be called more than once, with different engines, if we plan
- * to use the context with them. The context backing objects and the ringbuffers
- * (specially the ringbuffer backing objects) suck a lot of memory up, and that's why
- * the creation is a deferred call: it's better to make sure first that we need to use
- * a given ring with the context.
- *
- * Return: non-zero on error.
- */
 static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
                                            struct intel_engine_cs *engine)
 {
        struct drm_i915_gem_object *ctx_obj;
        struct intel_context *ce = &ctx->engine[engine->id];
+       struct i915_vma *vma;
        uint32_t context_size;
-       struct intel_ringbuffer *ringbuf;
+       struct intel_ring *ring;
        int ret;
 
        WARN_ON(ce->state);
@@ -2519,60 +2120,63 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
                return PTR_ERR(ctx_obj);
        }
 
-       ringbuf = intel_engine_create_ringbuffer(engine, ctx->ring_size);
-       if (IS_ERR(ringbuf)) {
-               ret = PTR_ERR(ringbuf);
+       vma = i915_vma_create(ctx_obj, &ctx->i915->ggtt.base, NULL);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
+               goto error_deref_obj;
+       }
+
+       ring = intel_engine_create_ring(engine, ctx->ring_size);
+       if (IS_ERR(ring)) {
+               ret = PTR_ERR(ring);
                goto error_deref_obj;
        }
 
-       ret = populate_lr_context(ctx, ctx_obj, engine, ringbuf);
+       ret = populate_lr_context(ctx, ctx_obj, engine, ring);
        if (ret) {
                DRM_DEBUG_DRIVER("Failed to populate LRC: %d\n", ret);
-               goto error_ringbuf;
+               goto error_ring_free;
        }
 
-       ce->ringbuf = ringbuf;
-       ce->state = ctx_obj;
+       ce->ring = ring;
+       ce->state = vma;
        ce->initialised = engine->init_context == NULL;
 
        return 0;
 
-error_ringbuf:
-       intel_ringbuffer_free(ringbuf);
+error_ring_free:
+       intel_ring_free(ring);
 error_deref_obj:
-       drm_gem_object_unreference(&ctx_obj->base);
-       ce->ringbuf = NULL;
-       ce->state = NULL;
+       i915_gem_object_put(ctx_obj);
        return ret;
 }
 
-void intel_lr_context_reset(struct drm_i915_private *dev_priv,
-                           struct i915_gem_context *ctx)
+void intel_lr_context_resume(struct drm_i915_private *dev_priv)
 {
+       struct i915_gem_context *ctx = dev_priv->kernel_context;
        struct intel_engine_cs *engine;
 
        for_each_engine(engine, dev_priv) {
                struct intel_context *ce = &ctx->engine[engine->id];
-               struct drm_i915_gem_object *ctx_obj = ce->state;
                void *vaddr;
                uint32_t *reg_state;
 
-               if (!ctx_obj)
+               if (!ce->state)
                        continue;
 
-               vaddr = i915_gem_object_pin_map(ctx_obj);
+               vaddr = i915_gem_object_pin_map(ce->state->obj, I915_MAP_WB);
                if (WARN_ON(IS_ERR(vaddr)))
                        continue;
 
                reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE;
-               ctx_obj->dirty = true;
 
                reg_state[CTX_RING_HEAD+1] = 0;
                reg_state[CTX_RING_TAIL+1] = 0;
 
-               i915_gem_object_unpin_map(ctx_obj);
+               ce->state->obj->dirty = true;
+               i915_gem_object_unpin_map(ce->state->obj);
 
-               ce->ringbuf->head = 0;
-               ce->ringbuf->tail = 0;
+               ce->ring->head = 0;
+               ce->ring->tail = 0;
        }
 }
index 2b8255c..4fed816 100644 (file)
 #define GEN8_LR_CONTEXT_ALIGN 4096
 
 /* Execlists regs */
-#define RING_ELSP(ring)                                _MMIO((ring)->mmio_base + 0x230)
-#define RING_EXECLIST_STATUS_LO(ring)          _MMIO((ring)->mmio_base + 0x234)
-#define RING_EXECLIST_STATUS_HI(ring)          _MMIO((ring)->mmio_base + 0x234 + 4)
-#define RING_CONTEXT_CONTROL(ring)             _MMIO((ring)->mmio_base + 0x244)
+#define RING_ELSP(engine)                      _MMIO((engine)->mmio_base + 0x230)
+#define RING_EXECLIST_STATUS_LO(engine)                _MMIO((engine)->mmio_base + 0x234)
+#define RING_EXECLIST_STATUS_HI(engine)                _MMIO((engine)->mmio_base + 0x234 + 4)
+#define RING_CONTEXT_CONTROL(engine)           _MMIO((engine)->mmio_base + 0x244)
 #define          CTX_CTRL_INHIBIT_SYN_CTX_SWITCH       (1 << 3)
 #define          CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT   (1 << 0)
 #define   CTX_CTRL_RS_CTX_ENABLE                (1 << 1)
-#define RING_CONTEXT_STATUS_BUF_BASE(ring)     _MMIO((ring)->mmio_base + 0x370)
-#define RING_CONTEXT_STATUS_BUF_LO(ring, i)    _MMIO((ring)->mmio_base + 0x370 + (i) * 8)
-#define RING_CONTEXT_STATUS_BUF_HI(ring, i)    _MMIO((ring)->mmio_base + 0x370 + (i) * 8 + 4)
-#define RING_CONTEXT_STATUS_PTR(ring)          _MMIO((ring)->mmio_base + 0x3a0)
+#define RING_CONTEXT_STATUS_BUF_BASE(engine)   _MMIO((engine)->mmio_base + 0x370)
+#define RING_CONTEXT_STATUS_BUF_LO(engine, i)  _MMIO((engine)->mmio_base + 0x370 + (i) * 8)
+#define RING_CONTEXT_STATUS_BUF_HI(engine, i)  _MMIO((engine)->mmio_base + 0x370 + (i) * 8 + 4)
+#define RING_CONTEXT_STATUS_PTR(engine)                _MMIO((engine)->mmio_base + 0x3a0)
 
 /* The docs specify that the write pointer wraps around after 5h, "After status
  * is written out to the last available status QW at offset 5h, this pointer
@@ -67,35 +67,10 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request
 int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request);
 void intel_logical_ring_stop(struct intel_engine_cs *engine);
 void intel_logical_ring_cleanup(struct intel_engine_cs *engine);
-int intel_logical_rings_init(struct drm_device *dev);
+int logical_render_ring_init(struct intel_engine_cs *engine);
+int logical_xcs_ring_init(struct intel_engine_cs *engine);
 
-int logical_ring_flush_all_caches(struct drm_i915_gem_request *req);
-/**
- * intel_logical_ring_advance() - advance the ringbuffer tail
- * @ringbuf: Ringbuffer to advance.
- *
- * The tail is only updated in our logical ringbuffer struct.
- */
-static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf)
-{
-       ringbuf->tail &= ringbuf->size - 1;
-}
-/**
- * intel_logical_ring_emit() - write a DWORD to the ringbuffer.
- * @ringbuf: Ringbuffer to write to.
- * @data: DWORD to write.
- */
-static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
-                                          u32 data)
-{
-       iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
-       ringbuf->tail += 4;
-}
-static inline void intel_logical_ring_emit_reg(struct intel_ringbuffer *ringbuf,
-                                              i915_reg_t reg)
-{
-       intel_logical_ring_emit(ringbuf, i915_mmio_reg_offset(reg));
-}
+int intel_engines_init(struct drm_device *dev);
 
 /* Logical Ring Contexts */
 
@@ -112,19 +87,13 @@ void intel_lr_context_unpin(struct i915_gem_context *ctx,
 
 struct drm_i915_private;
 
-void intel_lr_context_reset(struct drm_i915_private *dev_priv,
-                           struct i915_gem_context *ctx);
+void intel_lr_context_resume(struct drm_i915_private *dev_priv);
 uint64_t intel_lr_context_descriptor(struct i915_gem_context *ctx,
                                     struct intel_engine_cs *engine);
 
 /* Execlists */
 int intel_sanitize_enable_execlists(struct drm_i915_private *dev_priv,
                                    int enable_execlists);
-struct i915_execbuffer_params;
-int intel_execlists_submission(struct i915_execbuffer_params *params,
-                              struct drm_i915_gem_execbuffer2 *args,
-                              struct list_head *vmas);
-
-void intel_execlists_cancel_requests(struct intel_engine_cs *engine);
+void intel_execlists_enable_submission(struct drm_i915_private *dev_priv);
 
 #endif /* _INTEL_LRC_H_ */
index 4955047..e1d47d5 100644 (file)
@@ -48,6 +48,20 @@ struct intel_lvds_connector {
        struct notifier_block lid_notifier;
 };
 
+struct intel_lvds_pps {
+       /* 100us units */
+       int t1_t2;
+       int t3;
+       int t4;
+       int t5;
+       int tx;
+
+       int divider;
+
+       int port;
+       bool powerdown_on_reset;
+};
+
 struct intel_lvds_encoder {
        struct intel_encoder base;
 
@@ -55,6 +69,9 @@ struct intel_lvds_encoder {
        i915_reg_t reg;
        u32 a3_power;
 
+       struct intel_lvds_pps init_pps;
+       u32 init_lvds_val;
+
        struct intel_lvds_connector *attached_connector;
 };
 
@@ -136,28 +153,108 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
        pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
 }
 
-static void intel_pre_enable_lvds(struct intel_encoder *encoder)
+static void intel_lvds_pps_get_hw_state(struct drm_i915_private *dev_priv,
+                                       struct intel_lvds_pps *pps)
+{
+       u32 val;
+
+       pps->powerdown_on_reset = I915_READ(PP_CONTROL(0)) & PANEL_POWER_RESET;
+
+       val = I915_READ(PP_ON_DELAYS(0));
+       pps->port = (val & PANEL_PORT_SELECT_MASK) >>
+                   PANEL_PORT_SELECT_SHIFT;
+       pps->t1_t2 = (val & PANEL_POWER_UP_DELAY_MASK) >>
+                    PANEL_POWER_UP_DELAY_SHIFT;
+       pps->t5 = (val & PANEL_LIGHT_ON_DELAY_MASK) >>
+                 PANEL_LIGHT_ON_DELAY_SHIFT;
+
+       val = I915_READ(PP_OFF_DELAYS(0));
+       pps->t3 = (val & PANEL_POWER_DOWN_DELAY_MASK) >>
+                 PANEL_POWER_DOWN_DELAY_SHIFT;
+       pps->tx = (val & PANEL_LIGHT_OFF_DELAY_MASK) >>
+                 PANEL_LIGHT_OFF_DELAY_SHIFT;
+
+       val = I915_READ(PP_DIVISOR(0));
+       pps->divider = (val & PP_REFERENCE_DIVIDER_MASK) >>
+                      PP_REFERENCE_DIVIDER_SHIFT;
+       val = (val & PANEL_POWER_CYCLE_DELAY_MASK) >>
+             PANEL_POWER_CYCLE_DELAY_SHIFT;
+       /*
+        * Remove the BSpec specified +1 (100ms) offset that accounts for a
+        * too short power-cycle delay due to the asynchronous programming of
+        * the register.
+        */
+       if (val)
+               val--;
+       /* Convert from 100ms to 100us units */
+       pps->t4 = val * 1000;
+
+       if (INTEL_INFO(dev_priv)->gen <= 4 &&
+           pps->t1_t2 == 0 && pps->t5 == 0 && pps->t3 == 0 && pps->tx == 0) {
+               DRM_DEBUG_KMS("Panel power timings uninitialized, "
+                             "setting defaults\n");
+               /* Set T2 to 40ms and T5 to 200ms in 100 usec units */
+               pps->t1_t2 = 40 * 10;
+               pps->t5 = 200 * 10;
+               /* Set T3 to 35ms and Tx to 200ms in 100 usec units */
+               pps->t3 = 35 * 10;
+               pps->tx = 200 * 10;
+       }
+
+       DRM_DEBUG_DRIVER("LVDS PPS:t1+t2 %d t3 %d t4 %d t5 %d tx %d "
+                        "divider %d port %d powerdown_on_reset %d\n",
+                        pps->t1_t2, pps->t3, pps->t4, pps->t5, pps->tx,
+                        pps->divider, pps->port, pps->powerdown_on_reset);
+}
+
+static void intel_lvds_pps_init_hw(struct drm_i915_private *dev_priv,
+                                  struct intel_lvds_pps *pps)
+{
+       u32 val;
+
+       val = I915_READ(PP_CONTROL(0));
+       WARN_ON((val & PANEL_UNLOCK_MASK) != PANEL_UNLOCK_REGS);
+       if (pps->powerdown_on_reset)
+               val |= PANEL_POWER_RESET;
+       I915_WRITE(PP_CONTROL(0), val);
+
+       I915_WRITE(PP_ON_DELAYS(0), (pps->port << PANEL_PORT_SELECT_SHIFT) |
+                                   (pps->t1_t2 << PANEL_POWER_UP_DELAY_SHIFT) |
+                                   (pps->t5 << PANEL_LIGHT_ON_DELAY_SHIFT));
+       I915_WRITE(PP_OFF_DELAYS(0), (pps->t3 << PANEL_POWER_DOWN_DELAY_SHIFT) |
+                                    (pps->tx << PANEL_LIGHT_OFF_DELAY_SHIFT));
+
+       val = pps->divider << PP_REFERENCE_DIVIDER_SHIFT;
+       val |= (DIV_ROUND_UP(pps->t4, 1000) + 1) <<
+              PANEL_POWER_CYCLE_DELAY_SHIFT;
+       I915_WRITE(PP_DIVISOR(0), val);
+}
+
+static void intel_pre_enable_lvds(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *pipe_config,
+                                 struct drm_connector_state *conn_state)
 {
        struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        int pipe = crtc->pipe;
        u32 temp;
 
-       if (HAS_PCH_SPLIT(dev)) {
+       if (HAS_PCH_SPLIT(dev_priv)) {
                assert_fdi_rx_pll_disabled(dev_priv, pipe);
                assert_shared_dpll_disabled(dev_priv,
-                                           crtc->config->shared_dpll);
+                                           pipe_config->shared_dpll);
        } else {
                assert_pll_disabled(dev_priv, pipe);
        }
 
-       temp = I915_READ(lvds_encoder->reg);
+       intel_lvds_pps_init_hw(dev_priv, &lvds_encoder->init_pps);
+
+       temp = lvds_encoder->init_lvds_val;
        temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
 
-       if (HAS_PCH_CPT(dev)) {
+       if (HAS_PCH_CPT(dev_priv)) {
                temp &= ~PORT_TRANS_SEL_MASK;
                temp |= PORT_TRANS_SEL_CPT(pipe);
        } else {
@@ -170,7 +267,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
 
        /* set the corresponsding LVDS_BORDER bit */
        temp &= ~LVDS_BORDER_ENABLE;
-       temp |= crtc->config->gmch_pfit.lvds_border_bits;
+       temp |= pipe_config->gmch_pfit.lvds_border_bits;
        /* Set the B0-B3 data pairs corresponding to whether we're going to
         * set the DPLLs for dual-channel mode or not.
         */
@@ -193,7 +290,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
        if (IS_GEN4(dev_priv)) {
                /* Bspec wording suggests that LVDS port dithering only exists
                 * for 18bpp panels. */
-               if (crtc->config->dither && crtc->config->pipe_bpp == 18)
+               if (pipe_config->dither && pipe_config->pipe_bpp == 18)
                        temp |= LVDS_ENABLE_DITHER;
                else
                        temp &= ~LVDS_ENABLE_DITHER;
@@ -210,57 +307,45 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
 /**
  * Sets the power state for the panel.
  */
-static void intel_enable_lvds(struct intel_encoder *encoder)
+static void intel_enable_lvds(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config,
+                             struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
        struct intel_connector *intel_connector =
                &lvds_encoder->attached_connector->base;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       i915_reg_t ctl_reg, stat_reg;
-
-       if (HAS_PCH_SPLIT(dev)) {
-               ctl_reg = PCH_PP_CONTROL;
-               stat_reg = PCH_PP_STATUS;
-       } else {
-               ctl_reg = PP_CONTROL;
-               stat_reg = PP_STATUS;
-       }
 
        I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) | LVDS_PORT_EN);
 
-       I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
+       I915_WRITE(PP_CONTROL(0), I915_READ(PP_CONTROL(0)) | PANEL_POWER_ON);
        POSTING_READ(lvds_encoder->reg);
-       if (intel_wait_for_register(dev_priv, stat_reg, PP_ON, PP_ON, 1000))
+       if (intel_wait_for_register(dev_priv, PP_STATUS(0), PP_ON, PP_ON, 1000))
                DRM_ERROR("timed out waiting for panel to power on\n");
 
        intel_panel_enable_backlight(intel_connector);
 }
 
-static void intel_disable_lvds(struct intel_encoder *encoder)
+static void intel_disable_lvds(struct intel_encoder *encoder,
+                              struct intel_crtc_state *old_crtc_state,
+                              struct drm_connector_state *old_conn_state)
 {
-       struct drm_device *dev = encoder->base.dev;
        struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       i915_reg_t ctl_reg, stat_reg;
-
-       if (HAS_PCH_SPLIT(dev)) {
-               ctl_reg = PCH_PP_CONTROL;
-               stat_reg = PCH_PP_STATUS;
-       } else {
-               ctl_reg = PP_CONTROL;
-               stat_reg = PP_STATUS;
-       }
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 
-       I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
-       if (intel_wait_for_register(dev_priv, stat_reg, PP_ON, 0, 1000))
+       I915_WRITE(PP_CONTROL(0), I915_READ(PP_CONTROL(0)) & ~PANEL_POWER_ON);
+       if (intel_wait_for_register(dev_priv, PP_STATUS(0), PP_ON, 0, 1000))
                DRM_ERROR("timed out waiting for panel to power off\n");
 
        I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) & ~LVDS_PORT_EN);
        POSTING_READ(lvds_encoder->reg);
 }
 
-static void gmch_disable_lvds(struct intel_encoder *encoder)
+static void gmch_disable_lvds(struct intel_encoder *encoder,
+                             struct intel_crtc_state *old_crtc_state,
+                             struct drm_connector_state *old_conn_state)
+
 {
        struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
        struct intel_connector *intel_connector =
@@ -268,10 +353,12 @@ static void gmch_disable_lvds(struct intel_encoder *encoder)
 
        intel_panel_disable_backlight(intel_connector);
 
-       intel_disable_lvds(encoder);
+       intel_disable_lvds(encoder, old_crtc_state, old_conn_state);
 }
 
-static void pch_disable_lvds(struct intel_encoder *encoder)
+static void pch_disable_lvds(struct intel_encoder *encoder,
+                            struct intel_crtc_state *old_crtc_state,
+                            struct drm_connector_state *old_conn_state)
 {
        struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
        struct intel_connector *intel_connector =
@@ -280,9 +367,11 @@ static void pch_disable_lvds(struct intel_encoder *encoder)
        intel_panel_disable_backlight(intel_connector);
 }
 
-static void pch_post_disable_lvds(struct intel_encoder *encoder)
+static void pch_post_disable_lvds(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *old_crtc_state,
+                                 struct drm_connector_state *old_conn_state)
 {
-       intel_disable_lvds(encoder);
+       intel_disable_lvds(encoder, old_crtc_state, old_conn_state);
 }
 
 static enum drm_mode_status
@@ -304,7 +393,8 @@ intel_lvds_mode_valid(struct drm_connector *connector,
 }
 
 static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
-                                     struct intel_crtc_state *pipe_config)
+                                     struct intel_crtc_state *pipe_config,
+                                     struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = intel_encoder->base.dev;
        struct intel_lvds_encoder *lvds_encoder =
@@ -900,17 +990,6 @@ void intel_lvds_init(struct drm_device *dev)
        int pipe;
        u8 pin;
 
-       /*
-        * Unlock registers and just leave them unlocked. Do this before
-        * checking quirk lists to avoid bogus WARNINGs.
-        */
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_PP_CONTROL,
-                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
-       } else if (INTEL_INFO(dev_priv)->gen < 5) {
-               I915_WRITE(PP_CONTROL,
-                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
-       }
        if (!intel_lvds_supported(dev))
                return;
 
@@ -943,18 +1022,6 @@ void intel_lvds_init(struct drm_device *dev)
                DRM_DEBUG_KMS("LVDS is not present in VBT, but enabled anyway\n");
        }
 
-        /* Set the Panel Power On/Off timings if uninitialized. */
-       if (INTEL_INFO(dev_priv)->gen < 5 &&
-           I915_READ(PP_ON_DELAYS) == 0 && I915_READ(PP_OFF_DELAYS) == 0) {
-               /* Set T2 to 40ms and T5 to 200ms */
-               I915_WRITE(PP_ON_DELAYS, 0x019007d0);
-
-               /* Set T3 to 35ms and Tx to 200ms */
-               I915_WRITE(PP_OFF_DELAYS, 0x015e07d0);
-
-               DRM_DEBUG_KMS("Panel power timings uninitialized, setting defaults\n");
-       }
-
        lvds_encoder = kzalloc(sizeof(*lvds_encoder), GFP_KERNEL);
        if (!lvds_encoder)
                return;
@@ -1020,6 +1087,10 @@ void intel_lvds_init(struct drm_device *dev)
                                      dev->mode_config.scaling_mode_property,
                                      DRM_MODE_SCALE_ASPECT);
        intel_connector->panel.fitting_mode = DRM_MODE_SCALE_ASPECT;
+
+       intel_lvds_pps_get_hw_state(dev_priv, &lvds_encoder->init_pps);
+       lvds_encoder->init_lvds_val = lvds;
+
        /*
         * LVDS discovery:
         * 1) check for EDID on DDC
@@ -1054,17 +1125,6 @@ void intel_lvds_init(struct drm_device *dev)
        }
        lvds_connector->base.edid = edid;
 
-       if (IS_ERR_OR_NULL(edid)) {
-               /* Didn't get an EDID, so
-                * Set wide sync ranges so we get all modes
-                * handed to valid_mode for checking
-                */
-               connector->display_info.min_vfreq = 0;
-               connector->display_info.max_vfreq = 200;
-               connector->display_info.min_hfreq = 0;
-               connector->display_info.max_hfreq = 200;
-       }
-
        list_for_each_entry(scan, &connector->probed_modes, head) {
                if (scan->type & DRM_MODE_TYPE_PREFERRED) {
                        DRM_DEBUG_KMS("using preferred mode from EDID: ");
index 927825f..80bb924 100644 (file)
@@ -97,7 +97,8 @@ struct drm_i915_mocs_table {
  *       end.
  */
 static const struct drm_i915_mocs_entry skylake_mocs_table[] = {
-       { /* 0x00000009 */
+       [I915_MOCS_UNCACHED] = {
+         /* 0x00000009 */
          .control_value = LE_CACHEABILITY(LE_UC) |
                           LE_TGT_CACHE(LE_TC_LLC_ELLC) |
                           LE_LRUM(0) | LE_AOM(0) | LE_RSC(0) | LE_SCC(0) |
@@ -106,7 +107,7 @@ static const struct drm_i915_mocs_entry skylake_mocs_table[] = {
          /* 0x0010 */
          .l3cc_value =    L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC),
        },
-       {
+       [I915_MOCS_PTE] = {
          /* 0x00000038 */
          .control_value = LE_CACHEABILITY(LE_PAGETABLE) |
                           LE_TGT_CACHE(LE_TC_LLC_ELLC) |
@@ -115,7 +116,7 @@ static const struct drm_i915_mocs_entry skylake_mocs_table[] = {
          /* 0x0030 */
          .l3cc_value =    L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB),
        },
-       {
+       [I915_MOCS_CACHED] = {
          /* 0x0000003b */
          .control_value = LE_CACHEABILITY(LE_WB) |
                           LE_TGT_CACHE(LE_TC_LLC_ELLC) |
@@ -128,7 +129,7 @@ static const struct drm_i915_mocs_entry skylake_mocs_table[] = {
 
 /* NOTE: the LE_TGT_CACHE is not used on Broxton */
 static const struct drm_i915_mocs_entry broxton_mocs_table[] = {
-       {
+       [I915_MOCS_UNCACHED] = {
          /* 0x00000009 */
          .control_value = LE_CACHEABILITY(LE_UC) |
                           LE_TGT_CACHE(LE_TC_LLC_ELLC) |
@@ -138,7 +139,7 @@ static const struct drm_i915_mocs_entry broxton_mocs_table[] = {
          /* 0x0010 */
          .l3cc_value =    L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC),
        },
-       {
+       [I915_MOCS_PTE] = {
          /* 0x00000038 */
          .control_value = LE_CACHEABILITY(LE_PAGETABLE) |
                           LE_TGT_CACHE(LE_TC_LLC_ELLC) |
@@ -148,7 +149,7 @@ static const struct drm_i915_mocs_entry broxton_mocs_table[] = {
          /* 0x0030 */
          .l3cc_value =    L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB),
        },
-       {
+       [I915_MOCS_CACHED] = {
          /* 0x00000039 */
          .control_value = LE_CACHEABILITY(LE_UC) |
                           LE_TGT_CACHE(LE_TC_LLC_ELLC) |
@@ -203,9 +204,9 @@ static bool get_mocs_settings(struct drm_i915_private *dev_priv,
        return result;
 }
 
-static i915_reg_t mocs_register(enum intel_engine_id ring, int index)
+static i915_reg_t mocs_register(enum intel_engine_id engine_id, int index)
 {
-       switch (ring) {
+       switch (engine_id) {
        case RCS:
                return GEN9_GFX_MOCS(index);
        case VCS:
@@ -217,7 +218,7 @@ static i915_reg_t mocs_register(enum intel_engine_id ring, int index)
        case VCS2:
                return GEN9_MFX1_MOCS(index);
        default:
-               MISSING_CASE(ring);
+               MISSING_CASE(engine_id);
                return INVALID_MMIO_REG;
        }
 }
@@ -275,7 +276,7 @@ int intel_mocs_init_engine(struct intel_engine_cs *engine)
 static int emit_mocs_control_table(struct drm_i915_gem_request *req,
                                   const struct drm_i915_mocs_table *table)
 {
-       struct intel_ringbuffer *ringbuf = req->ringbuf;
+       struct intel_ring *ring = req->ring;
        enum intel_engine_id engine = req->engine->id;
        unsigned int index;
        int ret;
@@ -287,14 +288,11 @@ static int emit_mocs_control_table(struct drm_i915_gem_request *req,
        if (ret)
                return ret;
 
-       intel_logical_ring_emit(ringbuf,
-                               MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
 
        for (index = 0; index < table->size; index++) {
-               intel_logical_ring_emit_reg(ringbuf,
-                                           mocs_register(engine, index));
-               intel_logical_ring_emit(ringbuf,
-                                       table->table[index].control_value);
+               intel_ring_emit_reg(ring, mocs_register(engine, index));
+               intel_ring_emit(ring, table->table[index].control_value);
        }
 
        /*
@@ -306,14 +304,12 @@ static int emit_mocs_control_table(struct drm_i915_gem_request *req,
         * that value to all the used entries.
         */
        for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
-               intel_logical_ring_emit_reg(ringbuf,
-                                           mocs_register(engine, index));
-               intel_logical_ring_emit(ringbuf,
-                                       table->table[0].control_value);
+               intel_ring_emit_reg(ring, mocs_register(engine, index));
+               intel_ring_emit(ring, table->table[0].control_value);
        }
 
-       intel_logical_ring_emit(ringbuf, MI_NOOP);
-       intel_logical_ring_advance(ringbuf);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -340,7 +336,7 @@ static inline u32 l3cc_combine(const struct drm_i915_mocs_table *table,
 static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
                                const struct drm_i915_mocs_table *table)
 {
-       struct intel_ringbuffer *ringbuf = req->ringbuf;
+       struct intel_ring *ring = req->ring;
        unsigned int i;
        int ret;
 
@@ -351,19 +347,18 @@ static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
        if (ret)
                return ret;
 
-       intel_logical_ring_emit(ringbuf,
+       intel_ring_emit(ring,
                        MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
 
        for (i = 0; i < table->size/2; i++) {
-               intel_logical_ring_emit_reg(ringbuf, GEN9_LNCFCMOCS(i));
-               intel_logical_ring_emit(ringbuf,
-                                       l3cc_combine(table, 2*i, 2*i+1));
+               intel_ring_emit_reg(ring, GEN9_LNCFCMOCS(i));
+               intel_ring_emit(ring, l3cc_combine(table, 2*i, 2*i+1));
        }
 
        if (table->size & 0x01) {
                /* Odd table size - 1 left over */
-               intel_logical_ring_emit_reg(ringbuf, GEN9_LNCFCMOCS(i));
-               intel_logical_ring_emit(ringbuf, l3cc_combine(table, 2*i, 0));
+               intel_ring_emit_reg(ring, GEN9_LNCFCMOCS(i));
+               intel_ring_emit(ring, l3cc_combine(table, 2*i, 0));
                i++;
        }
 
@@ -373,12 +368,12 @@ static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
         * they are reserved by the hardware.
         */
        for (; i < GEN9_NUM_MOCS_ENTRIES / 2; i++) {
-               intel_logical_ring_emit_reg(ringbuf, GEN9_LNCFCMOCS(i));
-               intel_logical_ring_emit(ringbuf, l3cc_combine(table, 0, 0));
+               intel_ring_emit_reg(ring, GEN9_LNCFCMOCS(i));
+               intel_ring_emit(ring, l3cc_combine(table, 0, 0));
        }
 
-       intel_logical_ring_emit(ringbuf, MI_NOOP);
-       intel_logical_ring_advance(ringbuf);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
index 4640299..a8bd9f7 100644 (file)
@@ -54,6 +54,6 @@
 
 int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req);
 void intel_mocs_init_l3cc_table(struct drm_device *dev);
-int intel_mocs_init_engine(struct intel_engine_cs *ring);
+int intel_mocs_init_engine(struct intel_engine_cs *engine);
 
 #endif
index f2584d0..951e834 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/fb.h>
 #include <drm/drm_edid.h>
 #include <drm/drmP.h>
 #include "intel_drv.h"
index 3212d88..a24bc8c 100644 (file)
@@ -30,6 +30,7 @@
 #include "i915_drv.h"
 #include "i915_reg.h"
 #include "intel_drv.h"
+#include "intel_frontbuffer.h"
 
 /* Limits for overlay size. According to intel doc, the real limits are:
  * Y width: 4095, UV width (planar): 2047, Y height: 2047,
@@ -170,8 +171,8 @@ struct overlay_registers {
 struct intel_overlay {
        struct drm_i915_private *i915;
        struct intel_crtc *crtc;
-       struct drm_i915_gem_object *vid_bo;
-       struct drm_i915_gem_object *old_vid_bo;
+       struct i915_vma *vma;
+       struct i915_vma *old_vma;
        bool active;
        bool pfit_active;
        u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
@@ -183,8 +184,7 @@ struct intel_overlay {
        u32 flip_addr;
        struct drm_i915_gem_object *reg_bo;
        /* flip handling */
-       struct drm_i915_gem_request *last_flip_req;
-       void (*flip_tail)(struct intel_overlay *);
+       struct i915_gem_active last_flip;
 };
 
 static struct overlay_registers __iomem *
@@ -196,7 +196,7 @@ intel_overlay_map_regs(struct intel_overlay *overlay)
        if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
                regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr;
        else
-               regs = io_mapping_map_wc(dev_priv->ggtt.mappable,
+               regs = io_mapping_map_wc(&dev_priv->ggtt.mappable,
                                         overlay->flip_addr,
                                         PAGE_SIZE);
 
@@ -210,37 +210,46 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
                io_mapping_unmap(regs);
 }
 
-static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
+static void intel_overlay_submit_request(struct intel_overlay *overlay,
                                         struct drm_i915_gem_request *req,
-                                        void (*tail)(struct intel_overlay *))
+                                        i915_gem_retire_fn retire)
 {
-       int ret;
-
-       WARN_ON(overlay->last_flip_req);
-       i915_gem_request_assign(&overlay->last_flip_req, req);
+       GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip,
+                                       &overlay->i915->drm.struct_mutex));
+       overlay->last_flip.retire = retire;
+       i915_gem_active_set(&overlay->last_flip, req);
        i915_add_request(req);
+}
 
-       overlay->flip_tail = tail;
-       ret = i915_wait_request(overlay->last_flip_req);
-       if (ret)
-               return ret;
+static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
+                                        struct drm_i915_gem_request *req,
+                                        i915_gem_retire_fn retire)
+{
+       intel_overlay_submit_request(overlay, req, retire);
+       return i915_gem_active_retire(&overlay->last_flip,
+                                     &overlay->i915->drm.struct_mutex);
+}
 
-       i915_gem_request_assign(&overlay->last_flip_req, NULL);
-       return 0;
+static struct drm_i915_gem_request *alloc_request(struct intel_overlay *overlay)
+{
+       struct drm_i915_private *dev_priv = overlay->i915;
+       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
+
+       return i915_gem_request_alloc(engine, dev_priv->kernel_context);
 }
 
 /* overlay needs to be disable in OCMD reg */
 static int intel_overlay_on(struct intel_overlay *overlay)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
-       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
        struct drm_i915_gem_request *req;
+       struct intel_ring *ring;
        int ret;
 
        WARN_ON(overlay->active);
        WARN_ON(IS_I830(dev_priv) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
 
-       req = i915_gem_request_alloc(engine, NULL);
+       req = alloc_request(overlay);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
@@ -252,11 +261,12 @@ static int intel_overlay_on(struct intel_overlay *overlay)
 
        overlay->active = true;
 
-       intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
-       intel_ring_emit(engine, overlay->flip_addr | OFC_UPDATE);
-       intel_ring_emit(engine, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       ring = req->ring;
+       intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
+       intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
+       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return intel_overlay_do_wait_request(overlay, req, NULL);
 }
@@ -266,8 +276,8 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
                                  bool load_polyphase_filter)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
-       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
        struct drm_i915_gem_request *req;
+       struct intel_ring *ring;
        u32 flip_addr = overlay->flip_addr;
        u32 tmp;
        int ret;
@@ -282,7 +292,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
        if (tmp & (1 << 17))
                DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
 
-       req = i915_gem_request_alloc(engine, NULL);
+       req = alloc_request(overlay);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
@@ -292,38 +302,48 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
                return ret;
        }
 
-       intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
-       intel_ring_emit(engine, flip_addr);
-       intel_ring_advance(engine);
+       ring = req->ring;
+       intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
+       intel_ring_emit(ring, flip_addr);
+       intel_ring_advance(ring);
 
-       WARN_ON(overlay->last_flip_req);
-       i915_gem_request_assign(&overlay->last_flip_req, req);
-       i915_add_request(req);
+       intel_overlay_submit_request(overlay, req, NULL);
 
        return 0;
 }
 
-static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
+static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
+                                              struct drm_i915_gem_request *req)
 {
-       struct drm_i915_gem_object *obj = overlay->old_vid_bo;
+       struct intel_overlay *overlay =
+               container_of(active, typeof(*overlay), last_flip);
+       struct i915_vma *vma;
 
-       i915_gem_object_ggtt_unpin(obj);
-       drm_gem_object_unreference(&obj->base);
+       vma = fetch_and_zero(&overlay->old_vma);
+       if (WARN_ON(!vma))
+               return;
 
-       overlay->old_vid_bo = NULL;
+       i915_gem_track_fb(vma->obj, NULL,
+                         INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
+
+       i915_gem_object_unpin_from_display_plane(vma);
+       i915_vma_put(vma);
 }
 
-static void intel_overlay_off_tail(struct intel_overlay *overlay)
+static void intel_overlay_off_tail(struct i915_gem_active *active,
+                                  struct drm_i915_gem_request *req)
 {
-       struct drm_i915_gem_object *obj = overlay->vid_bo;
+       struct intel_overlay *overlay =
+               container_of(active, typeof(*overlay), last_flip);
+       struct i915_vma *vma;
 
        /* never have the overlay hw on without showing a frame */
-       if (WARN_ON(!obj))
+       vma = fetch_and_zero(&overlay->vma);
+       if (WARN_ON(!vma))
                return;
 
-       i915_gem_object_ggtt_unpin(obj);
-       drm_gem_object_unreference(&obj->base);
-       overlay->vid_bo = NULL;
+       i915_gem_object_unpin_from_display_plane(vma);
+       i915_vma_put(vma);
 
        overlay->crtc->overlay = NULL;
        overlay->crtc = NULL;
@@ -334,8 +354,8 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay)
 static int intel_overlay_off(struct intel_overlay *overlay)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
-       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
        struct drm_i915_gem_request *req;
+       struct intel_ring *ring;
        u32 flip_addr = overlay->flip_addr;
        int ret;
 
@@ -347,7 +367,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
         * of the hw. Do it in both cases */
        flip_addr |= OFC_UPDATE;
 
-       req = i915_gem_request_alloc(engine, NULL);
+       req = alloc_request(overlay);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
@@ -357,46 +377,36 @@ static int intel_overlay_off(struct intel_overlay *overlay)
                return ret;
        }
 
+       ring = req->ring;
        /* wait for overlay to go idle */
-       intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
-       intel_ring_emit(engine, flip_addr);
-       intel_ring_emit(engine, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+       intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
+       intel_ring_emit(ring, flip_addr);
+       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
        /* turn overlay off */
        if (IS_I830(dev_priv)) {
                /* Workaround: Don't disable the overlay fully, since otherwise
                 * it dies on the next OVERLAY_ON cmd. */
-               intel_ring_emit(engine, MI_NOOP);
-               intel_ring_emit(engine, MI_NOOP);
-               intel_ring_emit(engine, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
        } else {
-               intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
-               intel_ring_emit(engine, flip_addr);
-               intel_ring_emit(engine,
+               intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
+               intel_ring_emit(ring, flip_addr);
+               intel_ring_emit(ring,
                                MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
        }
-       intel_ring_advance(engine);
+       intel_ring_advance(ring);
 
-       return intel_overlay_do_wait_request(overlay, req, intel_overlay_off_tail);
+       return intel_overlay_do_wait_request(overlay, req,
+                                            intel_overlay_off_tail);
 }
 
 /* recover from an interruption due to a signal
  * We have to be careful not to repeat work forever an make forward progess. */
 static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
 {
-       int ret;
-
-       if (overlay->last_flip_req == NULL)
-               return 0;
-
-       ret = i915_wait_request(overlay->last_flip_req);
-       if (ret)
-               return ret;
-
-       if (overlay->flip_tail)
-               overlay->flip_tail(overlay);
-
-       i915_gem_request_assign(&overlay->last_flip_req, NULL);
-       return 0;
+       return i915_gem_active_retire(&overlay->last_flip,
+                                     &overlay->i915->drm.struct_mutex);
 }
 
 /* Wait for pending overlay flip and release old frame.
@@ -406,7 +416,6 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
 static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
-       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
        int ret;
 
        lockdep_assert_held(&dev_priv->drm.struct_mutex);
@@ -414,14 +423,15 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
        /* Only wait if there is actually an old frame to release to
         * guarantee forward progress.
         */
-       if (!overlay->old_vid_bo)
+       if (!overlay->old_vma)
                return 0;
 
        if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
                /* synchronous slowpath */
                struct drm_i915_gem_request *req;
+               struct intel_ring *ring;
 
-               req = i915_gem_request_alloc(engine, NULL);
+               req = alloc_request(overlay);
                if (IS_ERR(req))
                        return PTR_ERR(req);
 
@@ -431,22 +441,19 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
                        return ret;
                }
 
-               intel_ring_emit(engine,
+               ring = req->ring;
+               intel_ring_emit(ring,
                                MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-               intel_ring_emit(engine, MI_NOOP);
-               intel_ring_advance(engine);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_advance(ring);
 
                ret = intel_overlay_do_wait_request(overlay, req,
                                                    intel_overlay_release_old_vid_tail);
                if (ret)
                        return ret;
-       }
+       } else
+               intel_overlay_release_old_vid_tail(&overlay->last_flip, NULL);
 
-       intel_overlay_release_old_vid_tail(overlay);
-
-
-       i915_gem_track_fb(overlay->old_vid_bo, NULL,
-                         INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
        return 0;
 }
 
@@ -459,7 +466,6 @@ void intel_overlay_reset(struct drm_i915_private *dev_priv)
 
        intel_overlay_release_old_vid(overlay);
 
-       overlay->last_flip_req = NULL;
        overlay->old_xscale = 0;
        overlay->old_yscale = 0;
        overlay->crtc = NULL;
@@ -740,6 +746,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        struct drm_i915_private *dev_priv = overlay->i915;
        u32 swidth, swidthsw, sheight, ostride;
        enum pipe pipe = overlay->crtc->pipe;
+       struct i915_vma *vma;
 
        lockdep_assert_held(&dev_priv->drm.struct_mutex);
        WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
@@ -748,12 +755,12 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        if (ret != 0)
                return ret;
 
-       ret = i915_gem_object_pin_to_display_plane(new_bo, 0,
+       vma = i915_gem_object_pin_to_display_plane(new_bo, 0,
                                                   &i915_ggtt_view_normal);
-       if (ret != 0)
-               return ret;
+       if (IS_ERR(vma))
+               return PTR_ERR(vma);
 
-       ret = i915_gem_object_put_fence(new_bo);
+       ret = i915_vma_put_fence(vma);
        if (ret)
                goto out_unpin;
 
@@ -794,7 +801,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        swidth = params->src_w;
        swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width);
        sheight = params->src_h;
-       iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_Y, &regs->OBUF_0Y);
+       iowrite32(i915_ggtt_offset(vma) + params->offset_Y, &regs->OBUF_0Y);
        ostride = params->stride_Y;
 
        if (params->format & I915_OVERLAY_YUV_PLANAR) {
@@ -808,8 +815,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
                                      params->src_w/uv_hscale);
                swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
                sheight |= (params->src_h/uv_vscale) << 16;
-               iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_U, &regs->OBUF_0U);
-               iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_V, &regs->OBUF_0V);
+               iowrite32(i915_ggtt_offset(vma) + params->offset_U,
+                         &regs->OBUF_0U);
+               iowrite32(i915_ggtt_offset(vma) + params->offset_V,
+                         &regs->OBUF_0V);
                ostride |= params->stride_UV << 16;
        }
 
@@ -830,19 +839,18 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        if (ret)
                goto out_unpin;
 
-       i915_gem_track_fb(overlay->vid_bo, new_bo,
+       i915_gem_track_fb(overlay->vma->obj, new_bo,
                          INTEL_FRONTBUFFER_OVERLAY(pipe));
 
-       overlay->old_vid_bo = overlay->vid_bo;
-       overlay->vid_bo = new_bo;
+       overlay->old_vma = overlay->vma;
+       overlay->vma = vma;
 
-       intel_frontbuffer_flip(&dev_priv->drm,
-                              INTEL_FRONTBUFFER_OVERLAY(pipe));
+       intel_frontbuffer_flip(dev_priv, INTEL_FRONTBUFFER_OVERLAY(pipe));
 
        return 0;
 
 out_unpin:
-       i915_gem_object_ggtt_unpin(new_bo);
+       i915_gem_object_unpin_from_display_plane(vma);
        return ret;
 }
 
@@ -870,12 +878,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
        iowrite32(0, &regs->OCMD);
        intel_overlay_unmap_regs(overlay, regs);
 
-       ret = intel_overlay_off(overlay);
-       if (ret != 0)
-               return ret;
-
-       intel_overlay_off_tail(overlay);
-       return 0;
+       return intel_overlay_off(overlay);
 }
 
 static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
@@ -1122,9 +1125,8 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
        }
        crtc = to_intel_crtc(drmmode_crtc);
 
-       new_bo = to_intel_bo(drm_gem_object_lookup(file_priv,
-                                                  put_image_rec->bo_handle));
-       if (&new_bo->base == NULL) {
+       new_bo = i915_gem_object_lookup(file_priv, put_image_rec->bo_handle);
+       if (!new_bo) {
                ret = -ENOENT;
                goto out_free;
        }
@@ -1132,7 +1134,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
        drm_modeset_lock_all(dev);
        mutex_lock(&dev->struct_mutex);
 
-       if (new_bo->tiling_mode) {
+       if (i915_gem_object_is_tiled(new_bo)) {
                DRM_DEBUG_KMS("buffer used for overlay image can not be tiled\n");
                ret = -EINVAL;
                goto out_unlock;
@@ -1220,7 +1222,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
 out_unlock:
        mutex_unlock(&dev->struct_mutex);
        drm_modeset_unlock_all(dev);
-       drm_gem_object_unreference_unlocked(&new_bo->base);
+       i915_gem_object_put_unlocked(new_bo);
 out_free:
        kfree(params);
 
@@ -1371,6 +1373,7 @@ void intel_setup_overlay(struct drm_i915_private *dev_priv)
        struct intel_overlay *overlay;
        struct drm_i915_gem_object *reg_bo;
        struct overlay_registers __iomem *regs;
+       struct i915_vma *vma = NULL;
        int ret;
 
        if (!HAS_OVERLAY(dev_priv))
@@ -1404,12 +1407,14 @@ void intel_setup_overlay(struct drm_i915_private *dev_priv)
                }
                overlay->flip_addr = reg_bo->phys_handle->busaddr;
        } else {
-               ret = i915_gem_obj_ggtt_pin(reg_bo, PAGE_SIZE, PIN_MAPPABLE);
-               if (ret) {
+               vma = i915_gem_object_ggtt_pin(reg_bo, NULL,
+                                              0, PAGE_SIZE, PIN_MAPPABLE);
+               if (IS_ERR(vma)) {
                        DRM_ERROR("failed to pin overlay register bo\n");
+                       ret = PTR_ERR(vma);
                        goto out_free_bo;
                }
-               overlay->flip_addr = i915_gem_obj_ggtt_offset(reg_bo);
+               overlay->flip_addr = i915_ggtt_offset(vma);
 
                ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
                if (ret) {
@@ -1441,10 +1446,10 @@ void intel_setup_overlay(struct drm_i915_private *dev_priv)
        return;
 
 out_unpin_bo:
-       if (!OVERLAY_NEEDS_PHYSICAL(dev_priv))
-               i915_gem_object_ggtt_unpin(reg_bo);
+       if (vma)
+               i915_vma_unpin(vma);
 out_free_bo:
-       drm_gem_object_unreference(&reg_bo->base);
+       i915_gem_object_put(reg_bo);
 out_free:
        mutex_unlock(&dev_priv->drm.struct_mutex);
        kfree(overlay);
@@ -1461,7 +1466,7 @@ void intel_cleanup_overlay(struct drm_i915_private *dev_priv)
         * hardware should be off already */
        WARN_ON(dev_priv->overlay->active);
 
-       drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
+       i915_gem_object_put_unlocked(dev_priv->overlay->reg_bo);
        kfree(dev_priv->overlay);
 }
 
@@ -1484,7 +1489,7 @@ intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
                regs = (struct overlay_registers __iomem *)
                        overlay->reg_bo->phys_handle->vaddr;
        else
-               regs = io_mapping_map_atomic_wc(dev_priv->ggtt.mappable,
+               regs = io_mapping_map_atomic_wc(&dev_priv->ggtt.mappable,
                                                overlay->flip_addr);
 
        return regs;
index 96c65d7..be4b4d5 100644 (file)
@@ -841,7 +841,7 @@ static void lpt_enable_backlight(struct intel_connector *connector)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
        struct intel_panel *panel = &connector->panel;
-       u32 pch_ctl1, pch_ctl2;
+       u32 pch_ctl1, pch_ctl2, schicken;
 
        pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
        if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
@@ -850,6 +850,22 @@ static void lpt_enable_backlight(struct intel_connector *connector)
                I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
        }
 
+       if (HAS_PCH_LPT(dev_priv)) {
+               schicken = I915_READ(SOUTH_CHICKEN2);
+               if (panel->backlight.alternate_pwm_increment)
+                       schicken |= LPT_PWM_GRANULARITY;
+               else
+                       schicken &= ~LPT_PWM_GRANULARITY;
+               I915_WRITE(SOUTH_CHICKEN2, schicken);
+       } else {
+               schicken = I915_READ(SOUTH_CHICKEN1);
+               if (panel->backlight.alternate_pwm_increment)
+                       schicken |= SPT_PWM_GRANULARITY;
+               else
+                       schicken &= ~SPT_PWM_GRANULARITY;
+               I915_WRITE(SOUTH_CHICKEN1, schicken);
+       }
+
        pch_ctl2 = panel->backlight.max << 16;
        I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
 
@@ -1242,10 +1258,10 @@ static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
  */
 static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
 {
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
        u32 mul;
 
-       if (I915_READ(SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY)
+       if (panel->backlight.alternate_pwm_increment)
                mul = 128;
        else
                mul = 16;
@@ -1261,9 +1277,10 @@ static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
 static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_panel *panel = &connector->panel;
        u32 mul, clock;
 
-       if (I915_READ(SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY)
+       if (panel->backlight.alternate_pwm_increment)
                mul = 16;
        else
                mul = 128;
@@ -1414,6 +1431,13 @@ static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unus
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
        struct intel_panel *panel = &connector->panel;
        u32 pch_ctl1, pch_ctl2, val;
+       bool alt;
+
+       if (HAS_PCH_LPT(dev_priv))
+               alt = I915_READ(SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY;
+       else
+               alt = I915_READ(SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY;
+       panel->backlight.alternate_pwm_increment = alt;
 
        pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
        panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
@@ -1430,10 +1454,11 @@ static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unus
        panel->backlight.min = get_backlight_min_vbt(connector);
 
        val = lpt_get_backlight(connector);
-       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
 
-       panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) &&
-               panel->backlight.level != 0;
+       panel->backlight.enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
 
        return 0;
 }
@@ -1459,11 +1484,13 @@ static int pch_setup_backlight(struct intel_connector *connector, enum pipe unus
        panel->backlight.min = get_backlight_min_vbt(connector);
 
        val = pch_get_backlight(connector);
-       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
 
        cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
        panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
-               (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0;
+               (pch_ctl1 & BLM_PCH_PWM_ENABLE);
 
        return 0;
 }
@@ -1498,9 +1525,11 @@ static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unu
        panel->backlight.min = get_backlight_min_vbt(connector);
 
        val = i9xx_get_backlight(connector);
-       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
 
-       panel->backlight.enabled = panel->backlight.level != 0;
+       panel->backlight.enabled = val != 0;
 
        return 0;
 }
@@ -1530,10 +1559,11 @@ static int i965_setup_backlight(struct intel_connector *connector, enum pipe unu
        panel->backlight.min = get_backlight_min_vbt(connector);
 
        val = i9xx_get_backlight(connector);
-       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
 
-       panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
-               panel->backlight.level != 0;
+       panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
 
        return 0;
 }
@@ -1562,10 +1592,11 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
        panel->backlight.min = get_backlight_min_vbt(connector);
 
        val = _vlv_get_backlight(dev_priv, pipe);
-       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
 
-       panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
-               panel->backlight.level != 0;
+       panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
 
        return 0;
 }
@@ -1607,10 +1638,11 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
                return -ENODEV;
 
        val = bxt_get_backlight(connector);
-       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+       val = intel_panel_compute_brightness(connector, val);
+       panel->backlight.level = clamp(val, panel->backlight.min,
+                                      panel->backlight.max);
 
-       panel->backlight.enabled = (pwm_ctl & BXT_BLC_PWM_ENABLE) &&
-               panel->backlight.level != 0;
+       panel->backlight.enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
 
        return 0;
 }
index 2d24813..a2f751c 100644 (file)
@@ -340,6 +340,11 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
                I915_WRITE(FW_BLC_SELF, val);
                POSTING_READ(FW_BLC_SELF);
        } else if (IS_I915GM(dev)) {
+               /*
+                * FIXME can't find a bit like this for 915G, and
+                * and yet it does have the related watermark in
+                * FW_BLC_SELF. What's going on?
+                */
                val = enable ? _MASKED_BIT_ENABLE(INSTPM_SELF_EN) :
                               _MASKED_BIT_DISABLE(INSTPM_SELF_EN);
                I915_WRITE(INSTPM, val);
@@ -960,7 +965,7 @@ static uint16_t vlv_compute_wm_level(struct intel_plane *plane,
        if (dev_priv->wm.pri_latency[level] == 0)
                return USHRT_MAX;
 
-       if (!state->visible)
+       if (!state->base.visible)
                return 0;
 
        cpp = drm_format_plane_cpp(state->base.fb->pixel_format, 0);
@@ -1002,7 +1007,7 @@ static void vlv_compute_fifo(struct intel_crtc *crtc)
                if (plane->base.type == DRM_PLANE_TYPE_CURSOR)
                        continue;
 
-               if (state->visible) {
+               if (state->base.visible) {
                        wm_state->num_active_planes++;
                        total_rate += drm_format_plane_cpp(state->base.fb->pixel_format, 0);
                }
@@ -1018,7 +1023,7 @@ static void vlv_compute_fifo(struct intel_crtc *crtc)
                        continue;
                }
 
-               if (!state->visible) {
+               if (!state->base.visible) {
                        plane->wm.fifo_size = 0;
                        continue;
                }
@@ -1118,7 +1123,7 @@ static void vlv_compute_wm(struct intel_crtc *crtc)
                struct intel_plane_state *state =
                        to_intel_plane_state(plane->base.state);
 
-               if (!state->visible)
+               if (!state->base.visible)
                        continue;
 
                /* normal watermarks */
@@ -1580,7 +1585,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
                obj = intel_fb_obj(enabled->primary->state->fb);
 
                /* self-refresh seems busted with untiled */
-               if (obj->tiling_mode == I915_TILING_NONE)
+               if (!i915_gem_object_is_tiled(obj))
                        enabled = NULL;
        }
 
@@ -1604,6 +1609,9 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
                unsigned long line_time_us;
                int entries;
 
+               if (IS_I915GM(dev) || IS_I945GM(dev))
+                       cpp = 4;
+
                line_time_us = max(htotal * 1000 / clock, 1);
 
                /* Use ns/us then divide to preserve precision */
@@ -1618,7 +1626,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
                if (IS_I945G(dev) || IS_I945GM(dev))
                        I915_WRITE(FW_BLC_SELF,
                                   FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
-               else if (IS_I915GM(dev))
+               else
                        I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
        }
 
@@ -1767,7 +1775,7 @@ static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate,
                drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0;
        uint32_t method1, method2;
 
-       if (!cstate->base.active || !pstate->visible)
+       if (!cstate->base.active || !pstate->base.visible)
                return 0;
 
        method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), cpp, mem_value);
@@ -1777,7 +1785,7 @@ static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate,
 
        method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
                                 cstate->base.adjusted_mode.crtc_htotal,
-                                drm_rect_width(&pstate->dst),
+                                drm_rect_width(&pstate->base.dst),
                                 cpp, mem_value);
 
        return min(method1, method2);
@@ -1795,13 +1803,13 @@ static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate,
                drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0;
        uint32_t method1, method2;
 
-       if (!cstate->base.active || !pstate->visible)
+       if (!cstate->base.active || !pstate->base.visible)
                return 0;
 
        method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), cpp, mem_value);
        method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
                                 cstate->base.adjusted_mode.crtc_htotal,
-                                drm_rect_width(&pstate->dst),
+                                drm_rect_width(&pstate->base.dst),
                                 cpp, mem_value);
        return min(method1, method2);
 }
@@ -1820,7 +1828,7 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
         * this is necessary to avoid flickering.
         */
        int cpp = 4;
-       int width = pstate->visible ? pstate->base.crtc_w : 64;
+       int width = pstate->base.visible ? pstate->base.crtc_w : 64;
 
        if (!cstate->base.active)
                return 0;
@@ -1838,10 +1846,10 @@ static uint32_t ilk_compute_fbc_wm(const struct intel_crtc_state *cstate,
        int cpp = pstate->base.fb ?
                drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0;
 
-       if (!cstate->base.active || !pstate->visible)
+       if (!cstate->base.active || !pstate->base.visible)
                return 0;
 
-       return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->dst), cpp);
+       return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->base.dst), cpp);
 }
 
 static unsigned int ilk_display_fifo_size(const struct drm_device *dev)
@@ -2118,33 +2126,35 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8])
                wm[7] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) &
                                GEN9_MEM_LATENCY_LEVEL_MASK;
 
+               /*
+                * If a level n (n > 1) has a 0us latency, all levels m (m >= n)
+                * need to be disabled. We make sure to sanitize the values out
+                * of the punit to satisfy this requirement.
+                */
+               for (level = 1; level <= max_level; level++) {
+                       if (wm[level] == 0) {
+                               for (i = level + 1; i <= max_level; i++)
+                                       wm[i] = 0;
+                               break;
+                       }
+               }
+
                /*
                 * WaWmMemoryReadLatency:skl
                 *
                 * punit doesn't take into account the read latency so we need
-                * to add 2us to the various latency levels we retrieve from
-                * the punit.
-                *   - W0 is a bit special in that it's the only level that
-                *   can't be disabled if we want to have display working, so
-                *   we always add 2us there.
-                *   - For levels >=1, punit returns 0us latency when they are
-                *   disabled, so we respect that and don't add 2us then
-                *
-                * Additionally, if a level n (n > 1) has a 0us latency, all
-                * levels m (m >= n) need to be disabled. We make sure to
-                * sanitize the values out of the punit to satisfy this
-                * requirement.
+                * to add 2us to the various latency levels we retrieve from the
+                * punit when level 0 response data us 0us.
                 */
-               wm[0] += 2;
-               for (level = 1; level <= max_level; level++)
-                       if (wm[level] != 0)
+               if (wm[0] == 0) {
+                       wm[0] += 2;
+                       for (level = 1; level <= max_level; level++) {
+                               if (wm[level] == 0)
+                                       break;
                                wm[level] += 2;
-                       else {
-                               for (i = level + 1; i <= max_level; i++)
-                                       wm[i] = 0;
-
-                               break;
                        }
+               }
+
        } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                uint64_t sskpd = I915_READ64(MCH_SSKPD);
 
@@ -2358,10 +2368,10 @@ static int ilk_compute_pipe_wm(struct intel_crtc_state *cstate)
 
        pipe_wm->pipe_enabled = cstate->base.active;
        if (sprstate) {
-               pipe_wm->sprites_enabled = sprstate->visible;
-               pipe_wm->sprites_scaled = sprstate->visible &&
-                       (drm_rect_width(&sprstate->dst) != drm_rect_width(&sprstate->src) >> 16 ||
-                        drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
+               pipe_wm->sprites_enabled = sprstate->base.visible;
+               pipe_wm->sprites_scaled = sprstate->base.visible &&
+                       (drm_rect_width(&sprstate->base.dst) != drm_rect_width(&sprstate->base.src) >> 16 ||
+                        drm_rect_height(&sprstate->base.dst) != drm_rect_height(&sprstate->base.src) >> 16);
        }
 
        usable_level = max_level;
@@ -2845,13 +2855,6 @@ bool ilk_disable_lp_wm(struct drm_device *dev)
        return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
 }
 
-/*
- * On gen9, we need to allocate Display Data Buffer (DDB) portions to the
- * different active planes.
- */
-
-#define SKL_DDB_SIZE           896     /* in blocks */
-#define BXT_DDB_SIZE           512
 #define SKL_SAGV_BLOCK_TIME    30 /* µs */
 
 /*
@@ -2876,6 +2879,19 @@ skl_wm_plane_id(const struct intel_plane *plane)
        }
 }
 
+static bool
+intel_has_sagv(struct drm_i915_private *dev_priv)
+{
+       if (IS_KABYLAKE(dev_priv))
+               return true;
+
+       if (IS_SKYLAKE(dev_priv) &&
+           dev_priv->sagv_status != I915_SAGV_NOT_CONTROLLED)
+               return true;
+
+       return false;
+}
+
 /*
  * SAGV dynamically adjusts the system agent voltage and clock frequencies
  * depending on power and performance requirements. The display engine access
@@ -2888,12 +2904,14 @@ skl_wm_plane_id(const struct intel_plane *plane)
  *  - We're not using an interlaced display configuration
  */
 int
-skl_enable_sagv(struct drm_i915_private *dev_priv)
+intel_enable_sagv(struct drm_i915_private *dev_priv)
 {
        int ret;
 
-       if (dev_priv->skl_sagv_status == I915_SKL_SAGV_NOT_CONTROLLED ||
-           dev_priv->skl_sagv_status == I915_SKL_SAGV_ENABLED)
+       if (!intel_has_sagv(dev_priv))
+               return 0;
+
+       if (dev_priv->sagv_status == I915_SAGV_ENABLED)
                return 0;
 
        DRM_DEBUG_KMS("Enabling the SAGV\n");
@@ -2909,21 +2927,21 @@ skl_enable_sagv(struct drm_i915_private *dev_priv)
         * Some skl systems, pre-release machines in particular,
         * don't actually have an SAGV.
         */
-       if (ret == -ENXIO) {
+       if (IS_SKYLAKE(dev_priv) && ret == -ENXIO) {
                DRM_DEBUG_DRIVER("No SAGV found on system, ignoring\n");
-               dev_priv->skl_sagv_status = I915_SKL_SAGV_NOT_CONTROLLED;
+               dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED;
                return 0;
        } else if (ret < 0) {
                DRM_ERROR("Failed to enable the SAGV\n");
                return ret;
        }
 
-       dev_priv->skl_sagv_status = I915_SKL_SAGV_ENABLED;
+       dev_priv->sagv_status = I915_SAGV_ENABLED;
        return 0;
 }
 
 static int
-skl_do_sagv_disable(struct drm_i915_private *dev_priv)
+intel_do_sagv_disable(struct drm_i915_private *dev_priv)
 {
        int ret;
        uint32_t temp = GEN9_SAGV_DISABLE;
@@ -2937,19 +2955,21 @@ skl_do_sagv_disable(struct drm_i915_private *dev_priv)
 }
 
 int
-skl_disable_sagv(struct drm_i915_private *dev_priv)
+intel_disable_sagv(struct drm_i915_private *dev_priv)
 {
        int ret, result;
 
-       if (dev_priv->skl_sagv_status == I915_SKL_SAGV_NOT_CONTROLLED ||
-           dev_priv->skl_sagv_status == I915_SKL_SAGV_DISABLED)
+       if (!intel_has_sagv(dev_priv))
+               return 0;
+
+       if (dev_priv->sagv_status == I915_SAGV_DISABLED)
                return 0;
 
        DRM_DEBUG_KMS("Disabling the SAGV\n");
        mutex_lock(&dev_priv->rps.hw_lock);
 
        /* bspec says to keep retrying for at least 1 ms */
-       ret = wait_for(result = skl_do_sagv_disable(dev_priv), 1);
+       ret = wait_for(result = intel_do_sagv_disable(dev_priv), 1);
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        if (ret == -ETIMEDOUT) {
@@ -2961,20 +2981,20 @@ skl_disable_sagv(struct drm_i915_private *dev_priv)
         * Some skl systems, pre-release machines in particular,
         * don't actually have an SAGV.
         */
-       if (result == -ENXIO) {
+       if (IS_SKYLAKE(dev_priv) && result == -ENXIO) {
                DRM_DEBUG_DRIVER("No SAGV found on system, ignoring\n");
-               dev_priv->skl_sagv_status = I915_SKL_SAGV_NOT_CONTROLLED;
+               dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED;
                return 0;
        } else if (result < 0) {
                DRM_ERROR("Failed to disable the SAGV\n");
                return result;
        }
 
-       dev_priv->skl_sagv_status = I915_SKL_SAGV_DISABLED;
+       dev_priv->sagv_status = I915_SAGV_DISABLED;
        return 0;
 }
 
-bool skl_can_enable_sagv(struct drm_atomic_state *state)
+bool intel_can_enable_sagv(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -2983,6 +3003,9 @@ bool skl_can_enable_sagv(struct drm_atomic_state *state)
        enum pipe pipe;
        int level, plane;
 
+       if (!intel_has_sagv(dev_priv))
+               return false;
+
        /*
         * SKL workaround: bspec recommends we disable the SAGV when we have
         * more then one pipe enabled
@@ -3049,10 +3072,8 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
        else
                *num_active = hweight32(dev_priv->active_crtcs);
 
-       if (IS_BROXTON(dev))
-               ddb_size = BXT_DDB_SIZE;
-       else
-               ddb_size = SKL_DDB_SIZE;
+       ddb_size = INTEL_INFO(dev_priv)->ddb_size;
+       WARN_ON(ddb_size == 0);
 
        ddb_size -= 4; /* 4 blocks for bypass path allocation */
 
@@ -3144,14 +3165,14 @@ skl_plane_downscale_amount(const struct intel_plane_state *pstate)
        uint32_t downscale_h, downscale_w;
        uint32_t src_w, src_h, dst_w, dst_h;
 
-       if (WARN_ON(!pstate->visible))
+       if (WARN_ON(!pstate->base.visible))
                return DRM_PLANE_HELPER_NO_SCALING;
 
        /* n.b., src is 16.16 fixed point, dst is whole integer */
-       src_w = drm_rect_width(&pstate->src);
-       src_h = drm_rect_height(&pstate->src);
-       dst_w = drm_rect_width(&pstate->dst);
-       dst_h = drm_rect_height(&pstate->dst);
+       src_w = drm_rect_width(&pstate->base.src);
+       src_h = drm_rect_height(&pstate->base.src);
+       dst_w = drm_rect_width(&pstate->base.dst);
+       dst_h = drm_rect_height(&pstate->base.dst);
        if (intel_rotation_90_or_270(pstate->base.rotation))
                swap(dst_w, dst_h);
 
@@ -3173,15 +3194,15 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *cstate,
        uint32_t width = 0, height = 0;
        unsigned format = fb ? fb->pixel_format : DRM_FORMAT_XRGB8888;
 
-       if (!intel_pstate->visible)
+       if (!intel_pstate->base.visible)
                return 0;
        if (pstate->plane->type == DRM_PLANE_TYPE_CURSOR)
                return 0;
        if (y && format != DRM_FORMAT_NV12)
                return 0;
 
-       width = drm_rect_width(&intel_pstate->src) >> 16;
-       height = drm_rect_height(&intel_pstate->src) >> 16;
+       width = drm_rect_width(&intel_pstate->base.src) >> 16;
+       height = drm_rect_height(&intel_pstate->base.src) >> 16;
 
        if (intel_rotation_90_or_270(pstate->rotation))
                swap(width, height);
@@ -3280,8 +3301,8 @@ skl_ddb_min_alloc(const struct drm_plane_state *pstate,
            fb->modifier[0] != I915_FORMAT_MOD_Yf_TILED)
                return 8;
 
-       src_w = drm_rect_width(&intel_pstate->src) >> 16;
-       src_h = drm_rect_height(&intel_pstate->src) >> 16;
+       src_w = drm_rect_width(&intel_pstate->base.src) >> 16;
+       src_h = drm_rect_height(&intel_pstate->base.src) >> 16;
 
        if (intel_rotation_90_or_270(pstate->rotation))
                swap(src_w, src_h);
@@ -3372,7 +3393,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
                if (intel_plane->pipe != pipe)
                        continue;
 
-               if (!to_intel_plane_state(pstate)->visible) {
+               if (!to_intel_plane_state(pstate)->base.visible) {
                        minimum[id] = 0;
                        y_minimum[id] = 0;
                        continue;
@@ -3473,29 +3494,14 @@ static uint32_t skl_wm_method1(uint32_t pixel_rate, uint8_t cpp, uint32_t latenc
 }
 
 static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
-                              uint32_t horiz_pixels, uint8_t cpp,
-                              uint64_t tiling, uint32_t latency)
+                              uint32_t latency, uint32_t plane_blocks_per_line)
 {
        uint32_t ret;
-       uint32_t plane_bytes_per_line, plane_blocks_per_line;
        uint32_t wm_intermediate_val;
 
        if (latency == 0)
                return UINT_MAX;
 
-       plane_bytes_per_line = horiz_pixels * cpp;
-
-       if (tiling == I915_FORMAT_MOD_Y_TILED ||
-           tiling == I915_FORMAT_MOD_Yf_TILED) {
-               plane_bytes_per_line *= 4;
-               plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
-               plane_blocks_per_line /= 4;
-       } else if (tiling == DRM_FORMAT_MOD_NONE) {
-               plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512) + 1;
-       } else {
-               plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
-       }
-
        wm_intermediate_val = latency * pixel_rate;
        ret = DIV_ROUND_UP(wm_intermediate_val, pipe_htotal * 1000) *
                                plane_blocks_per_line;
@@ -3511,7 +3517,7 @@ static uint32_t skl_adjusted_plane_pixel_rate(const struct intel_crtc_state *cst
        uint64_t pixel_rate;
 
        /* Shouldn't reach here on disabled planes... */
-       if (WARN_ON(!pstate->visible))
+       if (WARN_ON(!pstate->base.visible))
                return 0;
 
        /*
@@ -3546,14 +3552,15 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
        uint8_t cpp;
        uint32_t width = 0, height = 0;
        uint32_t plane_pixel_rate;
+       uint32_t y_tile_minimum, y_min_scanlines;
 
-       if (latency == 0 || !cstate->base.active || !intel_pstate->visible) {
+       if (latency == 0 || !cstate->base.active || !intel_pstate->base.visible) {
                *enabled = false;
                return 0;
        }
 
-       width = drm_rect_width(&intel_pstate->src) >> 16;
-       height = drm_rect_height(&intel_pstate->src) >> 16;
+       width = drm_rect_width(&intel_pstate->base.src) >> 16;
+       height = drm_rect_height(&intel_pstate->base.src) >> 16;
 
        if (intel_rotation_90_or_270(pstate->rotation))
                swap(width, height);
@@ -3561,38 +3568,51 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
        cpp = drm_format_plane_cpp(fb->pixel_format, 0);
        plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate, intel_pstate);
 
+       if (intel_rotation_90_or_270(pstate->rotation)) {
+               int cpp = (fb->pixel_format == DRM_FORMAT_NV12) ?
+                       drm_format_plane_cpp(fb->pixel_format, 1) :
+                       drm_format_plane_cpp(fb->pixel_format, 0);
+
+               switch (cpp) {
+               case 1:
+                       y_min_scanlines = 16;
+                       break;
+               case 2:
+                       y_min_scanlines = 8;
+                       break;
+               default:
+                       WARN(1, "Unsupported pixel depth for rotation");
+               case 4:
+                       y_min_scanlines = 4;
+                       break;
+               }
+       } else {
+               y_min_scanlines = 4;
+       }
+
+       plane_bytes_per_line = width * cpp;
+       if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
+           fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
+               plane_blocks_per_line =
+                     DIV_ROUND_UP(plane_bytes_per_line * y_min_scanlines, 512);
+               plane_blocks_per_line /= y_min_scanlines;
+       } else if (fb->modifier[0] == DRM_FORMAT_MOD_NONE) {
+               plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512)
+                                       + 1;
+       } else {
+               plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
+       }
+
        method1 = skl_wm_method1(plane_pixel_rate, cpp, latency);
        method2 = skl_wm_method2(plane_pixel_rate,
                                 cstate->base.adjusted_mode.crtc_htotal,
-                                width,
-                                cpp,
-                                fb->modifier[0],
-                                latency);
+                                latency,
+                                plane_blocks_per_line);
 
-       plane_bytes_per_line = width * cpp;
-       plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
+       y_tile_minimum = plane_blocks_per_line * y_min_scanlines;
 
        if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
            fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
-               uint32_t min_scanlines = 4;
-               uint32_t y_tile_minimum;
-               if (intel_rotation_90_or_270(pstate->rotation)) {
-                       int cpp = (fb->pixel_format == DRM_FORMAT_NV12) ?
-                               drm_format_plane_cpp(fb->pixel_format, 1) :
-                               drm_format_plane_cpp(fb->pixel_format, 0);
-
-                       switch (cpp) {
-                       case 1:
-                               min_scanlines = 16;
-                               break;
-                       case 2:
-                               min_scanlines = 8;
-                               break;
-                       case 8:
-                               WARN(1, "Unsupported pixel depth for rotation");
-                       }
-               }
-               y_tile_minimum = plane_blocks_per_line * min_scanlines;
                selected_result = max(method2, y_tile_minimum);
        } else {
                if ((ddb_allocation / plane_blocks_per_line) >= 1)
@@ -3606,10 +3626,12 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 
        if (level >= 1 && level <= 7) {
                if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
-                   fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)
-                       res_lines += 4;
-               else
+                   fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
+                       res_blocks += y_tile_minimum;
+                       res_lines += y_min_scanlines;
+               } else {
                        res_blocks++;
+               }
        }
 
        if (res_blocks >= ddb_allocation || res_lines > 31) {
@@ -3828,183 +3850,82 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
                I915_WRITE(reg, 0);
 }
 
-static void skl_write_wm_values(struct drm_i915_private *dev_priv,
-                               const struct skl_wm_values *new)
+void skl_write_plane_wm(struct intel_crtc *intel_crtc,
+                       const struct skl_wm_values *wm,
+                       int plane)
 {
-       struct drm_device *dev = &dev_priv->drm;
-       struct intel_crtc *crtc;
-
-       for_each_intel_crtc(dev, crtc) {
-               int i, level, max_level = ilk_wm_max_level(dev);
-               enum pipe pipe = crtc->pipe;
-
-               if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
-                       continue;
-               if (!crtc->active)
-                       continue;
-
-               I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);
-
-               for (level = 0; level <= max_level; level++) {
-                       for (i = 0; i < intel_num_planes(crtc); i++)
-                               I915_WRITE(PLANE_WM(pipe, i, level),
-                                          new->plane[pipe][i][level]);
-                       I915_WRITE(CUR_WM(pipe, level),
-                                  new->plane[pipe][PLANE_CURSOR][level]);
-               }
-               for (i = 0; i < intel_num_planes(crtc); i++)
-                       I915_WRITE(PLANE_WM_TRANS(pipe, i),
-                                  new->plane_trans[pipe][i]);
-               I915_WRITE(CUR_WM_TRANS(pipe),
-                          new->plane_trans[pipe][PLANE_CURSOR]);
-
-               for (i = 0; i < intel_num_planes(crtc); i++) {
-                       skl_ddb_entry_write(dev_priv,
-                                           PLANE_BUF_CFG(pipe, i),
-                                           &new->ddb.plane[pipe][i]);
-                       skl_ddb_entry_write(dev_priv,
-                                           PLANE_NV12_BUF_CFG(pipe, i),
-                                           &new->ddb.y_plane[pipe][i]);
-               }
+       struct drm_crtc *crtc = &intel_crtc->base;
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       int level, max_level = ilk_wm_max_level(dev);
+       enum pipe pipe = intel_crtc->pipe;
 
-               skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
-                                   &new->ddb.plane[pipe][PLANE_CURSOR]);
+       for (level = 0; level <= max_level; level++) {
+               I915_WRITE(PLANE_WM(pipe, plane, level),
+                          wm->plane[pipe][plane][level]);
        }
-}
+       I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);
 
-/*
- * When setting up a new DDB allocation arrangement, we need to correctly
- * sequence the times at which the new allocations for the pipes are taken into
- * account or we'll have pipes fetching from space previously allocated to
- * another pipe.
- *
- * Roughly the sequence looks like:
- *  1. re-allocate the pipe(s) with the allocation being reduced and not
- *     overlapping with a previous light-up pipe (another way to put it is:
- *     pipes with their new allocation strickly included into their old ones).
- *  2. re-allocate the other pipes that get their allocation reduced
- *  3. allocate the pipes having their allocation increased
- *
- * Steps 1. and 2. are here to take care of the following case:
- * - Initially DDB looks like this:
- *     |   B    |   C    |
- * - enable pipe A.
- * - pipe B has a reduced DDB allocation that overlaps with the old pipe C
- *   allocation
- *     |  A  |  B  |  C  |
- *
- * We need to sequence the re-allocation: C, B, A (and not B, C, A).
- */
+       skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane),
+                           &wm->ddb.plane[pipe][plane]);
+       skl_ddb_entry_write(dev_priv, PLANE_NV12_BUF_CFG(pipe, plane),
+                           &wm->ddb.y_plane[pipe][plane]);
+}
 
-static void
-skl_wm_flush_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, int pass)
+void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
+                        const struct skl_wm_values *wm)
 {
-       int plane;
-
-       DRM_DEBUG_KMS("flush pipe %c (pass %d)\n", pipe_name(pipe), pass);
+       struct drm_crtc *crtc = &intel_crtc->base;
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       int level, max_level = ilk_wm_max_level(dev);
+       enum pipe pipe = intel_crtc->pipe;
 
-       for_each_plane(dev_priv, pipe, plane) {
-               I915_WRITE(PLANE_SURF(pipe, plane),
-                          I915_READ(PLANE_SURF(pipe, plane)));
+       for (level = 0; level <= max_level; level++) {
+               I915_WRITE(CUR_WM(pipe, level),
+                          wm->plane[pipe][PLANE_CURSOR][level]);
        }
-       I915_WRITE(CURBASE(pipe), I915_READ(CURBASE(pipe)));
+       I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
+
+       skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
+                           &wm->ddb.plane[pipe][PLANE_CURSOR]);
 }
 
-static bool
-skl_ddb_allocation_included(const struct skl_ddb_allocation *old,
-                           const struct skl_ddb_allocation *new,
-                           enum pipe pipe)
+bool skl_ddb_allocation_equals(const struct skl_ddb_allocation *old,
+                              const struct skl_ddb_allocation *new,
+                              enum pipe pipe)
 {
-       uint16_t old_size, new_size;
-
-       old_size = skl_ddb_entry_size(&old->pipe[pipe]);
-       new_size = skl_ddb_entry_size(&new->pipe[pipe]);
-
-       return old_size != new_size &&
-              new->pipe[pipe].start >= old->pipe[pipe].start &&
-              new->pipe[pipe].end <= old->pipe[pipe].end;
+       return new->pipe[pipe].start == old->pipe[pipe].start &&
+              new->pipe[pipe].end == old->pipe[pipe].end;
 }
 
-static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
-                               struct skl_wm_values *new_values)
+static inline bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
+                                          const struct skl_ddb_entry *b)
 {
-       struct drm_device *dev = &dev_priv->drm;
-       struct skl_ddb_allocation *cur_ddb, *new_ddb;
-       bool reallocated[I915_MAX_PIPES] = {};
-       struct intel_crtc *crtc;
-       enum pipe pipe;
-
-       new_ddb = &new_values->ddb;
-       cur_ddb = &dev_priv->wm.skl_hw.ddb;
-
-       /*
-        * First pass: flush the pipes with the new allocation contained into
-        * the old space.
-        *
-        * We'll wait for the vblank on those pipes to ensure we can safely
-        * re-allocate the freed space without this pipe fetching from it.
-        */
-       for_each_intel_crtc(dev, crtc) {
-               if (!crtc->active)
-                       continue;
-
-               pipe = crtc->pipe;
-
-               if (!skl_ddb_allocation_included(cur_ddb, new_ddb, pipe))
-                       continue;
-
-               skl_wm_flush_pipe(dev_priv, pipe, 1);
-               intel_wait_for_vblank(dev, pipe);
-
-               reallocated[pipe] = true;
-       }
-
+       return a->start < b->end && b->start < a->end;
+}
 
-       /*
-        * Second pass: flush the pipes that are having their allocation
-        * reduced, but overlapping with a previous allocation.
-        *
-        * Here as well we need to wait for the vblank to make sure the freed
-        * space is not used anymore.
-        */
-       for_each_intel_crtc(dev, crtc) {
-               if (!crtc->active)
-                       continue;
+bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
+                                const struct skl_ddb_allocation *old,
+                                const struct skl_ddb_allocation *new,
+                                enum pipe pipe)
+{
+       struct drm_device *dev = state->dev;
+       struct intel_crtc *intel_crtc;
+       enum pipe otherp;
 
-               pipe = crtc->pipe;
+       for_each_intel_crtc(dev, intel_crtc) {
+               otherp = intel_crtc->pipe;
 
-               if (reallocated[pipe])
+               if (otherp == pipe)
                        continue;
 
-               if (skl_ddb_entry_size(&new_ddb->pipe[pipe]) <
-                   skl_ddb_entry_size(&cur_ddb->pipe[pipe])) {
-                       skl_wm_flush_pipe(dev_priv, pipe, 2);
-                       intel_wait_for_vblank(dev, pipe);
-                       reallocated[pipe] = true;
-               }
+               if (skl_ddb_entries_overlap(&new->pipe[pipe],
+                                           &old->pipe[otherp]))
+                       return true;
        }
 
-       /*
-        * Third pass: flush the pipes that got more space allocated.
-        *
-        * We don't need to actively wait for the update here, next vblank
-        * will just get more DDB space with the correct WM values.
-        */
-       for_each_intel_crtc(dev, crtc) {
-               if (!crtc->active)
-                       continue;
-
-               pipe = crtc->pipe;
-
-               /*
-                * At this point, only the pipes more space than before are
-                * left to re-allocate.
-                */
-               if (reallocated[pipe])
-                       continue;
-
-               skl_wm_flush_pipe(dev_priv, pipe, 3);
-       }
+       return false;
 }
 
 static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
@@ -4041,6 +3962,41 @@ pipes_modified(struct drm_atomic_state *state)
        return ret;
 }
 
+int
+skl_ddb_add_affected_planes(struct intel_crtc_state *cstate)
+{
+       struct drm_atomic_state *state = cstate->base.state;
+       struct drm_device *dev = state->dev;
+       struct drm_crtc *crtc = cstate->base.crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+       struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
+       struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
+       struct drm_plane_state *plane_state;
+       struct drm_plane *plane;
+       enum pipe pipe = intel_crtc->pipe;
+       int id;
+
+       WARN_ON(!drm_atomic_get_existing_crtc_state(state, crtc));
+
+       drm_for_each_plane_mask(plane, dev, crtc->state->plane_mask) {
+               id = skl_wm_plane_id(to_intel_plane(plane));
+
+               if (skl_ddb_entry_equal(&cur_ddb->plane[pipe][id],
+                                       &new_ddb->plane[pipe][id]) &&
+                   skl_ddb_entry_equal(&cur_ddb->y_plane[pipe][id],
+                                       &new_ddb->y_plane[pipe][id]))
+                       continue;
+
+               plane_state = drm_atomic_get_plane_state(state, plane);
+               if (IS_ERR(plane_state))
+                       return PTR_ERR(plane_state);
+       }
+
+       return 0;
+}
+
 static int
 skl_compute_ddb(struct drm_atomic_state *state)
 {
@@ -4105,7 +4061,7 @@ skl_compute_ddb(struct drm_atomic_state *state)
                if (ret)
                        return ret;
 
-               ret = drm_atomic_add_affected_planes(state, &intel_crtc->base);
+               ret = skl_ddb_add_affected_planes(cstate);
                if (ret)
                        return ret;
        }
@@ -4206,7 +4162,7 @@ static void skl_update_wm(struct drm_crtc *crtc)
        struct skl_wm_values *hw_vals = &dev_priv->wm.skl_hw;
        struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
        struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
-       int pipe;
+       enum pipe pipe = intel_crtc->pipe;
 
        if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
                return;
@@ -4215,15 +4171,22 @@ static void skl_update_wm(struct drm_crtc *crtc)
 
        mutex_lock(&dev_priv->wm.wm_mutex);
 
-       skl_write_wm_values(dev_priv, results);
-       skl_flush_wm_values(dev_priv, results);
-
        /*
-        * Store the new configuration (but only for the pipes that have
-        * changed; the other values weren't recomputed).
+        * If this pipe isn't active already, we're going to be enabling it
+        * very soon. Since it's safe to update a pipe's ddb allocation while
+        * the pipe's shut off, just do so here. Already active pipes will have
+        * their watermarks updated once we update their planes.
         */
-       for_each_pipe_masked(dev_priv, pipe, results->dirty_pipes)
-               skl_copy_wm_for_pipe(hw_vals, results, pipe);
+       if (crtc->state->active_changed) {
+               int plane;
+
+               for (plane = 0; plane < intel_num_planes(intel_crtc); plane++)
+                       skl_write_plane_wm(intel_crtc, results, plane);
+
+               skl_write_cursor_wm(intel_crtc, results);
+       }
+
+       skl_copy_wm_for_pipe(hw_vals, results, pipe);
 
        mutex_unlock(&dev_priv->wm.wm_mutex);
 }
@@ -5103,7 +5066,7 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv,
         */
        if (!(dev_priv->gt.awake &&
              dev_priv->rps.enabled &&
-             dev_priv->rps.cur_freq < dev_priv->rps.max_freq_softlimit))
+             dev_priv->rps.cur_freq < dev_priv->rps.boost_freq))
                return;
 
        /* Force a RPS boost (and don't count it against the client) if
@@ -5294,35 +5257,31 @@ int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6)
 
 static void gen6_init_rps_frequencies(struct drm_i915_private *dev_priv)
 {
-       uint32_t rp_state_cap;
-       u32 ddcc_status = 0;
-       int ret;
-
        /* All of these values are in units of 50MHz */
-       dev_priv->rps.cur_freq          = 0;
+
        /* static values from HW: RP0 > RP1 > RPn (min_freq) */
        if (IS_BROXTON(dev_priv)) {
-               rp_state_cap = I915_READ(BXT_RP_STATE_CAP);
+               u32 rp_state_cap = I915_READ(BXT_RP_STATE_CAP);
                dev_priv->rps.rp0_freq = (rp_state_cap >> 16) & 0xff;
                dev_priv->rps.rp1_freq = (rp_state_cap >>  8) & 0xff;
                dev_priv->rps.min_freq = (rp_state_cap >>  0) & 0xff;
        } else {
-               rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+               u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
                dev_priv->rps.rp0_freq = (rp_state_cap >>  0) & 0xff;
                dev_priv->rps.rp1_freq = (rp_state_cap >>  8) & 0xff;
                dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff;
        }
-
        /* hw_max = RP0 until we check for overclocking */
-       dev_priv->rps.max_freq          = dev_priv->rps.rp0_freq;
+       dev_priv->rps.max_freq = dev_priv->rps.rp0_freq;
 
        dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq;
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv) ||
            IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
-               ret = sandybridge_pcode_read(dev_priv,
-                                       HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL,
-                                       &ddcc_status);
-               if (0 == ret)
+               u32 ddcc_status = 0;
+
+               if (sandybridge_pcode_read(dev_priv,
+                                          HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL,
+                                          &ddcc_status) == 0)
                        dev_priv->rps.efficient_freq =
                                clamp_t(u8,
                                        ((ddcc_status >> 8) & 0xff),
@@ -5332,29 +5291,26 @@ static void gen6_init_rps_frequencies(struct drm_i915_private *dev_priv)
 
        if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
                /* Store the frequency values in 16.66 MHZ units, which is
-                  the natural hardware unit for SKL */
+                * the natural hardware unit for SKL
+                */
                dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER;
                dev_priv->rps.rp1_freq *= GEN9_FREQ_SCALER;
                dev_priv->rps.min_freq *= GEN9_FREQ_SCALER;
                dev_priv->rps.max_freq *= GEN9_FREQ_SCALER;
                dev_priv->rps.efficient_freq *= GEN9_FREQ_SCALER;
        }
+}
 
-       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+static void reset_rps(struct drm_i915_private *dev_priv,
+                     void (*set)(struct drm_i915_private *, u8))
+{
+       u8 freq = dev_priv->rps.cur_freq;
 
-       /* Preserve min/max settings in case of re-init */
-       if (dev_priv->rps.max_freq_softlimit == 0)
-               dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
+       /* force a reset */
+       dev_priv->rps.power = -1;
+       dev_priv->rps.cur_freq = -1;
 
-       if (dev_priv->rps.min_freq_softlimit == 0) {
-               if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
-                       dev_priv->rps.min_freq_softlimit =
-                               max_t(int, dev_priv->rps.efficient_freq,
-                                     intel_freq_opcode(dev_priv, 450));
-               else
-                       dev_priv->rps.min_freq_softlimit =
-                               dev_priv->rps.min_freq;
-       }
+       set(dev_priv, freq);
 }
 
 /* See the Gen9_GT_PM_Programming_Guide doc for the below */
@@ -5362,8 +5318,6 @@ static void gen9_enable_rps(struct drm_i915_private *dev_priv)
 {
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
-       gen6_init_rps_frequencies(dev_priv);
-
        /* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
        if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) {
                /*
@@ -5393,8 +5347,7 @@ static void gen9_enable_rps(struct drm_i915_private *dev_priv)
        /* Leaning on the below call to gen6_set_rps to program/setup the
         * Up/Down EI & threshold registers, as well as the RP_CONTROL,
         * RP_INTERRUPT_LIMITS & RPNSWREQ registers */
-       dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv, dev_priv->rps.idle_freq);
+       reset_rps(dev_priv, gen6_set_rps);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
@@ -5481,9 +5434,6 @@ static void gen8_enable_rps(struct drm_i915_private *dev_priv)
        /* 2a: Disable RC states. */
        I915_WRITE(GEN6_RC_CONTROL, 0);
 
-       /* Initialize rps frequencies */
-       gen6_init_rps_frequencies(dev_priv);
-
        /* 2b: Program RC6 thresholds.*/
        I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16);
        I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); /* 12500 * 1280ns */
@@ -5540,8 +5490,7 @@ static void gen8_enable_rps(struct drm_i915_private *dev_priv)
 
        /* 6: Ring frequency + overclocking (our driver does this later */
 
-       dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv, dev_priv->rps.idle_freq);
+       reset_rps(dev_priv, gen6_set_rps);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
@@ -5549,7 +5498,7 @@ static void gen8_enable_rps(struct drm_i915_private *dev_priv)
 static void gen6_enable_rps(struct drm_i915_private *dev_priv)
 {
        struct intel_engine_cs *engine;
-       u32 rc6vids, pcu_mbox = 0, rc6_mask = 0;
+       u32 rc6vids, rc6_mask = 0;
        u32 gtfifodbg;
        int rc6_mode;
        int ret;
@@ -5573,9 +5522,6 @@ static void gen6_enable_rps(struct drm_i915_private *dev_priv)
 
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
-       /* Initialize rps frequencies */
-       gen6_init_rps_frequencies(dev_priv);
-
        /* disable the counters and set deterministic thresholds */
        I915_WRITE(GEN6_RC_CONTROL, 0);
 
@@ -5626,16 +5572,7 @@ static void gen6_enable_rps(struct drm_i915_private *dev_priv)
        if (ret)
                DRM_DEBUG_DRIVER("Failed to set the min frequency\n");
 
-       ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox);
-       if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */
-               DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n",
-                                (dev_priv->rps.max_freq_softlimit & 0xff) * 50,
-                                (pcu_mbox & 0xff) * 50);
-               dev_priv->rps.max_freq = pcu_mbox & 0xff;
-       }
-
-       dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv, dev_priv->rps.idle_freq);
+       reset_rps(dev_priv, gen6_set_rps);
 
        rc6vids = 0;
        ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
@@ -5654,7 +5591,7 @@ static void gen6_enable_rps(struct drm_i915_private *dev_priv)
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
-static void __gen6_update_ring_freq(struct drm_i915_private *dev_priv)
+static void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
 {
        int min_freq = 15;
        unsigned int gpu_freq;
@@ -5738,23 +5675,13 @@ static void __gen6_update_ring_freq(struct drm_i915_private *dev_priv)
        }
 }
 
-void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
-{
-       if (!HAS_CORE_RING_FREQ(dev_priv))
-               return;
-
-       mutex_lock(&dev_priv->rps.hw_lock);
-       __gen6_update_ring_freq(dev_priv);
-       mutex_unlock(&dev_priv->rps.hw_lock);
-}
-
 static int cherryview_rps_max_freq(struct drm_i915_private *dev_priv)
 {
        u32 val, rp0;
 
        val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
 
-       switch (INTEL_INFO(dev_priv)->eu_total) {
+       switch (INTEL_INFO(dev_priv)->sseu.eu_total) {
        case 8:
                /* (2 * 4) config */
                rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT);
@@ -5892,8 +5819,6 @@ static void valleyview_setup_pctx(struct drm_i915_private *dev_priv)
        u32 pcbr;
        int pctx_size = 24*1024;
 
-       mutex_lock(&dev_priv->drm.struct_mutex);
-
        pcbr = I915_READ(VLV_PCBR);
        if (pcbr) {
                /* BIOS set it up already, grab the pre-alloc'd space */
@@ -5929,7 +5854,6 @@ static void valleyview_setup_pctx(struct drm_i915_private *dev_priv)
 out:
        DRM_DEBUG_DRIVER("PCBR: 0x%08x\n", I915_READ(VLV_PCBR));
        dev_priv->vlv_pctx = pctx;
-       mutex_unlock(&dev_priv->drm.struct_mutex);
 }
 
 static void valleyview_cleanup_pctx(struct drm_i915_private *dev_priv)
@@ -5937,7 +5861,7 @@ static void valleyview_cleanup_pctx(struct drm_i915_private *dev_priv)
        if (WARN_ON(!dev_priv->vlv_pctx))
                return;
 
-       drm_gem_object_unreference_unlocked(&dev_priv->vlv_pctx->base);
+       i915_gem_object_put_unlocked(dev_priv->vlv_pctx);
        dev_priv->vlv_pctx = NULL;
 }
 
@@ -5960,8 +5884,6 @@ static void valleyview_init_gt_powersave(struct drm_i915_private *dev_priv)
 
        vlv_init_gpll_ref_freq(dev_priv);
 
-       mutex_lock(&dev_priv->rps.hw_lock);
-
        val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
        switch ((val >> 6) & 3) {
        case 0:
@@ -5997,17 +5919,6 @@ static void valleyview_init_gt_powersave(struct drm_i915_private *dev_priv)
        DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
                         intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
                         dev_priv->rps.min_freq);
-
-       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
-
-       /* Preserve min/max settings in case of re-init */
-       if (dev_priv->rps.max_freq_softlimit == 0)
-               dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
-
-       if (dev_priv->rps.min_freq_softlimit == 0)
-               dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
-
-       mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
 static void cherryview_init_gt_powersave(struct drm_i915_private *dev_priv)
@@ -6018,8 +5929,6 @@ static void cherryview_init_gt_powersave(struct drm_i915_private *dev_priv)
 
        vlv_init_gpll_ref_freq(dev_priv);
 
-       mutex_lock(&dev_priv->rps.hw_lock);
-
        mutex_lock(&dev_priv->sb_lock);
        val = vlv_cck_read(dev_priv, CCK_FUSE_REG);
        mutex_unlock(&dev_priv->sb_lock);
@@ -6061,17 +5970,6 @@ static void cherryview_init_gt_powersave(struct drm_i915_private *dev_priv)
                   dev_priv->rps.rp1_freq |
                   dev_priv->rps.min_freq) & 1,
                  "Odd GPU freq values\n");
-
-       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
-
-       /* Preserve min/max settings in case of re-init */
-       if (dev_priv->rps.max_freq_softlimit == 0)
-               dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
-
-       if (dev_priv->rps.min_freq_softlimit == 0)
-               dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
-
-       mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
 static void valleyview_cleanup_gt_powersave(struct drm_i915_private *dev_priv)
@@ -6162,16 +6060,7 @@ static void cherryview_enable_rps(struct drm_i915_private *dev_priv)
        DRM_DEBUG_DRIVER("GPLL enabled? %s\n", yesno(val & GPLLENABLE));
        DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
 
-       dev_priv->rps.cur_freq = (val >> 8) & 0xff;
-       DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
-                        intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
-                        dev_priv->rps.cur_freq);
-
-       DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
-                        intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq),
-                        dev_priv->rps.idle_freq);
-
-       valleyview_set_rps(dev_priv, dev_priv->rps.idle_freq);
+       reset_rps(dev_priv, valleyview_set_rps);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
@@ -6251,16 +6140,7 @@ static void valleyview_enable_rps(struct drm_i915_private *dev_priv)
        DRM_DEBUG_DRIVER("GPLL enabled? %s\n", yesno(val & GPLLENABLE));
        DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
 
-       dev_priv->rps.cur_freq = (val >> 8) & 0xff;
-       DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
-                        intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
-                        dev_priv->rps.cur_freq);
-
-       DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
-                        intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq),
-                        dev_priv->rps.idle_freq);
-
-       valleyview_set_rps(dev_priv, dev_priv->rps.idle_freq);
+       reset_rps(dev_priv, valleyview_set_rps);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
@@ -6589,19 +6469,11 @@ EXPORT_SYMBOL_GPL(i915_gpu_lower);
  */
 bool i915_gpu_busy(void)
 {
-       struct drm_i915_private *dev_priv;
-       struct intel_engine_cs *engine;
        bool ret = false;
 
        spin_lock_irq(&mchdev_lock);
-       if (!i915_mch_dev)
-               goto out_unlock;
-       dev_priv = i915_mch_dev;
-
-       for_each_engine(engine, dev_priv)
-               ret |= !list_empty(&engine->request_list);
-
-out_unlock:
+       if (i915_mch_dev)
+               ret = i915_mch_dev->gt.awake;
        spin_unlock_irq(&mchdev_lock);
 
        return ret;
@@ -6757,10 +6629,51 @@ void intel_init_gt_powersave(struct drm_i915_private *dev_priv)
                intel_runtime_pm_get(dev_priv);
        }
 
+       mutex_lock(&dev_priv->drm.struct_mutex);
+       mutex_lock(&dev_priv->rps.hw_lock);
+
+       /* Initialize RPS limits (for userspace) */
        if (IS_CHERRYVIEW(dev_priv))
                cherryview_init_gt_powersave(dev_priv);
        else if (IS_VALLEYVIEW(dev_priv))
                valleyview_init_gt_powersave(dev_priv);
+       else if (INTEL_GEN(dev_priv) >= 6)
+               gen6_init_rps_frequencies(dev_priv);
+
+       /* Derive initial user preferences/limits from the hardware limits */
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+       dev_priv->rps.cur_freq = dev_priv->rps.idle_freq;
+
+       dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
+       dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
+
+       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+               dev_priv->rps.min_freq_softlimit =
+                       max_t(int,
+                             dev_priv->rps.efficient_freq,
+                             intel_freq_opcode(dev_priv, 450));
+
+       /* After setting max-softlimit, find the overclock max freq */
+       if (IS_GEN6(dev_priv) ||
+           IS_IVYBRIDGE(dev_priv) || IS_HASWELL(dev_priv)) {
+               u32 params = 0;
+
+               sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &params);
+               if (params & BIT(31)) { /* OC supported */
+                       DRM_DEBUG_DRIVER("Overclocking supported, max: %dMHz, overclock: %dMHz\n",
+                                        (dev_priv->rps.max_freq & 0xff) * 50,
+                                        (params & 0xff) * 50);
+                       dev_priv->rps.max_freq = params & 0xff;
+               }
+       }
+
+       /* Finally allow us to boost to max by default */
+       dev_priv->rps.boost_freq = dev_priv->rps.max_freq;
+
+       mutex_unlock(&dev_priv->rps.hw_lock);
+       mutex_unlock(&dev_priv->drm.struct_mutex);
+
+       intel_autoenable_gt_powersave(dev_priv);
 }
 
 void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv)
@@ -6772,13 +6685,6 @@ void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv)
                intel_runtime_pm_put(dev_priv);
 }
 
-static void gen6_suspend_rps(struct drm_i915_private *dev_priv)
-{
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
-       gen6_disable_rps_interrupts(dev_priv);
-}
-
 /**
  * intel_suspend_gt_powersave - suspend PM work and helper threads
  * @dev_priv: i915 device
@@ -6792,60 +6698,76 @@ void intel_suspend_gt_powersave(struct drm_i915_private *dev_priv)
        if (INTEL_GEN(dev_priv) < 6)
                return;
 
-       gen6_suspend_rps(dev_priv);
+       if (cancel_delayed_work_sync(&dev_priv->rps.autoenable_work))
+               intel_runtime_pm_put(dev_priv);
+
+       /* gen6_rps_idle() will be called later to disable interrupts */
+}
+
+void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv)
+{
+       dev_priv->rps.enabled = true; /* force disabling */
+       intel_disable_gt_powersave(dev_priv);
 
-       /* Force GPU to min freq during suspend */
-       gen6_rps_idle(dev_priv);
+       gen6_reset_rps_interrupts(dev_priv);
 }
 
 void intel_disable_gt_powersave(struct drm_i915_private *dev_priv)
 {
-       if (IS_IRONLAKE_M(dev_priv)) {
-               ironlake_disable_drps(dev_priv);
-       } else if (INTEL_INFO(dev_priv)->gen >= 6) {
-               intel_suspend_gt_powersave(dev_priv);
+       if (!READ_ONCE(dev_priv->rps.enabled))
+               return;
 
-               mutex_lock(&dev_priv->rps.hw_lock);
-               if (INTEL_INFO(dev_priv)->gen >= 9) {
-                       gen9_disable_rc6(dev_priv);
-                       gen9_disable_rps(dev_priv);
-               } else if (IS_CHERRYVIEW(dev_priv))
-                       cherryview_disable_rps(dev_priv);
-               else if (IS_VALLEYVIEW(dev_priv))
-                       valleyview_disable_rps(dev_priv);
-               else
-                       gen6_disable_rps(dev_priv);
+       mutex_lock(&dev_priv->rps.hw_lock);
 
-               dev_priv->rps.enabled = false;
-               mutex_unlock(&dev_priv->rps.hw_lock);
+       if (INTEL_GEN(dev_priv) >= 9) {
+               gen9_disable_rc6(dev_priv);
+               gen9_disable_rps(dev_priv);
+       } else if (IS_CHERRYVIEW(dev_priv)) {
+               cherryview_disable_rps(dev_priv);
+       } else if (IS_VALLEYVIEW(dev_priv)) {
+               valleyview_disable_rps(dev_priv);
+       } else if (INTEL_GEN(dev_priv) >= 6) {
+               gen6_disable_rps(dev_priv);
+       }  else if (IS_IRONLAKE_M(dev_priv)) {
+               ironlake_disable_drps(dev_priv);
        }
+
+       dev_priv->rps.enabled = false;
+       mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
-static void intel_gen6_powersave_work(struct work_struct *work)
+void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv =
-               container_of(work, struct drm_i915_private,
-                            rps.delayed_resume_work.work);
+       /* We shouldn't be disabling as we submit, so this should be less
+        * racy than it appears!
+        */
+       if (READ_ONCE(dev_priv->rps.enabled))
+               return;
 
-       mutex_lock(&dev_priv->rps.hw_lock);
+       /* Powersaving is controlled by the host when inside a VM */
+       if (intel_vgpu_active(dev_priv))
+               return;
 
-       gen6_reset_rps_interrupts(dev_priv);
+       mutex_lock(&dev_priv->rps.hw_lock);
 
        if (IS_CHERRYVIEW(dev_priv)) {
                cherryview_enable_rps(dev_priv);
        } else if (IS_VALLEYVIEW(dev_priv)) {
                valleyview_enable_rps(dev_priv);
-       } else if (INTEL_INFO(dev_priv)->gen >= 9) {
+       } else if (INTEL_GEN(dev_priv) >= 9) {
                gen9_enable_rc6(dev_priv);
                gen9_enable_rps(dev_priv);
                if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
-                       __gen6_update_ring_freq(dev_priv);
+                       gen6_update_ring_freq(dev_priv);
        } else if (IS_BROADWELL(dev_priv)) {
                gen8_enable_rps(dev_priv);
-               __gen6_update_ring_freq(dev_priv);
-       } else {
+               gen6_update_ring_freq(dev_priv);
+       } else if (INTEL_GEN(dev_priv) >= 6) {
                gen6_enable_rps(dev_priv);
-               __gen6_update_ring_freq(dev_priv);
+               gen6_update_ring_freq(dev_priv);
+       } else if (IS_IRONLAKE_M(dev_priv)) {
+               ironlake_enable_drps(dev_priv);
+               intel_init_emon(dev_priv);
        }
 
        WARN_ON(dev_priv->rps.max_freq < dev_priv->rps.min_freq);
@@ -6855,25 +6777,52 @@ static void intel_gen6_powersave_work(struct work_struct *work)
        WARN_ON(dev_priv->rps.efficient_freq > dev_priv->rps.max_freq);
 
        dev_priv->rps.enabled = true;
+       mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+static void __intel_autoenable_gt_powersave(struct work_struct *work)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(work, typeof(*dev_priv), rps.autoenable_work.work);
+       struct intel_engine_cs *rcs;
+       struct drm_i915_gem_request *req;
 
-       gen6_enable_rps_interrupts(dev_priv);
+       if (READ_ONCE(dev_priv->rps.enabled))
+               goto out;
 
-       mutex_unlock(&dev_priv->rps.hw_lock);
+       rcs = &dev_priv->engine[RCS];
+       if (rcs->last_context)
+               goto out;
 
+       if (!rcs->init_context)
+               goto out;
+
+       mutex_lock(&dev_priv->drm.struct_mutex);
+
+       req = i915_gem_request_alloc(rcs, dev_priv->kernel_context);
+       if (IS_ERR(req))
+               goto unlock;
+
+       if (!i915.enable_execlists && i915_switch_context(req) == 0)
+               rcs->init_context(req);
+
+       /* Mark the device busy, calling intel_enable_gt_powersave() */
+       i915_add_request_no_flush(req);
+
+unlock:
+       mutex_unlock(&dev_priv->drm.struct_mutex);
+out:
        intel_runtime_pm_put(dev_priv);
 }
 
-void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
+void intel_autoenable_gt_powersave(struct drm_i915_private *dev_priv)
 {
-       /* Powersaving is controlled by the host when inside a VM */
-       if (intel_vgpu_active(dev_priv))
+       if (READ_ONCE(dev_priv->rps.enabled))
                return;
 
        if (IS_IRONLAKE_M(dev_priv)) {
                ironlake_enable_drps(dev_priv);
-               mutex_lock(&dev_priv->drm.struct_mutex);
                intel_init_emon(dev_priv);
-               mutex_unlock(&dev_priv->drm.struct_mutex);
        } else if (INTEL_INFO(dev_priv)->gen >= 6) {
                /*
                 * PCU communication is slow and this doesn't need to be
@@ -6887,21 +6836,13 @@ void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
                 * paths, so the _noresume version is enough (and in case of
                 * runtime resume it's necessary).
                 */
-               if (schedule_delayed_work(&dev_priv->rps.delayed_resume_work,
-                                          round_jiffies_up_relative(HZ)))
+               if (queue_delayed_work(dev_priv->wq,
+                                      &dev_priv->rps.autoenable_work,
+                                      round_jiffies_up_relative(HZ)))
                        intel_runtime_pm_get_noresume(dev_priv);
        }
 }
 
-void intel_reset_gt_powersave(struct drm_i915_private *dev_priv)
-{
-       if (INTEL_INFO(dev_priv)->gen < 6)
-               return;
-
-       gen6_suspend_rps(dev_priv);
-       dev_priv->rps.enabled = false;
-}
-
 static void ibx_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -8046,7 +7987,7 @@ static void __intel_rps_boost_work(struct work_struct *work)
        if (!i915_gem_request_completed(req))
                gen6_rps_boost(req->i915, NULL, req->emitted_jiffies);
 
-       i915_gem_request_unreference(req);
+       i915_gem_request_put(req);
        kfree(boost);
 }
 
@@ -8064,8 +8005,7 @@ void intel_queue_rps_boost_for_request(struct drm_i915_gem_request *req)
        if (boost == NULL)
                return;
 
-       i915_gem_request_reference(req);
-       boost->req = req;
+       boost->req = i915_gem_request_get(req);
 
        INIT_WORK(&boost->work, __intel_rps_boost_work);
        queue_work(req->i915->wq, &boost->work);
@@ -8078,11 +8018,9 @@ void intel_pm_setup(struct drm_device *dev)
        mutex_init(&dev_priv->rps.hw_lock);
        spin_lock_init(&dev_priv->rps.client_lock);
 
-       INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
-                         intel_gen6_powersave_work);
+       INIT_DELAYED_WORK(&dev_priv->rps.autoenable_work,
+                         __intel_autoenable_gt_powersave);
        INIT_LIST_HEAD(&dev_priv->rps.clients);
-       INIT_LIST_HEAD(&dev_priv->rps.semaphores.link);
-       INIT_LIST_HEAD(&dev_priv->rps.mmioflips.link);
 
        dev_priv->pm.suspended = false;
        atomic_set(&dev_priv->pm.wakeref_count, 0);
index cf171b4..108ba1e 100644 (file)
@@ -645,9 +645,8 @@ unlock:
        mutex_unlock(&dev_priv->psr.lock);
 }
 
-static void intel_psr_exit(struct drm_device *dev)
+static void intel_psr_exit(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_dp *intel_dp = dev_priv->psr.enabled;
        struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
        enum pipe pipe = to_intel_crtc(crtc)->pipe;
@@ -656,7 +655,7 @@ static void intel_psr_exit(struct drm_device *dev)
        if (!dev_priv->psr.active)
                return;
 
-       if (HAS_DDI(dev)) {
+       if (HAS_DDI(dev_priv)) {
                val = I915_READ(EDP_PSR_CTL);
 
                WARN_ON(!(val & EDP_PSR_ENABLE));
@@ -691,7 +690,7 @@ static void intel_psr_exit(struct drm_device *dev)
 
 /**
  * intel_psr_single_frame_update - Single Frame Update
- * @dev: DRM device
+ * @dev_priv: i915 device
  * @frontbuffer_bits: frontbuffer plane tracking bits
  *
  * Some platforms support a single frame update feature that is used to
@@ -699,10 +698,9 @@ static void intel_psr_exit(struct drm_device *dev)
  * So far it is only implemented for Valleyview and Cherryview because
  * hardware requires this to be done before a page flip.
  */
-void intel_psr_single_frame_update(struct drm_device *dev,
+void intel_psr_single_frame_update(struct drm_i915_private *dev_priv,
                                   unsigned frontbuffer_bits)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc *crtc;
        enum pipe pipe;
        u32 val;
@@ -711,7 +709,7 @@ void intel_psr_single_frame_update(struct drm_device *dev,
         * Single frame update is already supported on BDW+ but it requires
         * many W/A and it isn't really needed.
         */
-       if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
+       if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
                return;
 
        mutex_lock(&dev_priv->psr.lock);
@@ -737,7 +735,7 @@ void intel_psr_single_frame_update(struct drm_device *dev,
 
 /**
  * intel_psr_invalidate - Invalidade PSR
- * @dev: DRM device
+ * @dev_priv: i915 device
  * @frontbuffer_bits: frontbuffer plane tracking bits
  *
  * Since the hardware frontbuffer tracking has gaps we need to integrate
@@ -747,10 +745,9 @@ void intel_psr_single_frame_update(struct drm_device *dev,
  *
  * Dirty frontbuffers relevant to PSR are tracked in busy_frontbuffer_bits."
  */
-void intel_psr_invalidate(struct drm_device *dev,
+void intel_psr_invalidate(struct drm_i915_private *dev_priv,
                          unsigned frontbuffer_bits)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc *crtc;
        enum pipe pipe;
 
@@ -767,14 +764,14 @@ void intel_psr_invalidate(struct drm_device *dev,
        dev_priv->psr.busy_frontbuffer_bits |= frontbuffer_bits;
 
        if (frontbuffer_bits)
-               intel_psr_exit(dev);
+               intel_psr_exit(dev_priv);
 
        mutex_unlock(&dev_priv->psr.lock);
 }
 
 /**
  * intel_psr_flush - Flush PSR
- * @dev: DRM device
+ * @dev_priv: i915 device
  * @frontbuffer_bits: frontbuffer plane tracking bits
  * @origin: which operation caused the flush
  *
@@ -785,10 +782,9 @@ void intel_psr_invalidate(struct drm_device *dev,
  *
  * Dirty frontbuffers relevant to PSR are tracked in busy_frontbuffer_bits.
  */
-void intel_psr_flush(struct drm_device *dev,
+void intel_psr_flush(struct drm_i915_private *dev_priv,
                     unsigned frontbuffer_bits, enum fb_op_origin origin)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc *crtc;
        enum pipe pipe;
 
@@ -806,7 +802,7 @@ void intel_psr_flush(struct drm_device *dev,
 
        /* By definition flush = invalidate + flush */
        if (frontbuffer_bits)
-               intel_psr_exit(dev);
+               intel_psr_exit(dev_priv);
 
        if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
                if (!work_busy(&dev_priv->psr.work.work))
index 5bd6985..08f6fea 100644 (file)
 #ifndef _INTEL_RENDERSTATE_H
 #define _INTEL_RENDERSTATE_H
 
-#include "i915_drv.h"
+#include <linux/types.h>
 
-extern const struct intel_renderstate_rodata gen6_null_state;
-extern const struct intel_renderstate_rodata gen7_null_state;
-extern const struct intel_renderstate_rodata gen8_null_state;
-extern const struct intel_renderstate_rodata gen9_null_state;
+struct intel_renderstate_rodata {
+       const u32 *reloc;
+       const u32 *batch;
+       const u32 batch_items;
+};
 
 #define RO_RENDERSTATE(_g)                                             \
        const struct intel_renderstate_rodata gen ## _g ## _null_state = { \
@@ -38,4 +39,9 @@ extern const struct intel_renderstate_rodata gen9_null_state;
                .batch_items = sizeof(gen ## _g ## _null_state_batch)/4, \
        }
 
+extern const struct intel_renderstate_rodata gen6_null_state;
+extern const struct intel_renderstate_rodata gen7_null_state;
+extern const struct intel_renderstate_rodata gen8_null_state;
+extern const struct intel_renderstate_rodata gen9_null_state;
+
 #endif /* INTEL_RENDERSTATE_H */
index 1d3161b..ed9955d 100644 (file)
@@ -47,57 +47,44 @@ int __intel_ring_space(int head, int tail, int size)
        return space - I915_RING_FREE_SPACE;
 }
 
-void intel_ring_update_space(struct intel_ringbuffer *ringbuf)
+void intel_ring_update_space(struct intel_ring *ring)
 {
-       if (ringbuf->last_retired_head != -1) {
-               ringbuf->head = ringbuf->last_retired_head;
-               ringbuf->last_retired_head = -1;
+       if (ring->last_retired_head != -1) {
+               ring->head = ring->last_retired_head;
+               ring->last_retired_head = -1;
        }
 
-       ringbuf->space = __intel_ring_space(ringbuf->head & HEAD_ADDR,
-                                           ringbuf->tail, ringbuf->size);
-}
-
-static void __intel_ring_advance(struct intel_engine_cs *engine)
-{
-       struct intel_ringbuffer *ringbuf = engine->buffer;
-       ringbuf->tail &= ringbuf->size - 1;
-       engine->write_tail(engine, ringbuf->tail);
+       ring->space = __intel_ring_space(ring->head & HEAD_ADDR,
+                                        ring->tail, ring->size);
 }
 
 static int
-gen2_render_ring_flush(struct drm_i915_gem_request *req,
-                      u32      invalidate_domains,
-                      u32      flush_domains)
+gen2_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        u32 cmd;
        int ret;
 
        cmd = MI_FLUSH;
-       if (((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) == 0)
-               cmd |= MI_NO_WRITE_FLUSH;
 
-       if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
+       if (mode & EMIT_INVALIDATE)
                cmd |= MI_READ_FLUSH;
 
        ret = intel_ring_begin(req, 2);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, cmd);
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, cmd);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static int
-gen4_render_ring_flush(struct drm_i915_gem_request *req,
-                      u32      invalidate_domains,
-                      u32      flush_domains)
+gen4_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        u32 cmd;
        int ret;
 
@@ -129,23 +116,20 @@ gen4_render_ring_flush(struct drm_i915_gem_request *req,
         * are flushed at any MI_FLUSH.
         */
 
-       cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
-       if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER)
-               cmd &= ~MI_NO_WRITE_FLUSH;
-       if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
+       cmd = MI_FLUSH;
+       if (mode & EMIT_INVALIDATE) {
                cmd |= MI_EXE_FLUSH;
-
-       if (invalidate_domains & I915_GEM_DOMAIN_COMMAND &&
-           (IS_G4X(req->i915) || IS_GEN5(req->i915)))
-               cmd |= MI_INVALIDATE_ISP;
+               if (IS_G4X(req->i915) || IS_GEN5(req->i915))
+                       cmd |= MI_INVALIDATE_ISP;
+       }
 
        ret = intel_ring_begin(req, 2);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, cmd);
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, cmd);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -190,45 +174,46 @@ gen4_render_ring_flush(struct drm_i915_gem_request *req,
 static int
 intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *engine = req->engine;
-       u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
+       struct intel_ring *ring = req->ring;
+       u32 scratch_addr =
+               i915_ggtt_offset(req->engine->scratch) + 2 * CACHELINE_BYTES;
        int ret;
 
        ret = intel_ring_begin(req, 6);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(5));
-       intel_ring_emit(engine, PIPE_CONTROL_CS_STALL |
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(5));
+       intel_ring_emit(ring, PIPE_CONTROL_CS_STALL |
                        PIPE_CONTROL_STALL_AT_SCOREBOARD);
-       intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
-       intel_ring_emit(engine, 0); /* low dword */
-       intel_ring_emit(engine, 0); /* high dword */
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
+       intel_ring_emit(ring, 0); /* low dword */
+       intel_ring_emit(ring, 0); /* high dword */
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        ret = intel_ring_begin(req, 6);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(5));
-       intel_ring_emit(engine, PIPE_CONTROL_QW_WRITE);
-       intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
-       intel_ring_emit(engine, 0);
-       intel_ring_emit(engine, 0);
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(5));
+       intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE);
+       intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static int
-gen6_render_ring_flush(struct drm_i915_gem_request *req,
-                      u32 invalidate_domains, u32 flush_domains)
+gen6_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
+       u32 scratch_addr =
+               i915_ggtt_offset(req->engine->scratch) + 2 * CACHELINE_BYTES;
        u32 flags = 0;
-       u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
        int ret;
 
        /* Force SNB workarounds for PIPE_CONTROL flushes */
@@ -240,7 +225,7 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req,
         * number of bits based on the write domains has little performance
         * impact.
         */
-       if (flush_domains) {
+       if (mode & EMIT_FLUSH) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
                /*
@@ -249,7 +234,7 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req,
                 */
                flags |= PIPE_CONTROL_CS_STALL;
        }
-       if (invalidate_domains) {
+       if (mode & EMIT_INVALIDATE) {
                flags |= PIPE_CONTROL_TLB_INVALIDATE;
                flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
                flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
@@ -266,11 +251,11 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req,
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
-       intel_ring_emit(engine, flags);
-       intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
-       intel_ring_emit(engine, 0);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
+       intel_ring_emit(ring, flags);
+       intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
+       intel_ring_emit(ring, 0);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -278,30 +263,31 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req,
 static int
 gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        int ret;
 
        ret = intel_ring_begin(req, 4);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
-       intel_ring_emit(engine, PIPE_CONTROL_CS_STALL |
-                             PIPE_CONTROL_STALL_AT_SCOREBOARD);
-       intel_ring_emit(engine, 0);
-       intel_ring_emit(engine, 0);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
+       intel_ring_emit(ring,
+                       PIPE_CONTROL_CS_STALL |
+                       PIPE_CONTROL_STALL_AT_SCOREBOARD);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, 0);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static int
-gen7_render_ring_flush(struct drm_i915_gem_request *req,
-                      u32 invalidate_domains, u32 flush_domains)
+gen7_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
+       u32 scratch_addr =
+               i915_ggtt_offset(req->engine->scratch) + 2 * CACHELINE_BYTES;
        u32 flags = 0;
-       u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
        int ret;
 
        /*
@@ -318,13 +304,13 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req,
         * number of bits based on the write domains has little performance
         * impact.
         */
-       if (flush_domains) {
+       if (mode & EMIT_FLUSH) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
                flags |= PIPE_CONTROL_FLUSH_ENABLE;
        }
-       if (invalidate_domains) {
+       if (mode & EMIT_INVALIDATE) {
                flags |= PIPE_CONTROL_TLB_INVALIDATE;
                flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
                flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
@@ -350,11 +336,11 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req,
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
-       intel_ring_emit(engine, flags);
-       intel_ring_emit(engine, scratch_addr);
-       intel_ring_emit(engine, 0);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
+       intel_ring_emit(ring, flags);
+       intel_ring_emit(ring, scratch_addr);
+       intel_ring_emit(ring, 0);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -363,41 +349,41 @@ static int
 gen8_emit_pipe_control(struct drm_i915_gem_request *req,
                       u32 flags, u32 scratch_addr)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        int ret;
 
        ret = intel_ring_begin(req, 6);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(6));
-       intel_ring_emit(engine, flags);
-       intel_ring_emit(engine, scratch_addr);
-       intel_ring_emit(engine, 0);
-       intel_ring_emit(engine, 0);
-       intel_ring_emit(engine, 0);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
+       intel_ring_emit(ring, flags);
+       intel_ring_emit(ring, scratch_addr);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, 0);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static int
-gen8_render_ring_flush(struct drm_i915_gem_request *req,
-                      u32 invalidate_domains, u32 flush_domains)
+gen8_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
 {
+       u32 scratch_addr =
+               i915_ggtt_offset(req->engine->scratch) + 2 * CACHELINE_BYTES;
        u32 flags = 0;
-       u32 scratch_addr = req->engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
        int ret;
 
        flags |= PIPE_CONTROL_CS_STALL;
 
-       if (flush_domains) {
+       if (mode & EMIT_FLUSH) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
                flags |= PIPE_CONTROL_FLUSH_ENABLE;
        }
-       if (invalidate_domains) {
+       if (mode & EMIT_INVALIDATE) {
                flags |= PIPE_CONTROL_TLB_INVALIDATE;
                flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
                flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
@@ -419,14 +405,7 @@ gen8_render_ring_flush(struct drm_i915_gem_request *req,
        return gen8_emit_pipe_control(req, flags, scratch_addr);
 }
 
-static void ring_write_tail(struct intel_engine_cs *engine,
-                           u32 value)
-{
-       struct drm_i915_private *dev_priv = engine->i915;
-       I915_WRITE_TAIL(engine, value);
-}
-
-u64 intel_ring_get_active_head(struct intel_engine_cs *engine)
+u64 intel_engine_get_active_head(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv = engine->i915;
        u64 acthd;
@@ -488,7 +467,7 @@ static void intel_ring_setup_status_page(struct intel_engine_cs *engine)
                mmio = RING_HWS_PGA(engine->mmio_base);
        }
 
-       I915_WRITE(mmio, (u32)engine->status_page.gfx_addr);
+       I915_WRITE(mmio, engine->status_page.ggtt_offset);
        POSTING_READ(mmio);
 
        /*
@@ -519,7 +498,7 @@ static bool stop_ring(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv = engine->i915;
 
-       if (!IS_GEN2(dev_priv)) {
+       if (INTEL_GEN(dev_priv) > 2) {
                I915_WRITE_MODE(engine, _MASKED_BIT_ENABLE(STOP_RING));
                if (intel_wait_for_register(dev_priv,
                                            RING_MI_MODE(engine->mmio_base),
@@ -539,9 +518,9 @@ static bool stop_ring(struct intel_engine_cs *engine)
 
        I915_WRITE_CTL(engine, 0);
        I915_WRITE_HEAD(engine, 0);
-       engine->write_tail(engine, 0);
+       I915_WRITE_TAIL(engine, 0);
 
-       if (!IS_GEN2(dev_priv)) {
+       if (INTEL_GEN(dev_priv) > 2) {
                (void)I915_READ_CTL(engine);
                I915_WRITE_MODE(engine, _MASKED_BIT_DISABLE(STOP_RING));
        }
@@ -549,16 +528,10 @@ static bool stop_ring(struct intel_engine_cs *engine)
        return (I915_READ_HEAD(engine) & HEAD_ADDR) == 0;
 }
 
-void intel_engine_init_hangcheck(struct intel_engine_cs *engine)
-{
-       memset(&engine->hangcheck, 0, sizeof(engine->hangcheck));
-}
-
 static int init_ring_common(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv = engine->i915;
-       struct intel_ringbuffer *ringbuf = engine->buffer;
-       struct drm_i915_gem_object *obj = ringbuf->obj;
+       struct intel_ring *ring = engine->buffer;
        int ret = 0;
 
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
@@ -586,10 +559,12 @@ static int init_ring_common(struct intel_engine_cs *engine)
                }
        }
 
-       if (I915_NEED_GFX_HWS(dev_priv))
-               intel_ring_setup_status_page(engine);
-       else
+       if (HWS_NEEDS_PHYSICAL(dev_priv))
                ring_setup_phys_status_page(engine);
+       else
+               intel_ring_setup_status_page(engine);
+
+       intel_engine_reset_breadcrumbs(engine);
 
        /* Enforce ordering by reading HEAD register back */
        I915_READ_HEAD(engine);
@@ -598,40 +573,39 @@ static int init_ring_common(struct intel_engine_cs *engine)
         * registers with the above sequence (the readback of the HEAD registers
         * also enforces ordering), otherwise the hw might lose the new ring
         * register values. */
-       I915_WRITE_START(engine, i915_gem_obj_ggtt_offset(obj));
+       I915_WRITE_START(engine, i915_ggtt_offset(ring->vma));
 
        /* WaClearRingBufHeadRegAtInit:ctg,elk */
        if (I915_READ_HEAD(engine))
                DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
                          engine->name, I915_READ_HEAD(engine));
-       I915_WRITE_HEAD(engine, 0);
-       (void)I915_READ_HEAD(engine);
+
+       intel_ring_update_space(ring);
+       I915_WRITE_HEAD(engine, ring->head);
+       I915_WRITE_TAIL(engine, ring->tail);
+       (void)I915_READ_TAIL(engine);
 
        I915_WRITE_CTL(engine,
-                       ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES)
+                       ((ring->size - PAGE_SIZE) & RING_NR_PAGES)
                        | RING_VALID);
 
        /* If the head is still not zero, the ring is dead */
-       if (wait_for((I915_READ_CTL(engine) & RING_VALID) != 0 &&
-                    I915_READ_START(engine) == i915_gem_obj_ggtt_offset(obj) &&
-                    (I915_READ_HEAD(engine) & HEAD_ADDR) == 0, 50)) {
+       if (intel_wait_for_register_fw(dev_priv, RING_CTL(engine->mmio_base),
+                                      RING_VALID, RING_VALID,
+                                      50)) {
                DRM_ERROR("%s initialization failed "
-                         "ctl %08x (valid? %d) head %08x tail %08x start %08x [expected %08lx]\n",
+                         "ctl %08x (valid? %d) head %08x [%08x] tail %08x [%08x] start %08x [expected %08x]\n",
                          engine->name,
                          I915_READ_CTL(engine),
                          I915_READ_CTL(engine) & RING_VALID,
-                         I915_READ_HEAD(engine), I915_READ_TAIL(engine),
+                         I915_READ_HEAD(engine), ring->head,
+                         I915_READ_TAIL(engine), ring->tail,
                          I915_READ_START(engine),
-                         (unsigned long)i915_gem_obj_ggtt_offset(obj));
+                         i915_ggtt_offset(ring->vma));
                ret = -EIO;
                goto out;
        }
 
-       ringbuf->last_retired_head = -1;
-       ringbuf->head = I915_READ_HEAD(engine);
-       ringbuf->tail = I915_READ_TAIL(engine) & TAIL_ADDR;
-       intel_ring_update_space(ringbuf);
-
        intel_engine_init_hangcheck(engine);
 
 out:
@@ -640,59 +614,25 @@ out:
        return ret;
 }
 
-void intel_fini_pipe_control(struct intel_engine_cs *engine)
+static void reset_ring_common(struct intel_engine_cs *engine,
+                             struct drm_i915_gem_request *request)
 {
-       if (engine->scratch.obj == NULL)
-               return;
-
-       i915_gem_object_ggtt_unpin(engine->scratch.obj);
-       drm_gem_object_unreference(&engine->scratch.obj->base);
-       engine->scratch.obj = NULL;
-}
-
-int intel_init_pipe_control(struct intel_engine_cs *engine, int size)
-{
-       struct drm_i915_gem_object *obj;
-       int ret;
-
-       WARN_ON(engine->scratch.obj);
-
-       obj = i915_gem_object_create_stolen(&engine->i915->drm, size);
-       if (!obj)
-               obj = i915_gem_object_create(&engine->i915->drm, size);
-       if (IS_ERR(obj)) {
-               DRM_ERROR("Failed to allocate scratch page\n");
-               ret = PTR_ERR(obj);
-               goto err;
-       }
-
-       ret = i915_gem_obj_ggtt_pin(obj, 4096, PIN_HIGH);
-       if (ret)
-               goto err_unref;
+       struct intel_ring *ring = request->ring;
 
-       engine->scratch.obj = obj;
-       engine->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj);
-       DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
-                        engine->name, engine->scratch.gtt_offset);
-       return 0;
-
-err_unref:
-       drm_gem_object_unreference(&engine->scratch.obj->base);
-err:
-       return ret;
+       ring->head = request->postfix;
+       ring->last_retired_head = -1;
 }
 
 static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        struct i915_workarounds *w = &req->i915->workarounds;
        int ret, i;
 
        if (w->count == 0)
                return 0;
 
-       engine->gpu_caches_dirty = true;
-       ret = intel_ring_flush_all_caches(req);
+       ret = req->engine->emit_flush(req, EMIT_BARRIER);
        if (ret)
                return ret;
 
@@ -700,17 +640,16 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(w->count));
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(w->count));
        for (i = 0; i < w->count; i++) {
-               intel_ring_emit_reg(engine, w->reg[i].addr);
-               intel_ring_emit(engine, w->reg[i].value);
+               intel_ring_emit_reg(ring, w->reg[i].addr);
+               intel_ring_emit(ring, w->reg[i].value);
        }
-       intel_ring_emit(engine, MI_NOOP);
+       intel_ring_emit(ring, MI_NOOP);
 
-       intel_ring_advance(engine);
+       intel_ring_advance(ring);
 
-       engine->gpu_caches_dirty = true;
-       ret = intel_ring_flush_all_caches(req);
+       ret = req->engine->emit_flush(req, EMIT_BARRIER);
        if (ret)
                return ret;
 
@@ -1022,7 +961,7 @@ static int skl_tune_iz_hashing(struct intel_engine_cs *engine)
                 * Only consider slices where one, and only one, subslice has 7
                 * EUs
                 */
-               if (!is_power_of_2(dev_priv->info.subslice_7eu[i]))
+               if (!is_power_of_2(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i]))
                        continue;
 
                /*
@@ -1031,7 +970,7 @@ static int skl_tune_iz_hashing(struct intel_engine_cs *engine)
                 *
                 * ->    0 <= ss <= 3;
                 */
-               ss = ffs(dev_priv->info.subslice_7eu[i]) - 1;
+               ss = ffs(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i]) - 1;
                vals[i] = 3 - ss;
        }
 
@@ -1329,191 +1268,194 @@ static void render_ring_cleanup(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv = engine->i915;
 
-       if (dev_priv->semaphore_obj) {
-               i915_gem_object_ggtt_unpin(dev_priv->semaphore_obj);
-               drm_gem_object_unreference(&dev_priv->semaphore_obj->base);
-               dev_priv->semaphore_obj = NULL;
-       }
-
-       intel_fini_pipe_control(engine);
+       i915_vma_unpin_and_release(&dev_priv->semaphore);
 }
 
-static int gen8_rcs_signal(struct drm_i915_gem_request *signaller_req,
-                          unsigned int num_dwords)
+static int gen8_rcs_signal(struct drm_i915_gem_request *req)
 {
-#define MBOX_UPDATE_DWORDS 8
-       struct intel_engine_cs *signaller = signaller_req->engine;
-       struct drm_i915_private *dev_priv = signaller_req->i915;
+       struct intel_ring *ring = req->ring;
+       struct drm_i915_private *dev_priv = req->i915;
        struct intel_engine_cs *waiter;
        enum intel_engine_id id;
        int ret, num_rings;
 
-       num_rings = hweight32(INTEL_INFO(dev_priv)->ring_mask);
-       num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
-#undef MBOX_UPDATE_DWORDS
-
-       ret = intel_ring_begin(signaller_req, num_dwords);
+       num_rings = INTEL_INFO(dev_priv)->num_rings;
+       ret = intel_ring_begin(req, (num_rings-1) * 8);
        if (ret)
                return ret;
 
        for_each_engine_id(waiter, dev_priv, id) {
-               u64 gtt_offset = signaller->semaphore.signal_ggtt[id];
+               u64 gtt_offset = req->engine->semaphore.signal_ggtt[id];
                if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
                        continue;
 
-               intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6));
-               intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB |
-                                          PIPE_CONTROL_QW_WRITE |
-                                          PIPE_CONTROL_CS_STALL);
-               intel_ring_emit(signaller, lower_32_bits(gtt_offset));
-               intel_ring_emit(signaller, upper_32_bits(gtt_offset));
-               intel_ring_emit(signaller, signaller_req->seqno);
-               intel_ring_emit(signaller, 0);
-               intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
-                                          MI_SEMAPHORE_TARGET(waiter->hw_id));
-               intel_ring_emit(signaller, 0);
+               intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
+               intel_ring_emit(ring,
+                               PIPE_CONTROL_GLOBAL_GTT_IVB |
+                               PIPE_CONTROL_QW_WRITE |
+                               PIPE_CONTROL_CS_STALL);
+               intel_ring_emit(ring, lower_32_bits(gtt_offset));
+               intel_ring_emit(ring, upper_32_bits(gtt_offset));
+               intel_ring_emit(ring, req->fence.seqno);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring,
+                               MI_SEMAPHORE_SIGNAL |
+                               MI_SEMAPHORE_TARGET(waiter->hw_id));
+               intel_ring_emit(ring, 0);
        }
+       intel_ring_advance(ring);
 
        return 0;
 }
 
-static int gen8_xcs_signal(struct drm_i915_gem_request *signaller_req,
-                          unsigned int num_dwords)
+static int gen8_xcs_signal(struct drm_i915_gem_request *req)
 {
-#define MBOX_UPDATE_DWORDS 6
-       struct intel_engine_cs *signaller = signaller_req->engine;
-       struct drm_i915_private *dev_priv = signaller_req->i915;
+       struct intel_ring *ring = req->ring;
+       struct drm_i915_private *dev_priv = req->i915;
        struct intel_engine_cs *waiter;
        enum intel_engine_id id;
        int ret, num_rings;
 
-       num_rings = hweight32(INTEL_INFO(dev_priv)->ring_mask);
-       num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
-#undef MBOX_UPDATE_DWORDS
-
-       ret = intel_ring_begin(signaller_req, num_dwords);
+       num_rings = INTEL_INFO(dev_priv)->num_rings;
+       ret = intel_ring_begin(req, (num_rings-1) * 6);
        if (ret)
                return ret;
 
        for_each_engine_id(waiter, dev_priv, id) {
-               u64 gtt_offset = signaller->semaphore.signal_ggtt[id];
+               u64 gtt_offset = req->engine->semaphore.signal_ggtt[id];
                if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
                        continue;
 
-               intel_ring_emit(signaller, (MI_FLUSH_DW + 1) |
-                                          MI_FLUSH_DW_OP_STOREDW);
-               intel_ring_emit(signaller, lower_32_bits(gtt_offset) |
-                                          MI_FLUSH_DW_USE_GTT);
-               intel_ring_emit(signaller, upper_32_bits(gtt_offset));
-               intel_ring_emit(signaller, signaller_req->seqno);
-               intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
-                                          MI_SEMAPHORE_TARGET(waiter->hw_id));
-               intel_ring_emit(signaller, 0);
+               intel_ring_emit(ring,
+                               (MI_FLUSH_DW + 1) | MI_FLUSH_DW_OP_STOREDW);
+               intel_ring_emit(ring,
+                               lower_32_bits(gtt_offset) |
+                               MI_FLUSH_DW_USE_GTT);
+               intel_ring_emit(ring, upper_32_bits(gtt_offset));
+               intel_ring_emit(ring, req->fence.seqno);
+               intel_ring_emit(ring,
+                               MI_SEMAPHORE_SIGNAL |
+                               MI_SEMAPHORE_TARGET(waiter->hw_id));
+               intel_ring_emit(ring, 0);
        }
+       intel_ring_advance(ring);
 
        return 0;
 }
 
-static int gen6_signal(struct drm_i915_gem_request *signaller_req,
-                      unsigned int num_dwords)
+static int gen6_signal(struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *signaller = signaller_req->engine;
-       struct drm_i915_private *dev_priv = signaller_req->i915;
-       struct intel_engine_cs *useless;
-       enum intel_engine_id id;
+       struct intel_ring *ring = req->ring;
+       struct drm_i915_private *dev_priv = req->i915;
+       struct intel_engine_cs *engine;
        int ret, num_rings;
 
-#define MBOX_UPDATE_DWORDS 3
-       num_rings = hweight32(INTEL_INFO(dev_priv)->ring_mask);
-       num_dwords += round_up((num_rings-1) * MBOX_UPDATE_DWORDS, 2);
-#undef MBOX_UPDATE_DWORDS
-
-       ret = intel_ring_begin(signaller_req, num_dwords);
+       num_rings = INTEL_INFO(dev_priv)->num_rings;
+       ret = intel_ring_begin(req, round_up((num_rings-1) * 3, 2));
        if (ret)
                return ret;
 
-       for_each_engine_id(useless, dev_priv, id) {
-               i915_reg_t mbox_reg = signaller->semaphore.mbox.signal[id];
+       for_each_engine(engine, dev_priv) {
+               i915_reg_t mbox_reg;
 
+               if (!(BIT(engine->hw_id) & GEN6_SEMAPHORES_MASK))
+                       continue;
+
+               mbox_reg = req->engine->semaphore.mbox.signal[engine->hw_id];
                if (i915_mmio_reg_valid(mbox_reg)) {
-                       intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
-                       intel_ring_emit_reg(signaller, mbox_reg);
-                       intel_ring_emit(signaller, signaller_req->seqno);
+                       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+                       intel_ring_emit_reg(ring, mbox_reg);
+                       intel_ring_emit(ring, req->fence.seqno);
                }
        }
 
        /* If num_dwords was rounded, make sure the tail pointer is correct */
        if (num_rings % 2 == 0)
-               intel_ring_emit(signaller, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
+
+       return 0;
+}
+
+static void i9xx_submit_request(struct drm_i915_gem_request *request)
+{
+       struct drm_i915_private *dev_priv = request->i915;
+
+       I915_WRITE_TAIL(request->engine,
+                       intel_ring_offset(request->ring, request->tail));
+}
+
+static int i9xx_emit_request(struct drm_i915_gem_request *req)
+{
+       struct intel_ring *ring = req->ring;
+       int ret;
+
+       ret = intel_ring_begin(req, 4);
+       if (ret)
+               return ret;
+
+       intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
+       intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+       intel_ring_emit(ring, req->fence.seqno);
+       intel_ring_emit(ring, MI_USER_INTERRUPT);
+       intel_ring_advance(ring);
+
+       req->tail = ring->tail;
 
        return 0;
 }
 
 /**
- * gen6_add_request - Update the semaphore mailbox registers
+ * gen6_sema_emit_request - Update the semaphore mailbox registers
  *
  * @request - request to write to the ring
  *
  * Update the mailbox registers in the *other* rings with the current seqno.
  * This acts like a signal in the canonical semaphore.
  */
-static int
-gen6_add_request(struct drm_i915_gem_request *req)
+static int gen6_sema_emit_request(struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *engine = req->engine;
        int ret;
 
-       if (engine->semaphore.signal)
-               ret = engine->semaphore.signal(req, 4);
-       else
-               ret = intel_ring_begin(req, 4);
-
+       ret = req->engine->semaphore.signal(req);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, MI_STORE_DWORD_INDEX);
-       intel_ring_emit(engine,
-                       I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-       intel_ring_emit(engine, req->seqno);
-       intel_ring_emit(engine, MI_USER_INTERRUPT);
-       __intel_ring_advance(engine);
-
-       return 0;
+       return i9xx_emit_request(req);
 }
 
-static int
-gen8_render_add_request(struct drm_i915_gem_request *req)
+static int gen8_render_emit_request(struct drm_i915_gem_request *req)
 {
        struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        int ret;
 
-       if (engine->semaphore.signal)
-               ret = engine->semaphore.signal(req, 8);
-       else
-               ret = intel_ring_begin(req, 8);
+       if (engine->semaphore.signal) {
+               ret = engine->semaphore.signal(req);
+               if (ret)
+                       return ret;
+       }
+
+       ret = intel_ring_begin(req, 8);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(6));
-       intel_ring_emit(engine, (PIPE_CONTROL_GLOBAL_GTT_IVB |
-                                PIPE_CONTROL_CS_STALL |
-                                PIPE_CONTROL_QW_WRITE));
-       intel_ring_emit(engine, intel_hws_seqno_address(req->engine));
-       intel_ring_emit(engine, 0);
-       intel_ring_emit(engine, i915_gem_request_get_seqno(req));
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
+       intel_ring_emit(ring, (PIPE_CONTROL_GLOBAL_GTT_IVB |
+                              PIPE_CONTROL_CS_STALL |
+                              PIPE_CONTROL_QW_WRITE));
+       intel_ring_emit(ring, intel_hws_seqno_address(engine));
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, i915_gem_request_get_seqno(req));
        /* We're thrashing one dword of HWS. */
-       intel_ring_emit(engine, 0);
-       intel_ring_emit(engine, MI_USER_INTERRUPT);
-       intel_ring_emit(engine, MI_NOOP);
-       __intel_ring_advance(engine);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_USER_INTERRUPT);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
-       return 0;
-}
+       req->tail = ring->tail;
 
-static inline bool i915_gem_has_seqno_wrapped(struct drm_i915_private *dev_priv,
-                                             u32 seqno)
-{
-       return dev_priv->last_seqno < seqno;
+       return 0;
 }
 
 /**
@@ -1525,82 +1467,71 @@ static inline bool i915_gem_has_seqno_wrapped(struct drm_i915_private *dev_priv,
  */
 
 static int
-gen8_ring_sync(struct drm_i915_gem_request *waiter_req,
-              struct intel_engine_cs *signaller,
-              u32 seqno)
+gen8_ring_sync_to(struct drm_i915_gem_request *req,
+                 struct drm_i915_gem_request *signal)
 {
-       struct intel_engine_cs *waiter = waiter_req->engine;
-       struct drm_i915_private *dev_priv = waiter_req->i915;
-       u64 offset = GEN8_WAIT_OFFSET(waiter, signaller->id);
+       struct intel_ring *ring = req->ring;
+       struct drm_i915_private *dev_priv = req->i915;
+       u64 offset = GEN8_WAIT_OFFSET(req->engine, signal->engine->id);
        struct i915_hw_ppgtt *ppgtt;
        int ret;
 
-       ret = intel_ring_begin(waiter_req, 4);
+       ret = intel_ring_begin(req, 4);
        if (ret)
                return ret;
 
-       intel_ring_emit(waiter, MI_SEMAPHORE_WAIT |
-                               MI_SEMAPHORE_GLOBAL_GTT |
-                               MI_SEMAPHORE_SAD_GTE_SDD);
-       intel_ring_emit(waiter, seqno);
-       intel_ring_emit(waiter, lower_32_bits(offset));
-       intel_ring_emit(waiter, upper_32_bits(offset));
-       intel_ring_advance(waiter);
+       intel_ring_emit(ring,
+                       MI_SEMAPHORE_WAIT |
+                       MI_SEMAPHORE_GLOBAL_GTT |
+                       MI_SEMAPHORE_SAD_GTE_SDD);
+       intel_ring_emit(ring, signal->fence.seqno);
+       intel_ring_emit(ring, lower_32_bits(offset));
+       intel_ring_emit(ring, upper_32_bits(offset));
+       intel_ring_advance(ring);
 
        /* When the !RCS engines idle waiting upon a semaphore, they lose their
         * pagetables and we must reload them before executing the batch.
         * We do this on the i915_switch_context() following the wait and
         * before the dispatch.
         */
-       ppgtt = waiter_req->ctx->ppgtt;
-       if (ppgtt && waiter_req->engine->id != RCS)
-               ppgtt->pd_dirty_rings |= intel_engine_flag(waiter_req->engine);
+       ppgtt = req->ctx->ppgtt;
+       if (ppgtt && req->engine->id != RCS)
+               ppgtt->pd_dirty_rings |= intel_engine_flag(req->engine);
        return 0;
 }
 
 static int
-gen6_ring_sync(struct drm_i915_gem_request *waiter_req,
-              struct intel_engine_cs *signaller,
-              u32 seqno)
+gen6_ring_sync_to(struct drm_i915_gem_request *req,
+                 struct drm_i915_gem_request *signal)
 {
-       struct intel_engine_cs *waiter = waiter_req->engine;
+       struct intel_ring *ring = req->ring;
        u32 dw1 = MI_SEMAPHORE_MBOX |
                  MI_SEMAPHORE_COMPARE |
                  MI_SEMAPHORE_REGISTER;
-       u32 wait_mbox = signaller->semaphore.mbox.wait[waiter->id];
+       u32 wait_mbox = signal->engine->semaphore.mbox.wait[req->engine->hw_id];
        int ret;
 
-       /* Throughout all of the GEM code, seqno passed implies our current
-        * seqno is >= the last seqno executed. However for hardware the
-        * comparison is strictly greater than.
-        */
-       seqno -= 1;
-
        WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID);
 
-       ret = intel_ring_begin(waiter_req, 4);
+       ret = intel_ring_begin(req, 4);
        if (ret)
                return ret;
 
-       /* If seqno wrap happened, omit the wait with no-ops */
-       if (likely(!i915_gem_has_seqno_wrapped(waiter_req->i915, seqno))) {
-               intel_ring_emit(waiter, dw1 | wait_mbox);
-               intel_ring_emit(waiter, seqno);
-               intel_ring_emit(waiter, 0);
-               intel_ring_emit(waiter, MI_NOOP);
-       } else {
-               intel_ring_emit(waiter, MI_NOOP);
-               intel_ring_emit(waiter, MI_NOOP);
-               intel_ring_emit(waiter, MI_NOOP);
-               intel_ring_emit(waiter, MI_NOOP);
-       }
-       intel_ring_advance(waiter);
+       intel_ring_emit(ring, dw1 | wait_mbox);
+       /* Throughout all of the GEM code, seqno passed implies our current
+        * seqno is >= the last seqno executed. However for hardware the
+        * comparison is strictly greater than.
+        */
+       intel_ring_emit(ring, signal->fence.seqno - 1);
+       intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static void
-gen5_seqno_barrier(struct intel_engine_cs *ring)
+gen5_seqno_barrier(struct intel_engine_cs *engine)
 {
        /* MI_STORE are internally buffered by the GPU and not flushed
         * either by MI_FLUSH or SyncFlush or any other combination of
@@ -1693,40 +1624,18 @@ i8xx_irq_disable(struct intel_engine_cs *engine)
 }
 
 static int
-bsd_ring_flush(struct drm_i915_gem_request *req,
-              u32     invalidate_domains,
-              u32     flush_domains)
+bsd_ring_flush(struct drm_i915_gem_request *req, u32 mode)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        int ret;
 
        ret = intel_ring_begin(req, 2);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, MI_FLUSH);
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
-       return 0;
-}
-
-static int
-i9xx_add_request(struct drm_i915_gem_request *req)
-{
-       struct intel_engine_cs *engine = req->engine;
-       int ret;
-
-       ret = intel_ring_begin(req, 4);
-       if (ret)
-               return ret;
-
-       intel_ring_emit(engine, MI_STORE_DWORD_INDEX);
-       intel_ring_emit(engine,
-                       I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-       intel_ring_emit(engine, req->seqno);
-       intel_ring_emit(engine, MI_USER_INTERRUPT);
-       __intel_ring_advance(engine);
-
+       intel_ring_emit(ring, MI_FLUSH);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
        return 0;
 }
 
@@ -1788,24 +1697,24 @@ gen8_irq_disable(struct intel_engine_cs *engine)
 }
 
 static int
-i965_dispatch_execbuffer(struct drm_i915_gem_request *req,
-                        u64 offset, u32 length,
-                        unsigned dispatch_flags)
+i965_emit_bb_start(struct drm_i915_gem_request *req,
+                  u64 offset, u32 length,
+                  unsigned int dispatch_flags)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        int ret;
 
        ret = intel_ring_begin(req, 2);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine,
+       intel_ring_emit(ring,
                        MI_BATCH_BUFFER_START |
                        MI_BATCH_GTT |
                        (dispatch_flags & I915_DISPATCH_SECURE ?
                         0 : MI_BATCH_NON_SECURE_I965));
-       intel_ring_emit(engine, offset);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, offset);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -1815,12 +1724,12 @@ i965_dispatch_execbuffer(struct drm_i915_gem_request *req,
 #define I830_TLB_ENTRIES (2)
 #define I830_WA_SIZE max(I830_TLB_ENTRIES*4096, I830_BATCH_LIMIT)
 static int
-i830_dispatch_execbuffer(struct drm_i915_gem_request *req,
-                        u64 offset, u32 len,
-                        unsigned dispatch_flags)
+i830_emit_bb_start(struct drm_i915_gem_request *req,
+                  u64 offset, u32 len,
+                  unsigned int dispatch_flags)
 {
-       struct intel_engine_cs *engine = req->engine;
-       u32 cs_offset = engine->scratch.gtt_offset;
+       struct intel_ring *ring = req->ring;
+       u32 cs_offset = i915_ggtt_offset(req->engine->scratch);
        int ret;
 
        ret = intel_ring_begin(req, 6);
@@ -1828,13 +1737,13 @@ i830_dispatch_execbuffer(struct drm_i915_gem_request *req,
                return ret;
 
        /* Evict the invalid PTE TLBs */
-       intel_ring_emit(engine, COLOR_BLT_CMD | BLT_WRITE_RGBA);
-       intel_ring_emit(engine, BLT_DEPTH_32 | BLT_ROP_COLOR_COPY | 4096);
-       intel_ring_emit(engine, I830_TLB_ENTRIES << 16 | 4); /* load each page */
-       intel_ring_emit(engine, cs_offset);
-       intel_ring_emit(engine, 0xdeadbeef);
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, COLOR_BLT_CMD | BLT_WRITE_RGBA);
+       intel_ring_emit(ring, BLT_DEPTH_32 | BLT_ROP_COLOR_COPY | 4096);
+       intel_ring_emit(ring, I830_TLB_ENTRIES << 16 | 4); /* load each page */
+       intel_ring_emit(ring, cs_offset);
+       intel_ring_emit(ring, 0xdeadbeef);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        if ((dispatch_flags & I915_DISPATCH_PINNED) == 0) {
                if (len > I830_BATCH_LIMIT)
@@ -1848,17 +1757,17 @@ i830_dispatch_execbuffer(struct drm_i915_gem_request *req,
                 * stable batch scratch bo area (so that the CS never
                 * stumbles over its tlb invalidation bug) ...
                 */
-               intel_ring_emit(engine, SRC_COPY_BLT_CMD | BLT_WRITE_RGBA);
-               intel_ring_emit(engine,
+               intel_ring_emit(ring, SRC_COPY_BLT_CMD | BLT_WRITE_RGBA);
+               intel_ring_emit(ring,
                                BLT_DEPTH_32 | BLT_ROP_SRC_COPY | 4096);
-               intel_ring_emit(engine, DIV_ROUND_UP(len, 4096) << 16 | 4096);
-               intel_ring_emit(engine, cs_offset);
-               intel_ring_emit(engine, 4096);
-               intel_ring_emit(engine, offset);
+               intel_ring_emit(ring, DIV_ROUND_UP(len, 4096) << 16 | 4096);
+               intel_ring_emit(ring, cs_offset);
+               intel_ring_emit(ring, 4096);
+               intel_ring_emit(ring, offset);
 
-               intel_ring_emit(engine, MI_FLUSH);
-               intel_ring_emit(engine, MI_NOOP);
-               intel_ring_advance(engine);
+               intel_ring_emit(ring, MI_FLUSH);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_advance(ring);
 
                /* ... and execute it. */
                offset = cs_offset;
@@ -1868,30 +1777,30 @@ i830_dispatch_execbuffer(struct drm_i915_gem_request *req,
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
-       intel_ring_emit(engine, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
-                                         0 : MI_BATCH_NON_SECURE));
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
+       intel_ring_emit(ring, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
+                                       0 : MI_BATCH_NON_SECURE));
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static int
-i915_dispatch_execbuffer(struct drm_i915_gem_request *req,
-                        u64 offset, u32 len,
-                        unsigned dispatch_flags)
+i915_emit_bb_start(struct drm_i915_gem_request *req,
+                  u64 offset, u32 len,
+                  unsigned int dispatch_flags)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        int ret;
 
        ret = intel_ring_begin(req, 2);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
-       intel_ring_emit(engine, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
-                                         0 : MI_BATCH_NON_SECURE));
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
+       intel_ring_emit(ring, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
+                                       0 : MI_BATCH_NON_SECURE));
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -1909,79 +1818,79 @@ static void cleanup_phys_status_page(struct intel_engine_cs *engine)
 
 static void cleanup_status_page(struct intel_engine_cs *engine)
 {
-       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
 
-       obj = engine->status_page.obj;
-       if (obj == NULL)
+       vma = fetch_and_zero(&engine->status_page.vma);
+       if (!vma)
                return;
 
-       kunmap(sg_page(obj->pages->sgl));
-       i915_gem_object_ggtt_unpin(obj);
-       drm_gem_object_unreference(&obj->base);
-       engine->status_page.obj = NULL;
+       i915_vma_unpin(vma);
+       i915_gem_object_unpin_map(vma->obj);
+       i915_vma_put(vma);
 }
 
 static int init_status_page(struct intel_engine_cs *engine)
 {
-       struct drm_i915_gem_object *obj = engine->status_page.obj;
-
-       if (obj == NULL) {
-               unsigned flags;
-               int ret;
+       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
+       unsigned int flags;
+       int ret;
 
-               obj = i915_gem_object_create(&engine->i915->drm, 4096);
-               if (IS_ERR(obj)) {
-                       DRM_ERROR("Failed to allocate status page\n");
-                       return PTR_ERR(obj);
-               }
+       obj = i915_gem_object_create(&engine->i915->drm, 4096);
+       if (IS_ERR(obj)) {
+               DRM_ERROR("Failed to allocate status page\n");
+               return PTR_ERR(obj);
+       }
 
-               ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
-               if (ret)
-                       goto err_unref;
-
-               flags = 0;
-               if (!HAS_LLC(engine->i915))
-                       /* On g33, we cannot place HWS above 256MiB, so
-                        * restrict its pinning to the low mappable arena.
-                        * Though this restriction is not documented for
-                        * gen4, gen5, or byt, they also behave similarly
-                        * and hang if the HWS is placed at the top of the
-                        * GTT. To generalise, it appears that all !llc
-                        * platforms have issues with us placing the HWS
-                        * above the mappable region (even though we never
-                        * actualy map it).
-                        */
-                       flags |= PIN_MAPPABLE;
-               ret = i915_gem_obj_ggtt_pin(obj, 4096, flags);
-               if (ret) {
-err_unref:
-                       drm_gem_object_unreference(&obj->base);
-                       return ret;
-               }
+       ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
+       if (ret)
+               goto err;
 
-               engine->status_page.obj = obj;
+       vma = i915_vma_create(obj, &engine->i915->ggtt.base, NULL);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
+               goto err;
        }
 
-       engine->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj);
-       engine->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
-       memset(engine->status_page.page_addr, 0, PAGE_SIZE);
+       flags = PIN_GLOBAL;
+       if (!HAS_LLC(engine->i915))
+               /* On g33, we cannot place HWS above 256MiB, so
+                * restrict its pinning to the low mappable arena.
+                * Though this restriction is not documented for
+                * gen4, gen5, or byt, they also behave similarly
+                * and hang if the HWS is placed at the top of the
+                * GTT. To generalise, it appears that all !llc
+                * platforms have issues with us placing the HWS
+                * above the mappable region (even though we never
+                * actualy map it).
+                */
+               flags |= PIN_MAPPABLE;
+       ret = i915_vma_pin(vma, 0, 4096, flags);
+       if (ret)
+               goto err;
 
-       DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
-                       engine->name, engine->status_page.gfx_addr);
+       engine->status_page.vma = vma;
+       engine->status_page.ggtt_offset = i915_ggtt_offset(vma);
+       engine->status_page.page_addr =
+               i915_gem_object_pin_map(obj, I915_MAP_WB);
 
+       DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
+                        engine->name, i915_ggtt_offset(vma));
        return 0;
+
+err:
+       i915_gem_object_put(obj);
+       return ret;
 }
 
 static int init_phys_status_page(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv = engine->i915;
 
-       if (!dev_priv->status_page_dmah) {
-               dev_priv->status_page_dmah =
-                       drm_pci_alloc(&dev_priv->drm, PAGE_SIZE, PAGE_SIZE);
-               if (!dev_priv->status_page_dmah)
-                       return -ENOMEM;
-       }
+       dev_priv->status_page_dmah =
+               drm_pci_alloc(&dev_priv->drm, PAGE_SIZE, PAGE_SIZE);
+       if (!dev_priv->status_page_dmah)
+               return -ENOMEM;
 
        engine->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
        memset(engine->status_page.page_addr, 0, PAGE_SIZE);
@@ -1989,115 +1898,105 @@ static int init_phys_status_page(struct intel_engine_cs *engine)
        return 0;
 }
 
-void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
-{
-       GEM_BUG_ON(ringbuf->vma == NULL);
-       GEM_BUG_ON(ringbuf->virtual_start == NULL);
-
-       if (HAS_LLC(ringbuf->obj->base.dev) && !ringbuf->obj->stolen)
-               i915_gem_object_unpin_map(ringbuf->obj);
-       else
-               i915_vma_unpin_iomap(ringbuf->vma);
-       ringbuf->virtual_start = NULL;
-
-       i915_gem_object_ggtt_unpin(ringbuf->obj);
-       ringbuf->vma = NULL;
-}
-
-int intel_pin_and_map_ringbuffer_obj(struct drm_i915_private *dev_priv,
-                                    struct intel_ringbuffer *ringbuf)
+int intel_ring_pin(struct intel_ring *ring)
 {
-       struct drm_i915_gem_object *obj = ringbuf->obj;
        /* Ring wraparound at offset 0 sometimes hangs. No idea why. */
-       unsigned flags = PIN_OFFSET_BIAS | 4096;
+       unsigned int flags = PIN_GLOBAL | PIN_OFFSET_BIAS | 4096;
+       enum i915_map_type map;
+       struct i915_vma *vma = ring->vma;
        void *addr;
        int ret;
 
-       if (HAS_LLC(dev_priv) && !obj->stolen) {
-               ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, flags);
-               if (ret)
-                       return ret;
+       GEM_BUG_ON(ring->vaddr);
 
-               ret = i915_gem_object_set_to_cpu_domain(obj, true);
-               if (ret)
-                       goto err_unpin;
+       map = HAS_LLC(ring->engine->i915) ? I915_MAP_WB : I915_MAP_WC;
 
-               addr = i915_gem_object_pin_map(obj);
-               if (IS_ERR(addr)) {
-                       ret = PTR_ERR(addr);
-                       goto err_unpin;
-               }
-       } else {
-               ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
-                                           flags | PIN_MAPPABLE);
-               if (ret)
-                       return ret;
+       if (vma->obj->stolen)
+               flags |= PIN_MAPPABLE;
 
-               ret = i915_gem_object_set_to_gtt_domain(obj, true);
-               if (ret)
-                       goto err_unpin;
+       if (!(vma->flags & I915_VMA_GLOBAL_BIND)) {
+               if (flags & PIN_MAPPABLE || map == I915_MAP_WC)
+                       ret = i915_gem_object_set_to_gtt_domain(vma->obj, true);
+               else
+                       ret = i915_gem_object_set_to_cpu_domain(vma->obj, true);
+               if (unlikely(ret))
+                       return ret;
+       }
 
-               /* Access through the GTT requires the device to be awake. */
-               assert_rpm_wakelock_held(dev_priv);
+       ret = i915_vma_pin(vma, 0, PAGE_SIZE, flags);
+       if (unlikely(ret))
+               return ret;
 
-               addr = i915_vma_pin_iomap(i915_gem_obj_to_ggtt(obj));
-               if (IS_ERR(addr)) {
-                       ret = PTR_ERR(addr);
-                       goto err_unpin;
-               }
-       }
+       if (i915_vma_is_map_and_fenceable(vma))
+               addr = (void __force *)i915_vma_pin_iomap(vma);
+       else
+               addr = i915_gem_object_pin_map(vma->obj, map);
+       if (IS_ERR(addr))
+               goto err;
 
-       ringbuf->virtual_start = addr;
-       ringbuf->vma = i915_gem_obj_to_ggtt(obj);
+       ring->vaddr = addr;
        return 0;
 
-err_unpin:
-       i915_gem_object_ggtt_unpin(obj);
-       return ret;
+err:
+       i915_vma_unpin(vma);
+       return PTR_ERR(addr);
 }
 
-static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
+void intel_ring_unpin(struct intel_ring *ring)
 {
-       drm_gem_object_unreference(&ringbuf->obj->base);
-       ringbuf->obj = NULL;
+       GEM_BUG_ON(!ring->vma);
+       GEM_BUG_ON(!ring->vaddr);
+
+       if (i915_vma_is_map_and_fenceable(ring->vma))
+               i915_vma_unpin_iomap(ring->vma);
+       else
+               i915_gem_object_unpin_map(ring->vma->obj);
+       ring->vaddr = NULL;
+
+       i915_vma_unpin(ring->vma);
 }
 
-static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
-                                     struct intel_ringbuffer *ringbuf)
+static struct i915_vma *
+intel_ring_create_vma(struct drm_i915_private *dev_priv, int size)
 {
        struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
 
-       obj = NULL;
-       if (!HAS_LLC(dev))
-               obj = i915_gem_object_create_stolen(dev, ringbuf->size);
-       if (obj == NULL)
-               obj = i915_gem_object_create(dev, ringbuf->size);
+       obj = i915_gem_object_create_stolen(&dev_priv->drm, size);
+       if (!obj)
+               obj = i915_gem_object_create(&dev_priv->drm, size);
        if (IS_ERR(obj))
-               return PTR_ERR(obj);
+               return ERR_CAST(obj);
 
        /* mark ring buffers as read-only from GPU side by default */
        obj->gt_ro = 1;
 
-       ringbuf->obj = obj;
+       vma = i915_vma_create(obj, &dev_priv->ggtt.base, NULL);
+       if (IS_ERR(vma))
+               goto err;
 
-       return 0;
+       return vma;
+
+err:
+       i915_gem_object_put(obj);
+       return vma;
 }
 
-struct intel_ringbuffer *
-intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
+struct intel_ring *
+intel_engine_create_ring(struct intel_engine_cs *engine, int size)
 {
-       struct intel_ringbuffer *ring;
-       int ret;
+       struct intel_ring *ring;
+       struct i915_vma *vma;
+
+       GEM_BUG_ON(!is_power_of_2(size));
 
        ring = kzalloc(sizeof(*ring), GFP_KERNEL);
-       if (ring == NULL) {
-               DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
-                                engine->name);
+       if (!ring)
                return ERR_PTR(-ENOMEM);
-       }
 
        ring->engine = engine;
-       list_add(&ring->link, &engine->buffers);
+
+       INIT_LIST_HEAD(&ring->request_list);
 
        ring->size = size;
        /* Workaround an erratum on the i830 which causes a hang if
@@ -2111,23 +2010,20 @@ intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
        ring->last_retired_head = -1;
        intel_ring_update_space(ring);
 
-       ret = intel_alloc_ringbuffer_obj(&engine->i915->drm, ring);
-       if (ret) {
-               DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n",
-                                engine->name, ret);
-               list_del(&ring->link);
+       vma = intel_ring_create_vma(engine->i915, size);
+       if (IS_ERR(vma)) {
                kfree(ring);
-               return ERR_PTR(ret);
+               return ERR_CAST(vma);
        }
+       ring->vma = vma;
 
        return ring;
 }
 
 void
-intel_ringbuffer_free(struct intel_ringbuffer *ring)
+intel_ring_free(struct intel_ring *ring)
 {
-       intel_destroy_ringbuffer_obj(ring);
-       list_del(&ring->link);
+       i915_vma_put(ring->vma);
        kfree(ring);
 }
 
@@ -2143,7 +2039,12 @@ static int intel_ring_context_pin(struct i915_gem_context *ctx,
                return 0;
 
        if (ce->state) {
-               ret = i915_gem_obj_ggtt_pin(ce->state, ctx->ggtt_alignment, 0);
+               ret = i915_gem_object_set_to_gtt_domain(ce->state->obj, false);
+               if (ret)
+                       goto error;
+
+               ret = i915_vma_pin(ce->state, 0, ctx->ggtt_alignment,
+                                  PIN_GLOBAL | PIN_HIGH);
                if (ret)
                        goto error;
        }
@@ -2158,7 +2059,7 @@ static int intel_ring_context_pin(struct i915_gem_context *ctx,
        if (ctx == ctx->i915->kernel_context)
                ce->initialised = true;
 
-       i915_gem_context_reference(ctx);
+       i915_gem_context_get(ctx);
        return 0;
 
 error:
@@ -2177,30 +2078,25 @@ static void intel_ring_context_unpin(struct i915_gem_context *ctx,
                return;
 
        if (ce->state)
-               i915_gem_object_ggtt_unpin(ce->state);
+               i915_vma_unpin(ce->state);
 
-       i915_gem_context_unreference(ctx);
+       i915_gem_context_put(ctx);
 }
 
-static int intel_init_ring_buffer(struct drm_device *dev,
-                                 struct intel_engine_cs *engine)
+static int intel_init_ring_buffer(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_ringbuffer *ringbuf;
+       struct drm_i915_private *dev_priv = engine->i915;
+       struct intel_ring *ring;
        int ret;
 
        WARN_ON(engine->buffer);
 
-       engine->i915 = dev_priv;
-       INIT_LIST_HEAD(&engine->active_list);
-       INIT_LIST_HEAD(&engine->request_list);
-       INIT_LIST_HEAD(&engine->execlist_queue);
-       INIT_LIST_HEAD(&engine->buffers);
-       i915_gem_batch_pool_init(dev, &engine->batch_pool);
+       intel_engine_setup_common(engine);
+
        memset(engine->semaphore.sync_seqno, 0,
               sizeof(engine->semaphore.sync_seqno));
 
-       ret = intel_engine_init_breadcrumbs(engine);
+       ret = intel_engine_init_common(engine);
        if (ret)
                goto error;
 
@@ -2215,44 +2111,38 @@ static int intel_init_ring_buffer(struct drm_device *dev,
        if (ret)
                goto error;
 
-       ringbuf = intel_engine_create_ringbuffer(engine, 32 * PAGE_SIZE);
-       if (IS_ERR(ringbuf)) {
-               ret = PTR_ERR(ringbuf);
+       ring = intel_engine_create_ring(engine, 32 * PAGE_SIZE);
+       if (IS_ERR(ring)) {
+               ret = PTR_ERR(ring);
                goto error;
        }
-       engine->buffer = ringbuf;
 
-       if (I915_NEED_GFX_HWS(dev_priv)) {
-               ret = init_status_page(engine);
+       if (HWS_NEEDS_PHYSICAL(dev_priv)) {
+               WARN_ON(engine->id != RCS);
+               ret = init_phys_status_page(engine);
                if (ret)
                        goto error;
        } else {
-               WARN_ON(engine->id != RCS);
-               ret = init_phys_status_page(engine);
+               ret = init_status_page(engine);
                if (ret)
                        goto error;
        }
 
-       ret = intel_pin_and_map_ringbuffer_obj(dev_priv, ringbuf);
+       ret = intel_ring_pin(ring);
        if (ret) {
-               DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
-                               engine->name, ret);
-               intel_destroy_ringbuffer_obj(ringbuf);
+               intel_ring_free(ring);
                goto error;
        }
-
-       ret = i915_cmd_parser_init_ring(engine);
-       if (ret)
-               goto error;
+       engine->buffer = ring;
 
        return 0;
 
 error:
-       intel_cleanup_engine(engine);
+       intel_engine_cleanup(engine);
        return ret;
 }
 
-void intel_cleanup_engine(struct intel_engine_cs *engine)
+void intel_engine_cleanup(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv;
 
@@ -2262,49 +2152,39 @@ void intel_cleanup_engine(struct intel_engine_cs *engine)
        dev_priv = engine->i915;
 
        if (engine->buffer) {
-               intel_stop_engine(engine);
-               WARN_ON(!IS_GEN2(dev_priv) && (I915_READ_MODE(engine) & MODE_IDLE) == 0);
+               WARN_ON(INTEL_GEN(dev_priv) > 2 &&
+                       (I915_READ_MODE(engine) & MODE_IDLE) == 0);
 
-               intel_unpin_ringbuffer_obj(engine->buffer);
-               intel_ringbuffer_free(engine->buffer);
+               intel_ring_unpin(engine->buffer);
+               intel_ring_free(engine->buffer);
                engine->buffer = NULL;
        }
 
        if (engine->cleanup)
                engine->cleanup(engine);
 
-       if (I915_NEED_GFX_HWS(dev_priv)) {
-               cleanup_status_page(engine);
-       } else {
+       if (HWS_NEEDS_PHYSICAL(dev_priv)) {
                WARN_ON(engine->id != RCS);
                cleanup_phys_status_page(engine);
+       } else {
+               cleanup_status_page(engine);
        }
 
-       i915_cmd_parser_fini_ring(engine);
-       i915_gem_batch_pool_fini(&engine->batch_pool);
-       intel_engine_fini_breadcrumbs(engine);
+       intel_engine_cleanup_common(engine);
 
        intel_ring_context_unpin(dev_priv->kernel_context, engine);
 
        engine->i915 = NULL;
 }
 
-int intel_engine_idle(struct intel_engine_cs *engine)
+void intel_legacy_submission_resume(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_gem_request *req;
+       struct intel_engine_cs *engine;
 
-       /* Wait upon the last request to be completed */
-       if (list_empty(&engine->request_list))
-               return 0;
-
-       req = list_entry(engine->request_list.prev,
-                        struct drm_i915_gem_request,
-                        list);
-
-       /* Make sure we do not trigger any retires */
-       return __i915_wait_request(req,
-                                  req->i915->mm.interruptible,
-                                  NULL, NULL);
+       for_each_engine(engine, dev_priv) {
+               engine->buffer->head = engine->buffer->tail;
+               engine->buffer->last_retired_head = -1;
+       }
 }
 
 int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
@@ -2317,7 +2197,7 @@ int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
         */
        request->reserved_space += LEGACY_REQUEST_SIZE;
 
-       request->ringbuf = request->engine->buffer;
+       request->ring = request->engine->buffer;
 
        ret = intel_ring_begin(request, 0);
        if (ret)
@@ -2329,12 +2209,12 @@ int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
 
 static int wait_for_space(struct drm_i915_gem_request *req, int bytes)
 {
-       struct intel_ringbuffer *ringbuf = req->ringbuf;
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        struct drm_i915_gem_request *target;
+       int ret;
 
-       intel_ring_update_space(ringbuf);
-       if (ringbuf->space >= bytes)
+       intel_ring_update_space(ring);
+       if (ring->space >= bytes)
                return 0;
 
        /*
@@ -2348,35 +2228,37 @@ static int wait_for_space(struct drm_i915_gem_request *req, int bytes)
         */
        GEM_BUG_ON(!req->reserved_space);
 
-       list_for_each_entry(target, &engine->request_list, list) {
+       list_for_each_entry(target, &ring->request_list, ring_link) {
                unsigned space;
 
-               /*
-                * The request queue is per-engine, so can contain requests
-                * from multiple ringbuffers. Here, we must ignore any that
-                * aren't from the ringbuffer we're considering.
-                */
-               if (target->ringbuf != ringbuf)
-                       continue;
-
                /* Would completion of this request free enough space? */
-               space = __intel_ring_space(target->postfix, ringbuf->tail,
-                                          ringbuf->size);
+               space = __intel_ring_space(target->postfix, ring->tail,
+                                          ring->size);
                if (space >= bytes)
                        break;
        }
 
-       if (WARN_ON(&target->list == &engine->request_list))
+       if (WARN_ON(&target->ring_link == &ring->request_list))
                return -ENOSPC;
 
-       return i915_wait_request(target);
+       ret = i915_wait_request(target,
+                               I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
+                               NULL, NO_WAITBOOST);
+       if (ret)
+               return ret;
+
+       i915_gem_request_retire_upto(target);
+
+       intel_ring_update_space(ring);
+       GEM_BUG_ON(ring->space < bytes);
+       return 0;
 }
 
 int intel_ring_begin(struct drm_i915_gem_request *req, int num_dwords)
 {
-       struct intel_ringbuffer *ringbuf = req->ringbuf;
-       int remain_actual = ringbuf->size - ringbuf->tail;
-       int remain_usable = ringbuf->effective_size - ringbuf->tail;
+       struct intel_ring *ring = req->ring;
+       int remain_actual = ring->size - ring->tail;
+       int remain_usable = ring->effective_size - ring->tail;
        int bytes = num_dwords * sizeof(u32);
        int total_bytes, wait_bytes;
        bool need_wrap = false;
@@ -2403,37 +2285,33 @@ int intel_ring_begin(struct drm_i915_gem_request *req, int num_dwords)
                wait_bytes = total_bytes;
        }
 
-       if (wait_bytes > ringbuf->space) {
+       if (wait_bytes > ring->space) {
                int ret = wait_for_space(req, wait_bytes);
                if (unlikely(ret))
                        return ret;
-
-               intel_ring_update_space(ringbuf);
-               if (unlikely(ringbuf->space < wait_bytes))
-                       return -EAGAIN;
        }
 
        if (unlikely(need_wrap)) {
-               GEM_BUG_ON(remain_actual > ringbuf->space);
-               GEM_BUG_ON(ringbuf->tail + remain_actual > ringbuf->size);
+               GEM_BUG_ON(remain_actual > ring->space);
+               GEM_BUG_ON(ring->tail + remain_actual > ring->size);
 
                /* Fill the tail with MI_NOOP */
-               memset(ringbuf->virtual_start + ringbuf->tail,
-                      0, remain_actual);
-               ringbuf->tail = 0;
-               ringbuf->space -= remain_actual;
+               memset(ring->vaddr + ring->tail, 0, remain_actual);
+               ring->tail = 0;
+               ring->space -= remain_actual;
        }
 
-       ringbuf->space -= bytes;
-       GEM_BUG_ON(ringbuf->space < 0);
+       ring->space -= bytes;
+       GEM_BUG_ON(ring->space < 0);
        return 0;
 }
 
 /* Align the ring tail to a cacheline boundary */
 int intel_ring_cacheline_align(struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *engine = req->engine;
-       int num_dwords = (engine->buffer->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t);
+       struct intel_ring *ring = req->ring;
+       int num_dwords =
+               (ring->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t);
        int ret;
 
        if (num_dwords == 0)
@@ -2445,61 +2323,16 @@ int intel_ring_cacheline_align(struct drm_i915_gem_request *req)
                return ret;
 
        while (num_dwords--)
-               intel_ring_emit(engine, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
 
-       intel_ring_advance(engine);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
-void intel_ring_init_seqno(struct intel_engine_cs *engine, u32 seqno)
-{
-       struct drm_i915_private *dev_priv = engine->i915;
-
-       /* Our semaphore implementation is strictly monotonic (i.e. we proceed
-        * so long as the semaphore value in the register/page is greater
-        * than the sync value), so whenever we reset the seqno,
-        * so long as we reset the tracking semaphore value to 0, it will
-        * always be before the next request's seqno. If we don't reset
-        * the semaphore value, then when the seqno moves backwards all
-        * future waits will complete instantly (causing rendering corruption).
-        */
-       if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) {
-               I915_WRITE(RING_SYNC_0(engine->mmio_base), 0);
-               I915_WRITE(RING_SYNC_1(engine->mmio_base), 0);
-               if (HAS_VEBOX(dev_priv))
-                       I915_WRITE(RING_SYNC_2(engine->mmio_base), 0);
-       }
-       if (dev_priv->semaphore_obj) {
-               struct drm_i915_gem_object *obj = dev_priv->semaphore_obj;
-               struct page *page = i915_gem_object_get_dirty_page(obj, 0);
-               void *semaphores = kmap(page);
-               memset(semaphores + GEN8_SEMAPHORE_OFFSET(engine->id, 0),
-                      0, I915_NUM_ENGINES * gen8_semaphore_seqno_size);
-               kunmap(page);
-       }
-       memset(engine->semaphore.sync_seqno, 0,
-              sizeof(engine->semaphore.sync_seqno));
-
-       intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno);
-       if (engine->irq_seqno_barrier)
-               engine->irq_seqno_barrier(engine);
-       engine->last_submitted_seqno = seqno;
-
-       engine->hangcheck.seqno = seqno;
-
-       /* After manually advancing the seqno, fake the interrupt in case
-        * there are any waiters for that seqno.
-        */
-       rcu_read_lock();
-       intel_engine_wakeup(engine);
-       rcu_read_unlock();
-}
-
-static void gen6_bsd_ring_write_tail(struct intel_engine_cs *engine,
-                                    u32 value)
+static void gen6_bsd_submit_request(struct drm_i915_gem_request *request)
 {
-       struct drm_i915_private *dev_priv = engine->i915;
+       struct drm_i915_private *dev_priv = request->i915;
 
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
@@ -2523,8 +2356,7 @@ static void gen6_bsd_ring_write_tail(struct intel_engine_cs *engine,
                DRM_ERROR("timed out waiting for the BSD ring to wake up\n");
 
        /* Now that the ring is fully powered up, update the tail */
-       I915_WRITE_FW(RING_TAIL(engine->mmio_base), value);
-       POSTING_READ_FW(RING_TAIL(engine->mmio_base));
+       i9xx_submit_request(request);
 
        /* Let the ring send IDLE messages to the GT again,
         * and so let it sleep to conserve power when idle.
@@ -2535,10 +2367,9 @@ static void gen6_bsd_ring_write_tail(struct intel_engine_cs *engine,
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
-static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req,
-                              u32 invalidate, u32 flush)
+static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req, u32 mode)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        uint32_t cmd;
        int ret;
 
@@ -2563,30 +2394,29 @@ static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req,
         * operation is complete. This bit is only valid when the
         * Post-Sync Operation field is a value of 1h or 3h."
         */
-       if (invalidate & I915_GEM_GPU_DOMAINS)
+       if (mode & EMIT_INVALIDATE)
                cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
 
-       intel_ring_emit(engine, cmd);
-       intel_ring_emit(engine,
-                       I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
+       intel_ring_emit(ring, cmd);
+       intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
        if (INTEL_GEN(req->i915) >= 8) {
-               intel_ring_emit(engine, 0); /* upper addr */
-               intel_ring_emit(engine, 0); /* value */
+               intel_ring_emit(ring, 0); /* upper addr */
+               intel_ring_emit(ring, 0); /* value */
        } else  {
-               intel_ring_emit(engine, 0);
-               intel_ring_emit(engine, MI_NOOP);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, MI_NOOP);
        }
-       intel_ring_advance(engine);
+       intel_ring_advance(ring);
        return 0;
 }
 
 static int
-gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
-                             u64 offset, u32 len,
-                             unsigned dispatch_flags)
+gen8_emit_bb_start(struct drm_i915_gem_request *req,
+                  u64 offset, u32 len,
+                  unsigned int dispatch_flags)
 {
-       struct intel_engine_cs *engine = req->engine;
-       bool ppgtt = USES_PPGTT(engine->dev) &&
+       struct intel_ring *ring = req->ring;
+       bool ppgtt = USES_PPGTT(req->i915) &&
                        !(dispatch_flags & I915_DISPATCH_SECURE);
        int ret;
 
@@ -2595,71 +2425,70 @@ gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
                return ret;
 
        /* FIXME(BDW): Address space and security selectors. */
-       intel_ring_emit(engine, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8) |
+       intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8) |
                        (dispatch_flags & I915_DISPATCH_RS ?
                         MI_BATCH_RESOURCE_STREAMER : 0));
-       intel_ring_emit(engine, lower_32_bits(offset));
-       intel_ring_emit(engine, upper_32_bits(offset));
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, lower_32_bits(offset));
+       intel_ring_emit(ring, upper_32_bits(offset));
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static int
-hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
-                            u64 offset, u32 len,
-                            unsigned dispatch_flags)
+hsw_emit_bb_start(struct drm_i915_gem_request *req,
+                 u64 offset, u32 len,
+                 unsigned int dispatch_flags)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        int ret;
 
        ret = intel_ring_begin(req, 2);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine,
+       intel_ring_emit(ring,
                        MI_BATCH_BUFFER_START |
                        (dispatch_flags & I915_DISPATCH_SECURE ?
                         0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW) |
                        (dispatch_flags & I915_DISPATCH_RS ?
                         MI_BATCH_RESOURCE_STREAMER : 0));
        /* bit0-7 is the length on GEN6+ */
-       intel_ring_emit(engine, offset);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, offset);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 static int
-gen6_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
-                             u64 offset, u32 len,
-                             unsigned dispatch_flags)
+gen6_emit_bb_start(struct drm_i915_gem_request *req,
+                  u64 offset, u32 len,
+                  unsigned int dispatch_flags)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        int ret;
 
        ret = intel_ring_begin(req, 2);
        if (ret)
                return ret;
 
-       intel_ring_emit(engine,
+       intel_ring_emit(ring,
                        MI_BATCH_BUFFER_START |
                        (dispatch_flags & I915_DISPATCH_SECURE ?
                         0 : MI_BATCH_NON_SECURE_I965));
        /* bit0-7 is the length on GEN6+ */
-       intel_ring_emit(engine, offset);
-       intel_ring_advance(engine);
+       intel_ring_emit(ring, offset);
+       intel_ring_advance(ring);
 
        return 0;
 }
 
 /* Blitter support (SandyBridge+) */
 
-static int gen6_ring_flush(struct drm_i915_gem_request *req,
-                          u32 invalidate, u32 flush)
+static int gen6_ring_flush(struct drm_i915_gem_request *req, u32 mode)
 {
-       struct intel_engine_cs *engine = req->engine;
+       struct intel_ring *ring = req->ring;
        uint32_t cmd;
        int ret;
 
@@ -2684,19 +2513,19 @@ static int gen6_ring_flush(struct drm_i915_gem_request *req,
         * operation is complete. This bit is only valid when the
         * Post-Sync Operation field is a value of 1h or 3h."
         */
-       if (invalidate & I915_GEM_DOMAIN_RENDER)
+       if (mode & EMIT_INVALIDATE)
                cmd |= MI_INVALIDATE_TLB;
-       intel_ring_emit(engine, cmd);
-       intel_ring_emit(engine,
+       intel_ring_emit(ring, cmd);
+       intel_ring_emit(ring,
                        I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
        if (INTEL_GEN(req->i915) >= 8) {
-               intel_ring_emit(engine, 0); /* upper addr */
-               intel_ring_emit(engine, 0); /* value */
+               intel_ring_emit(ring, 0); /* upper addr */
+               intel_ring_emit(ring, 0); /* value */
        } else  {
-               intel_ring_emit(engine, 0);
-               intel_ring_emit(engine, MI_NOOP);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, MI_NOOP);
        }
-       intel_ring_advance(engine);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -2707,38 +2536,39 @@ static void intel_ring_init_semaphores(struct drm_i915_private *dev_priv,
        struct drm_i915_gem_object *obj;
        int ret, i;
 
-       if (!i915_semaphore_is_enabled(dev_priv))
+       if (!i915.semaphores)
                return;
 
-       if (INTEL_GEN(dev_priv) >= 8 && !dev_priv->semaphore_obj) {
+       if (INTEL_GEN(dev_priv) >= 8 && !dev_priv->semaphore) {
+               struct i915_vma *vma;
+
                obj = i915_gem_object_create(&dev_priv->drm, 4096);
-               if (IS_ERR(obj)) {
-                       DRM_ERROR("Failed to allocate semaphore bo. Disabling semaphores\n");
-                       i915.semaphores = 0;
-               } else {
-                       i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
-                       ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_NONBLOCK);
-                       if (ret != 0) {
-                               drm_gem_object_unreference(&obj->base);
-                               DRM_ERROR("Failed to pin semaphore bo. Disabling semaphores\n");
-                               i915.semaphores = 0;
-                       } else {
-                               dev_priv->semaphore_obj = obj;
-                       }
-               }
-       }
+               if (IS_ERR(obj))
+                       goto err;
 
-       if (!i915_semaphore_is_enabled(dev_priv))
-               return;
+               vma = i915_vma_create(obj, &dev_priv->ggtt.base, NULL);
+               if (IS_ERR(vma))
+                       goto err_obj;
+
+               ret = i915_gem_object_set_to_gtt_domain(obj, false);
+               if (ret)
+                       goto err_obj;
+
+               ret = i915_vma_pin(vma, 0, 0, PIN_GLOBAL | PIN_HIGH);
+               if (ret)
+                       goto err_obj;
+
+               dev_priv->semaphore = vma;
+       }
 
        if (INTEL_GEN(dev_priv) >= 8) {
-               u64 offset = i915_gem_obj_ggtt_offset(dev_priv->semaphore_obj);
+               u32 offset = i915_ggtt_offset(dev_priv->semaphore);
 
-               engine->semaphore.sync_to = gen8_ring_sync;
+               engine->semaphore.sync_to = gen8_ring_sync_to;
                engine->semaphore.signal = gen8_xcs_signal;
 
                for (i = 0; i < I915_NUM_ENGINES; i++) {
-                       u64 ring_offset;
+                       u32 ring_offset;
 
                        if (i != engine->id)
                                ring_offset = offset + GEN8_SEMAPHORE_OFFSET(engine->id, i);
@@ -2748,7 +2578,7 @@ static void intel_ring_init_semaphores(struct drm_i915_private *dev_priv,
                        engine->semaphore.signal_ggtt[i] = ring_offset;
                }
        } else if (INTEL_GEN(dev_priv) >= 6) {
-               engine->semaphore.sync_to = gen6_ring_sync;
+               engine->semaphore.sync_to = gen6_ring_sync_to;
                engine->semaphore.signal = gen6_signal;
 
                /*
@@ -2758,52 +2588,62 @@ static void intel_ring_init_semaphores(struct drm_i915_private *dev_priv,
                 * initialized as INVALID.  Gen8 will initialize the
                 * sema between VCS2 and RCS later.
                 */
-               for (i = 0; i < I915_NUM_ENGINES; i++) {
+               for (i = 0; i < GEN6_NUM_SEMAPHORES; i++) {
                        static const struct {
                                u32 wait_mbox;
                                i915_reg_t mbox_reg;
-                       } sem_data[I915_NUM_ENGINES][I915_NUM_ENGINES] = {
-                               [RCS] = {
-                                       [VCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_RV,  .mbox_reg = GEN6_VRSYNC },
-                                       [BCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_RB,  .mbox_reg = GEN6_BRSYNC },
-                                       [VECS] = { .wait_mbox = MI_SEMAPHORE_SYNC_RVE, .mbox_reg = GEN6_VERSYNC },
+                       } sem_data[GEN6_NUM_SEMAPHORES][GEN6_NUM_SEMAPHORES] = {
+                               [RCS_HW] = {
+                                       [VCS_HW] =  { .wait_mbox = MI_SEMAPHORE_SYNC_RV,  .mbox_reg = GEN6_VRSYNC },
+                                       [BCS_HW] =  { .wait_mbox = MI_SEMAPHORE_SYNC_RB,  .mbox_reg = GEN6_BRSYNC },
+                                       [VECS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_RVE, .mbox_reg = GEN6_VERSYNC },
                                },
-                               [VCS] = {
-                                       [RCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VR,  .mbox_reg = GEN6_RVSYNC },
-                                       [BCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VB,  .mbox_reg = GEN6_BVSYNC },
-                                       [VECS] = { .wait_mbox = MI_SEMAPHORE_SYNC_VVE, .mbox_reg = GEN6_VEVSYNC },
+                               [VCS_HW] = {
+                                       [RCS_HW] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VR,  .mbox_reg = GEN6_RVSYNC },
+                                       [BCS_HW] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VB,  .mbox_reg = GEN6_BVSYNC },
+                                       [VECS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_VVE, .mbox_reg = GEN6_VEVSYNC },
                                },
-                               [BCS] = {
-                                       [RCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_BR,  .mbox_reg = GEN6_RBSYNC },
-                                       [VCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_BV,  .mbox_reg = GEN6_VBSYNC },
-                                       [VECS] = { .wait_mbox = MI_SEMAPHORE_SYNC_BVE, .mbox_reg = GEN6_VEBSYNC },
+                               [BCS_HW] = {
+                                       [RCS_HW] =  { .wait_mbox = MI_SEMAPHORE_SYNC_BR,  .mbox_reg = GEN6_RBSYNC },
+                                       [VCS_HW] =  { .wait_mbox = MI_SEMAPHORE_SYNC_BV,  .mbox_reg = GEN6_VBSYNC },
+                                       [VECS_HW] = { .wait_mbox = MI_SEMAPHORE_SYNC_BVE, .mbox_reg = GEN6_VEBSYNC },
                                },
-                               [VECS] = {
-                                       [RCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VER, .mbox_reg = GEN6_RVESYNC },
-                                       [VCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VEV, .mbox_reg = GEN6_VVESYNC },
-                                       [BCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VEB, .mbox_reg = GEN6_BVESYNC },
+                               [VECS_HW] = {
+                                       [RCS_HW] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VER, .mbox_reg = GEN6_RVESYNC },
+                                       [VCS_HW] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VEV, .mbox_reg = GEN6_VVESYNC },
+                                       [BCS_HW] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VEB, .mbox_reg = GEN6_BVESYNC },
                                },
                        };
                        u32 wait_mbox;
                        i915_reg_t mbox_reg;
 
-                       if (i == engine->id || i == VCS2) {
+                       if (i == engine->hw_id) {
                                wait_mbox = MI_SEMAPHORE_SYNC_INVALID;
                                mbox_reg = GEN6_NOSYNC;
                        } else {
-                               wait_mbox = sem_data[engine->id][i].wait_mbox;
-                               mbox_reg = sem_data[engine->id][i].mbox_reg;
+                               wait_mbox = sem_data[engine->hw_id][i].wait_mbox;
+                               mbox_reg = sem_data[engine->hw_id][i].mbox_reg;
                        }
 
                        engine->semaphore.mbox.wait[i] = wait_mbox;
                        engine->semaphore.mbox.signal[i] = mbox_reg;
                }
        }
+
+       return;
+
+err_obj:
+       i915_gem_object_put(obj);
+err:
+       DRM_DEBUG_DRIVER("Failed to allocate space for semaphores, disabling\n");
+       i915.semaphores = 0;
 }
 
 static void intel_ring_init_irq(struct drm_i915_private *dev_priv,
                                struct intel_engine_cs *engine)
 {
+       engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT << engine->irq_shift;
+
        if (INTEL_GEN(dev_priv) >= 8) {
                engine->irq_enable = gen8_irq_enable;
                engine->irq_disable = gen8_irq_disable;
@@ -2828,83 +2668,76 @@ static void intel_ring_init_irq(struct drm_i915_private *dev_priv,
 static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv,
                                      struct intel_engine_cs *engine)
 {
+       intel_ring_init_irq(dev_priv, engine);
+       intel_ring_init_semaphores(dev_priv, engine);
+
        engine->init_hw = init_ring_common;
-       engine->write_tail = ring_write_tail;
+       engine->reset_hw = reset_ring_common;
 
-       engine->add_request = i9xx_add_request;
-       if (INTEL_GEN(dev_priv) >= 6)
-               engine->add_request = gen6_add_request;
+       engine->emit_request = i9xx_emit_request;
+       if (i915.semaphores)
+               engine->emit_request = gen6_sema_emit_request;
+       engine->submit_request = i9xx_submit_request;
 
        if (INTEL_GEN(dev_priv) >= 8)
-               engine->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
+               engine->emit_bb_start = gen8_emit_bb_start;
        else if (INTEL_GEN(dev_priv) >= 6)
-               engine->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+               engine->emit_bb_start = gen6_emit_bb_start;
        else if (INTEL_GEN(dev_priv) >= 4)
-               engine->dispatch_execbuffer = i965_dispatch_execbuffer;
+               engine->emit_bb_start = i965_emit_bb_start;
        else if (IS_I830(dev_priv) || IS_845G(dev_priv))
-               engine->dispatch_execbuffer = i830_dispatch_execbuffer;
+               engine->emit_bb_start = i830_emit_bb_start;
        else
-               engine->dispatch_execbuffer = i915_dispatch_execbuffer;
-
-       intel_ring_init_irq(dev_priv, engine);
-       intel_ring_init_semaphores(dev_priv, engine);
+               engine->emit_bb_start = i915_emit_bb_start;
 }
 
-int intel_init_render_ring_buffer(struct drm_device *dev)
+int intel_init_render_ring_buffer(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
+       struct drm_i915_private *dev_priv = engine->i915;
        int ret;
 
-       engine->name = "render ring";
-       engine->id = RCS;
-       engine->exec_id = I915_EXEC_RENDER;
-       engine->hw_id = 0;
-       engine->mmio_base = RENDER_RING_BASE;
-
        intel_ring_default_vfuncs(dev_priv, engine);
 
-       engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
        if (HAS_L3_DPF(dev_priv))
                engine->irq_keep_mask = GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 
        if (INTEL_GEN(dev_priv) >= 8) {
                engine->init_context = intel_rcs_ctx_init;
-               engine->add_request = gen8_render_add_request;
-               engine->flush = gen8_render_ring_flush;
-               if (i915_semaphore_is_enabled(dev_priv))
+               engine->emit_request = gen8_render_emit_request;
+               engine->emit_flush = gen8_render_ring_flush;
+               if (i915.semaphores)
                        engine->semaphore.signal = gen8_rcs_signal;
        } else if (INTEL_GEN(dev_priv) >= 6) {
                engine->init_context = intel_rcs_ctx_init;
-               engine->flush = gen7_render_ring_flush;
+               engine->emit_flush = gen7_render_ring_flush;
                if (IS_GEN6(dev_priv))
-                       engine->flush = gen6_render_ring_flush;
+                       engine->emit_flush = gen6_render_ring_flush;
        } else if (IS_GEN5(dev_priv)) {
-               engine->flush = gen4_render_ring_flush;
+               engine->emit_flush = gen4_render_ring_flush;
        } else {
                if (INTEL_GEN(dev_priv) < 4)
-                       engine->flush = gen2_render_ring_flush;
+                       engine->emit_flush = gen2_render_ring_flush;
                else
-                       engine->flush = gen4_render_ring_flush;
+                       engine->emit_flush = gen4_render_ring_flush;
                engine->irq_enable_mask = I915_USER_INTERRUPT;
        }
 
        if (IS_HASWELL(dev_priv))
-               engine->dispatch_execbuffer = hsw_ring_dispatch_execbuffer;
+               engine->emit_bb_start = hsw_emit_bb_start;
 
        engine->init_hw = init_render_ring;
        engine->cleanup = render_ring_cleanup;
 
-       ret = intel_init_ring_buffer(dev, engine);
+       ret = intel_init_ring_buffer(engine);
        if (ret)
                return ret;
 
        if (INTEL_GEN(dev_priv) >= 6) {
-               ret = intel_init_pipe_control(engine, 4096);
+               ret = intel_engine_create_scratch(engine, 4096);
                if (ret)
                        return ret;
        } else if (HAS_BROKEN_CS_TLB(dev_priv)) {
-               ret = intel_init_pipe_control(engine, I830_WA_SIZE);
+               ret = intel_engine_create_scratch(engine, I830_WA_SIZE);
                if (ret)
                        return ret;
        }
@@ -2912,166 +2745,71 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
        return 0;
 }
 
-int intel_init_bsd_ring_buffer(struct drm_device *dev)
+int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_engine_cs *engine = &dev_priv->engine[VCS];
-
-       engine->name = "bsd ring";
-       engine->id = VCS;
-       engine->exec_id = I915_EXEC_BSD;
-       engine->hw_id = 1;
+       struct drm_i915_private *dev_priv = engine->i915;
 
        intel_ring_default_vfuncs(dev_priv, engine);
 
        if (INTEL_GEN(dev_priv) >= 6) {
-               engine->mmio_base = GEN6_BSD_RING_BASE;
                /* gen6 bsd needs a special wa for tail updates */
                if (IS_GEN6(dev_priv))
-                       engine->write_tail = gen6_bsd_ring_write_tail;
-               engine->flush = gen6_bsd_ring_flush;
-               if (INTEL_GEN(dev_priv) >= 8)
-                       engine->irq_enable_mask =
-                               GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
-               else
+                       engine->submit_request = gen6_bsd_submit_request;
+               engine->emit_flush = gen6_bsd_ring_flush;
+               if (INTEL_GEN(dev_priv) < 8)
                        engine->irq_enable_mask = GT_BSD_USER_INTERRUPT;
        } else {
                engine->mmio_base = BSD_RING_BASE;
-               engine->flush = bsd_ring_flush;
+               engine->emit_flush = bsd_ring_flush;
                if (IS_GEN5(dev_priv))
                        engine->irq_enable_mask = ILK_BSD_USER_INTERRUPT;
                else
                        engine->irq_enable_mask = I915_BSD_USER_INTERRUPT;
        }
 
-       return intel_init_ring_buffer(dev, engine);
+       return intel_init_ring_buffer(engine);
 }
 
 /**
  * Initialize the second BSD ring (eg. Broadwell GT3, Skylake GT3)
  */
-int intel_init_bsd2_ring_buffer(struct drm_device *dev)
+int intel_init_bsd2_ring_buffer(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_engine_cs *engine = &dev_priv->engine[VCS2];
-
-       engine->name = "bsd2 ring";
-       engine->id = VCS2;
-       engine->exec_id = I915_EXEC_BSD;
-       engine->hw_id = 4;
-       engine->mmio_base = GEN8_BSD2_RING_BASE;
+       struct drm_i915_private *dev_priv = engine->i915;
 
        intel_ring_default_vfuncs(dev_priv, engine);
 
-       engine->flush = gen6_bsd_ring_flush;
-       engine->irq_enable_mask =
-                       GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
+       engine->emit_flush = gen6_bsd_ring_flush;
 
-       return intel_init_ring_buffer(dev, engine);
+       return intel_init_ring_buffer(engine);
 }
 
-int intel_init_blt_ring_buffer(struct drm_device *dev)
+int intel_init_blt_ring_buffer(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_engine_cs *engine = &dev_priv->engine[BCS];
-
-       engine->name = "blitter ring";
-       engine->id = BCS;
-       engine->exec_id = I915_EXEC_BLT;
-       engine->hw_id = 2;
-       engine->mmio_base = BLT_RING_BASE;
+       struct drm_i915_private *dev_priv = engine->i915;
 
        intel_ring_default_vfuncs(dev_priv, engine);
 
-       engine->flush = gen6_ring_flush;
-       if (INTEL_GEN(dev_priv) >= 8)
-               engine->irq_enable_mask =
-                       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
-       else
+       engine->emit_flush = gen6_ring_flush;
+       if (INTEL_GEN(dev_priv) < 8)
                engine->irq_enable_mask = GT_BLT_USER_INTERRUPT;
 
-       return intel_init_ring_buffer(dev, engine);
+       return intel_init_ring_buffer(engine);
 }
 
-int intel_init_vebox_ring_buffer(struct drm_device *dev)
+int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_engine_cs *engine = &dev_priv->engine[VECS];
-
-       engine->name = "video enhancement ring";
-       engine->id = VECS;
-       engine->exec_id = I915_EXEC_VEBOX;
-       engine->hw_id = 3;
-       engine->mmio_base = VEBOX_RING_BASE;
+       struct drm_i915_private *dev_priv = engine->i915;
 
        intel_ring_default_vfuncs(dev_priv, engine);
 
-       engine->flush = gen6_ring_flush;
+       engine->emit_flush = gen6_ring_flush;
 
-       if (INTEL_GEN(dev_priv) >= 8) {
-               engine->irq_enable_mask =
-                       GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
-       } else {
+       if (INTEL_GEN(dev_priv) < 8) {
                engine->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
                engine->irq_enable = hsw_vebox_irq_enable;
                engine->irq_disable = hsw_vebox_irq_disable;
        }
 
-       return intel_init_ring_buffer(dev, engine);
-}
-
-int
-intel_ring_flush_all_caches(struct drm_i915_gem_request *req)
-{
-       struct intel_engine_cs *engine = req->engine;
-       int ret;
-
-       if (!engine->gpu_caches_dirty)
-               return 0;
-
-       ret = engine->flush(req, 0, I915_GEM_GPU_DOMAINS);
-       if (ret)
-               return ret;
-
-       trace_i915_gem_ring_flush(req, 0, I915_GEM_GPU_DOMAINS);
-
-       engine->gpu_caches_dirty = false;
-       return 0;
-}
-
-int
-intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req)
-{
-       struct intel_engine_cs *engine = req->engine;
-       uint32_t flush_domains;
-       int ret;
-
-       flush_domains = 0;
-       if (engine->gpu_caches_dirty)
-               flush_domains = I915_GEM_GPU_DOMAINS;
-
-       ret = engine->flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
-       if (ret)
-               return ret;
-
-       trace_i915_gem_ring_flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
-
-       engine->gpu_caches_dirty = false;
-       return 0;
-}
-
-void
-intel_stop_engine(struct intel_engine_cs *engine)
-{
-       int ret;
-
-       if (!intel_engine_initialized(engine))
-               return;
-
-       ret = intel_engine_idle(engine);
-       if (ret)
-               DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
-                         engine->name, ret);
-
-       stop_ring(engine);
+       return intel_init_ring_buffer(engine);
 }
index 12cb7ed..ec0b4a0 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/hashtable.h>
 #include "i915_gem_batch_pool.h"
+#include "i915_gem_request.h"
 
 #define I915_CMD_HASH_ORDER 9
 
  */
 #define I915_RING_FREE_SPACE 64
 
-struct  intel_hw_status_page {
-       u32             *page_addr;
-       unsigned int    gfx_addr;
-       struct          drm_i915_gem_object *obj;
+struct intel_hw_status_page {
+       struct i915_vma *vma;
+       u32 *page_addr;
+       u32 ggtt_offset;
 };
 
-#define I915_READ_TAIL(ring) I915_READ(RING_TAIL((ring)->mmio_base))
-#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val)
+#define I915_READ_TAIL(engine) I915_READ(RING_TAIL((engine)->mmio_base))
+#define I915_WRITE_TAIL(engine, val) I915_WRITE(RING_TAIL((engine)->mmio_base), val)
 
-#define I915_READ_START(ring) I915_READ(RING_START((ring)->mmio_base))
-#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val)
+#define I915_READ_START(engine) I915_READ(RING_START((engine)->mmio_base))
+#define I915_WRITE_START(engine, val) I915_WRITE(RING_START((engine)->mmio_base), val)
 
-#define I915_READ_HEAD(ring)  I915_READ(RING_HEAD((ring)->mmio_base))
-#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val)
+#define I915_READ_HEAD(engine)  I915_READ(RING_HEAD((engine)->mmio_base))
+#define I915_WRITE_HEAD(engine, val) I915_WRITE(RING_HEAD((engine)->mmio_base), val)
 
-#define I915_READ_CTL(ring) I915_READ(RING_CTL((ring)->mmio_base))
-#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val)
+#define I915_READ_CTL(engine) I915_READ(RING_CTL((engine)->mmio_base))
+#define I915_WRITE_CTL(engine, val) I915_WRITE(RING_CTL((engine)->mmio_base), val)
 
-#define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base))
-#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
+#define I915_READ_IMR(engine) I915_READ(RING_IMR((engine)->mmio_base))
+#define I915_WRITE_IMR(engine, val) I915_WRITE(RING_IMR((engine)->mmio_base), val)
 
-#define I915_READ_MODE(ring) I915_READ(RING_MI_MODE((ring)->mmio_base))
-#define I915_WRITE_MODE(ring, val) I915_WRITE(RING_MI_MODE((ring)->mmio_base), val)
+#define I915_READ_MODE(engine) I915_READ(RING_MI_MODE((engine)->mmio_base))
+#define I915_WRITE_MODE(engine, val) I915_WRITE(RING_MI_MODE((engine)->mmio_base), val)
 
 /* seqno size is actually only a uint32, but since we plan to use MI_FLUSH_DW to
  * do the writes, and that must have qw aligned offsets, simply pretend it's 8b.
@@ -56,13 +57,13 @@ struct  intel_hw_status_page {
 #define GEN8_SEMAPHORE_OFFSET(__from, __to)                         \
        (((__from) * I915_NUM_ENGINES  + (__to)) * gen8_semaphore_seqno_size)
 #define GEN8_SIGNAL_OFFSET(__ring, to)                      \
-       (i915_gem_obj_ggtt_offset(dev_priv->semaphore_obj) + \
+       (dev_priv->semaphore->node.start + \
         GEN8_SEMAPHORE_OFFSET((__ring)->id, (to)))
 #define GEN8_WAIT_OFFSET(__ring, from)                      \
-       (i915_gem_obj_ggtt_offset(dev_priv->semaphore_obj) + \
+       (dev_priv->semaphore->node.start + \
         GEN8_SEMAPHORE_OFFSET(from, (__ring)->id))
 
-enum intel_ring_hangcheck_action {
+enum intel_engine_hangcheck_action {
        HANGCHECK_IDLE = 0,
        HANGCHECK_WAIT,
        HANGCHECK_ACTIVE,
@@ -72,23 +73,22 @@ enum intel_ring_hangcheck_action {
 
 #define HANGCHECK_SCORE_RING_HUNG 31
 
-struct intel_ring_hangcheck {
+struct intel_engine_hangcheck {
        u64 acthd;
-       unsigned long user_interrupts;
        u32 seqno;
        int score;
-       enum intel_ring_hangcheck_action action;
+       enum intel_engine_hangcheck_action action;
        int deadlock;
        u32 instdone[I915_NUM_INSTDONE_REG];
 };
 
-struct intel_ringbuffer {
-       struct drm_i915_gem_object *obj;
-       void __iomem *virtual_start;
+struct intel_ring {
        struct i915_vma *vma;
+       void *vaddr;
 
        struct intel_engine_cs *engine;
-       struct list_head link;
+
+       struct list_head request_list;
 
        u32 head;
        u32 tail;
@@ -121,12 +121,12 @@ struct drm_i915_reg_table;
  *    an option for future use.
  *  size: size of the batch in DWORDS
  */
-struct  i915_ctx_workarounds {
+struct i915_ctx_workarounds {
        struct i915_wa_ctx_bb {
                u32 offset;
                u32 size;
        } indirect_ctx, per_ctx;
-       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
 };
 
 struct drm_i915_gem_request;
@@ -144,11 +144,18 @@ struct intel_engine_cs {
 #define I915_NUM_ENGINES 5
 #define _VCS(n) (VCS + (n))
        unsigned int exec_id;
-       unsigned int hw_id;
-       unsigned int guc_id; /* XXX same as hw_id? */
+       enum intel_engine_hw_id {
+               RCS_HW = 0,
+               VCS_HW,
+               BCS_HW,
+               VECS_HW,
+               VCS2_HW
+       } hw_id;
+       enum intel_engine_hw_id guc_id; /* XXX same as hw_id? */
+       u64 fence_context;
        u32             mmio_base;
-       struct intel_ringbuffer *buffer;
-       struct list_head buffers;
+       unsigned int irq_shift;
+       struct intel_ring *buffer;
 
        /* Rather than have every client wait upon all user interrupts,
         * with the herd waking after every interrupt and each doing the
@@ -167,8 +174,7 @@ struct intel_engine_cs {
         * the overhead of waking that client is much preferred.
         */
        struct intel_breadcrumbs {
-               struct task_struct *irq_seqno_bh; /* bh for user interrupts */
-               unsigned long irq_wakeups;
+               struct task_struct __rcu *irq_seqno_bh; /* bh for interrupts */
                bool irq_posted;
 
                spinlock_t lock; /* protects the lists of requests */
@@ -178,6 +184,9 @@ struct intel_engine_cs {
                struct task_struct *signaler; /* used for fence signalling */
                struct drm_i915_gem_request *first_signal;
                struct timer_list fake_irq; /* used after a missed interrupt */
+               struct timer_list hangcheck; /* detect missed interrupts */
+
+               unsigned long timeout;
 
                bool irq_enabled : 1;
                bool rpm_wakelock : 1;
@@ -192,36 +201,48 @@ struct intel_engine_cs {
 
        struct intel_hw_status_page status_page;
        struct i915_ctx_workarounds wa_ctx;
+       struct i915_vma *scratch;
 
        u32             irq_keep_mask; /* always keep these interrupts */
        u32             irq_enable_mask; /* bitmask to enable ring interrupt */
-       void            (*irq_enable)(struct intel_engine_cs *ring);
-       void            (*irq_disable)(struct intel_engine_cs *ring);
+       void            (*irq_enable)(struct intel_engine_cs *engine);
+       void            (*irq_disable)(struct intel_engine_cs *engine);
 
-       int             (*init_hw)(struct intel_engine_cs *ring);
+       int             (*init_hw)(struct intel_engine_cs *engine);
+       void            (*reset_hw)(struct intel_engine_cs *engine,
+                                   struct drm_i915_gem_request *req);
 
        int             (*init_context)(struct drm_i915_gem_request *req);
 
-       void            (*write_tail)(struct intel_engine_cs *ring,
-                                     u32 value);
-       int __must_check (*flush)(struct drm_i915_gem_request *req,
-                                 u32   invalidate_domains,
-                                 u32   flush_domains);
-       int             (*add_request)(struct drm_i915_gem_request *req);
+       int             (*emit_flush)(struct drm_i915_gem_request *request,
+                                     u32 mode);
+#define EMIT_INVALIDATE        BIT(0)
+#define EMIT_FLUSH     BIT(1)
+#define EMIT_BARRIER   (EMIT_INVALIDATE | EMIT_FLUSH)
+       int             (*emit_bb_start)(struct drm_i915_gem_request *req,
+                                        u64 offset, u32 length,
+                                        unsigned int dispatch_flags);
+#define I915_DISPATCH_SECURE BIT(0)
+#define I915_DISPATCH_PINNED BIT(1)
+#define I915_DISPATCH_RS     BIT(2)
+       int             (*emit_request)(struct drm_i915_gem_request *req);
+
+       /* Pass the request to the hardware queue (e.g. directly into
+        * the legacy ringbuffer or to the end of an execlist).
+        *
+        * This is called from an atomic context with irqs disabled; must
+        * be irq safe.
+        */
+       void            (*submit_request)(struct drm_i915_gem_request *req);
+
        /* Some chipsets are not quite as coherent as advertised and need
         * an expensive kick to force a true read of the up-to-date seqno.
         * However, the up-to-date seqno is not always required and the last
         * seen value is good enough. Note that the seqno will always be
         * monotonic, even if not coherent.
         */
-       void            (*irq_seqno_barrier)(struct intel_engine_cs *ring);
-       int             (*dispatch_execbuffer)(struct drm_i915_gem_request *req,
-                                              u64 offset, u32 length,
-                                              unsigned dispatch_flags);
-#define I915_DISPATCH_SECURE 0x1
-#define I915_DISPATCH_PINNED 0x2
-#define I915_DISPATCH_RS     0x4
-       void            (*cleanup)(struct intel_engine_cs *ring);
+       void            (*irq_seqno_barrier)(struct intel_engine_cs *engine);
+       void            (*cleanup)(struct intel_engine_cs *engine);
 
        /* GEN8 signal/wait table - never trust comments!
         *        signal to     signal to    signal to   signal to      signal to
@@ -264,51 +285,36 @@ struct intel_engine_cs {
                u32     sync_seqno[I915_NUM_ENGINES-1];
 
                union {
+#define GEN6_SEMAPHORE_LAST    VECS_HW
+#define GEN6_NUM_SEMAPHORES    (GEN6_SEMAPHORE_LAST + 1)
+#define GEN6_SEMAPHORES_MASK   GENMASK(GEN6_SEMAPHORE_LAST, 0)
                        struct {
                                /* our mbox written by others */
-                               u32             wait[I915_NUM_ENGINES];
+                               u32             wait[GEN6_NUM_SEMAPHORES];
                                /* mboxes this ring signals to */
-                               i915_reg_t      signal[I915_NUM_ENGINES];
+                               i915_reg_t      signal[GEN6_NUM_SEMAPHORES];
                        } mbox;
                        u64             signal_ggtt[I915_NUM_ENGINES];
                };
 
                /* AKA wait() */
-               int     (*sync_to)(struct drm_i915_gem_request *to_req,
-                                  struct intel_engine_cs *from,
-                                  u32 seqno);
-               int     (*signal)(struct drm_i915_gem_request *signaller_req,
-                                 /* num_dwords needed by caller */
-                                 unsigned int num_dwords);
+               int     (*sync_to)(struct drm_i915_gem_request *req,
+                                  struct drm_i915_gem_request *signal);
+               int     (*signal)(struct drm_i915_gem_request *req);
        } semaphore;
 
        /* Execlists */
        struct tasklet_struct irq_tasklet;
        spinlock_t execlist_lock; /* used inside tasklet, use spin_lock_bh */
+       struct execlist_port {
+               struct drm_i915_gem_request *request;
+               unsigned int count;
+       } execlist_port[2];
        struct list_head execlist_queue;
        unsigned int fw_domains;
-       unsigned int next_context_status_buffer;
-       unsigned int idle_lite_restore_wa;
        bool disable_lite_restore_wa;
+       bool preempt_wa;
        u32 ctx_desc_template;
-       int             (*emit_request)(struct drm_i915_gem_request *request);
-       int             (*emit_flush)(struct drm_i915_gem_request *request,
-                                     u32 invalidate_domains,
-                                     u32 flush_domains);
-       int             (*emit_bb_start)(struct drm_i915_gem_request *req,
-                                        u64 offset, unsigned dispatch_flags);
-
-       /**
-        * List of objects currently involved in rendering from the
-        * ringbuffer.
-        *
-        * Includes buffers having the contents of their GPU caches
-        * flushed, not necessarily primitives.  last_read_req
-        * represents when the rendering involved will be completed.
-        *
-        * A reference is held on the buffer while on this list.
-        */
-       struct list_head active_list;
 
        /**
         * List of breadcrumbs associated with GPU requests currently
@@ -322,23 +328,24 @@ struct intel_engine_cs {
         * inspecting request list.
         */
        u32 last_submitted_seqno;
+       u32 last_pending_seqno;
 
-       bool gpu_caches_dirty;
+       /* An RCU guarded pointer to the last request. No reference is
+        * held to the request, users must carefully acquire a reference to
+        * the request using i915_gem_active_get_rcu(), or hold the
+        * struct_mutex.
+        */
+       struct i915_gem_active last_request;
 
        struct i915_gem_context *last_context;
 
-       struct intel_ring_hangcheck hangcheck;
-
-       struct {
-               struct drm_i915_gem_object *obj;
-               u32 gtt_offset;
-       } scratch;
+       struct intel_engine_hangcheck hangcheck;
 
        bool needs_cmd_parser;
 
        /*
         * Table of commands the command parser needs to know about
-        * for this ring.
+        * for this engine.
         */
        DECLARE_HASHTABLE(cmd_hash, I915_CMD_HASH_ORDER);
 
@@ -352,11 +359,11 @@ struct intel_engine_cs {
         * Returns the bitmask for the length field of the specified command.
         * Return 0 for an unrecognized/invalid command.
         *
-        * If the command parser finds an entry for a command in the ring's
+        * If the command parser finds an entry for a command in the engine's
         * cmd_tables, it gets the command's length based on the table entry.
-        * If not, it calls this function to determine the per-ring length field
-        * encoding for the command (i.e. certain opcode ranges use certain bits
-        * to encode the command length in the header).
+        * If not, it calls this function to determine the per-engine length
+        * field encoding for the command (i.e. different opcode ranges use
+        * certain bits to encode the command length in the header).
         */
        u32 (*get_cmd_length_mask)(u32 cmd_header);
 };
@@ -374,8 +381,8 @@ intel_engine_flag(const struct intel_engine_cs *engine)
 }
 
 static inline u32
-intel_ring_sync_index(struct intel_engine_cs *engine,
-                     struct intel_engine_cs *other)
+intel_engine_sync_index(struct intel_engine_cs *engine,
+                       struct intel_engine_cs *other)
 {
        int idx;
 
@@ -437,55 +444,76 @@ intel_write_status_page(struct intel_engine_cs *engine,
 #define I915_GEM_HWS_SCRATCH_INDEX     0x40
 #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
 
-struct intel_ringbuffer *
-intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size);
-int intel_pin_and_map_ringbuffer_obj(struct drm_i915_private *dev_priv,
-                                    struct intel_ringbuffer *ringbuf);
-void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf);
-void intel_ringbuffer_free(struct intel_ringbuffer *ring);
+struct intel_ring *
+intel_engine_create_ring(struct intel_engine_cs *engine, int size);
+int intel_ring_pin(struct intel_ring *ring);
+void intel_ring_unpin(struct intel_ring *ring);
+void intel_ring_free(struct intel_ring *ring);
+
+void intel_engine_stop(struct intel_engine_cs *engine);
+void intel_engine_cleanup(struct intel_engine_cs *engine);
 
-void intel_stop_engine(struct intel_engine_cs *engine);
-void intel_cleanup_engine(struct intel_engine_cs *engine);
+void intel_legacy_submission_resume(struct drm_i915_private *dev_priv);
 
 int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request);
 
 int __must_check intel_ring_begin(struct drm_i915_gem_request *req, int n);
 int __must_check intel_ring_cacheline_align(struct drm_i915_gem_request *req);
-static inline void intel_ring_emit(struct intel_engine_cs *engine,
-                                  u32 data)
+
+static inline void intel_ring_emit(struct intel_ring *ring, u32 data)
 {
-       struct intel_ringbuffer *ringbuf = engine->buffer;
-       iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
-       ringbuf->tail += 4;
+       *(uint32_t *)(ring->vaddr + ring->tail) = data;
+       ring->tail += 4;
 }
-static inline void intel_ring_emit_reg(struct intel_engine_cs *engine,
-                                      i915_reg_t reg)
+
+static inline void intel_ring_emit_reg(struct intel_ring *ring, i915_reg_t reg)
 {
-       intel_ring_emit(engine, i915_mmio_reg_offset(reg));
+       intel_ring_emit(ring, i915_mmio_reg_offset(reg));
 }
-static inline void intel_ring_advance(struct intel_engine_cs *engine)
+
+static inline void intel_ring_advance(struct intel_ring *ring)
 {
-       struct intel_ringbuffer *ringbuf = engine->buffer;
-       ringbuf->tail &= ringbuf->size - 1;
+       /* Dummy function.
+        *
+        * This serves as a placeholder in the code so that the reader
+        * can compare against the preceding intel_ring_begin() and
+        * check that the number of dwords emitted matches the space
+        * reserved for the command packet (i.e. the value passed to
+        * intel_ring_begin()).
+        */
+}
+
+static inline u32 intel_ring_offset(struct intel_ring *ring, u32 value)
+{
+       /* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
+       return value & (ring->size - 1);
 }
+
 int __intel_ring_space(int head, int tail, int size);
-void intel_ring_update_space(struct intel_ringbuffer *ringbuf);
+void intel_ring_update_space(struct intel_ring *ring);
 
-int __must_check intel_engine_idle(struct intel_engine_cs *engine);
-void intel_ring_init_seqno(struct intel_engine_cs *engine, u32 seqno);
-int intel_ring_flush_all_caches(struct drm_i915_gem_request *req);
-int intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req);
+void intel_engine_init_seqno(struct intel_engine_cs *engine, u32 seqno);
 
-int intel_init_pipe_control(struct intel_engine_cs *engine, int size);
-void intel_fini_pipe_control(struct intel_engine_cs *engine);
+void intel_engine_setup_common(struct intel_engine_cs *engine);
+int intel_engine_init_common(struct intel_engine_cs *engine);
+int intel_engine_create_scratch(struct intel_engine_cs *engine, int size);
+void intel_engine_cleanup_common(struct intel_engine_cs *engine);
 
-int intel_init_render_ring_buffer(struct drm_device *dev);
-int intel_init_bsd_ring_buffer(struct drm_device *dev);
-int intel_init_bsd2_ring_buffer(struct drm_device *dev);
-int intel_init_blt_ring_buffer(struct drm_device *dev);
-int intel_init_vebox_ring_buffer(struct drm_device *dev);
+static inline int intel_engine_idle(struct intel_engine_cs *engine,
+                                   unsigned int flags)
+{
+       /* Wait upon the last request to be completed */
+       return i915_gem_active_wait_unlocked(&engine->last_request,
+                                            flags, NULL, NULL);
+}
+
+int intel_init_render_ring_buffer(struct intel_engine_cs *engine);
+int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine);
+int intel_init_bsd2_ring_buffer(struct intel_engine_cs *engine);
+int intel_init_blt_ring_buffer(struct intel_engine_cs *engine);
+int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine);
 
-u64 intel_ring_get_active_head(struct intel_engine_cs *engine);
+u64 intel_engine_get_active_head(struct intel_engine_cs *engine);
 static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine)
 {
        return intel_read_status_page(engine, I915_GEM_HWS_INDEX);
@@ -493,11 +521,6 @@ static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine)
 
 int init_workarounds_ring(struct intel_engine_cs *engine);
 
-static inline u32 intel_ring_get_tail(struct intel_ringbuffer *ringbuf)
-{
-       return ringbuf->tail;
-}
-
 /*
  * Arbitrary size for largest possible 'add request' sequence. The code paths
  * are complex and variable. Empirical measurement shows that the worst case
@@ -509,21 +532,10 @@ static inline u32 intel_ring_get_tail(struct intel_ringbuffer *ringbuf)
 
 static inline u32 intel_hws_seqno_address(struct intel_engine_cs *engine)
 {
-       return engine->status_page.gfx_addr + I915_GEM_HWS_INDEX_ADDR;
+       return engine->status_page.ggtt_offset + I915_GEM_HWS_INDEX_ADDR;
 }
 
 /* intel_breadcrumbs.c -- user interrupt bottom-half for waiters */
-struct intel_wait {
-       struct rb_node node;
-       struct task_struct *tsk;
-       u32 seqno;
-};
-
-struct intel_signal_node {
-       struct rb_node node;
-       struct intel_wait wait;
-};
-
 int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine);
 
 static inline void intel_wait_init(struct intel_wait *wait, u32 seqno)
@@ -543,31 +555,43 @@ void intel_engine_remove_wait(struct intel_engine_cs *engine,
                              struct intel_wait *wait);
 void intel_engine_enable_signaling(struct drm_i915_gem_request *request);
 
-static inline bool intel_engine_has_waiter(struct intel_engine_cs *engine)
+static inline bool intel_engine_has_waiter(const struct intel_engine_cs *engine)
 {
-       return READ_ONCE(engine->breadcrumbs.irq_seqno_bh);
+       return rcu_access_pointer(engine->breadcrumbs.irq_seqno_bh);
 }
 
-static inline bool intel_engine_wakeup(struct intel_engine_cs *engine)
+static inline bool intel_engine_wakeup(const struct intel_engine_cs *engine)
 {
        bool wakeup = false;
-       struct task_struct *tsk = READ_ONCE(engine->breadcrumbs.irq_seqno_bh);
+
        /* Note that for this not to dangerously chase a dangling pointer,
-        * the caller is responsible for ensure that the task remain valid for
-        * wake_up_process() i.e. that the RCU grace period cannot expire.
+        * we must hold the rcu_read_lock here.
         *
         * Also note that tsk is likely to be in !TASK_RUNNING state so an
         * early test for tsk->state != TASK_RUNNING before wake_up_process()
         * is unlikely to be beneficial.
         */
-       if (tsk)
-               wakeup = wake_up_process(tsk);
+       if (intel_engine_has_waiter(engine)) {
+               struct task_struct *tsk;
+
+               rcu_read_lock();
+               tsk = rcu_dereference(engine->breadcrumbs.irq_seqno_bh);
+               if (tsk)
+                       wakeup = wake_up_process(tsk);
+               rcu_read_unlock();
+       }
+
        return wakeup;
 }
 
-void intel_engine_enable_fake_irq(struct intel_engine_cs *engine);
+void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine);
 void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
 unsigned int intel_kick_waiters(struct drm_i915_private *i915);
 unsigned int intel_kick_signalers(struct drm_i915_private *i915);
 
+static inline bool intel_engine_is_active(struct intel_engine_cs *engine)
+{
+       return i915_gem_active_isset(&engine->last_request);
+}
+
 #endif /* _INTEL_RINGBUFFER_H_ */
index 1c603bb..6c11168 100644 (file)
@@ -287,6 +287,7 @@ void intel_display_set_init_power(struct drm_i915_private *dev_priv,
  */
 static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
 {
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        struct drm_device *dev = &dev_priv->drm;
 
        /*
@@ -299,9 +300,9 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
         * sure vgacon can keep working normally without triggering interrupts
         * and error messages.
         */
-       vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
+       vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO);
        outb(inb(VGA_MSR_READ), VGA_MSR_WRITE);
-       vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
+       vga_put(pdev, VGA_RSRC_LEGACY_IO);
 
        if (IS_BROADWELL(dev))
                gen8_irq_power_well_post_enable(dev_priv,
@@ -318,7 +319,7 @@ static void hsw_power_well_pre_disable(struct drm_i915_private *dev_priv)
 static void skl_power_well_post_enable(struct drm_i915_private *dev_priv,
                                       struct i915_power_well *power_well)
 {
-       struct drm_device *dev = &dev_priv->drm;
+       struct pci_dev *pdev = dev_priv->drm.pdev;
 
        /*
         * After we re-enable the power well, if we touch VGA register 0x3d5
@@ -331,9 +332,9 @@ static void skl_power_well_post_enable(struct drm_i915_private *dev_priv,
         * and error messages.
         */
        if (power_well->data == SKL_DISP_PW_2) {
-               vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
+               vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO);
                outb(inb(VGA_MSR_READ), VGA_MSR_WRITE);
-               vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
+               vga_put(pdev, VGA_RSRC_LEGACY_IO);
 
                gen8_irq_power_well_post_enable(dev_priv,
                                                1 << PIPE_C | 1 << PIPE_B);
@@ -592,6 +593,8 @@ void bxt_disable_dc9(struct drm_i915_private *dev_priv)
        DRM_DEBUG_KMS("Disabling DC9\n");
 
        gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+
+       intel_pps_unlock_regs_wa(dev_priv);
 }
 
 static void assert_csr_loaded(struct drm_i915_private *dev_priv)
@@ -854,7 +857,7 @@ static void bxt_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
                                           struct i915_power_well *power_well)
 {
        enum skl_disp_power_wells power_well_id = power_well->data;
-       struct i915_power_well *cmn_a_well;
+       struct i915_power_well *cmn_a_well = NULL;
 
        if (power_well_id == BXT_DPIO_CMN_BC) {
                /*
@@ -867,7 +870,7 @@ static void bxt_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
 
        bxt_ddi_phy_init(dev_priv, bxt_power_well_to_phy(power_well));
 
-       if (power_well_id == BXT_DPIO_CMN_BC)
+       if (cmn_a_well)
                intel_power_well_put(dev_priv, cmn_a_well);
 }
 
@@ -1121,6 +1124,8 @@ static void vlv_display_power_well_init(struct drm_i915_private *dev_priv)
        }
 
        i915_redisable_vga_power_on(&dev_priv->drm);
+
+       intel_pps_unlock_regs_wa(dev_priv);
 }
 
 static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv)
@@ -2284,7 +2289,7 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
  */
 void intel_power_domains_fini(struct drm_i915_private *dev_priv)
 {
-       struct device *device = &dev_priv->drm.pdev->dev;
+       struct device *kdev = &dev_priv->drm.pdev->dev;
 
        /*
         * The i915.ko module is still not prepared to be loaded when
@@ -2306,7 +2311,7 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv)
         * the platform doesn't support runtime PM.
         */
        if (!HAS_RUNTIME_PM(dev_priv))
-               pm_runtime_put(device);
+               pm_runtime_put(kdev);
 }
 
 static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv)
@@ -2647,10 +2652,10 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
  */
 void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
 {
-       struct drm_device *dev = &dev_priv->drm;
-       struct device *device = &dev->pdev->dev;
+       struct pci_dev *pdev = dev_priv->drm.pdev;
+       struct device *kdev = &pdev->dev;
 
-       pm_runtime_get_sync(device);
+       pm_runtime_get_sync(kdev);
 
        atomic_inc(&dev_priv->pm.wakeref_count);
        assert_rpm_wakelock_held(dev_priv);
@@ -2668,11 +2673,11 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
  */
 bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
 {
-       struct drm_device *dev = &dev_priv->drm;
-       struct device *device = &dev->pdev->dev;
+       struct pci_dev *pdev = dev_priv->drm.pdev;
+       struct device *kdev = &pdev->dev;
 
        if (IS_ENABLED(CONFIG_PM)) {
-               int ret = pm_runtime_get_if_in_use(device);
+               int ret = pm_runtime_get_if_in_use(kdev);
 
                /*
                 * In cases runtime PM is disabled by the RPM core and we get
@@ -2710,11 +2715,11 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
  */
 void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
 {
-       struct drm_device *dev = &dev_priv->drm;
-       struct device *device = &dev->pdev->dev;
+       struct pci_dev *pdev = dev_priv->drm.pdev;
+       struct device *kdev = &pdev->dev;
 
        assert_rpm_wakelock_held(dev_priv);
-       pm_runtime_get_noresume(device);
+       pm_runtime_get_noresume(kdev);
 
        atomic_inc(&dev_priv->pm.wakeref_count);
 }
@@ -2729,15 +2734,15 @@ void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
  */
 void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
 {
-       struct drm_device *dev = &dev_priv->drm;
-       struct device *device = &dev->pdev->dev;
+       struct pci_dev *pdev = dev_priv->drm.pdev;
+       struct device *kdev = &pdev->dev;
 
        assert_rpm_wakelock_held(dev_priv);
        if (atomic_dec_and_test(&dev_priv->pm.wakeref_count))
                atomic_inc(&dev_priv->pm.atomic_seq);
 
-       pm_runtime_mark_last_busy(device);
-       pm_runtime_put_autosuspend(device);
+       pm_runtime_mark_last_busy(kdev);
+       pm_runtime_put_autosuspend(kdev);
 }
 
 /**
@@ -2752,11 +2757,12 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
  */
 void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
 {
+       struct pci_dev *pdev = dev_priv->drm.pdev;
        struct drm_device *dev = &dev_priv->drm;
-       struct device *device = &dev->pdev->dev;
+       struct device *kdev = &pdev->dev;
 
-       pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
-       pm_runtime_mark_last_busy(device);
+       pm_runtime_set_autosuspend_delay(kdev, 10000); /* 10s */
+       pm_runtime_mark_last_busy(kdev);
 
        /*
         * Take a permanent reference to disable the RPM functionality and drop
@@ -2765,10 +2771,10 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
         * platforms without RPM support.
         */
        if (!HAS_RUNTIME_PM(dev)) {
-               pm_runtime_dont_use_autosuspend(device);
-               pm_runtime_get_sync(device);
+               pm_runtime_dont_use_autosuspend(kdev);
+               pm_runtime_get_sync(kdev);
        } else {
-               pm_runtime_use_autosuspend(device);
+               pm_runtime_use_autosuspend(kdev);
        }
 
        /*
@@ -2776,6 +2782,5 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
         * We drop that here and will reacquire it during unloading in
         * intel_power_domains_fini().
         */
-       pm_runtime_put_autosuspend(device);
+       pm_runtime_put_autosuspend(kdev);
 }
-
index e378f35..c551024 100644 (file)
@@ -1003,24 +1003,22 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
 }
 
 static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
-                                        const struct drm_display_mode *adjusted_mode)
+                                        struct intel_crtc_state *pipe_config)
 {
        uint8_t sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
-       struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        union hdmi_infoframe frame;
        int ret;
        ssize_t len;
 
        ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
-                                                      adjusted_mode);
+                                                      &pipe_config->base.adjusted_mode);
        if (ret < 0) {
                DRM_ERROR("couldn't fill AVI infoframe\n");
                return false;
        }
 
        if (intel_sdvo->rgb_quant_range_selectable) {
-               if (intel_crtc->config->limited_color_range)
+               if (pipe_config->limited_color_range)
                        frame.avi.quantization_range =
                                HDMI_QUANTIZATION_RANGE_LIMITED;
                else
@@ -1125,7 +1123,8 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
 }
 
 static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
-                                     struct intel_crtc_state *pipe_config)
+                                     struct intel_crtc_state *pipe_config,
+                                     struct drm_connector_state *conn_state)
 {
        struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
@@ -1192,22 +1191,21 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
        return true;
 }
 
-static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
+static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
+                                 struct intel_crtc_state *crtc_state,
+                                 struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *crtc = to_intel_crtc(intel_encoder->base.crtc);
-       const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
-       struct drm_display_mode *mode = &crtc->config->base.mode;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
+       struct drm_display_mode *mode = &crtc_state->base.mode;
        struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
        u32 sdvox;
        struct intel_sdvo_in_out_map in_out;
        struct intel_sdvo_dtd input_dtd, output_dtd;
        int rate;
 
-       if (!mode)
-               return;
-
        /* First, set the input mapping for the first input to our controlled
         * output. This is only correct if we're a single-input device, in
         * which case the first input is the output from the appropriate SDVO
@@ -1240,11 +1238,11 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
        if (!intel_sdvo_set_target_input(intel_sdvo))
                return;
 
-       if (crtc->config->has_hdmi_sink) {
+       if (crtc_state->has_hdmi_sink) {
                intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
                intel_sdvo_set_colorimetry(intel_sdvo,
                                           SDVO_COLORIMETRY_RGB256);
-               intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode);
+               intel_sdvo_set_avi_infoframe(intel_sdvo, crtc_state);
        } else
                intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
 
@@ -1260,7 +1258,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
                DRM_INFO("Setting input timings on %s failed\n",
                         SDVO_NAME(intel_sdvo));
 
-       switch (crtc->config->pixel_multiplier) {
+       switch (crtc_state->pixel_multiplier) {
        default:
                WARN(1, "unknown pixel multiplier specified\n");
        case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
@@ -1275,7 +1273,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
                /* The real mode polarity is set by the SDVO commands, using
                 * struct intel_sdvo_dtd. */
                sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
-               if (!HAS_PCH_SPLIT(dev) && crtc->config->limited_color_range)
+               if (!HAS_PCH_SPLIT(dev) && crtc_state->limited_color_range)
                        sdvox |= HDMI_COLOR_RANGE_16_235;
                if (INTEL_INFO(dev)->gen < 5)
                        sdvox |= SDVO_BORDER_ENABLE;
@@ -1301,7 +1299,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
        } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
                /* done in crtc_mode_set as it lives inside the dpll register */
        } else {
-               sdvox |= (crtc->config->pixel_multiplier - 1)
+               sdvox |= (crtc_state->pixel_multiplier - 1)
                        << SDVO_PORT_MULTIPLY_SHIFT;
        }
 
@@ -1434,7 +1432,9 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
             pipe_config->pixel_multiplier, encoder_pixel_multiplier);
 }
 
-static void intel_disable_sdvo(struct intel_encoder *encoder)
+static void intel_disable_sdvo(struct intel_encoder *encoder,
+                              struct intel_crtc_state *old_crtc_state,
+                              struct drm_connector_state *conn_state)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
@@ -1477,16 +1477,22 @@ static void intel_disable_sdvo(struct intel_encoder *encoder)
        }
 }
 
-static void pch_disable_sdvo(struct intel_encoder *encoder)
+static void pch_disable_sdvo(struct intel_encoder *encoder,
+                            struct intel_crtc_state *old_crtc_state,
+                            struct drm_connector_state *old_conn_state)
 {
 }
 
-static void pch_post_disable_sdvo(struct intel_encoder *encoder)
+static void pch_post_disable_sdvo(struct intel_encoder *encoder,
+                                 struct intel_crtc_state *old_crtc_state,
+                                 struct drm_connector_state *old_conn_state)
 {
-       intel_disable_sdvo(encoder);
+       intel_disable_sdvo(encoder, old_crtc_state, old_conn_state);
 }
 
-static void intel_enable_sdvo(struct intel_encoder *encoder)
+static void intel_enable_sdvo(struct intel_encoder *encoder,
+                             struct intel_crtc_state *pipe_config,
+                             struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -2930,10 +2936,12 @@ static bool
 intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
                          struct drm_device *dev)
 {
+       struct pci_dev *pdev = dev->pdev;
+
        sdvo->ddc.owner = THIS_MODULE;
        sdvo->ddc.class = I2C_CLASS_DDC;
        snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
-       sdvo->ddc.dev.parent = &dev->pdev->dev;
+       sdvo->ddc.dev.parent = &pdev->dev;
        sdvo->ddc.algo_data = sdvo;
        sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
 
index 7c08e4f..73a521f 100644 (file)
@@ -36,6 +36,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_plane_helper.h>
 #include "intel_drv.h"
+#include "intel_frontbuffer.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
@@ -202,23 +203,24 @@ skl_update_plane(struct drm_plane *drm_plane,
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_plane *intel_plane = to_intel_plane(drm_plane);
        struct drm_framebuffer *fb = plane_state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
+       struct drm_crtc *crtc = crtc_state->base.crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        const int pipe = intel_plane->pipe;
        const int plane = intel_plane->plane + 1;
-       u32 plane_ctl, stride_div, stride;
+       u32 plane_ctl;
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-       u32 surf_addr;
-       u32 tile_height, plane_offset, plane_size;
+       u32 surf_addr = plane_state->main.offset;
        unsigned int rotation = plane_state->base.rotation;
-       int x_offset, y_offset;
-       int crtc_x = plane_state->dst.x1;
-       int crtc_y = plane_state->dst.y1;
-       uint32_t crtc_w = drm_rect_width(&plane_state->dst);
-       uint32_t crtc_h = drm_rect_height(&plane_state->dst);
-       uint32_t x = plane_state->src.x1 >> 16;
-       uint32_t y = plane_state->src.y1 >> 16;
-       uint32_t src_w = drm_rect_width(&plane_state->src) >> 16;
-       uint32_t src_h = drm_rect_height(&plane_state->src) >> 16;
+       u32 stride = skl_plane_stride(fb, 0, rotation);
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
+       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
+       uint32_t x = plane_state->main.x;
+       uint32_t y = plane_state->main.y;
+       uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
 
        plane_ctl = PLANE_CTL_ENABLE |
                PLANE_CTL_PIPE_GAMMA_ENABLE |
@@ -229,14 +231,8 @@ skl_update_plane(struct drm_plane *drm_plane,
 
        plane_ctl |= skl_plane_ctl_rotation(rotation);
 
-       stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
-                                              fb->pixel_format);
-
-       /* Sizes are 0 based */
-       src_w--;
-       src_h--;
-       crtc_w--;
-       crtc_h--;
+       if (wm->dirty_pipes & drm_crtc_mask(crtc))
+               skl_write_plane_wm(intel_crtc, wm, plane);
 
        if (key->flags) {
                I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
@@ -249,28 +245,15 @@ skl_update_plane(struct drm_plane *drm_plane,
        else if (key->flags & I915_SET_COLORKEY_SOURCE)
                plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
 
-       surf_addr = intel_plane_obj_offset(intel_plane, obj, 0);
-
-       if (intel_rotation_90_or_270(rotation)) {
-               int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
-
-               /* stride: Surface height in tiles */
-               tile_height = intel_tile_height(dev_priv, fb->modifier[0], cpp);
-               stride = DIV_ROUND_UP(fb->height, tile_height);
-               plane_size = (src_w << 16) | src_h;
-               x_offset = stride * tile_height - y - (src_h + 1);
-               y_offset = x;
-       } else {
-               stride = fb->pitches[0] / stride_div;
-               plane_size = (src_h << 16) | src_w;
-               x_offset = x;
-               y_offset = y;
-       }
-       plane_offset = y_offset << 16 | x_offset;
+       /* Sizes are 0 based */
+       src_w--;
+       src_h--;
+       crtc_w--;
+       crtc_h--;
 
-       I915_WRITE(PLANE_OFFSET(pipe, plane), plane_offset);
+       I915_WRITE(PLANE_OFFSET(pipe, plane), (y << 16) | x);
        I915_WRITE(PLANE_STRIDE(pipe, plane), stride);
-       I915_WRITE(PLANE_SIZE(pipe, plane), plane_size);
+       I915_WRITE(PLANE_SIZE(pipe, plane), (src_h << 16) | src_w);
 
        /* program plane scaler */
        if (plane_state->scaler_id >= 0) {
@@ -295,7 +278,8 @@ skl_update_plane(struct drm_plane *drm_plane,
        }
 
        I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
-       I915_WRITE(PLANE_SURF(pipe, plane), surf_addr);
+       I915_WRITE(PLANE_SURF(pipe, plane),
+                  intel_fb_gtt_offset(fb, rotation) + surf_addr);
        POSTING_READ(PLANE_SURF(pipe, plane));
 }
 
@@ -308,6 +292,14 @@ skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
        const int pipe = intel_plane->pipe;
        const int plane = intel_plane->plane + 1;
 
+       /*
+        * We only populate skl_results on watermark updates, and if the
+        * plane's visiblity isn't actually changing neither is its watermarks.
+        */
+       if (!dplane->state->visible)
+               skl_write_plane_wm(to_intel_crtc(crtc),
+                                  &dev_priv->wm.skl_results, plane);
+
        I915_WRITE(PLANE_CTL(pipe, plane), 0);
 
        I915_WRITE(PLANE_SURF(pipe, plane), 0);
@@ -362,22 +354,20 @@ vlv_update_plane(struct drm_plane *dplane,
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_plane *intel_plane = to_intel_plane(dplane);
        struct drm_framebuffer *fb = plane_state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_plane->pipe;
        int plane = intel_plane->plane;
        u32 sprctl;
        u32 sprsurf_offset, linear_offset;
        unsigned int rotation = dplane->state->rotation;
-       int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-       int crtc_x = plane_state->dst.x1;
-       int crtc_y = plane_state->dst.y1;
-       uint32_t crtc_w = drm_rect_width(&plane_state->dst);
-       uint32_t crtc_h = drm_rect_height(&plane_state->dst);
-       uint32_t x = plane_state->src.x1 >> 16;
-       uint32_t y = plane_state->src.y1 >> 16;
-       uint32_t src_w = drm_rect_width(&plane_state->src) >> 16;
-       uint32_t src_h = drm_rect_height(&plane_state->src) >> 16;
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
+       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
+       uint32_t x = plane_state->base.src.x1 >> 16;
+       uint32_t y = plane_state->base.src.y1 >> 16;
+       uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
 
        sprctl = SP_ENABLE;
 
@@ -430,7 +420,7 @@ vlv_update_plane(struct drm_plane *dplane,
         */
        sprctl |= SP_GAMMA_ENABLE;
 
-       if (obj->tiling_mode != I915_TILING_NONE)
+       if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                sprctl |= SP_TILED;
 
        /* Sizes are 0 based */
@@ -439,19 +429,18 @@ vlv_update_plane(struct drm_plane *dplane,
        crtc_w--;
        crtc_h--;
 
-       linear_offset = y * fb->pitches[0] + x * cpp;
-       sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
-                                                  fb->pitches[0], rotation);
-       linear_offset -= sprsurf_offset;
+       intel_add_fb_offsets(&x, &y, plane_state, 0);
+       sprsurf_offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
 
-       if (rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == DRM_ROTATE_180) {
                sprctl |= SP_ROTATE_180;
 
                x += src_w;
                y += src_h;
-               linear_offset += src_h * fb->pitches[0] + src_w * cpp;
        }
 
+       linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
+
        if (key->flags) {
                I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value);
                I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value);
@@ -467,7 +456,7 @@ vlv_update_plane(struct drm_plane *dplane,
        I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
        I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
 
-       if (obj->tiling_mode != I915_TILING_NONE)
+       if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x);
        else
                I915_WRITE(SPLINOFF(pipe, plane), linear_offset);
@@ -476,8 +465,8 @@ vlv_update_plane(struct drm_plane *dplane,
 
        I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
        I915_WRITE(SPCNTR(pipe, plane), sprctl);
-       I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
-                  sprsurf_offset);
+       I915_WRITE(SPSURF(pipe, plane),
+                  intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
        POSTING_READ(SPSURF(pipe, plane));
 }
 
@@ -505,21 +494,19 @@ ivb_update_plane(struct drm_plane *plane,
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *fb = plane_state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        enum pipe pipe = intel_plane->pipe;
        u32 sprctl, sprscale = 0;
        u32 sprsurf_offset, linear_offset;
        unsigned int rotation = plane_state->base.rotation;
-       int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-       int crtc_x = plane_state->dst.x1;
-       int crtc_y = plane_state->dst.y1;
-       uint32_t crtc_w = drm_rect_width(&plane_state->dst);
-       uint32_t crtc_h = drm_rect_height(&plane_state->dst);
-       uint32_t x = plane_state->src.x1 >> 16;
-       uint32_t y = plane_state->src.y1 >> 16;
-       uint32_t src_w = drm_rect_width(&plane_state->src) >> 16;
-       uint32_t src_h = drm_rect_height(&plane_state->src) >> 16;
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
+       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
+       uint32_t x = plane_state->base.src.x1 >> 16;
+       uint32_t y = plane_state->base.src.y1 >> 16;
+       uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
 
        sprctl = SPRITE_ENABLE;
 
@@ -552,7 +539,7 @@ ivb_update_plane(struct drm_plane *plane,
         */
        sprctl |= SPRITE_GAMMA_ENABLE;
 
-       if (obj->tiling_mode != I915_TILING_NONE)
+       if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                sprctl |= SPRITE_TILED;
 
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
@@ -572,22 +559,21 @@ ivb_update_plane(struct drm_plane *plane,
        if (crtc_w != src_w || crtc_h != src_h)
                sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
 
-       linear_offset = y * fb->pitches[0] + x * cpp;
-       sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
-                                                  fb->pitches[0], rotation);
-       linear_offset -= sprsurf_offset;
+       intel_add_fb_offsets(&x, &y, plane_state, 0);
+       sprsurf_offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
 
-       if (rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == DRM_ROTATE_180) {
                sprctl |= SPRITE_ROTATE_180;
 
                /* HSW and BDW does this automagically in hardware */
                if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
                        x += src_w;
                        y += src_h;
-                       linear_offset += src_h * fb->pitches[0] + src_w * cpp;
                }
        }
 
+       linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
+
        if (key->flags) {
                I915_WRITE(SPRKEYVAL(pipe), key->min_value);
                I915_WRITE(SPRKEYMAX(pipe), key->max_value);
@@ -606,7 +592,7 @@ ivb_update_plane(struct drm_plane *plane,
         * register */
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                I915_WRITE(SPROFFSET(pipe), (y << 16) | x);
-       else if (obj->tiling_mode != I915_TILING_NONE)
+       else if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
        else
                I915_WRITE(SPRLINOFF(pipe), linear_offset);
@@ -616,7 +602,7 @@ ivb_update_plane(struct drm_plane *plane,
                I915_WRITE(SPRSCALE(pipe), sprscale);
        I915_WRITE(SPRCTL(pipe), sprctl);
        I915_WRITE(SPRSURF(pipe),
-                  i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
+                  intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
        POSTING_READ(SPRSURF(pipe));
 }
 
@@ -646,21 +632,19 @@ ilk_update_plane(struct drm_plane *plane,
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *fb = plane_state->base.fb;
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_plane->pipe;
        u32 dvscntr, dvsscale;
        u32 dvssurf_offset, linear_offset;
        unsigned int rotation = plane_state->base.rotation;
-       int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-       int crtc_x = plane_state->dst.x1;
-       int crtc_y = plane_state->dst.y1;
-       uint32_t crtc_w = drm_rect_width(&plane_state->dst);
-       uint32_t crtc_h = drm_rect_height(&plane_state->dst);
-       uint32_t x = plane_state->src.x1 >> 16;
-       uint32_t y = plane_state->src.y1 >> 16;
-       uint32_t src_w = drm_rect_width(&plane_state->src) >> 16;
-       uint32_t src_h = drm_rect_height(&plane_state->src) >> 16;
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
+       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
+       uint32_t x = plane_state->base.src.x1 >> 16;
+       uint32_t y = plane_state->base.src.y1 >> 16;
+       uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
 
        dvscntr = DVS_ENABLE;
 
@@ -693,7 +677,7 @@ ilk_update_plane(struct drm_plane *plane,
         */
        dvscntr |= DVS_GAMMA_ENABLE;
 
-       if (obj->tiling_mode != I915_TILING_NONE)
+       if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                dvscntr |= DVS_TILED;
 
        if (IS_GEN6(dev))
@@ -709,19 +693,18 @@ ilk_update_plane(struct drm_plane *plane,
        if (crtc_w != src_w || crtc_h != src_h)
                dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
 
-       linear_offset = y * fb->pitches[0] + x * cpp;
-       dvssurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
-                                                  fb->pitches[0], rotation);
-       linear_offset -= dvssurf_offset;
+       intel_add_fb_offsets(&x, &y, plane_state, 0);
+       dvssurf_offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
 
-       if (rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == DRM_ROTATE_180) {
                dvscntr |= DVS_ROTATE_180;
 
                x += src_w;
                y += src_h;
-               linear_offset += src_h * fb->pitches[0] + src_w * cpp;
        }
 
+       linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
+
        if (key->flags) {
                I915_WRITE(DVSKEYVAL(pipe), key->min_value);
                I915_WRITE(DVSKEYMAX(pipe), key->max_value);
@@ -736,7 +719,7 @@ ilk_update_plane(struct drm_plane *plane,
        I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
 
-       if (obj->tiling_mode != I915_TILING_NONE)
+       if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
        else
                I915_WRITE(DVSLINOFF(pipe), linear_offset);
@@ -745,7 +728,7 @@ ilk_update_plane(struct drm_plane *plane,
        I915_WRITE(DVSSCALE(pipe), dvsscale);
        I915_WRITE(DVSCNTR(pipe), dvscntr);
        I915_WRITE(DVSSURF(pipe),
-                  i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
+                  intel_fb_gtt_offset(fb, rotation) + dvssurf_offset);
        POSTING_READ(DVSSURF(pipe));
 }
 
@@ -778,15 +761,26 @@ intel_check_sprite_plane(struct drm_plane *plane,
        int crtc_x, crtc_y;
        unsigned int crtc_w, crtc_h;
        uint32_t src_x, src_y, src_w, src_h;
-       struct drm_rect *src = &state->src;
-       struct drm_rect *dst = &state->dst;
+       struct drm_rect *src = &state->base.src;
+       struct drm_rect *dst = &state->base.dst;
        const struct drm_rect *clip = &state->clip;
        int hscale, vscale;
        int max_scale, min_scale;
        bool can_scale;
+       int ret;
+
+       src->x1 = state->base.src_x;
+       src->y1 = state->base.src_y;
+       src->x2 = state->base.src_x + state->base.src_w;
+       src->y2 = state->base.src_y + state->base.src_h;
+
+       dst->x1 = state->base.crtc_x;
+       dst->y1 = state->base.crtc_y;
+       dst->x2 = state->base.crtc_x + state->base.crtc_w;
+       dst->y2 = state->base.crtc_y + state->base.crtc_h;
 
        if (!fb) {
-               state->visible = false;
+               state->base.visible = false;
                return 0;
        }
 
@@ -834,14 +828,14 @@ intel_check_sprite_plane(struct drm_plane *plane,
        vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale);
        BUG_ON(vscale < 0);
 
-       state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
+       state->base.visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
 
        crtc_x = dst->x1;
        crtc_y = dst->y1;
        crtc_w = drm_rect_width(dst);
        crtc_h = drm_rect_height(dst);
 
-       if (state->visible) {
+       if (state->base.visible) {
                /* check again in case clipping clamped the results */
                hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
                if (hscale < 0) {
@@ -898,12 +892,12 @@ intel_check_sprite_plane(struct drm_plane *plane,
                                crtc_w &= ~1;
 
                        if (crtc_w == 0)
-                               state->visible = false;
+                               state->base.visible = false;
                }
        }
 
        /* Check size restrictions when scaling */
-       if (state->visible && (src_w != crtc_w || src_h != crtc_h)) {
+       if (state->base.visible && (src_w != crtc_w || src_h != crtc_h)) {
                unsigned int width_bytes;
                int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 
@@ -912,10 +906,10 @@ intel_check_sprite_plane(struct drm_plane *plane,
                /* FIXME interlacing min height is 6 */
 
                if (crtc_w < 3 || crtc_h < 3)
-                       state->visible = false;
+                       state->base.visible = false;
 
                if (src_w < 3 || src_h < 3)
-                       state->visible = false;
+                       state->base.visible = false;
 
                width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
 
@@ -926,7 +920,7 @@ intel_check_sprite_plane(struct drm_plane *plane,
                }
        }
 
-       if (state->visible) {
+       if (state->base.visible) {
                src->x1 = src_x << 16;
                src->x2 = (src_x + src_w) << 16;
                src->y1 = src_y << 16;
@@ -938,6 +932,12 @@ intel_check_sprite_plane(struct drm_plane *plane,
        dst->y1 = crtc_y;
        dst->y2 = crtc_y + crtc_h;
 
+       if (INTEL_GEN(dev) >= 9) {
+               ret = skl_check_plane_surface(state);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
index 49136ad..d960e48 100644 (file)
@@ -838,7 +838,9 @@ intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
 }
 
 static void
-intel_enable_tv(struct intel_encoder *encoder)
+intel_enable_tv(struct intel_encoder *encoder,
+               struct intel_crtc_state *pipe_config,
+               struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -851,7 +853,9 @@ intel_enable_tv(struct intel_encoder *encoder)
 }
 
 static void
-intel_disable_tv(struct intel_encoder *encoder)
+intel_disable_tv(struct intel_encoder *encoder,
+                struct intel_crtc_state *old_crtc_state,
+                struct drm_connector_state *old_conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -908,7 +912,8 @@ intel_tv_get_config(struct intel_encoder *encoder,
 
 static bool
 intel_tv_compute_config(struct intel_encoder *encoder,
-                       struct intel_crtc_state *pipe_config)
+                       struct intel_crtc_state *pipe_config,
+                       struct drm_connector_state *conn_state)
 {
        struct intel_tv *intel_tv = enc_to_tv(encoder);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
@@ -1010,7 +1015,9 @@ static void set_color_conversion(struct drm_i915_private *dev_priv,
                   color_conversion->av);
 }
 
-static void intel_tv_pre_enable(struct intel_encoder *encoder)
+static void intel_tv_pre_enable(struct intel_encoder *encoder,
+                               struct intel_crtc_state *pipe_config,
+                               struct drm_connector_state *conn_state)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
index ff80a81..ee2306a 100644 (file)
@@ -435,7 +435,7 @@ void intel_uncore_sanitize(struct drm_i915_private *dev_priv)
        i915.enable_rc6 = sanitize_rc6_option(dev_priv, i915.enable_rc6);
 
        /* BIOS often leaves RC6 enabled, but disable it for hw init */
-       intel_disable_gt_powersave(dev_priv);
+       intel_sanitize_gt_powersave(dev_priv);
 }
 
 static void __intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
@@ -796,10 +796,9 @@ __unclaimed_reg_debug(struct drm_i915_private *dev_priv,
                      const bool read,
                      const bool before)
 {
-       if (WARN(check_for_unclaimed_mmio(dev_priv),
-                "Unclaimed register detected %s %s register 0x%x\n",
-                before ? "before" : "after",
-                read ? "reading" : "writing to",
+       if (WARN(check_for_unclaimed_mmio(dev_priv) && !before,
+                "Unclaimed %s register 0x%x\n",
+                read ? "read from" : "write to",
                 i915_mmio_reg_offset(reg)))
                i915.mmio_debug--; /* Only report the first N failures */
 }
@@ -1018,11 +1017,9 @@ gen5_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool
 __gen5_write(8)
 __gen5_write(16)
 __gen5_write(32)
-__gen5_write(64)
 __gen2_write(8)
 __gen2_write(16)
 __gen2_write(32)
-__gen2_write(64)
 
 #undef __gen5_write
 #undef __gen2_write
@@ -1112,23 +1109,18 @@ gen9_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, \
 __gen9_write(8)
 __gen9_write(16)
 __gen9_write(32)
-__gen9_write(64)
 __chv_write(8)
 __chv_write(16)
 __chv_write(32)
-__chv_write(64)
 __gen8_write(8)
 __gen8_write(16)
 __gen8_write(32)
-__gen8_write(64)
 __hsw_write(8)
 __hsw_write(16)
 __hsw_write(32)
-__hsw_write(64)
 __gen6_write(8)
 __gen6_write(16)
 __gen6_write(32)
-__gen6_write(64)
 
 #undef __gen9_write
 #undef __chv_write
@@ -1158,7 +1150,6 @@ static void vgpu_write##x(struct drm_i915_private *dev_priv, \
 __vgpu_write(8)
 __vgpu_write(16)
 __vgpu_write(32)
-__vgpu_write(64)
 
 #undef __vgpu_write
 #undef VGPU_WRITE_FOOTER
@@ -1169,7 +1160,6 @@ do { \
        dev_priv->uncore.funcs.mmio_writeb = x##_write8; \
        dev_priv->uncore.funcs.mmio_writew = x##_write16; \
        dev_priv->uncore.funcs.mmio_writel = x##_write32; \
-       dev_priv->uncore.funcs.mmio_writeq = x##_write64; \
 } while (0)
 
 #define ASSIGN_READ_MMIO_VFUNCS(x) \
@@ -1597,8 +1587,10 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv,
        if (engine_mask == ALL_ENGINES) {
                hw_mask = GEN6_GRDOM_FULL;
        } else {
+               unsigned int tmp;
+
                hw_mask = 0;
-               for_each_engine_masked(engine, dev_priv, engine_mask)
+               for_each_engine_masked(engine, dev_priv, engine_mask, tmp)
                        hw_mask |= hw_engine_mask[engine->id];
        }
 
@@ -1618,8 +1610,10 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv,
  * @timeout_ms: timeout in millisecond
  *
  * This routine waits until the target register @reg contains the expected
- * @value after applying the @mask, i.e. it waits until
- *   (I915_READ_FW(@reg) & @mask) == @value
+ * @value after applying the @mask, i.e. it waits until ::
+ *
+ *     (I915_READ_FW(reg) & mask) == value
+ *
  * Otherwise, the wait will timeout after @timeout_ms milliseconds.
  *
  * Note that this routine assumes the caller holds forcewake asserted, it is
@@ -1652,8 +1646,10 @@ int intel_wait_for_register_fw(struct drm_i915_private *dev_priv,
  * @timeout_ms: timeout in millisecond
  *
  * This routine waits until the target register @reg contains the expected
- * @value after applying the @mask, i.e. it waits until
- *   (I915_READ(@reg) & @mask) == @value
+ * @value after applying the @mask, i.e. it waits until ::
+ *
+ *     (I915_READ(reg) & mask) == value
+ *
  * Otherwise, the wait will timeout after @timeout_ms milliseconds.
  *
  * Returns 0 if the register matches the desired condition, or -ETIMEOUT.
@@ -1710,15 +1706,16 @@ static int gen8_reset_engines(struct drm_i915_private *dev_priv,
                              unsigned engine_mask)
 {
        struct intel_engine_cs *engine;
+       unsigned int tmp;
 
-       for_each_engine_masked(engine, dev_priv, engine_mask)
+       for_each_engine_masked(engine, dev_priv, engine_mask, tmp)
                if (gen8_request_engine_reset(engine))
                        goto not_ready;
 
        return gen6_reset_engines(dev_priv, engine_mask);
 
 not_ready:
-       for_each_engine_masked(engine, dev_priv, engine_mask)
+       for_each_engine_masked(engine, dev_priv, engine_mask, tmp)
                gen8_unrequest_engine_reset(engine);
 
        return -EIO;
index 7bf90e9..98df09c 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/component.h>
 #include <linux/device.h>
 #include <linux/dma-buf.h>
-#include <linux/fb.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/reservation.h>
@@ -58,12 +57,6 @@ static int legacyfb_depth = 16;
 module_param(legacyfb_depth, int, 0444);
 #endif
 
-unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
-{
-       return drm_crtc_index(crtc->crtc);
-}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
-
 static void imx_drm_driver_lastclose(struct drm_device *drm)
 {
        struct imx_drm_device *imxdrm = drm->dev_private;
@@ -71,43 +64,6 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
        drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
 }
 
-static int imx_drm_driver_unload(struct drm_device *drm)
-{
-       struct imx_drm_device *imxdrm = drm->dev_private;
-
-       drm_kms_helper_poll_fini(drm);
-
-       if (imxdrm->fbhelper)
-               drm_fbdev_cma_fini(imxdrm->fbhelper);
-
-       component_unbind_all(drm->dev, drm);
-
-       drm_vblank_cleanup(drm);
-       drm_mode_config_cleanup(drm);
-
-       platform_set_drvdata(drm->platformdev, NULL);
-
-       return 0;
-}
-
-int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
-{
-       return drm_crtc_vblank_get(imx_drm_crtc->crtc);
-}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
-
-void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
-{
-       drm_crtc_vblank_put(imx_drm_crtc->crtc);
-}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
-
-void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
-{
-       drm_crtc_handle_vblank(imx_drm_crtc->crtc);
-}
-EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
-
 static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
 {
        struct imx_drm_device *imxdrm = drm->dev_private;
@@ -195,54 +151,49 @@ static int imx_drm_atomic_check(struct drm_device *dev,
        return ret;
 }
 
+static int imx_drm_atomic_commit(struct drm_device *dev,
+                                struct drm_atomic_state *state,
+                                bool nonblock)
+{
+       struct drm_plane_state *plane_state;
+       struct drm_plane *plane;
+       struct dma_buf *dma_buf;
+       int i;
+
+       /*
+        * If the plane fb has an dma-buf attached, fish out the exclusive
+        * fence for the atomic helper to wait on.
+        */
+       for_each_plane_in_state(state, plane, plane_state, i) {
+               if ((plane->state->fb != plane_state->fb) && plane_state->fb) {
+                       dma_buf = drm_fb_cma_get_gem_obj(plane_state->fb,
+                                                        0)->base.dma_buf;
+                       if (!dma_buf)
+                               continue;
+                       plane_state->fence =
+                               reservation_object_get_excl_rcu(dma_buf->resv);
+               }
+       }
+
+       return drm_atomic_helper_commit(dev, state, nonblock);
+}
+
 static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
        .fb_create = drm_fb_cma_create,
        .output_poll_changed = imx_drm_output_poll_changed,
        .atomic_check = imx_drm_atomic_check,
-       .atomic_commit = drm_atomic_helper_commit,
+       .atomic_commit = imx_drm_atomic_commit,
 };
 
 static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
-       struct drm_crtc *crtc;
-       struct drm_crtc_state *crtc_state;
-       struct drm_plane_state *plane_state;
-       struct drm_gem_cma_object *cma_obj;
-       struct fence *excl;
-       unsigned shared_count;
-       struct fence **shared;
-       unsigned int i, j;
-       int ret;
-
-       /* Wait for fences. */
-       for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               plane_state = crtc->primary->state;
-               if (plane_state->fb) {
-                       cma_obj = drm_fb_cma_get_gem_obj(plane_state->fb, 0);
-                       if (cma_obj->base.dma_buf) {
-                               ret = reservation_object_get_fences_rcu(
-                                       cma_obj->base.dma_buf->resv, &excl,
-                                       &shared_count, &shared);
-                               if (unlikely(ret))
-                                       DRM_ERROR("failed to get fences "
-                                                 "for buffer\n");
-
-                               if (excl) {
-                                       fence_wait(excl, false);
-                                       fence_put(excl);
-                               }
-                               for (j = 0; j < shared_count; i++) {
-                                       fence_wait(shared[j], false);
-                                       fence_put(shared[j]);
-                               }
-                       }
-               }
-       }
 
        drm_atomic_helper_commit_modeset_disables(dev, state);
 
-       drm_atomic_helper_commit_planes(dev, state, true);
+       drm_atomic_helper_commit_planes(dev, state,
+                               DRM_PLANE_COMMIT_ACTIVE_ONLY |
+                               DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);
 
        drm_atomic_helper_commit_modeset_enables(dev, state);
 
@@ -257,111 +208,6 @@ static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
        .atomic_commit_tail = imx_drm_atomic_commit_tail,
 };
 
-/*
- * Main DRM initialisation. This binds, initialises and registers
- * with DRM the subcomponents of the driver.
- */
-static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
-{
-       struct imx_drm_device *imxdrm;
-       struct drm_connector *connector;
-       int ret;
-
-       imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
-       if (!imxdrm)
-               return -ENOMEM;
-
-       imxdrm->drm = drm;
-
-       drm->dev_private = imxdrm;
-
-       /*
-        * enable drm irq mode.
-        * - with irq_enabled = true, we can use the vblank feature.
-        *
-        * P.S. note that we wouldn't use drm irq handler but
-        *      just specific driver own one instead because
-        *      drm framework supports only one irq handler and
-        *      drivers can well take care of their interrupts
-        */
-       drm->irq_enabled = true;
-
-       /*
-        * set max width and height as default value(4096x4096).
-        * this value would be used to check framebuffer size limitation
-        * at drm_mode_addfb().
-        */
-       drm->mode_config.min_width = 64;
-       drm->mode_config.min_height = 64;
-       drm->mode_config.max_width = 4096;
-       drm->mode_config.max_height = 4096;
-       drm->mode_config.funcs = &imx_drm_mode_config_funcs;
-       drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
-
-       drm_mode_config_init(drm);
-
-       ret = drm_vblank_init(drm, MAX_CRTC);
-       if (ret)
-               goto err_kms;
-
-       platform_set_drvdata(drm->platformdev, drm);
-
-       /* Now try and bind all our sub-components */
-       ret = component_bind_all(drm->dev, drm);
-       if (ret)
-               goto err_vblank;
-
-       /*
-        * All components are now added, we can publish the connector sysfs
-        * entries to userspace.  This will generate hotplug events and so
-        * userspace will expect to be able to access DRM at this point.
-        */
-       list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
-               ret = drm_connector_register(connector);
-               if (ret) {
-                       dev_err(drm->dev,
-                               "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
-                               connector->base.id,
-                               connector->name, ret);
-                       goto err_unbind;
-               }
-       }
-
-       drm_mode_config_reset(drm);
-
-       /*
-        * All components are now initialised, so setup the fb helper.
-        * The fb helper takes copies of key hardware information, so the
-        * crtcs/connectors/encoders must not change after this point.
-        */
-#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
-       if (legacyfb_depth != 16 && legacyfb_depth != 32) {
-               dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
-               legacyfb_depth = 16;
-       }
-       imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
-                               drm->mode_config.num_crtc, MAX_CRTC);
-       if (IS_ERR(imxdrm->fbhelper)) {
-               ret = PTR_ERR(imxdrm->fbhelper);
-               imxdrm->fbhelper = NULL;
-               goto err_unbind;
-       }
-#endif
-
-       drm_kms_helper_poll_init(drm);
-
-       return 0;
-
-err_unbind:
-       component_unbind_all(drm->dev, drm);
-err_vblank:
-       drm_vblank_cleanup(drm);
-err_kms:
-       drm_mode_config_cleanup(drm);
-
-       return ret;
-}
-
 /*
  * imx_drm_add_crtc - add a new crtc
  */
@@ -454,8 +300,6 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = {
 static struct drm_driver imx_drm_driver = {
        .driver_features        = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
                                  DRIVER_ATOMIC,
-       .load                   = imx_drm_driver_load,
-       .unload                 = imx_drm_driver_unload,
        .lastclose              = imx_drm_driver_lastclose,
        .gem_free_object_unlocked = drm_gem_cma_free_object,
        .gem_vm_ops             = &drm_gem_cma_vm_ops,
@@ -508,12 +352,122 @@ static int compare_of(struct device *dev, void *data)
 
 static int imx_drm_bind(struct device *dev)
 {
-       return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
+       struct drm_device *drm;
+       struct imx_drm_device *imxdrm;
+       int ret;
+
+       drm = drm_dev_alloc(&imx_drm_driver, dev);
+       if (!drm)
+               return -ENOMEM;
+
+       imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL);
+       if (!imxdrm) {
+               ret = -ENOMEM;
+               goto err_unref;
+       }
+
+       imxdrm->drm = drm;
+       drm->dev_private = imxdrm;
+
+       /*
+        * enable drm irq mode.
+        * - with irq_enabled = true, we can use the vblank feature.
+        *
+        * P.S. note that we wouldn't use drm irq handler but
+        *      just specific driver own one instead because
+        *      drm framework supports only one irq handler and
+        *      drivers can well take care of their interrupts
+        */
+       drm->irq_enabled = true;
+
+       /*
+        * set max width and height as default value(4096x4096).
+        * this value would be used to check framebuffer size limitation
+        * at drm_mode_addfb().
+        */
+       drm->mode_config.min_width = 64;
+       drm->mode_config.min_height = 64;
+       drm->mode_config.max_width = 4096;
+       drm->mode_config.max_height = 4096;
+       drm->mode_config.funcs = &imx_drm_mode_config_funcs;
+       drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
+
+       drm_mode_config_init(drm);
+
+       ret = drm_vblank_init(drm, MAX_CRTC);
+       if (ret)
+               goto err_kms;
+
+       dev_set_drvdata(dev, drm);
+
+       /* Now try and bind all our sub-components */
+       ret = component_bind_all(dev, drm);
+       if (ret)
+               goto err_vblank;
+
+       drm_mode_config_reset(drm);
+
+       /*
+        * All components are now initialised, so setup the fb helper.
+        * The fb helper takes copies of key hardware information, so the
+        * crtcs/connectors/encoders must not change after this point.
+        */
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
+       if (legacyfb_depth != 16 && legacyfb_depth != 32) {
+               dev_warn(dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
+               legacyfb_depth = 16;
+       }
+       imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
+                               drm->mode_config.num_crtc, MAX_CRTC);
+       if (IS_ERR(imxdrm->fbhelper)) {
+               ret = PTR_ERR(imxdrm->fbhelper);
+               imxdrm->fbhelper = NULL;
+               goto err_unbind;
+       }
+#endif
+
+       drm_kms_helper_poll_init(drm);
+
+       ret = drm_dev_register(drm, 0);
+       if (ret)
+               goto err_fbhelper;
+
+       return 0;
+
+err_fbhelper:
+       drm_kms_helper_poll_fini(drm);
+       if (imxdrm->fbhelper)
+               drm_fbdev_cma_fini(imxdrm->fbhelper);
+err_unbind:
+       component_unbind_all(drm->dev, drm);
+err_vblank:
+       drm_vblank_cleanup(drm);
+err_kms:
+       drm_mode_config_cleanup(drm);
+err_unref:
+       drm_dev_unref(drm);
+
+       return ret;
 }
 
 static void imx_drm_unbind(struct device *dev)
 {
-       drm_put_dev(dev_get_drvdata(dev));
+       struct drm_device *drm = dev_get_drvdata(dev);
+       struct imx_drm_device *imxdrm = drm->dev_private;
+
+       drm_dev_unregister(drm);
+
+       drm_kms_helper_poll_fini(drm);
+
+       if (imxdrm->fbhelper)
+               drm_fbdev_cma_fini(imxdrm->fbhelper);
+
+       drm_mode_config_cleanup(drm);
+
+       component_unbind_all(drm->dev, drm);
+       dev_set_drvdata(dev, NULL);
+
+       drm_dev_unref(drm);
 }
 
 static const struct component_master_ops imx_drm_ops = {
index 07d33e4..5a91cb1 100644 (file)
@@ -13,8 +13,6 @@ struct drm_plane;
 struct imx_drm_crtc;
 struct platform_device;
 
-unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
-
 struct imx_crtc_state {
        struct drm_crtc_state                   base;
        u32                                     bus_format;
@@ -44,10 +42,6 @@ int imx_drm_init_drm(struct platform_device *pdev,
                int preferred_bpp);
 int imx_drm_exit_drm(void);
 
-int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
-void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
-void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
-
 void imx_drm_mode_config_init(struct drm_device *drm);
 
 struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
index b03919e..3ce391c 100644 (file)
@@ -57,7 +57,11 @@ struct imx_ldb_channel {
        struct imx_ldb *ldb;
        struct drm_connector connector;
        struct drm_encoder encoder;
+
+       /* Defines what is connected to the ldb, only one at a time */
        struct drm_panel *panel;
+       struct drm_bridge *bridge;
+
        struct device_node *child;
        struct i2c_adapter *ddc;
        int chno;
@@ -66,6 +70,7 @@ struct imx_ldb_channel {
        struct drm_display_mode mode;
        int mode_valid;
        u32 bus_format;
+       u32 bus_flags;
 };
 
 static inline struct imx_ldb_channel *con_to_imx_ldb_ch(struct drm_connector *c)
@@ -251,11 +256,13 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
        drm_panel_enable(imx_ldb_ch->panel);
 }
 
-static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
-                        struct drm_display_mode *orig_mode,
-                        struct drm_display_mode *mode)
+static void
+imx_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder,
+                               struct drm_crtc_state *crtc_state,
+                               struct drm_connector_state *connector_state)
 {
        struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
+       struct drm_display_mode *mode = &crtc_state->adjusted_mode;
        struct imx_ldb *ldb = imx_ldb_ch->ldb;
        int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
        unsigned long serial_clk;
@@ -297,17 +304,11 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        if (!bus_format) {
-               struct drm_connector *connector;
-
-               drm_for_each_connector(connector, encoder->dev) {
-                       struct drm_display_info *di = &connector->display_info;
+               struct drm_connector *connector = connector_state->connector;
+               struct drm_display_info *di = &connector->display_info;
 
-                       if (connector->encoder == encoder &&
-                           di->num_bus_formats) {
-                               bus_format = di->bus_formats[0];
-                               break;
-                       }
-               }
+               if (di->num_bus_formats)
+                       bus_format = di->bus_formats[0];
        }
        imx_ldb_ch_set_bus_format(imx_ldb_ch, bus_format);
 }
@@ -379,8 +380,13 @@ static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder,
        u32 bus_format = imx_ldb_ch->bus_format;
 
        /* Bus format description in DT overrides connector display info. */
-       if (!bus_format && di->num_bus_formats)
+       if (!bus_format && di->num_bus_formats) {
                bus_format = di->bus_formats[0];
+               imx_crtc_state->bus_flags = di->bus_flags;
+       } else {
+               bus_format = imx_ldb_ch->bus_format;
+               imx_crtc_state->bus_flags = imx_ldb_ch->bus_flags;
+       }
        switch (bus_format) {
        case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
                imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
@@ -420,7 +426,7 @@ static const struct drm_encoder_funcs imx_ldb_encoder_funcs = {
 };
 
 static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
-       .mode_set = imx_ldb_encoder_mode_set,
+       .atomic_mode_set = imx_ldb_encoder_atomic_mode_set,
        .enable = imx_ldb_encoder_enable,
        .disable = imx_ldb_encoder_disable,
        .atomic_check = imx_ldb_encoder_atomic_check,
@@ -466,10 +472,30 @@ static int imx_ldb_register(struct drm_device *drm,
        drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs,
                         DRM_MODE_ENCODER_LVDS, NULL);
 
-       drm_connector_helper_add(&imx_ldb_ch->connector,
-                       &imx_ldb_connector_helper_funcs);
-       drm_connector_init(drm, &imx_ldb_ch->connector,
-                          &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+       if (imx_ldb_ch->bridge) {
+               imx_ldb_ch->bridge->encoder = encoder;
+
+               imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
+               ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
+               if (ret) {
+                       DRM_ERROR("Failed to initialize bridge with drm\n");
+                       return ret;
+               }
+       } else {
+               /*
+                * We want to add the connector whenever there is no bridge
+                * that brings its own, not only when there is a panel. For
+                * historical reasons, the ldb driver can also work without
+                * a panel.
+                */
+               drm_connector_helper_add(&imx_ldb_ch->connector,
+                               &imx_ldb_connector_helper_funcs);
+               drm_connector_init(drm, &imx_ldb_ch->connector,
+                               &imx_ldb_connector_funcs,
+                               DRM_MODE_CONNECTOR_LVDS);
+               drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
+                               encoder);
+       }
 
        if (imx_ldb_ch->panel) {
                ret = drm_panel_attach(imx_ldb_ch->panel,
@@ -478,8 +504,6 @@ static int imx_ldb_register(struct drm_device *drm,
                        return ret;
        }
 
-       drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, encoder);
-
        return 0;
 }
 
@@ -548,6 +572,46 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
 
+static int imx_ldb_panel_ddc(struct device *dev,
+               struct imx_ldb_channel *channel, struct device_node *child)
+{
+       struct device_node *ddc_node;
+       const u8 *edidp;
+       int ret;
+
+       ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
+       if (ddc_node) {
+               channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
+               of_node_put(ddc_node);
+               if (!channel->ddc) {
+                       dev_warn(dev, "failed to get ddc i2c adapter\n");
+                       return -EPROBE_DEFER;
+               }
+       }
+
+       if (!channel->ddc) {
+               /* if no DDC available, fallback to hardcoded EDID */
+               dev_dbg(dev, "no ddc available\n");
+
+               edidp = of_get_property(child, "edid",
+                                       &channel->edid_len);
+               if (edidp) {
+                       channel->edid = kmemdup(edidp,
+                                               channel->edid_len,
+                                               GFP_KERNEL);
+               } else if (!channel->panel) {
+                       /* fallback to display-timings node */
+                       ret = of_get_drm_display_mode(child,
+                                                     &channel->mode,
+                                                     &channel->bus_flags,
+                                                     OF_USE_NATIVE_MODE);
+                       if (!ret)
+                               channel->mode_valid = 1;
+               }
+       }
+       return 0;
+}
+
 static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 {
        struct drm_device *drm = data;
@@ -555,7 +619,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
        const struct of_device_id *of_id =
                        of_match_device(imx_ldb_dt_ids, dev);
        struct device_node *child;
-       const u8 *edidp;
        struct imx_ldb *imx_ldb;
        int dual;
        int ret;
@@ -605,7 +668,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 
        for_each_child_of_node(np, child) {
                struct imx_ldb_channel *channel;
-               struct device_node *ddc_node;
                struct device_node *ep;
                int bus_format;
 
@@ -638,46 +700,25 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 
                        remote = of_graph_get_remote_port_parent(ep);
                        of_node_put(ep);
-                       if (remote)
+                       if (remote) {
                                channel->panel = of_drm_find_panel(remote);
-                       else
+                               channel->bridge = of_drm_find_bridge(remote);
+                       } else
                                return -EPROBE_DEFER;
                        of_node_put(remote);
-                       if (!channel->panel) {
-                               dev_err(dev, "panel not found: %s\n",
+
+                       if (!channel->panel && !channel->bridge) {
+                               dev_err(dev, "panel/bridge not found: %s\n",
                                        remote->full_name);
                                return -EPROBE_DEFER;
                        }
                }
 
-               ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
-               if (ddc_node) {
-                       channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
-                       of_node_put(ddc_node);
-                       if (!channel->ddc) {
-                               dev_warn(dev, "failed to get ddc i2c adapter\n");
-                               return -EPROBE_DEFER;
-                       }
-               }
-
-               if (!channel->ddc) {
-                       /* if no DDC available, fallback to hardcoded EDID */
-                       dev_dbg(dev, "no ddc available\n");
-
-                       edidp = of_get_property(child, "edid",
-                                               &channel->edid_len);
-                       if (edidp) {
-                               channel->edid = kmemdup(edidp,
-                                                       channel->edid_len,
-                                                       GFP_KERNEL);
-                       } else if (!channel->panel) {
-                               /* fallback to display-timings node */
-                               ret = of_get_drm_display_mode(child,
-                                                             &channel->mode,
-                                                             OF_USE_NATIVE_MODE);
-                               if (!ret)
-                                       channel->mode_valid = 1;
-                       }
+               /* panel ddc only if there is no bridge */
+               if (!channel->bridge) {
+                       ret = imx_ldb_panel_ddc(dev, channel, child);
+                       if (ret)
+                               return ret;
                }
 
                bus_format = of_get_bus_format(dev, child);
@@ -716,11 +757,10 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
        for (i = 0; i < 2; i++) {
                struct imx_ldb_channel *channel = &imx_ldb->channel[i];
 
-               if (!channel->connector.funcs)
-                       continue;
-
-               channel->connector.funcs->destroy(&channel->connector);
-               channel->encoder.funcs->destroy(&channel->encoder);
+               if (channel->bridge)
+                       drm_bridge_detach(channel->bridge);
+               if (channel->panel)
+                       drm_panel_detach(channel->panel);
 
                kfree(channel->edid);
                i2c_put_adapter(channel->ddc);
index 5e87594..8fc0888 100644 (file)
@@ -685,9 +685,6 @@ static void imx_tve_unbind(struct device *dev, struct device *master,
 {
        struct imx_tve *tve = dev_get_drvdata(dev);
 
-       tve->connector.funcs->destroy(&tve->connector);
-       tve->encoder.funcs->destroy(&tve->encoder);
-
        if (!IS_ERR(tve->dac_reg))
                regulator_disable(tve->dac_reg);
 }
index 462056e..4e1ae3f 100644 (file)
@@ -21,7 +21,6 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
-#include <linux/fb.h>
 #include <linux/clk.h>
 #include <linux/errno.h>
 #include <drm/drm_gem_cma_helper.h>
@@ -61,7 +60,8 @@ static void ipu_crtc_enable(struct drm_crtc *crtc)
        ipu_di_enable(ipu_crtc->di);
 }
 
-static void ipu_crtc_disable(struct drm_crtc *crtc)
+static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
+                                   struct drm_crtc_state *old_crtc_state)
 {
        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
        struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
@@ -77,6 +77,9 @@ static void ipu_crtc_disable(struct drm_crtc *crtc)
        }
        spin_unlock_irq(&crtc->dev->event_lock);
 
+       /* always disable planes on the CRTC */
+       drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, true);
+
        drm_crtc_vblank_off(crtc);
 }
 
@@ -123,9 +126,14 @@ static void imx_drm_crtc_destroy_state(struct drm_crtc *crtc,
        kfree(to_imx_crtc_state(state));
 }
 
+static void imx_drm_crtc_destroy(struct drm_crtc *crtc)
+{
+       imx_drm_remove_crtc(to_ipu_crtc(crtc)->imx_crtc);
+}
+
 static const struct drm_crtc_funcs ipu_crtc_funcs = {
        .set_config = drm_atomic_helper_set_config,
-       .destroy = drm_crtc_cleanup,
+       .destroy = imx_drm_crtc_destroy,
        .page_flip = drm_atomic_helper_page_flip,
        .reset = imx_drm_crtc_reset,
        .atomic_duplicate_state = imx_drm_crtc_duplicate_state,
@@ -136,7 +144,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
 {
        struct ipu_crtc *ipu_crtc = dev_id;
 
-       imx_drm_handle_vblank(ipu_crtc->imx_crtc);
+       drm_crtc_handle_vblank(&ipu_crtc->base);
 
        return IRQ_HANDLED;
 }
@@ -246,7 +254,7 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
        .mode_set_nofb = ipu_crtc_mode_set_nofb,
        .atomic_check = ipu_crtc_atomic_check,
        .atomic_begin = ipu_crtc_atomic_begin,
-       .disable = ipu_crtc_disable,
+       .atomic_disable = ipu_crtc_atomic_disable,
        .enable = ipu_crtc_enable,
 };
 
@@ -414,8 +422,6 @@ static void ipu_drm_unbind(struct device *dev, struct device *master,
 {
        struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
 
-       imx_drm_remove_crtc(ipu_crtc->imx_crtc);
-
        ipu_put_resources(ipu_crtc);
        if (ipu_crtc->plane[1])
                ipu_plane_put_resources(ipu_crtc->plane[1]);
index 29423e7..ce22d0a 100644 (file)
@@ -213,8 +213,12 @@ static void ipu_plane_enable(struct ipu_plane *ipu_plane)
                ipu_dp_enable_channel(ipu_plane->dp);
 }
 
-static void ipu_plane_disable(struct ipu_plane *ipu_plane)
+static int ipu_disable_plane(struct drm_plane *plane)
 {
+       struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
        ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
 
        if (ipu_plane->dp)
@@ -223,15 +227,6 @@ static void ipu_plane_disable(struct ipu_plane *ipu_plane)
        ipu_dmfc_disable_channel(ipu_plane->dmfc);
        if (ipu_plane->dp)
                ipu_dp_disable(ipu_plane->ipu);
-}
-
-static int ipu_disable_plane(struct drm_plane *plane)
-{
-       struct ipu_plane *ipu_plane = to_ipu_plane(plane);
-
-       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
-       ipu_plane_disable(ipu_plane);
 
        return 0;
 }
@@ -242,7 +237,6 @@ static void ipu_plane_destroy(struct drm_plane *plane)
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       ipu_disable_plane(plane);
        drm_plane_cleanup(plane);
        kfree(ipu_plane);
 }
@@ -320,8 +314,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
 
        /*
         * We support resizing active plane or changing its format by
-        * forcing CRTC mode change and disabling-enabling plane in plane's
-        * ->atomic_update callback.
+        * forcing CRTC mode change in plane's ->atomic_check callback
+        * and disabling all affected active planes in CRTC's ->atomic_disable
+        * callback.  The planes will be reenabled in plane's ->atomic_update
+        * callback.
         */
        if (old_fb && (state->src_w != old_state->src_w ||
                              state->src_h != old_state->src_h ||
@@ -395,12 +391,10 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
        if (old_state->fb) {
                struct drm_crtc_state *crtc_state = state->crtc->state;
 
-               if (!crtc_state->mode_changed) {
+               if (!drm_atomic_crtc_needs_modeset(crtc_state)) {
                        ipu_plane_atomic_set_base(ipu_plane, old_state);
                        return;
                }
-
-               ipu_disable_plane(plane);
        }
 
        switch (ipu_plane->dp_flow) {
index 1dad297..d796ada 100644 (file)
@@ -33,6 +33,7 @@ struct imx_parallel_display {
        void *edid;
        int edid_len;
        u32 bus_format;
+       u32 bus_flags;
        struct drm_display_mode mode;
        struct drm_panel *panel;
        struct drm_bridge *bridge;
@@ -80,6 +81,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
                        return -EINVAL;
 
                ret = of_get_drm_display_mode(np, &imxpd->mode,
+                                             &imxpd->bus_flags,
                                              OF_USE_NATIVE_MODE);
                if (ret)
                        return ret;
@@ -125,11 +127,13 @@ static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder,
        struct drm_display_info *di = &conn_state->connector->display_info;
        struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
 
-       imx_crtc_state->bus_flags = di->bus_flags;
-       if (!imxpd->bus_format && di->num_bus_formats)
+       if (!imxpd->bus_format && di->num_bus_formats) {
+               imx_crtc_state->bus_flags = di->bus_flags;
                imx_crtc_state->bus_format = di->bus_formats[0];
-       else
+       } else {
+               imx_crtc_state->bus_flags = imxpd->bus_flags;
                imx_crtc_state->bus_format = imxpd->bus_format;
+       }
        imx_crtc_state->di_hsync_pin = 2;
        imx_crtc_state->di_vsync_pin = 3;
 
@@ -289,8 +293,10 @@ static void imx_pd_unbind(struct device *dev, struct device *master,
 {
        struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
 
-       imxpd->encoder.funcs->destroy(&imxpd->encoder);
-       imxpd->connector.funcs->destroy(&imxpd->connector);
+       if (imxpd->bridge)
+               drm_bridge_detach(imxpd->bridge);
+       if (imxpd->panel)
+               drm_panel_detach(imxpd->panel);
 
        kfree(imxpd->edid);
 }
index 8f62671..019b7ca 100644 (file)
@@ -103,7 +103,8 @@ static void mtk_ovl_stop(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
-                          unsigned int h, unsigned int vrefresh)
+                          unsigned int h, unsigned int vrefresh,
+                          unsigned int bpc)
 {
        if (w != 0 && h != 0)
                writel_relaxed(h << 16 | w, comp->regs + DISP_REG_OVL_ROI_SIZE);
index 5fb80cb..0df05f9 100644 (file)
@@ -106,7 +106,8 @@ static void mtk_rdma_stop(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
-                           unsigned int height, unsigned int vrefresh)
+                           unsigned int height, unsigned int vrefresh,
+                           unsigned int bpc)
 {
        unsigned int threshold;
        unsigned int reg;
index 24aa3ba..01a21dd 100644 (file)
@@ -31,7 +31,7 @@
  * struct mtk_drm_crtc - MediaTek specific crtc structure.
  * @base: crtc object.
  * @enabled: records whether crtc_enable succeeded
- * @planes: array of 4 mtk_drm_plane structures, one for each overlay plane
+ * @planes: array of 4 drm_plane structures, one for each overlay plane
  * @pending_planes: whether any plane has pending changes to be applied
  * @config_regs: memory mapped mmsys configuration register space
  * @mutex: handle to one of the ten disp_mutex streams
@@ -45,7 +45,7 @@ struct mtk_drm_crtc {
        bool                            pending_needs_vblank;
        struct drm_pending_vblank_event *event;
 
-       struct mtk_drm_plane            planes[OVL_LAYER_NR];
+       struct drm_plane                planes[OVL_LAYER_NR];
        bool                            pending_planes;
 
        void __iomem                    *config_regs;
@@ -112,8 +112,7 @@ static void mtk_drm_crtc_reset(struct drm_crtc *crtc)
        struct mtk_crtc_state *state;
 
        if (crtc->state) {
-               if (crtc->state->mode_blob)
-                       drm_property_unreference_blob(crtc->state->mode_blob);
+               __drm_atomic_helper_crtc_destroy_state(crtc->state);
 
                state = to_mtk_crtc_state(crtc->state);
                memset(state, 0, sizeof(*state));
@@ -222,7 +221,9 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
 static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
 {
        struct drm_crtc *crtc = &mtk_crtc->base;
-       unsigned int width, height, vrefresh;
+       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC;
        int ret;
        int i;
 
@@ -234,6 +235,19 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
        height = crtc->state->adjusted_mode.vdisplay;
        vrefresh = crtc->state->adjusted_mode.vrefresh;
 
+       drm_for_each_encoder(encoder, crtc->dev) {
+               if (encoder->crtc != crtc)
+                       continue;
+
+               drm_for_each_connector(connector, crtc->dev) {
+                       if (connector->encoder != encoder)
+                               continue;
+                       if (connector->display_info.bpc != 0 &&
+                           bpc > connector->display_info.bpc)
+                               bpc = connector->display_info.bpc;
+               }
+       }
+
        ret = pm_runtime_get_sync(crtc->dev->dev);
        if (ret < 0) {
                DRM_ERROR("Failed to enable power domain: %d\n", ret);
@@ -266,13 +280,13 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
        for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
                struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
 
-               mtk_ddp_comp_config(comp, width, height, vrefresh);
+               mtk_ddp_comp_config(comp, width, height, vrefresh, bpc);
                mtk_ddp_comp_start(comp);
        }
 
        /* Initially configure all planes */
        for (i = 0; i < OVL_LAYER_NR; i++) {
-               struct drm_plane *plane = &mtk_crtc->planes[i].base;
+               struct drm_plane *plane = &mtk_crtc->planes[i];
                struct mtk_plane_state *plane_state;
 
                plane_state = to_mtk_plane_state(plane->state);
@@ -351,7 +365,7 @@ static void mtk_drm_crtc_disable(struct drm_crtc *crtc)
 
        /* Set all pending plane state to disabled */
        for (i = 0; i < OVL_LAYER_NR; i++) {
-               struct drm_plane *plane = &mtk_crtc->planes[i].base;
+               struct drm_plane *plane = &mtk_crtc->planes[i];
                struct mtk_plane_state *plane_state;
 
                plane_state = to_mtk_plane_state(plane->state);
@@ -397,7 +411,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
        if (mtk_crtc->event)
                mtk_crtc->pending_needs_vblank = true;
        for (i = 0; i < OVL_LAYER_NR; i++) {
-               struct drm_plane *plane = &mtk_crtc->planes[i].base;
+               struct drm_plane *plane = &mtk_crtc->planes[i];
                struct mtk_plane_state *plane_state;
 
                plane_state = to_mtk_plane_state(plane->state);
@@ -409,6 +423,9 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
        }
        if (pending_planes)
                mtk_crtc->pending_planes = true;
+       if (crtc->state->color_mgmt_changed)
+               for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
+                       mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state);
 }
 
 static const struct drm_crtc_funcs mtk_crtc_funcs = {
@@ -418,6 +435,7 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
        .reset                  = mtk_drm_crtc_reset,
        .atomic_duplicate_state = mtk_drm_crtc_duplicate_state,
        .atomic_destroy_state   = mtk_drm_crtc_destroy_state,
+       .gamma_set              = drm_atomic_helper_legacy_gamma_set,
 };
 
 static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
@@ -464,14 +482,14 @@ void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl)
        if (state->pending_config) {
                mtk_ddp_comp_config(ovl, state->pending_width,
                                    state->pending_height,
-                                   state->pending_vrefresh);
+                                   state->pending_vrefresh, 0);
 
                state->pending_config = false;
        }
 
        if (mtk_crtc->pending_planes) {
                for (i = 0; i < OVL_LAYER_NR; i++) {
-                       struct drm_plane *plane = &mtk_crtc->planes[i].base;
+                       struct drm_plane *plane = &mtk_crtc->planes[i];
                        struct mtk_plane_state *plane_state;
 
                        plane_state = to_mtk_plane_state(plane->state);
@@ -559,16 +577,17 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
                                (zpos == 1) ? DRM_PLANE_TYPE_CURSOR :
                                                DRM_PLANE_TYPE_OVERLAY;
                ret = mtk_plane_init(drm_dev, &mtk_crtc->planes[zpos],
-                                    BIT(pipe), type, zpos);
+                                    BIT(pipe), type);
                if (ret)
                        goto unprepare;
        }
 
-       ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, &mtk_crtc->planes[0].base,
-                               &mtk_crtc->planes[1].base, pipe);
+       ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, &mtk_crtc->planes[0],
+                               &mtk_crtc->planes[1], pipe);
        if (ret < 0)
                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++;
 
index 81e5566..a1550fa 100644 (file)
 #include "mtk_drm_plane.h"
 
 #define OVL_LAYER_NR   4
+#define MTK_LUT_SIZE   512
+#define MTK_MAX_BPC    10
+#define MTK_MIN_BPC    3
 
 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);
-void mtk_drm_crtc_check_flush(struct drm_crtc *crtc);
 void mtk_drm_crtc_commit(struct drm_crtc *crtc);
 void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl);
 int mtk_drm_crtc_create(struct drm_device *drm_dev,
index 3970fcf..df33b3c 100644 (file)
 #include "mtk_drm_drv.h"
 #include "mtk_drm_plane.h"
 #include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_crtc.h"
 
 #define DISP_OD_EN                             0x0000
 #define DISP_OD_INTEN                          0x0008
 #define DISP_OD_INTSTA                         0x000c
 #define DISP_OD_CFG                            0x0020
 #define DISP_OD_SIZE                           0x0030
+#define DISP_DITHER_5                          0x0114
+#define DISP_DITHER_7                          0x011c
+#define DISP_DITHER_15                         0x013c
+#define DISP_DITHER_16                         0x0140
 
 #define DISP_REG_UFO_START                     0x0000
 
 #define DISP_COLOR_WIDTH                       0x0c50
 #define DISP_COLOR_HEIGHT                      0x0c54
 
-#define        OD_RELAY_MODE           BIT(0)
+#define DISP_AAL_EN                            0x0000
+#define DISP_AAL_SIZE                          0x0030
 
-#define        UFO_BYPASS              BIT(2)
+#define DISP_GAMMA_EN                          0x0000
+#define DISP_GAMMA_CFG                         0x0020
+#define DISP_GAMMA_SIZE                                0x0030
+#define DISP_GAMMA_LUT                         0x0700
 
-#define        COLOR_BYPASS_ALL        BIT(7)
-#define        COLOR_SEQ_SEL           BIT(13)
+#define LUT_10BIT_MASK                         0x03ff
+
+#define COLOR_BYPASS_ALL                       BIT(7)
+#define COLOR_SEQ_SEL                          BIT(13)
+
+#define OD_RELAYMODE                           BIT(0)
+
+#define UFO_BYPASS                             BIT(2)
+
+#define AAL_EN                                 BIT(0)
+
+#define GAMMA_EN                               BIT(0)
+#define GAMMA_LUT_EN                           BIT(1)
+
+#define DISP_DITHERING                         BIT(2)
+#define DITHER_LSB_ERR_SHIFT_R(x)              (((x) & 0x7) << 28)
+#define DITHER_OVFLW_BIT_R(x)                  (((x) & 0x7) << 24)
+#define DITHER_ADD_LSHIFT_R(x)                 (((x) & 0x7) << 20)
+#define DITHER_ADD_RSHIFT_R(x)                 (((x) & 0x7) << 16)
+#define DITHER_NEW_BIT_MODE                    BIT(0)
+#define DITHER_LSB_ERR_SHIFT_B(x)              (((x) & 0x7) << 28)
+#define DITHER_OVFLW_BIT_B(x)                  (((x) & 0x7) << 24)
+#define DITHER_ADD_LSHIFT_B(x)                 (((x) & 0x7) << 20)
+#define DITHER_ADD_RSHIFT_B(x)                 (((x) & 0x7) << 16)
+#define DITHER_LSB_ERR_SHIFT_G(x)              (((x) & 0x7) << 12)
+#define DITHER_OVFLW_BIT_G(x)                  (((x) & 0x7) << 8)
+#define DITHER_ADD_LSHIFT_G(x)                 (((x) & 0x7) << 4)
+#define DITHER_ADD_RSHIFT_G(x)                 (((x) & 0x7) << 0)
+
+void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
+                   unsigned int CFG)
+{
+       /* If bpc equal to 0, the dithering function didn't be enabled */
+       if (bpc == 0)
+               return;
+
+       if (bpc >= MTK_MIN_BPC) {
+               writel(0, comp->regs + DISP_DITHER_5);
+               writel(0, comp->regs + DISP_DITHER_7);
+               writel(DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC - bpc) |
+                      DITHER_ADD_LSHIFT_R(MTK_MAX_BPC - bpc) |
+                      DITHER_NEW_BIT_MODE,
+                      comp->regs + DISP_DITHER_15);
+               writel(DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC - bpc) |
+                      DITHER_ADD_LSHIFT_B(MTK_MAX_BPC - bpc) |
+                      DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC - bpc) |
+                      DITHER_ADD_LSHIFT_G(MTK_MAX_BPC - bpc),
+                      comp->regs + DISP_DITHER_16);
+               writel(DISP_DITHERING, comp->regs + CFG);
+       }
+}
 
 static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
-                            unsigned int h, unsigned int vrefresh)
+                            unsigned int h, unsigned int vrefresh,
+                            unsigned int bpc)
 {
        writel(w, comp->regs + DISP_COLOR_WIDTH);
        writel(h, comp->regs + DISP_COLOR_HEIGHT);
@@ -60,14 +119,16 @@ static void mtk_color_start(struct mtk_ddp_comp *comp)
 }
 
 static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
-                         unsigned int h, unsigned int vrefresh)
+                         unsigned int h, unsigned int vrefresh,
+                         unsigned int bpc)
 {
        writel(w << 16 | h, comp->regs + DISP_OD_SIZE);
+       writel(OD_RELAYMODE, comp->regs + OD_RELAYMODE);
+       mtk_dither_set(comp, bpc, DISP_OD_CFG);
 }
 
 static void mtk_od_start(struct mtk_ddp_comp *comp)
 {
-       writel(OD_RELAY_MODE, comp->regs + DISP_OD_CFG);
        writel(1, comp->regs + DISP_OD_EN);
 }
 
@@ -76,6 +137,78 @@ static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
        writel(UFO_BYPASS, comp->regs + DISP_REG_UFO_START);
 }
 
+static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
+                          unsigned int h, unsigned int vrefresh,
+                          unsigned int bpc)
+{
+       writel(h << 16 | w, comp->regs + DISP_AAL_SIZE);
+}
+
+static void mtk_aal_start(struct mtk_ddp_comp *comp)
+{
+       writel(AAL_EN, comp->regs + DISP_AAL_EN);
+}
+
+static void mtk_aal_stop(struct mtk_ddp_comp *comp)
+{
+       writel_relaxed(0x0, comp->regs + DISP_AAL_EN);
+}
+
+static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
+                            unsigned int h, unsigned int vrefresh,
+                            unsigned int bpc)
+{
+       writel(h << 16 | w, comp->regs + DISP_GAMMA_SIZE);
+       mtk_dither_set(comp, bpc, DISP_GAMMA_CFG);
+}
+
+static void mtk_gamma_start(struct mtk_ddp_comp *comp)
+{
+       writel(GAMMA_EN, comp->regs  + DISP_GAMMA_EN);
+}
+
+static void mtk_gamma_stop(struct mtk_ddp_comp *comp)
+{
+       writel_relaxed(0x0, comp->regs  + DISP_GAMMA_EN);
+}
+
+static void mtk_gamma_set(struct mtk_ddp_comp *comp,
+                         struct drm_crtc_state *state)
+{
+       unsigned int i, reg;
+       struct drm_color_lut *lut;
+       void __iomem *lut_base;
+       u32 word;
+
+       if (state->gamma_lut) {
+               reg = readl(comp->regs + DISP_GAMMA_CFG);
+               reg = reg | GAMMA_LUT_EN;
+               writel(reg, comp->regs + DISP_GAMMA_CFG);
+               lut_base = comp->regs + DISP_GAMMA_LUT;
+               lut = (struct drm_color_lut *)state->gamma_lut->data;
+               for (i = 0; i < MTK_LUT_SIZE; i++) {
+                       word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
+                               (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
+                               ((lut[i].blue >> 6) & LUT_10BIT_MASK);
+                       writel(word, (lut_base + i * 4));
+               }
+       }
+}
+
+static const struct mtk_ddp_comp_funcs ddp_aal = {
+       .gamma_set = mtk_gamma_set,
+       .config = mtk_aal_config,
+       .start = mtk_aal_start,
+       .stop = mtk_aal_stop,
+};
+
+static const struct mtk_ddp_comp_funcs ddp_gamma = {
+       .gamma_set = mtk_gamma_set,
+       .config = mtk_gamma_config,
+       .start = mtk_gamma_start,
+       .stop = mtk_gamma_stop,
+};
+
 static const struct mtk_ddp_comp_funcs ddp_color = {
        .config = mtk_color_config,
        .start = mtk_color_start,
@@ -112,13 +245,13 @@ struct mtk_ddp_comp_match {
 };
 
 static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
-       [DDP_COMPONENT_AAL]     = { MTK_DISP_AAL,       0, NULL },
+       [DDP_COMPONENT_AAL]     = { MTK_DISP_AAL,       0, &ddp_aal },
        [DDP_COMPONENT_COLOR0]  = { MTK_DISP_COLOR,     0, &ddp_color },
        [DDP_COMPONENT_COLOR1]  = { MTK_DISP_COLOR,     1, &ddp_color },
        [DDP_COMPONENT_DPI0]    = { MTK_DPI,            0, NULL },
        [DDP_COMPONENT_DSI0]    = { MTK_DSI,            0, NULL },
        [DDP_COMPONENT_DSI1]    = { MTK_DSI,            1, NULL },
-       [DDP_COMPONENT_GAMMA]   = { MTK_DISP_GAMMA,     0, NULL },
+       [DDP_COMPONENT_GAMMA]   = { MTK_DISP_GAMMA,     0, &ddp_gamma },
        [DDP_COMPONENT_OD]      = { MTK_DISP_OD,        0, &ddp_od },
        [DDP_COMPONENT_OVL0]    = { MTK_DISP_OVL,       0, NULL },
        [DDP_COMPONENT_OVL1]    = { MTK_DISP_OVL,       1, NULL },
index 6b13ba9..22a33ee 100644 (file)
@@ -21,6 +21,7 @@ struct device_node;
 struct drm_crtc;
 struct drm_device;
 struct mtk_plane_state;
+struct drm_crtc_state;
 
 enum mtk_ddp_comp_type {
        MTK_DISP_OVL,
@@ -64,7 +65,7 @@ struct mtk_ddp_comp;
 
 struct mtk_ddp_comp_funcs {
        void (*config)(struct mtk_ddp_comp *comp, unsigned int w,
-                      unsigned int h, unsigned int vrefresh);
+                      unsigned int h, unsigned int vrefresh, unsigned int bpc);
        void (*start)(struct mtk_ddp_comp *comp);
        void (*stop)(struct mtk_ddp_comp *comp);
        void (*enable_vblank)(struct mtk_ddp_comp *comp, struct drm_crtc *crtc);
@@ -73,6 +74,8 @@ struct mtk_ddp_comp_funcs {
        void (*layer_off)(struct mtk_ddp_comp *comp, unsigned int idx);
        void (*layer_config)(struct mtk_ddp_comp *comp, unsigned int idx,
                             struct mtk_plane_state *state);
+       void (*gamma_set)(struct mtk_ddp_comp *comp,
+                         struct drm_crtc_state *state);
 };
 
 struct mtk_ddp_comp {
@@ -86,10 +89,10 @@ struct mtk_ddp_comp {
 
 static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
                                       unsigned int w, unsigned int h,
-                                      unsigned int vrefresh)
+                                      unsigned int vrefresh, unsigned int bpc)
 {
        if (comp->funcs && comp->funcs->config)
-               comp->funcs->config(comp, w, h, vrefresh);
+               comp->funcs->config(comp, w, h, vrefresh, bpc);
 }
 
 static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp)
@@ -139,6 +142,13 @@ static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp,
                comp->funcs->layer_config(comp, idx, state);
 }
 
+static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp,
+                                    struct drm_crtc_state *state)
+{
+       if (comp->funcs && comp->funcs->gamma_set)
+               comp->funcs->gamma_set(comp, state);
+}
+
 int mtk_ddp_comp_get_id(struct device_node *node,
                        enum mtk_ddp_comp_type comp_type);
 int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node,
@@ -146,5 +156,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node,
                      const struct mtk_ddp_comp_funcs *funcs);
 int mtk_ddp_comp_register(struct drm_device *drm, struct mtk_ddp_comp *comp);
 void mtk_ddp_comp_unregister(struct drm_device *drm, struct mtk_ddp_comp *comp);
+void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
+                   unsigned int CFG);
 
 #endif /* MTK_DRM_DDP_COMP_H */
index eebb7d8..cf83f65 100644 (file)
@@ -61,10 +61,27 @@ static void mtk_atomic_complete(struct mtk_drm_private *private,
 
        mtk_atomic_wait_for_fences(state);
 
+       /*
+        * Mediatek drm supports runtime PM, so plane registers cannot be
+        * written when their crtc is disabled.
+        *
+        * The comment for drm_atomic_helper_commit states:
+        *     For drivers supporting runtime PM the recommended sequence is
+        *
+        *     drm_atomic_helper_commit_modeset_disables(dev, state);
+        *     drm_atomic_helper_commit_modeset_enables(dev, state);
+        *     drm_atomic_helper_commit_planes(dev, state,
+        *                                     DRM_PLANE_COMMIT_ACTIVE_ONLY);
+        *
+        * See the kerneldoc entries for these three functions for more details.
+        */
        drm_atomic_helper_commit_modeset_disables(drm, state);
-       drm_atomic_helper_commit_planes(drm, state, false);
        drm_atomic_helper_commit_modeset_enables(drm, state);
+       drm_atomic_helper_commit_planes(drm, state,
+                                       DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
        drm_atomic_helper_wait_for_vblanks(drm, state);
+
        drm_atomic_helper_cleanup_planes(drm, state);
        drm_atomic_state_free(state);
 }
@@ -277,8 +294,8 @@ static int mtk_drm_bind(struct device *dev)
        int ret;
 
        drm = drm_dev_alloc(&mtk_drm_driver, dev);
-       if (!drm)
-               return -ENOMEM;
+       if (IS_ERR(drm))
+               return PTR_ERR(drm);
 
        drm->dev_private = private;
        private->drm = drm;
index 3995765..c461a23 100644 (file)
@@ -30,57 +30,12 @@ static const u32 formats[] = {
        DRM_FORMAT_RGB565,
 };
 
-static void mtk_plane_enable(struct mtk_drm_plane *mtk_plane, bool enable,
-                            dma_addr_t addr, struct drm_rect *dest)
-{
-       struct drm_plane *plane = &mtk_plane->base;
-       struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
-       unsigned int pitch, format;
-       int x, y;
-
-       if (WARN_ON(!plane->state || (enable && !plane->state->fb)))
-               return;
-
-       if (plane->state->fb) {
-               pitch = plane->state->fb->pitches[0];
-               format = plane->state->fb->pixel_format;
-       } else {
-               pitch = 0;
-               format = DRM_FORMAT_RGBA8888;
-       }
-
-       x = plane->state->crtc_x;
-       y = plane->state->crtc_y;
-
-       if (x < 0) {
-               addr -= x * 4;
-               x = 0;
-       }
-
-       if (y < 0) {
-               addr -= y * pitch;
-               y = 0;
-       }
-
-       state->pending.enable = enable;
-       state->pending.pitch = pitch;
-       state->pending.format = format;
-       state->pending.addr = addr;
-       state->pending.x = x;
-       state->pending.y = y;
-       state->pending.width = dest->x2 - dest->x1;
-       state->pending.height = dest->y2 - dest->y1;
-       wmb(); /* Make sure the above parameters are set before update */
-       state->pending.dirty = true;
-}
-
 static void mtk_plane_reset(struct drm_plane *plane)
 {
        struct mtk_plane_state *state;
 
        if (plane->state) {
-               if (plane->state->fb)
-                       drm_framebuffer_unreference(plane->state->fb);
+               __drm_atomic_helper_plane_destroy_state(plane->state);
 
                state = to_mtk_plane_state(plane->state);
                memset(state, 0, sizeof(*state));
@@ -134,20 +89,6 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
 {
        struct drm_framebuffer *fb = state->fb;
        struct drm_crtc_state *crtc_state;
-       bool visible;
-       struct drm_rect dest = {
-               .x1 = state->crtc_x,
-               .y1 = state->crtc_y,
-               .x2 = state->crtc_x + state->crtc_w,
-               .y2 = state->crtc_y + state->crtc_h,
-       };
-       struct drm_rect src = {
-               /* 16.16 fixed point */
-               .x1 = state->src_x,
-               .y1 = state->src_y,
-               .x2 = state->src_x + state->src_w,
-               .y2 = state->src_y + state->src_h,
-       };
        struct drm_rect clip = { 0, };
 
        if (!fb)
@@ -168,40 +109,45 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
        clip.x2 = crtc_state->mode.hdisplay;
        clip.y2 = crtc_state->mode.vdisplay;
 
-       return drm_plane_helper_check_update(plane, state->crtc, fb,
-                                            &src, &dest, &clip,
-                                            state->rotation,
-                                            DRM_PLANE_HELPER_NO_SCALING,
-                                            DRM_PLANE_HELPER_NO_SCALING,
-                                            true, true, &visible);
+       return drm_plane_helper_check_state(state, &clip,
+                                           DRM_PLANE_HELPER_NO_SCALING,
+                                           DRM_PLANE_HELPER_NO_SCALING,
+                                           true, true);
 }
 
 static void mtk_plane_atomic_update(struct drm_plane *plane,
                                    struct drm_plane_state *old_state)
 {
        struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
-       struct drm_crtc *crtc = state->base.crtc;
+       struct drm_crtc *crtc = plane->state->crtc;
+       struct drm_framebuffer *fb = plane->state->fb;
        struct drm_gem_object *gem;
        struct mtk_drm_gem_obj *mtk_gem;
-       struct mtk_drm_plane *mtk_plane = to_mtk_plane(plane);
-       struct drm_rect dest = {
-               .x1 = state->base.crtc_x,
-               .y1 = state->base.crtc_y,
-               .x2 = state->base.crtc_x + state->base.crtc_w,
-               .y2 = state->base.crtc_y + state->base.crtc_h,
-       };
-       struct drm_rect clip = { 0, };
+       unsigned int pitch, format;
+       dma_addr_t addr;
 
-       if (!crtc)
+       if (!crtc || WARN_ON(!fb))
                return;
 
-       clip.x2 = state->base.crtc->state->mode.hdisplay;
-       clip.y2 = state->base.crtc->state->mode.vdisplay;
-       drm_rect_intersect(&dest, &clip);
-
-       gem = mtk_fb_get_gem_obj(state->base.fb);
+       gem = mtk_fb_get_gem_obj(fb);
        mtk_gem = to_mtk_gem_obj(gem);
-       mtk_plane_enable(mtk_plane, true, mtk_gem->dma_addr, &dest);
+       addr = mtk_gem->dma_addr;
+       pitch = fb->pitches[0];
+       format = fb->pixel_format;
+
+       addr += (plane->state->src.x1 >> 16) * drm_format_plane_cpp(format, 0);
+       addr += (plane->state->src.y1 >> 16) * pitch;
+
+       state->pending.enable = true;
+       state->pending.pitch = pitch;
+       state->pending.format = format;
+       state->pending.addr = addr;
+       state->pending.x = plane->state->dst.x1;
+       state->pending.y = plane->state->dst.y1;
+       state->pending.width = drm_rect_width(&plane->state->dst);
+       state->pending.height = drm_rect_height(&plane->state->dst);
+       wmb(); /* Make sure the above parameters are set before update */
+       state->pending.dirty = true;
 }
 
 static void mtk_plane_atomic_disable(struct drm_plane *plane,
@@ -220,13 +166,12 @@ static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
        .atomic_disable = mtk_plane_atomic_disable,
 };
 
-int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
-                  unsigned long possible_crtcs, enum drm_plane_type type,
-                  unsigned int zpos)
+int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
+                  unsigned long possible_crtcs, enum drm_plane_type type)
 {
        int err;
 
-       err = drm_universal_plane_init(dev, &mtk_plane->base, possible_crtcs,
+       err = drm_universal_plane_init(dev, plane, possible_crtcs,
                                       &mtk_plane_funcs, formats,
                                       ARRAY_SIZE(formats), type, NULL);
        if (err) {
@@ -234,8 +179,7 @@ int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
                return err;
        }
 
-       drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs);
-       mtk_plane->idx = zpos;
+       drm_plane_helper_add(plane, &mtk_plane_helper_funcs);
 
        return 0;
 }
index 72a7b3e..6a20b49 100644 (file)
 #include <drm/drm_crtc.h>
 #include <linux/types.h>
 
-struct mtk_drm_plane {
-       struct drm_plane                base;
-       unsigned int                    idx;
-};
-
 struct mtk_plane_pending_state {
        bool                            config;
        bool                            enable;
@@ -41,19 +36,13 @@ struct mtk_plane_state {
        struct mtk_plane_pending_state  pending;
 };
 
-static inline struct mtk_drm_plane *to_mtk_plane(struct drm_plane *plane)
-{
-       return container_of(plane, struct mtk_drm_plane, base);
-}
-
 static inline struct mtk_plane_state *
 to_mtk_plane_state(struct drm_plane_state *state)
 {
        return container_of(state, struct mtk_plane_state, base);
 }
 
-int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
-                  unsigned long possible_crtcs, enum drm_plane_type type,
-                  unsigned int zpos);
+int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
+                  unsigned long possible_crtcs, enum drm_plane_type type);
 
 #endif
index 334562d..71227de 100644 (file)
@@ -1086,20 +1086,20 @@ static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi)
        return 0;
 }
 
-void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi)
+static void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi)
 {
        mtk_hdmi_aud_enable_packet(hdmi, true);
        hdmi->audio_enable = true;
 }
 
-void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi)
+static void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi)
 {
        mtk_hdmi_aud_enable_packet(hdmi, false);
        hdmi->audio_enable = false;
 }
 
-int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi,
-                            struct hdmi_audio_param *param)
+static int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi,
+                                   struct hdmi_audio_param *param)
 {
        if (!hdmi->audio_enable) {
                dev_err(hdmi->dev, "hdmi audio is in disable state!\n");
@@ -1624,7 +1624,8 @@ static void mtk_hdmi_audio_shutdown(struct device *dev, void *data)
        mtk_hdmi_audio_disable(hdmi);
 }
 
-int mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable)
+static int
+mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable)
 {
        struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
 
index 5e2f131..25b2a1a 100644 (file)
@@ -58,7 +58,7 @@ static const struct file_operations mga_driver_fops = {
 
 static struct drm_driver driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_PCI_DMA |
+           DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_LEGACY |
            DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
        .dev_priv_size = sizeof(drm_mga_buf_priv_t),
        .load = mga_driver_load,
index 2b4b125..1443b3a 100644 (file)
@@ -56,7 +56,7 @@ static void mgag200_kick_out_firmware_fb(struct pci_dev *pdev)
 #ifdef CONFIG_X86
        primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 #endif
-       remove_conflicting_framebuffers(ap, "mgag200drmfb", primary);
+       drm_fb_helper_remove_conflicting_framebuffers(ap, "mgag200drmfb", primary);
        kfree(ap);
 }
 
index d9b04b0..88dd221 100644 (file)
@@ -15,8 +15,6 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
 
-#include <linux/fb.h>
-
 #include "mgag200_drv.h"
 
 static void mga_dirty_update(struct mga_fbdev *mfbdev,
@@ -185,8 +183,10 @@ static int mgag200fb_create(struct drm_fb_helper *helper,
        }
 
        sysram = vmalloc(size);
-       if (!sysram)
+       if (!sysram) {
+               ret = -ENOMEM;
                goto err_sysram;
+       }
 
        info = drm_fb_helper_alloc_fbi(helper);
        if (IS_ERR(info)) {
index 13798b3..e79cbc2 100644 (file)
@@ -135,7 +135,7 @@ static int mga_vram_init(struct mga_device *mdev)
        aper->ranges[0].base = mdev->mc.vram_base;
        aper->ranges[0].size = mdev->mc.vram_window;
 
-       remove_conflicting_framebuffers(aper, "mgafb", true);
+       drm_fb_helper_remove_conflicting_framebuffers(aper, "mgafb", true);
        kfree(aper);
 
        if (!devm_request_mem_region(mdev->dev->dev, mdev->mc.vram_base, mdev->mc.vram_window,
index 68268e5..919b35f 100644 (file)
@@ -150,7 +150,8 @@ static int mgag200_bo_verify_access(struct ttm_buffer_object *bo, struct file *f
 {
        struct mgag200_bo *mgabo = mgag200_bo(bo);
 
-       return drm_vma_node_verify_access(&mgabo->gem.vma_node, filp);
+       return drm_vma_node_verify_access(&mgabo->gem.vma_node,
+                                         filp->private_data);
 }
 
 static int mgag200_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
index 7c7a031..d96b2b6 100644 (file)
@@ -11,6 +11,7 @@ config DRM_MSM
        select TMPFS
        select QCOM_SCM
        select SND_SOC_HDMI_CODEC if SND_SOC
+       select SYNC_FILE
        default y
        help
          DRM/KMS driver for MSM/snapdragon.
index 9737207..a968cad 100644 (file)
@@ -422,11 +422,28 @@ static const struct {
 
 static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name)
 {
-       int gpio = of_get_named_gpio(of_node, name, 0);
+       int gpio;
+
+       /* try with the gpio names as in the table (downstream bindings) */
+       gpio = of_get_named_gpio(of_node, name, 0);
        if (gpio < 0) {
                char name2[32];
-               snprintf(name2, sizeof(name2), "%s-gpio", name);
+
+               /* try with the gpio names as in the upstream bindings */
+               snprintf(name2, sizeof(name2), "%s-gpios", name);
                gpio = of_get_named_gpio(of_node, name2, 0);
+               if (gpio < 0) {
+                       char name3[32];
+
+                       /*
+                        * try again after stripping out the "qcom,hdmi-tx"
+                        * prefix. This is mainly to match "hpd-gpios" used
+                        * in the upstream bindings
+                        */
+                       if (sscanf(name2, "qcom,hdmi-tx-%s", name3))
+                               gpio = of_get_named_gpio(of_node, name3, 0);
+               }
+
                if (gpio < 0) {
                        DBG("failed to get gpio: %s (%d)", name, gpio);
                        gpio = -1;
index de9007e..73e2021 100644 (file)
@@ -243,7 +243,6 @@ void msm_hdmi_i2c_destroy(struct i2c_adapter *i2c)
 
 struct i2c_adapter *msm_hdmi_i2c_init(struct hdmi *hdmi)
 {
-       struct drm_device *dev = hdmi->dev;
        struct hdmi_i2c_adapter *hdmi_i2c;
        struct i2c_adapter *i2c = NULL;
        int ret;
@@ -267,10 +266,8 @@ struct i2c_adapter *msm_hdmi_i2c_init(struct hdmi *hdmi)
        i2c->algo = &msm_hdmi_i2c_algorithm;
 
        ret = i2c_add_adapter(i2c);
-       if (ret) {
-               dev_err(dev->dev, "failed to register hdmi i2c: %d\n", ret);
+       if (ret)
                goto fail;
-       }
 
        return i2c;
 
index 7b39e89..571a91e 100644 (file)
@@ -228,18 +228,21 @@ static struct device_node *mdp4_detect_lcdc_panel(struct drm_device *dev)
        struct device_node *endpoint, *panel_node;
        struct device_node *np = dev->dev->of_node;
 
-       endpoint = of_graph_get_next_endpoint(np, NULL);
+       /*
+        * LVDS/LCDC is the first port described in the list of ports in the
+        * MDP4 DT node.
+        */
+       endpoint = of_graph_get_endpoint_by_regs(np, 0, -1);
        if (!endpoint) {
-               DBG("no endpoint in MDP4 to fetch LVDS panel\n");
+               DBG("no LVDS remote endpoint\n");
                return NULL;
        }
 
-       /* don't proceed if we have an endpoint but no panel_node tied to it */
        panel_node = of_graph_get_remote_port_parent(endpoint);
        if (!panel_node) {
-               dev_err(dev->dev, "no valid panel node\n");
+               DBG("no valid panel node in LVDS endpoint\n");
                of_node_put(endpoint);
-               return ERR_PTR(-ENODEV);
+               return NULL;
        }
 
        of_node_put(endpoint);
@@ -262,14 +265,12 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
        switch (intf_type) {
        case DRM_MODE_ENCODER_LVDS:
                /*
-                * bail out early if:
-                * - there is no panel node (no need to initialize lcdc
-                *   encoder and lvds connector), or
-                * - panel node is a bad pointer
+                * bail out early if there is no panel node (no need to
+                * initialize LCDC encoder and LVDS connector)
                 */
                panel_node = mdp4_detect_lcdc_panel(dev);
-               if (IS_ERR_OR_NULL(panel_node))
-                       return PTR_ERR(panel_node);
+               if (!panel_node)
+                       return 0;
 
                encoder = mdp4_lcdc_encoder_init(dev, panel_node);
                if (IS_ERR(encoder)) {
index bc3d8e7..a06b064 100644 (file)
@@ -93,7 +93,7 @@ static const struct drm_encoder_funcs mdp4_lcdc_encoder_funcs = {
 };
 
 /* this should probably be a helper: */
-struct drm_connector *get_connector(struct drm_encoder *encoder)
+static struct drm_connector *get_connector(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_connector *connector;
index 9f96dfe..3903dbc 100644 (file)
@@ -81,7 +81,7 @@ static void mdp4_plane_install_properties(struct drm_plane *plane,
        // XXX
 }
 
-int mdp4_plane_set_property(struct drm_plane *plane,
+static int mdp4_plane_set_property(struct drm_plane *plane,
                struct drm_property *property, uint64_t val)
 {
        // XXX
@@ -99,7 +99,7 @@ static const struct drm_plane_funcs mdp4_plane_funcs = {
 };
 
 static int mdp4_plane_prepare_fb(struct drm_plane *plane,
-               const struct drm_plane_state *new_state)
+                                struct drm_plane_state *new_state)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
        struct mdp4_kms *mdp4_kms = get_kms(plane);
@@ -113,7 +113,7 @@ static int mdp4_plane_prepare_fb(struct drm_plane *plane,
 }
 
 static void mdp4_plane_cleanup_fb(struct drm_plane *plane,
-               const struct drm_plane_state *old_state)
+                                 struct drm_plane_state *old_state)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
        struct mdp4_kms *mdp4_kms = get_kms(plane);
index 432c098..951c002 100644 (file)
@@ -78,12 +78,12 @@ static void mdp5_plane_install_rotation_property(struct drm_device *dev,
        if (!dev->mode_config.rotation_property)
                dev->mode_config.rotation_property =
                        drm_mode_create_rotation_property(dev,
-                       BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y));
+                               DRM_ROTATE_0 | DRM_REFLECT_X | DRM_REFLECT_Y);
 
        if (dev->mode_config.rotation_property)
                drm_object_attach_property(&plane->base,
                        dev->mode_config.rotation_property,
-                       0);
+                       DRM_ROTATE_0);
 }
 
 /* helper to install properties which are common to planes and crtcs */
@@ -250,7 +250,7 @@ static const struct drm_plane_funcs mdp5_plane_funcs = {
 };
 
 static int mdp5_plane_prepare_fb(struct drm_plane *plane,
-               const struct drm_plane_state *new_state)
+                                struct drm_plane_state *new_state)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
        struct mdp5_kms *mdp5_kms = get_kms(plane);
@@ -264,7 +264,7 @@ static int mdp5_plane_prepare_fb(struct drm_plane *plane,
 }
 
 static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
-               const struct drm_plane_state *old_state)
+                                 struct drm_plane_state *old_state)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
        struct mdp5_kms *mdp5_kms = get_kms(plane);
@@ -309,8 +309,8 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
                        return -EINVAL;
                }
 
-               hflip = !!(state->rotation & BIT(DRM_REFLECT_X));
-               vflip = !!(state->rotation & BIT(DRM_REFLECT_Y));
+               hflip = !!(state->rotation & DRM_REFLECT_X);
+               vflip = !!(state->rotation & DRM_REFLECT_Y);
                if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) ||
                        (hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) {
                        dev_err(plane->dev->dev,
@@ -743,8 +743,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
        config |= get_scale_config(format, src_h, crtc_h, false);
        DBG("scale config = %x", config);
 
-       hflip = !!(pstate->rotation & BIT(DRM_REFLECT_X));
-       vflip = !!(pstate->rotation & BIT(DRM_REFLECT_Y));
+       hflip = !!(pstate->rotation & DRM_REFLECT_X);
+       vflip = !!(pstate->rotation & DRM_REFLECT_Y);
 
        spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
 
index 4a8a6f1..73bae38 100644 (file)
@@ -112,13 +112,13 @@ static void complete_commit(struct msm_commit *c, bool async)
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_kms *kms = priv->kms;
 
-       drm_atomic_helper_wait_for_fences(dev, state);
+       drm_atomic_helper_wait_for_fences(dev, state, false);
 
        kms->funcs->prepare_commit(kms, state);
 
        drm_atomic_helper_commit_modeset_disables(dev, state);
 
-       drm_atomic_helper_commit_planes(dev, state, false);
+       drm_atomic_helper_commit_planes(dev, state, 0);
 
        drm_atomic_helper_commit_modeset_enables(dev, state);
 
index 8a02370..fb5c0b0 100644 (file)
  * MSM driver version:
  * - 1.0.0 - initial interface
  * - 1.1.0 - adds madvise, and support for submits with > 4 cmd buffers
+ * - 1.2.0 - adds explicit fence support for submit ioctl
  */
 #define MSM_VERSION_MAJOR      1
-#define MSM_VERSION_MINOR      1
+#define MSM_VERSION_MINOR      2
 #define MSM_VERSION_PATCHLEVEL 0
 
 static void msm_fb_output_poll_changed(struct drm_device *dev)
@@ -347,9 +348,9 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
        int ret;
 
        ddev = drm_dev_alloc(drv, dev);
-       if (!ddev) {
+       if (IS_ERR(ddev)) {
                dev_err(dev, "failed to allocate drm_device\n");
-               return -ENOMEM;
+               return PTR_ERR(ddev);
        }
 
        platform_set_drvdata(pdev, ddev);
index 85f3047..b6ac27e 100644 (file)
@@ -593,18 +593,16 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
        bool write = !!(op & MSM_PREP_WRITE);
-
-       if (op & MSM_PREP_NOSYNC) {
-               if (!reservation_object_test_signaled_rcu(msm_obj->resv, write))
-                       return -EBUSY;
-       } else {
-               int ret;
-
-               ret = reservation_object_wait_timeout_rcu(msm_obj->resv, write,
-                               true, timeout_to_jiffies(timeout));
-               if (ret <= 0)
-                       return ret == 0 ? -ETIMEDOUT : ret;
-       }
+       unsigned long remain =
+               op & MSM_PREP_NOSYNC ? 0 : timeout_to_jiffies(timeout);
+       long ret;
+
+       ret = reservation_object_wait_timeout_rcu(msm_obj->resv, write,
+                                                 true,  remain);
+       if (ret == 0)
+               return remain == 0 ? -EBUSY : -ETIMEDOUT;
+       else if (ret < 0)
+               return ret;
 
        /* TODO cache maintenance */
 
index 880d6a9..b6a0f37 100644 (file)
@@ -15,6 +15,8 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/sync_file.h>
+
 #include "msm_drv.h"
 #include "msm_gpu.h"
 #include "msm_gem.h"
@@ -378,6 +380,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
        struct msm_file_private *ctx = file->driver_priv;
        struct msm_gem_submit *submit;
        struct msm_gpu *gpu = priv->gpu;
+       struct fence *in_fence = NULL;
+       struct sync_file *sync_file = NULL;
+       int out_fence_fd = -1;
        unsigned i;
        int ret;
 
@@ -387,13 +392,23 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
        /* for now, we just have 3d pipe.. eventually this would need to
         * be more clever to dispatch to appropriate gpu module:
         */
-       if (args->pipe != MSM_PIPE_3D0)
+       if (MSM_PIPE_ID(args->flags) != MSM_PIPE_3D0)
+               return -EINVAL;
+
+       if (MSM_PIPE_FLAGS(args->flags) & ~MSM_SUBMIT_FLAGS)
                return -EINVAL;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
 
+       if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
+               out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
+               if (out_fence_fd < 0) {
+                       ret = out_fence_fd;
+                       goto out_unlock;
+               }
+       }
        priv->struct_mutex_task = current;
 
        submit = submit_create(dev, gpu, args->nr_bos, args->nr_cmds);
@@ -410,9 +425,32 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
        if (ret)
                goto out;
 
-       ret = submit_fence_sync(submit);
-       if (ret)
-               goto out;
+       if (args->flags & MSM_SUBMIT_FENCE_FD_IN) {
+               in_fence = sync_file_get_fence(args->fence_fd);
+
+               if (!in_fence) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               /* TODO if we get an array-fence due to userspace merging multiple
+                * fences, we need a way to determine if all the backing fences
+                * are from our own context..
+                */
+
+               if (in_fence->context != gpu->fctx->context) {
+                       ret = fence_wait(in_fence, true);
+                       if (ret)
+                               goto out;
+               }
+
+       }
+
+       if (!(args->fence & MSM_SUBMIT_NO_IMPLICIT)) {
+               ret = submit_fence_sync(submit);
+               if (ret)
+                       goto out;
+       }
 
        ret = submit_pin_objects(submit);
        if (ret)
@@ -478,15 +516,39 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
 
        submit->nr_cmds = i;
 
-       ret = msm_gpu_submit(gpu, submit, ctx);
+       submit->fence = msm_fence_alloc(gpu->fctx);
+       if (IS_ERR(submit->fence)) {
+               ret = PTR_ERR(submit->fence);
+               submit->fence = NULL;
+               goto out;
+       }
+
+       if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
+               sync_file = sync_file_create(submit->fence);
+               if (!sync_file) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       msm_gpu_submit(gpu, submit, ctx);
 
        args->fence = submit->fence->seqno;
 
+       if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
+               fd_install(out_fence_fd, sync_file->file);
+               args->fence_fd = out_fence_fd;
+       }
+
 out:
+       if (in_fence)
+               fence_put(in_fence);
        submit_cleanup(submit);
        if (ret)
                msm_gem_submit_free(submit);
 out_unlock:
+       if (ret && (out_fence_fd >= 0))
+               put_unused_fd(out_fence_fd);
        priv->struct_mutex_task = NULL;
        mutex_unlock(&dev->struct_mutex);
        return ret;
index 36ed53e..5bb0983 100644 (file)
@@ -509,22 +509,15 @@ void msm_gpu_retire(struct msm_gpu *gpu)
 }
 
 /* add bo's to gpu's ring, and kick gpu: */
-int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
+void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                struct msm_file_private *ctx)
 {
        struct drm_device *dev = gpu->dev;
        struct msm_drm_private *priv = dev->dev_private;
-       int i, ret;
+       int i;
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       submit->fence = msm_fence_alloc(gpu->fctx);
-       if (IS_ERR(submit->fence)) {
-               ret = PTR_ERR(submit->fence);
-               submit->fence = NULL;
-               return ret;
-       }
-
        inactive_cancel(gpu);
 
        list_add_tail(&submit->node, &gpu->submit_list);
@@ -557,8 +550,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
        priv->lastctx = ctx;
 
        hangcheck_timer_reset(gpu);
-
-       return 0;
 }
 
 /*
index c902283..d61d98a 100644 (file)
@@ -163,7 +163,7 @@ int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime,
                uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs);
 
 void msm_gpu_retire(struct msm_gpu *gpu);
-int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
+void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                struct msm_file_private *ctx);
 
 int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
index 864323b..343b865 100644 (file)
@@ -1152,7 +1152,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                goto out;
 
-       ret = ttm_bo_move_ttm(bo, true, intr, no_wait_gpu, new_mem);
+       ret = ttm_bo_move_ttm(bo, intr, no_wait_gpu, new_mem);
 out:
        ttm_bo_mem_put(bo, &tmp_mem);
        return ret;
@@ -1180,7 +1180,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                return ret;
 
-       ret = ttm_bo_move_ttm(bo, true, intr, no_wait_gpu, &tmp_mem);
+       ret = ttm_bo_move_ttm(bo, intr, no_wait_gpu, &tmp_mem);
        if (ret)
                goto out;
 
@@ -1298,7 +1298,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
        /* Fallback to software copy. */
        ret = ttm_bo_wait(bo, intr, no_wait_gpu);
        if (ret == 0)
-               ret = ttm_bo_move_memcpy(bo, evict, intr, no_wait_gpu, new_mem);
+               ret = ttm_bo_move_memcpy(bo, intr, no_wait_gpu, new_mem);
 
 out:
        if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) {
@@ -1316,7 +1316,8 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
 {
        struct nouveau_bo *nvbo = nouveau_bo(bo);
 
-       return drm_vma_node_verify_access(&nvbo->gem.vma_node, filp);
+       return drm_vma_node_verify_access(&nvbo->gem.vma_node,
+                                         filp->private_data);
 }
 
 static int
index 66c1280..3100fd8 100644 (file)
@@ -351,7 +351,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
        boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 #endif
        if (nouveau_modeset != 2)
-               remove_conflicting_framebuffers(aper, "nouveaufb", boot);
+               drm_fb_helper_remove_conflicting_framebuffers(aper, "nouveaufb", boot);
        kfree(aper);
 
        ret = nvkm_device_pci_new(pdev, nouveau_config, nouveau_debug,
@@ -1067,8 +1067,8 @@ nouveau_platform_device_create(const struct nvkm_device_tegra_func *func,
                goto err_free;
 
        drm = drm_dev_alloc(&driver_platform, &pdev->dev);
-       if (!drm) {
-               err = -ENOMEM;
+       if (IS_ERR(drm)) {
+               err = PTR_ERR(drm);
                goto err_free;
        }
 
index d1f248f..9f56927 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/tty.h>
 #include <linux/sysrq.h>
 #include <linux/delay.h>
-#include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/screen_info.h>
 #include <linux/vga_switcheroo.h>
index 0eae8af..b1f3b81 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/backlight.h>
 #include <linux/delay.h>
-#include <linux/fb.h>
 #include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
index fc4c238..9f3d6f4 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/spi/spi.h>
-#include <linux/fb.h>
 #include <linux/gpio/consumer.h>
 #include <linux/of_gpio.h>
 
index 157c512..3557a4c 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/jiffies.h>
 #include <linux/sched.h>
 #include <linux/backlight.h>
-#include <linux/fb.h>
 #include <linux/gpio/consumer.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
index e256d87..dfd4e96 100644 (file)
@@ -125,16 +125,15 @@ u32 dss_of_port_get_port_number(struct device_node *port)
 
 static struct device_node *omapdss_of_get_remote_port(const struct device_node *node)
 {
-       struct device_node *np, *np_parent;
+       struct device_node *np;
 
        np = of_parse_phandle(node, "remote-endpoint", 0);
        if (!np)
                return NULL;
 
-       np_parent = of_get_next_parent(np);
-       of_node_put(np);
+       np = of_get_next_parent(np);
 
-       return np_parent;
+       return np;
 }
 
 struct device_node *
index 26c6134..e1cfba5 100644 (file)
@@ -96,7 +96,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit)
        dispc_runtime_get();
 
        drm_atomic_helper_commit_modeset_disables(dev, old_state);
-       drm_atomic_helper_commit_planes(dev, old_state, false);
+       drm_atomic_helper_commit_planes(dev, old_state, 0);
        drm_atomic_helper_commit_modeset_enables(dev, old_state);
 
        omap_atomic_wait_for_completion(dev, old_state);
@@ -295,9 +295,9 @@ static int omap_modeset_init_properties(struct drm_device *dev)
        if (priv->has_dmm) {
                dev->mode_config.rotation_property =
                        drm_mode_create_rotation_property(dev,
-                               BIT(DRM_ROTATE_0) | BIT(DRM_ROTATE_90) |
-                               BIT(DRM_ROTATE_180) | BIT(DRM_ROTATE_270) |
-                               BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y));
+                               DRM_ROTATE_0 | DRM_ROTATE_90 |
+                               DRM_ROTATE_180 | DRM_ROTATE_270 |
+                               DRM_REFLECT_X | DRM_REFLECT_Y);
                if (!dev->mode_config.rotation_property)
                        return -ENOMEM;
        }
index 31f5178..5f3337f 100644 (file)
@@ -179,24 +179,24 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
                                        (uint32_t)win->rotation);
                        /* fallthru to default to no rotation */
                case 0:
-               case BIT(DRM_ROTATE_0):
+               case DRM_ROTATE_0:
                        orient = 0;
                        break;
-               case BIT(DRM_ROTATE_90):
+               case DRM_ROTATE_90:
                        orient = MASK_XY_FLIP | MASK_X_INVERT;
                        break;
-               case BIT(DRM_ROTATE_180):
+               case DRM_ROTATE_180:
                        orient = MASK_X_INVERT | MASK_Y_INVERT;
                        break;
-               case BIT(DRM_ROTATE_270):
+               case DRM_ROTATE_270:
                        orient = MASK_XY_FLIP | MASK_Y_INVERT;
                        break;
                }
 
-               if (win->rotation & BIT(DRM_REFLECT_X))
+               if (win->rotation & DRM_REFLECT_X)
                        orient ^= MASK_X_INVERT;
 
-               if (win->rotation & BIT(DRM_REFLECT_Y))
+               if (win->rotation & DRM_REFLECT_Y)
                        orient ^= MASK_Y_INVERT;
 
                /* adjust x,y offset for flip/invert: */
@@ -213,7 +213,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
        } else {
                switch (win->rotation & DRM_ROTATE_MASK) {
                case 0:
-               case BIT(DRM_ROTATE_0):
+               case DRM_ROTATE_0:
                        /* OK */
                        break;
 
index 5252ab7..66ac8c4 100644 (file)
@@ -60,7 +60,7 @@ to_omap_plane_state(struct drm_plane_state *state)
 }
 
 static int omap_plane_prepare_fb(struct drm_plane *plane,
-                                const struct drm_plane_state *new_state)
+                                struct drm_plane_state *new_state)
 {
        if (!new_state->fb)
                return 0;
@@ -69,7 +69,7 @@ static int omap_plane_prepare_fb(struct drm_plane *plane,
 }
 
 static void omap_plane_cleanup_fb(struct drm_plane *plane,
-                                 const struct drm_plane_state *old_state)
+                                 struct drm_plane_state *old_state)
 {
        if (old_state->fb)
                omap_framebuffer_unpin(old_state->fb);
@@ -109,8 +109,8 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
        win.src_y = state->src_y >> 16;
 
        switch (state->rotation & DRM_ROTATE_MASK) {
-       case BIT(DRM_ROTATE_90):
-       case BIT(DRM_ROTATE_270):
+       case DRM_ROTATE_90:
+       case DRM_ROTATE_270:
                win.src_w = state->src_h >> 16;
                win.src_h = state->src_w >> 16;
                break;
@@ -149,7 +149,7 @@ static void omap_plane_atomic_disable(struct drm_plane *plane,
        struct omap_plane_state *omap_state = to_omap_plane_state(plane->state);
        struct omap_plane *omap_plane = to_omap_plane(plane);
 
-       plane->state->rotation = BIT(DRM_ROTATE_0);
+       plane->state->rotation = DRM_ROTATE_0;
        omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
                           ? 0 : omap_plane->id;
 
@@ -178,7 +178,7 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
                return -EINVAL;
 
        if (state->fb) {
-               if (state->rotation != BIT(DRM_ROTATE_0) &&
+               if (state->rotation != DRM_ROTATE_0 &&
                    !omap_framebuffer_supports_rotation(state->fb))
                        return -EINVAL;
        }
@@ -269,7 +269,7 @@ static void omap_plane_reset(struct drm_plane *plane)
         */
        omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
                           ? 0 : omap_plane->id;
-       omap_state->base.rotation = BIT(DRM_ROTATE_0);
+       omap_state->base.rotation = DRM_ROTATE_0;
 
        plane->state = &omap_state->base;
        plane->state->plane = plane;
index 1500ab9..62aba97 100644 (file)
@@ -18,6 +18,17 @@ config DRM_PANEL_SIMPLE
          that it can be automatically turned off when the panel goes into a
          low power state.
 
+config DRM_PANEL_JDI_LT070ME05000
+       tristate "JDI LT070ME05000 WUXGA DSI panel"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       depends on BACKLIGHT_CLASS_DEVICE
+       help
+         Say Y here if you want to enable support for JDI DSI video mode
+         panel as found in Google Nexus 7 (2013) devices.
+         The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses
+         24 bit per pixel.
+
 config DRM_PANEL_SAMSUNG_LD9040
        tristate "Samsung LD9040 RGB/SPI panel"
        depends on OF && SPI
index f277eed..a5c7ec0 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
+obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
 obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
 obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
new file mode 100644 (file)
index 0000000..5b2340e
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2016 InforceComputing
+ * Author: Vinay Simha BN <simhavcs@gmail.com>
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Author: Sumit Semwal <sumit.semwal@linaro.org>
+ *
+ * From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a
+ * JDI model LT070ME05000, and its data sheet is at:
+ * http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/backlight.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+static const char * const regulator_names[] = {
+       "vddp",
+       "iovcc"
+};
+
+struct jdi_panel {
+       struct drm_panel base;
+       struct mipi_dsi_device *dsi;
+
+       struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
+
+       struct gpio_desc *enable_gpio;
+       struct gpio_desc *reset_gpio;
+       struct gpio_desc *dcdc_en_gpio;
+       struct backlight_device *backlight;
+
+       bool prepared;
+       bool enabled;
+
+       const struct drm_display_mode *mode;
+};
+
+static inline struct jdi_panel *to_jdi_panel(struct drm_panel *panel)
+{
+       return container_of(panel, struct jdi_panel, base);
+}
+
+static int jdi_panel_init(struct jdi_panel *jdi)
+{
+       struct mipi_dsi_device *dsi = jdi->dsi;
+       struct device *dev = &jdi->dsi->dev;
+       int ret;
+
+       dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+       ret = mipi_dsi_dcs_soft_reset(dsi);
+       if (ret < 0)
+               return ret;
+
+       usleep_range(10000, 20000);
+
+       ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
+       if (ret < 0) {
+               dev_err(dev, "failed to set pixel format: %d\n", ret);
+               return ret;
+       }
+
+       ret = mipi_dsi_dcs_set_column_address(dsi, 0, jdi->mode->hdisplay - 1);
+       if (ret < 0) {
+               dev_err(dev, "failed to set column address: %d\n", ret);
+               return ret;
+       }
+
+       ret = mipi_dsi_dcs_set_page_address(dsi, 0, jdi->mode->vdisplay - 1);
+       if (ret < 0) {
+               dev_err(dev, "failed to set page address: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * BIT(5) BCTRL = 1 Backlight Control Block On, Brightness registers
+        *                  are active
+        * BIT(3) BL = 1    Backlight Control On
+        * BIT(2) DD = 0    Display Dimming is Off
+        */
+       ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
+                                (u8[]){ 0x24 }, 1);
+       if (ret < 0) {
+               dev_err(dev, "failed to write control display: %d\n", ret);
+               return ret;
+       }
+
+       /* CABC off */
+       ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE,
+                                (u8[]){ 0x00 }, 1);
+       if (ret < 0) {
+               dev_err(dev, "failed to set cabc off: %d\n", ret);
+               return ret;
+       }
+
+       ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+       if (ret < 0) {
+               dev_err(dev, "failed to set exit sleep mode: %d\n", ret);
+               return ret;
+       }
+
+       msleep(120);
+
+       ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x00}, 2);
+       if (ret < 0) {
+               dev_err(dev, "failed to set mcap: %d\n", ret);
+               return ret;
+       }
+
+       mdelay(10);
+
+       /* Interface setting, video mode */
+       ret = mipi_dsi_generic_write(dsi, (u8[])
+                                    {0xB3, 0x26, 0x08, 0x00, 0x20, 0x00}, 6);
+       if (ret < 0) {
+               dev_err(dev, "failed to set display interface setting: %d\n"
+                       , ret);
+               return ret;
+       }
+
+       mdelay(20);
+
+       ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x03}, 2);
+       if (ret < 0) {
+               dev_err(dev, "failed to set default values for mcap: %d\n"
+                       , ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int jdi_panel_on(struct jdi_panel *jdi)
+{
+       struct mipi_dsi_device *dsi = jdi->dsi;
+       struct device *dev = &jdi->dsi->dev;
+       int ret;
+
+       dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+       ret = mipi_dsi_dcs_set_display_on(dsi);
+       if (ret < 0)
+               dev_err(dev, "failed to set display on: %d\n", ret);
+
+       return ret;
+}
+
+static void jdi_panel_off(struct jdi_panel *jdi)
+{
+       struct mipi_dsi_device *dsi = jdi->dsi;
+       struct device *dev = &jdi->dsi->dev;
+       int ret;
+
+       dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+       ret = mipi_dsi_dcs_set_display_off(dsi);
+       if (ret < 0)
+               dev_err(dev, "failed to set display off: %d\n", ret);
+
+       ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+       if (ret < 0)
+               dev_err(dev, "failed to enter sleep mode: %d\n", ret);
+
+       msleep(100);
+}
+
+static int jdi_panel_disable(struct drm_panel *panel)
+{
+       struct jdi_panel *jdi = to_jdi_panel(panel);
+
+       if (!jdi->enabled)
+               return 0;
+
+       jdi->backlight->props.power = FB_BLANK_POWERDOWN;
+       backlight_update_status(jdi->backlight);
+
+       jdi->enabled = false;
+
+       return 0;
+}
+
+static int jdi_panel_unprepare(struct drm_panel *panel)
+{
+       struct jdi_panel *jdi = to_jdi_panel(panel);
+       struct device *dev = &jdi->dsi->dev;
+       int ret;
+
+       if (!jdi->prepared)
+               return 0;
+
+       jdi_panel_off(jdi);
+
+       ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
+       if (ret < 0)
+               dev_err(dev, "regulator disable failed, %d\n", ret);
+
+       gpiod_set_value(jdi->enable_gpio, 0);
+
+       gpiod_set_value(jdi->reset_gpio, 1);
+
+       gpiod_set_value(jdi->dcdc_en_gpio, 0);
+
+       jdi->prepared = false;
+
+       return 0;
+}
+
+static int jdi_panel_prepare(struct drm_panel *panel)
+{
+       struct jdi_panel *jdi = to_jdi_panel(panel);
+       struct device *dev = &jdi->dsi->dev;
+       int ret;
+
+       if (jdi->prepared)
+               return 0;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
+       if (ret < 0) {
+               dev_err(dev, "regulator enable failed, %d\n", ret);
+               return ret;
+       }
+
+       msleep(20);
+
+       gpiod_set_value(jdi->dcdc_en_gpio, 1);
+       usleep_range(10, 20);
+
+       gpiod_set_value(jdi->reset_gpio, 0);
+       usleep_range(10, 20);
+
+       gpiod_set_value(jdi->enable_gpio, 1);
+       usleep_range(10, 20);
+
+       ret = jdi_panel_init(jdi);
+       if (ret < 0) {
+               dev_err(dev, "failed to init panel: %d\n", ret);
+               goto poweroff;
+       }
+
+       ret = jdi_panel_on(jdi);
+       if (ret < 0) {
+               dev_err(dev, "failed to set panel on: %d\n", ret);
+               goto poweroff;
+       }
+
+       jdi->prepared = true;
+
+       return 0;
+
+poweroff:
+       ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
+       if (ret < 0)
+               dev_err(dev, "regulator disable failed, %d\n", ret);
+
+       gpiod_set_value(jdi->enable_gpio, 0);
+
+       gpiod_set_value(jdi->reset_gpio, 1);
+
+       gpiod_set_value(jdi->dcdc_en_gpio, 0);
+
+       return ret;
+}
+
+static int jdi_panel_enable(struct drm_panel *panel)
+{
+       struct jdi_panel *jdi = to_jdi_panel(panel);
+
+       if (jdi->enabled)
+               return 0;
+
+       jdi->backlight->props.power = FB_BLANK_UNBLANK;
+       backlight_update_status(jdi->backlight);
+
+       jdi->enabled = true;
+
+       return 0;
+}
+
+static const struct drm_display_mode default_mode = {
+               .clock = 155493,
+               .hdisplay = 1200,
+               .hsync_start = 1200 + 48,
+               .hsync_end = 1200 + 48 + 32,
+               .htotal = 1200 + 48 + 32 + 60,
+               .vdisplay = 1920,
+               .vsync_start = 1920 + 3,
+               .vsync_end = 1920 + 3 + 5,
+               .vtotal = 1920 + 3 + 5 + 6,
+               .vrefresh = 60,
+               .flags = 0,
+};
+
+static int jdi_panel_get_modes(struct drm_panel *panel)
+{
+       struct drm_display_mode *mode;
+       struct jdi_panel *jdi = to_jdi_panel(panel);
+       struct device *dev = &jdi->dsi->dev;
+
+       mode = drm_mode_duplicate(panel->drm, &default_mode);
+       if (!mode) {
+               dev_err(dev, "failed to add mode %ux%ux@%u\n",
+                       default_mode.hdisplay, default_mode.vdisplay,
+                       default_mode.vrefresh);
+               return -ENOMEM;
+       }
+
+       drm_mode_set_name(mode);
+
+       drm_mode_probed_add(panel->connector, mode);
+
+       panel->connector->display_info.width_mm = 95;
+       panel->connector->display_info.height_mm = 151;
+
+       return 1;
+}
+
+static int dsi_dcs_bl_get_brightness(struct backlight_device *bl)
+{
+       struct mipi_dsi_device *dsi = bl_get_data(bl);
+       int ret;
+       u16 brightness = bl->props.brightness;
+
+       dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+       ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
+       if (ret < 0)
+               return ret;
+
+       dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+       return brightness & 0xff;
+}
+
+static int dsi_dcs_bl_update_status(struct backlight_device *bl)
+{
+       struct mipi_dsi_device *dsi = bl_get_data(bl);
+       int ret;
+
+       dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+       ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);
+       if (ret < 0)
+               return ret;
+
+       dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+       return 0;
+}
+
+static const struct backlight_ops dsi_bl_ops = {
+       .update_status = dsi_dcs_bl_update_status,
+       .get_brightness = dsi_dcs_bl_get_brightness,
+};
+
+static struct backlight_device *
+drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi)
+{
+       struct device *dev = &dsi->dev;
+       struct backlight_properties props;
+
+       memset(&props, 0, sizeof(props));
+       props.type = BACKLIGHT_RAW;
+       props.brightness = 255;
+       props.max_brightness = 255;
+
+       return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
+                                             &dsi_bl_ops, &props);
+}
+
+static const struct drm_panel_funcs jdi_panel_funcs = {
+       .disable = jdi_panel_disable,
+       .unprepare = jdi_panel_unprepare,
+       .prepare = jdi_panel_prepare,
+       .enable = jdi_panel_enable,
+       .get_modes = jdi_panel_get_modes,
+};
+
+static const struct of_device_id jdi_of_match[] = {
+       { .compatible = "jdi,lt070me05000", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, jdi_of_match);
+
+static int jdi_panel_add(struct jdi_panel *jdi)
+{
+       struct device *dev = &jdi->dsi->dev;
+       int ret;
+       unsigned int i;
+
+       jdi->mode = &default_mode;
+
+       for (i = 0; i < ARRAY_SIZE(jdi->supplies); i++)
+               jdi->supplies[i].supply = regulator_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(jdi->supplies),
+                                     jdi->supplies);
+       if (ret < 0) {
+               dev_err(dev, "failed to init regulator, ret=%d\n", ret);
+               return ret;
+       }
+
+       jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+       if (IS_ERR(jdi->enable_gpio)) {
+               ret = PTR_ERR(jdi->enable_gpio);
+               dev_err(dev, "cannot get enable-gpio %d\n", ret);
+               return ret;
+       }
+
+       jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(jdi->reset_gpio)) {
+               ret = PTR_ERR(jdi->reset_gpio);
+               dev_err(dev, "cannot get reset-gpios %d\n", ret);
+               return ret;
+       }
+
+       jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW);
+       if (IS_ERR(jdi->dcdc_en_gpio)) {
+               ret = PTR_ERR(jdi->dcdc_en_gpio);
+               dev_err(dev, "cannot get dcdc-en-gpio %d\n", ret);
+               return ret;
+       }
+
+       jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi);
+       if (IS_ERR(jdi->backlight)) {
+               ret = PTR_ERR(jdi->backlight);
+               dev_err(dev, "failed to register backlight %d\n", ret);
+               return ret;
+       }
+
+       drm_panel_init(&jdi->base);
+       jdi->base.funcs = &jdi_panel_funcs;
+       jdi->base.dev = &jdi->dsi->dev;
+
+       ret = drm_panel_add(&jdi->base);
+
+       return ret;
+}
+
+static void jdi_panel_del(struct jdi_panel *jdi)
+{
+       if (jdi->base.dev)
+               drm_panel_remove(&jdi->base);
+}
+
+static int jdi_panel_probe(struct mipi_dsi_device *dsi)
+{
+       struct jdi_panel *jdi;
+       int ret;
+
+       dsi->lanes = 4;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->mode_flags =  MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
+                          MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
+       jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL);
+       if (!jdi)
+               return -ENOMEM;
+
+       mipi_dsi_set_drvdata(dsi, jdi);
+
+       jdi->dsi = dsi;
+
+       ret = jdi_panel_add(jdi);
+       if (ret < 0)
+               return ret;
+
+       return mipi_dsi_attach(dsi);
+}
+
+static int jdi_panel_remove(struct mipi_dsi_device *dsi)
+{
+       struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
+       int ret;
+
+       ret = jdi_panel_disable(&jdi->base);
+       if (ret < 0)
+               dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
+
+       ret = mipi_dsi_detach(dsi);
+       if (ret < 0)
+               dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",
+                       ret);
+
+       drm_panel_detach(&jdi->base);
+       jdi_panel_del(jdi);
+
+       return 0;
+}
+
+static void jdi_panel_shutdown(struct mipi_dsi_device *dsi)
+{
+       struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
+
+       jdi_panel_disable(&jdi->base);
+}
+
+static struct mipi_dsi_driver jdi_panel_driver = {
+       .driver = {
+               .name = "panel-jdi-lt070me05000",
+               .of_match_table = jdi_of_match,
+       },
+       .probe = jdi_panel_probe,
+       .remove = jdi_panel_remove,
+       .shutdown = jdi_panel_shutdown,
+};
+module_mipi_dsi_driver(jdi_panel_driver);
+
+MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
+MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");
+MODULE_DESCRIPTION("JDI LT070ME05000 WUXGA");
+MODULE_LICENSE("GPL v2");
index 85143d1..113db3c 100644 (file)
@@ -849,6 +849,34 @@ static const struct panel_desc innolux_at070tn92 = {
        .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 };
 
+static const struct display_timing innolux_g101ice_l01_timing = {
+       .pixelclock = { 60400000, 71100000, 74700000 },
+       .hactive = { 1280, 1280, 1280 },
+       .hfront_porch = { 41, 80, 100 },
+       .hback_porch = { 40, 79, 99 },
+       .hsync_len = { 1, 1, 1 },
+       .vactive = { 800, 800, 800 },
+       .vfront_porch = { 5, 11, 14 },
+       .vback_porch = { 4, 11, 14 },
+       .vsync_len = { 1, 1, 1 },
+       .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc innolux_g101ice_l01 = {
+       .timings = &innolux_g101ice_l01_timing,
+       .num_timings = 1,
+       .bpc = 8,
+       .size = {
+               .width = 217,
+               .height = 135,
+       },
+       .delay = {
+               .enable = 200,
+               .disable = 200,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+};
+
 static const struct drm_display_mode innolux_g121i1_l01_mode = {
        .clock = 71000,
        .hdisplay = 1280,
@@ -1186,7 +1214,7 @@ static const struct panel_desc olimex_lcd_olinuxino_43ts = {
                .width = 105,
                .height = 67,
        },
-       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 };
 
 /*
@@ -1245,6 +1273,7 @@ static const struct panel_desc ortustech_com43h4m85ulc = {
                .height = 93,
        },
        .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
 };
 
 static const struct drm_display_mode qd43003c0_40_mode = {
@@ -1384,6 +1413,11 @@ static const struct panel_desc sharp_lq123p1jx31 = {
                .width = 259,
                .height = 173,
        },
+       .delay = {
+               .prepare = 110,
+               .enable = 50,
+               .unprepare = 550,
+       },
 };
 
 static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
@@ -1430,6 +1464,11 @@ static const struct panel_desc starry_kr122ea0sra = {
                .width = 263,
                .height = 164,
        },
+       .delay = {
+               .prepare = 10 + 200,
+               .enable = 50,
+               .unprepare = 10 + 500,
+       },
 };
 
 static const struct drm_display_mode tpk_f07a_0102_mode = {
@@ -1574,6 +1613,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "innolux,at070tn92",
                .data = &innolux_at070tn92,
+       }, {
+               .compatible ="innolux,g101ice-l01",
+               .data = &innolux_g101ice_l01
        }, {
                .compatible ="innolux,g121i1-l01",
                .data = &innolux_g121i1_l01
index 3aef127..a61c0d4 100644 (file)
@@ -211,6 +211,7 @@ static void qxl_crtc_destroy(struct drm_crtc *crtc)
        struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc);
 
        drm_crtc_cleanup(crtc);
+       qxl_bo_unref(&qxl_crtc->cursor_bo);
        kfree(qxl_crtc);
 }
 
@@ -296,6 +297,52 @@ qxl_hide_cursor(struct qxl_device *qdev)
        return 0;
 }
 
+static int qxl_crtc_apply_cursor(struct drm_crtc *crtc)
+{
+       struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_cursor_cmd *cmd;
+       struct qxl_release *release;
+       int ret = 0;
+
+       if (!qcrtc->cursor_bo)
+               return 0;
+
+       ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd),
+                                        QXL_RELEASE_CURSOR_CMD,
+                                        &release, NULL);
+       if (ret)
+               return ret;
+
+       ret = qxl_release_list_add(release, qcrtc->cursor_bo);
+       if (ret)
+               goto out_free_release;
+
+       ret = qxl_release_reserve_list(release, false);
+       if (ret)
+               goto out_free_release;
+
+       cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
+       cmd->type = QXL_CURSOR_SET;
+       cmd->u.set.position.x = qcrtc->cur_x + qcrtc->hot_spot_x;
+       cmd->u.set.position.y = qcrtc->cur_y + qcrtc->hot_spot_y;
+
+       cmd->u.set.shape = qxl_bo_physical_address(qdev, qcrtc->cursor_bo, 0);
+
+       cmd->u.set.visible = 1;
+       qxl_release_unmap(qdev, release, &cmd->release_info);
+
+       qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
+       qxl_release_fence_buffer_objects(release);
+
+       return ret;
+
+out_free_release:
+       qxl_release_free(qdev, release);
+       return ret;
+}
+
 static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
                                struct drm_file *file_priv,
                                uint32_t handle,
@@ -400,7 +447,8 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
        }
        drm_gem_object_unreference_unlocked(obj);
 
-       qxl_bo_unref(&cursor_bo);
+       qxl_bo_unref (&qcrtc->cursor_bo);
+       qcrtc->cursor_bo = cursor_bo;
 
        return ret;
 
@@ -655,6 +703,12 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
                           bo->surf.stride, bo->surf.format);
                qxl_io_create_primary(qdev, 0, bo);
                bo->is_primary = true;
+
+               ret = qxl_crtc_apply_cursor(crtc);
+               if (ret) {
+                       DRM_ERROR("could not set cursor after modeset");
+                       ret = 0;
+               }
        }
 
        if (bo->is_primary) {
index ffe8853..9b728ed 100644 (file)
@@ -57,11 +57,8 @@ static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
 static int
 alloc_drawable(struct qxl_device *qdev, struct qxl_release **release)
 {
-       int ret;
-       ret = qxl_alloc_release_reserved(qdev, sizeof(struct qxl_drawable),
-                                        QXL_RELEASE_DRAWABLE, release,
-                                        NULL);
-       return ret;
+       return qxl_alloc_release_reserved(qdev, sizeof(struct qxl_drawable),
+                                         QXL_RELEASE_DRAWABLE, release, NULL);
 }
 
 static void
index 8e633ca..5f3e5ad 100644 (file)
@@ -137,6 +137,7 @@ struct qxl_crtc {
        int cur_y;
        int hot_spot_x;
        int hot_spot_y;
+       struct qxl_bo *cursor_bo;
 };
 
 struct qxl_output {
index 28c1423..2cd879a 100644 (file)
@@ -24,7 +24,6 @@
  *     David Airlie
  */
 #include <linux/module.h>
-#include <linux/fb.h>
 
 #include "drmP.h"
 #include "drm/drm.h"
index 5e1d789..fa5440d 100644 (file)
@@ -61,7 +61,7 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
        if (domain == QXL_GEM_DOMAIN_VRAM)
                qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag;
        if (domain == QXL_GEM_DOMAIN_SURFACE)
-               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0 | pflag;
+               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV | pflag;
        if (domain == QXL_GEM_DOMAIN_CPU)
                qbo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag;
        if (!c)
@@ -151,7 +151,7 @@ void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev,
 
        if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
                map = qdev->vram_mapping;
-       else if (bo->tbo.mem.mem_type == TTM_PL_PRIV0)
+       else if (bo->tbo.mem.mem_type == TTM_PL_PRIV)
                map = qdev->surface_mapping;
        else
                goto fallback;
@@ -191,7 +191,7 @@ void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev,
 
        if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
                map = qdev->vram_mapping;
-       else if (bo->tbo.mem.mem_type == TTM_PL_PRIV0)
+       else if (bo->tbo.mem.mem_type == TTM_PL_PRIV)
                map = qdev->surface_mapping;
        else
                goto fallback;
@@ -311,7 +311,7 @@ int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo)
 
 int qxl_surf_evict(struct qxl_device *qdev)
 {
-       return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0);
+       return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV);
 }
 
 int qxl_vram_evict(struct qxl_device *qdev)
index f599cd0..cd83f05 100644 (file)
@@ -203,12 +203,9 @@ qxl_release_free(struct qxl_device *qdev,
 static int qxl_release_bo_alloc(struct qxl_device *qdev,
                                struct qxl_bo **bo)
 {
-       int ret;
        /* pin releases bo's they are too messy to evict */
-       ret = qxl_bo_create(qdev, PAGE_SIZE, false, true,
-                           QXL_GEM_DOMAIN_VRAM, NULL,
-                           bo);
-       return ret;
+       return qxl_bo_create(qdev, PAGE_SIZE, false, true,
+                            QXL_GEM_DOMAIN_VRAM, NULL, bo);
 }
 
 int qxl_release_list_add(struct qxl_release *release, struct qxl_bo *bo)
index d50c967..e26c82d 100644 (file)
@@ -168,7 +168,7 @@ static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->default_caching = TTM_PL_FLAG_CACHED;
                break;
        case TTM_PL_VRAM:
-       case TTM_PL_PRIV0:
+       case TTM_PL_PRIV:
                /* "On-card" video ram */
                man->func = &ttm_bo_manager_func;
                man->gpu_offset = 0;
@@ -210,7 +210,8 @@ static int qxl_verify_access(struct ttm_buffer_object *bo, struct file *filp)
 {
        struct qxl_bo *qbo = to_qxl_bo(bo);
 
-       return drm_vma_node_verify_access(&qbo->gem_base.vma_node, filp);
+       return drm_vma_node_verify_access(&qbo->gem_base.vma_node,
+                                         filp->private_data);
 }
 
 static int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
@@ -235,7 +236,7 @@ static int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
                mem->bus.base = qdev->vram_base;
                mem->bus.offset = mem->start << PAGE_SHIFT;
                break;
-       case TTM_PL_PRIV0:
+       case TTM_PL_PRIV:
                mem->bus.is_iomem = true;
                mem->bus.base = qdev->surfaceram_base;
                mem->bus.offset = mem->start << PAGE_SHIFT;
@@ -361,8 +362,8 @@ static int qxl_bo_move(struct ttm_buffer_object *bo,
                qxl_move_null(bo, new_mem);
                return 0;
        }
-       return ttm_bo_move_memcpy(bo, evict, interruptible,
-                                 no_wait_gpu, new_mem);
+       return ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu,
+                                 new_mem);
 }
 
 static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
@@ -376,7 +377,7 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
        qbo = to_qxl_bo(bo);
        qdev = qbo->gem_base.dev->dev_private;
 
-       if (bo->mem.mem_type == TTM_PL_PRIV0 && qbo->surface_id)
+       if (bo->mem.mem_type == TTM_PL_PRIV && qbo->surface_id)
                qxl_surface_evict(qdev, qbo, new_mem ? true : false);
 }
 
@@ -422,7 +423,7 @@ int qxl_ttm_init(struct qxl_device *qdev)
                DRM_ERROR("Failed initializing VRAM heap.\n");
                return r;
        }
-       r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_PRIV0,
+       r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_PRIV,
                           qdev->surfaceram_size / PAGE_SIZE);
        if (r) {
                DRM_ERROR("Failed initializing Surfaces heap.\n");
@@ -445,7 +446,7 @@ int qxl_ttm_init(struct qxl_device *qdev)
 void qxl_ttm_fini(struct qxl_device *qdev)
 {
        ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM);
-       ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV0);
+       ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV);
        ttm_bo_device_release(&qdev->mman.bdev);
        qxl_ttm_global_fini(qdev);
        DRM_INFO("qxl: ttm finalized\n");
@@ -489,7 +490,7 @@ static int qxl_ttm_debugfs_init(struct qxl_device *qdev)
                if (i == 0)
                        qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_VRAM].priv;
                else
-                       qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_PRIV0].priv;
+                       qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_PRIV].priv;
 
        }
        return qxl_debugfs_add_files(qdev, qxl_mem_types_list, i);
index c57b4de..a982be5 100644 (file)
@@ -56,7 +56,7 @@ static const struct file_operations r128_driver_fops = {
 
 static struct drm_driver driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
+           DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_LEGACY |
            DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
        .dev_priv_size = sizeof(drm_r128_buf_priv_t),
        .load = r128_driver_load,
index 1dcf390..74f99ba 100644 (file)
@@ -1156,6 +1156,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
        u32 tmp, viewport_w, viewport_h;
        int r;
        bool bypass_lut = false;
+       char *format_name;
 
        /* no fb bound */
        if (!atomic && !crtc->primary->fb) {
@@ -1259,8 +1260,9 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
                bypass_lut = true;
                break;
        default:
-               DRM_ERROR("Unsupported screen format %s\n",
-                         drm_get_format_name(target_fb->pixel_format));
+               format_name = drm_get_format_name(target_fb->pixel_format);
+               DRM_ERROR("Unsupported screen format %s\n", format_name);
+               kfree(format_name);
                return -EINVAL;
        }
 
@@ -1435,8 +1437,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
               (viewport_w << 16) | viewport_h);
 
-       /* set pageflip to happen only at start of vblank interval (front porch) */
-       WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3);
+       /* set pageflip to happen anywhere in vblank interval */
+       WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
 
        if (!atomic && fb && fb != crtc->primary->fb) {
                radeon_fb = to_radeon_framebuffer(fb);
@@ -1471,6 +1473,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        u32 viewport_w, viewport_h;
        int r;
        bool bypass_lut = false;
+       char *format_name;
 
        /* no fb bound */
        if (!atomic && !crtc->primary->fb) {
@@ -1560,8 +1563,9 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
                bypass_lut = true;
                break;
        default:
-               DRM_ERROR("Unsupported screen format %s\n",
-                         drm_get_format_name(target_fb->pixel_format));
+               format_name = drm_get_format_name(target_fb->pixel_format);
+               DRM_ERROR("Unsupported screen format %s\n", format_name);
+               kfree(format_name);
                return -EINVAL;
        }
 
index cead089..432cb46 100644 (file)
@@ -389,22 +389,21 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
 {
        struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
        u8 msg[DP_DPCD_SIZE];
-       int ret, i;
+       int ret;
 
-       for (i = 0; i < 7; i++) {
-               ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg,
-                                      DP_DPCD_SIZE);
-               if (ret == DP_DPCD_SIZE) {
-                       memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
+       ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg,
+                              DP_DPCD_SIZE);
+       if (ret == DP_DPCD_SIZE) {
+               memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
 
-                       DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd),
-                                     dig_connector->dpcd);
+               DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd),
+                             dig_connector->dpcd);
 
-                       radeon_dp_probe_oui(radeon_connector);
+               radeon_dp_probe_oui(radeon_connector);
 
-                       return true;
-               }
+               return true;
        }
+
        dig_connector->dpcd[0] = 0;
        return false;
 }
index 0c1b9ff..f6ff41a 100644 (file)
@@ -1871,7 +1871,7 @@ int ci_mc_load_microcode(struct radeon_device *rdev)
 {
        const __be32 *fw_data = NULL;
        const __le32 *new_fw_data = NULL;
-       u32 running, blackout = 0, tmp;
+       u32 running, tmp;
        u32 *io_mc_regs = NULL;
        const __le32 *new_io_mc_regs = NULL;
        int i, regs_size, ucode_size;
@@ -1912,11 +1912,6 @@ int ci_mc_load_microcode(struct radeon_device *rdev)
        running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
 
        if (running == 0) {
-               if (running) {
-                       blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
-                       WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
-               }
-
                /* reset the engine and set to writable */
                WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
                WREG32(MC_SEQ_SUP_CNTL, 0x00000010);
@@ -1964,9 +1959,6 @@ int ci_mc_load_microcode(struct radeon_device *rdev)
                                break;
                        udelay(1);
                }
-
-               if (running)
-                       WREG32(MC_SHARED_BLACKOUT_CNTL, blackout);
        }
 
        return 0;
@@ -4201,11 +4193,7 @@ u32 cik_gfx_get_rptr(struct radeon_device *rdev,
 u32 cik_gfx_get_wptr(struct radeon_device *rdev,
                     struct radeon_ring *ring)
 {
-       u32 wptr;
-
-       wptr = RREG32(CP_RB0_WPTR);
-
-       return wptr;
+       return RREG32(CP_RB0_WPTR);
 }
 
 void cik_gfx_set_wptr(struct radeon_device *rdev,
@@ -8215,7 +8203,7 @@ static void cik_uvd_resume(struct radeon_device *rdev)
                return;
 
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
-       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0));
        if (r) {
                dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
                return;
index cead228..48db935 100644 (file)
 #define UVD_UDEC_ADDR_CONFIG           0xef4c
 #define UVD_UDEC_DB_ADDR_CONFIG                0xef50
 #define UVD_UDEC_DBW_ADDR_CONFIG       0xef54
+#define UVD_NO_OP                      0xeffc
 
 #define UVD_LMI_EXT40_ADDR             0xf498
 #define UVD_GP_SCRATCH4                        0xf4e0
index db275b7..0b6b576 100644 (file)
@@ -2878,9 +2878,8 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
        for (i = 0; i < rdev->num_crtc; i++) {
                if (save->crtc_enabled[i]) {
                        tmp = RREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i]);
-                       if ((tmp & 0x7) != 3) {
+                       if ((tmp & 0x7) != 0) {
                                tmp &= ~0x7;
-                               tmp |= 0x3;
                                WREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i], tmp);
                        }
                        tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]);
@@ -5580,7 +5579,7 @@ static void evergreen_uvd_resume(struct radeon_device *rdev)
                return;
 
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
-       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0));
        if (r) {
                dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
                return;
index c8e3d39..f3d88ca 100644 (file)
 #define UVD_UDEC_ADDR_CONFIG                           0xef4c
 #define UVD_UDEC_DB_ADDR_CONFIG                                0xef50
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xef54
+#define UVD_NO_OP                                      0xeffc
 #define UVD_RBC_RB_RPTR                                        0xf690
 #define UVD_RBC_RB_WPTR                                        0xf694
 #define UVD_STATUS                                     0xf6bc
index 4a3d7ca..103fc86 100644 (file)
@@ -2062,7 +2062,7 @@ static void cayman_uvd_resume(struct radeon_device *rdev)
                return;
 
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
-       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0));
        if (r) {
                dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
                return;
index 47eb49b..3c9fec8 100644 (file)
 #define UVD_UDEC_ADDR_CONFIG                           0xEF4C
 #define UVD_UDEC_DB_ADDR_CONFIG                                0xEF50
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xEF54
+#define UVD_NO_OP                                      0xEFFC
 #define UVD_RBC_RB_RPTR                                        0xF690
 #define UVD_RBC_RB_WPTR                                        0xF694
 #define UVD_STATUS                                     0xf6bc
index f25994b..f5e84f4 100644 (file)
@@ -1071,11 +1071,7 @@ u32 r100_gfx_get_rptr(struct radeon_device *rdev,
 u32 r100_gfx_get_wptr(struct radeon_device *rdev,
                      struct radeon_ring *ring)
 {
-       u32 wptr;
-
-       wptr = RREG32(RADEON_CP_RB_WPTR);
-
-       return wptr;
+       return RREG32(RADEON_CP_RB_WPTR);
 }
 
 void r100_gfx_set_wptr(struct radeon_device *rdev,
index 9247e7d..a951881 100644 (file)
@@ -2631,11 +2631,7 @@ u32 r600_gfx_get_rptr(struct radeon_device *rdev,
 u32 r600_gfx_get_wptr(struct radeon_device *rdev,
                      struct radeon_ring *ring)
 {
-       u32 wptr;
-
-       wptr = RREG32(R600_CP_RB_WPTR);
-
-       return wptr;
+       return RREG32(R600_CP_RB_WPTR);
 }
 
 void r600_gfx_set_wptr(struct radeon_device *rdev,
@@ -3097,7 +3093,7 @@ static void r600_uvd_resume(struct radeon_device *rdev)
                return;
 
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
-       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0));
        if (r) {
                dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
                return;
index 1e8495c..2e00a52 100644 (file)
 #define UVD_GPCOM_VCPU_DATA0                           0xef10
 #define UVD_GPCOM_VCPU_DATA1                           0xef14
 #define UVD_ENGINE_CNTL                                        0xef18
+#define UVD_NO_OP                                      0xeffc
 
 #define UVD_SEMA_CNTL                                  0xf400
 #define UVD_RB_ARB_CTRL                                        0xf480
index 5633ee3..1b0dcad 100644 (file)
@@ -742,6 +742,7 @@ struct radeon_flip_work {
        struct work_struct              unpin_work;
        struct radeon_device            *rdev;
        int                             crtc_id;
+       u32                             target_vblank;
        uint64_t                        base;
        struct drm_pending_vblank_event *event;
        struct radeon_bo                *old_rbo;
index 31c9a92..6efbd65 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/acpi.h>
 #include <linux/slab.h>
 #include <linux/power_supply.h>
+#include <linux/pm_runtime.h>
 #include <acpi/video.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include "radeon_acpi.h"
 #include "atom.h"
 
+#if defined(CONFIG_VGA_SWITCHEROO)
+bool radeon_atpx_dgpu_req_power_for_displays(void);
+#else
+static inline bool radeon_atpx_dgpu_req_power_for_displays(void) { return false; }
+#endif
+
 #define ACPI_AC_CLASS           "ac_adapter"
 
 extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev);
@@ -394,6 +401,16 @@ int radeon_atif_handler(struct radeon_device *rdev,
 #endif
                }
        }
+       if (req.pending & ATIF_DGPU_DISPLAY_EVENT) {
+               if ((rdev->flags & RADEON_IS_PX) &&
+                   radeon_atpx_dgpu_req_power_for_displays()) {
+                       pm_runtime_get_sync(rdev->ddev->dev);
+                       /* Just fire off a uevent and let userspace tell us what to do */
+                       drm_helper_hpd_irq_event(rdev->ddev);
+                       pm_runtime_mark_last_busy(rdev->ddev->dev);
+                       pm_runtime_put_autosuspend(rdev->ddev->dev);
+               }
+       }
        /* TODO: check other events */
 
        /* We've handled the event, stop the notifier chain. The ACPI interface
index ddef0d4..2fdcd04 100644 (file)
@@ -29,6 +29,7 @@ struct radeon_atpx {
        acpi_handle handle;
        struct radeon_atpx_functions functions;
        bool is_hybrid;
+       bool dgpu_req_power_for_displays;
 };
 
 static struct radeon_atpx_priv {
@@ -72,6 +73,10 @@ bool radeon_is_atpx_hybrid(void) {
        return radeon_atpx_priv.atpx.is_hybrid;
 }
 
+bool radeon_atpx_dgpu_req_power_for_displays(void) {
+       return radeon_atpx_priv.atpx.dgpu_req_power_for_displays;
+}
+
 /**
  * radeon_atpx_call - call an ATPX method
  *
index b79f3b0..50e96d2 100644 (file)
@@ -198,12 +198,12 @@ int radeon_get_monitor_bpc(struct drm_connector *connector)
                }
 
                /* Any defined maximum tmds clock limit we must not exceed? */
-               if (connector->max_tmds_clock > 0) {
+               if (connector->display_info.max_tmds_clock > 0) {
                        /* mode_clock is clock in kHz for mode to be modeset on this connector */
                        mode_clock = radeon_connector->pixelclock_for_modeset;
 
                        /* Maximum allowable input clock in kHz */
-                       max_tmds_clock = connector->max_tmds_clock * 1000;
+                       max_tmds_clock = connector->display_info.max_tmds_clock;
 
                        DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
                                          connector->name, mode_clock, max_tmds_clock);
index a00dd2f..eb92aef 100644 (file)
@@ -639,7 +639,7 @@ void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
  * Used at driver startup.
  * Returns true if virtual or false if not.
  */
-static bool radeon_device_is_virtual(void)
+bool radeon_device_is_virtual(void)
 {
 #ifdef CONFIG_X86
        return boot_cpu_has(X86_FEATURE_HYPERVISOR);
@@ -661,8 +661,9 @@ bool radeon_card_posted(struct radeon_device *rdev)
 {
        uint32_t reg;
 
-       /* for pass through, always force asic_init */
-       if (radeon_device_is_virtual())
+       /* for pass through, always force asic_init for CI */
+       if (rdev->family >= CHIP_BONAIRE &&
+           radeon_device_is_virtual())
                return false;
 
        /* required for EFI mode on macbook2,1 which uses an r5xx asic */
@@ -1956,14 +1957,3 @@ static void radeon_debugfs_remove_files(struct radeon_device *rdev)
        }
 #endif
 }
-
-#if defined(CONFIG_DEBUG_FS)
-int radeon_debugfs_init(struct drm_minor *minor)
-{
-       return 0;
-}
-
-void radeon_debugfs_cleanup(struct drm_minor *minor)
-{
-}
-#endif
index c3206fb..b8ab30a 100644 (file)
@@ -321,16 +321,30 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id)
        update_pending = radeon_page_flip_pending(rdev, crtc_id);
 
        /* Has the pageflip already completed in crtc, or is it certain
-        * to complete in this vblank?
+        * to complete in this vblank? GET_DISTANCE_TO_VBLANKSTART provides
+        * distance to start of "fudged earlier" vblank in vpos, distance to
+        * start of real vblank in hpos. vpos >= 0 && hpos < 0 means we are in
+        * the last few scanlines before start of real vblank, where the vblank
+        * irq can fire, so we have sampled update_pending a bit too early and
+        * know the flip will complete at leading edge of the upcoming real
+        * vblank. On pre-AVIVO hardware, flips also complete inside the real
+        * vblank, not only at leading edge, so if update_pending for hpos >= 0
+        *  == inside real vblank, the flip will complete almost immediately.
+        * Note that this method of completion handling is still not 100% race
+        * free, as we could execute before the radeon_flip_work_func managed
+        * to run and set the RADEON_FLIP_SUBMITTED status, thereby we no-op,
+        * but the flip still gets programmed into hw and completed during
+        * vblank, leading to a delayed emission of the flip completion event.
+        * This applies at least to pre-AVIVO hardware, where flips are always
+        * completing inside vblank, not only at leading edge of vblank.
         */
        if (update_pending &&
-           (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev,
-                                                              crtc_id,
-                                                              USE_REAL_VBLANKSTART,
-                                                              &vpos, &hpos, NULL, NULL,
-                                                              &rdev->mode_info.crtcs[crtc_id]->base.hwmode)) &&
-           ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
-            (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) {
+           (DRM_SCANOUTPOS_VALID &
+            radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id,
+                                       GET_DISTANCE_TO_VBLANKSTART,
+                                       &vpos, &hpos, NULL, NULL,
+                                       &rdev->mode_info.crtcs[crtc_id]->base.hwmode)) &&
+           ((vpos >= 0 && hpos < 0) || (hpos >= 0 && !ASIC_IS_AVIVO(rdev)))) {
                /* crtc didn't flip in this target vblank interval,
                 * but flip is pending in crtc. Based on the current
                 * scanout position we know that the current frame is
@@ -400,14 +414,13 @@ static void radeon_flip_work_func(struct work_struct *__work)
        struct radeon_flip_work *work =
                container_of(__work, struct radeon_flip_work, flip_work);
        struct radeon_device *rdev = work->rdev;
+       struct drm_device *dev = rdev->ddev;
        struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id];
 
        struct drm_crtc *crtc = &radeon_crtc->base;
        unsigned long flags;
        int r;
-       int vpos, hpos, stat, min_udelay = 0;
-       unsigned repcnt = 4;
-       struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
+       int vpos, hpos;
 
        down_read(&rdev->exclusive_lock);
        if (work->fence) {
@@ -438,59 +451,28 @@ static void radeon_flip_work_func(struct work_struct *__work)
                work->fence = NULL;
        }
 
+       /* Wait until we're out of the vertical blank period before the one
+        * targeted by the flip. Always wait on pre DCE4 to avoid races with
+        * flip completion handling from vblank irq, as these old asics don't
+        * have reliable pageflip completion interrupts.
+        */
+       while (radeon_crtc->enabled &&
+               (radeon_get_crtc_scanoutpos(dev, work->crtc_id, 0,
+                                           &vpos, &hpos, NULL, NULL,
+                                           &crtc->hwmode)
+               & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
+               (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
+               (!ASIC_IS_AVIVO(rdev) ||
+               ((int) (work->target_vblank -
+               dev->driver->get_vblank_counter(dev, work->crtc_id)) > 0)))
+               usleep_range(1000, 2000);
+
        /* We borrow the event spin lock for protecting flip_status */
        spin_lock_irqsave(&crtc->dev->event_lock, flags);
 
        /* set the proper interrupt */
        radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id);
 
-       /* If this happens to execute within the "virtually extended" vblank
-        * interval before the start of the real vblank interval then it needs
-        * to delay programming the mmio flip until the real vblank is entered.
-        * This prevents completing a flip too early due to the way we fudge
-        * our vblank counter and vblank timestamps in order to work around the
-        * problem that the hw fires vblank interrupts before actual start of
-        * vblank (when line buffer refilling is done for a frame). It
-        * complements the fudging logic in radeon_get_crtc_scanoutpos() for
-        * timestamping and radeon_get_vblank_counter_kms() for vblank counts.
-        *
-        * In practice this won't execute very often unless on very fast
-        * machines because the time window for this to happen is very small.
-        */
-       while (radeon_crtc->enabled && --repcnt) {
-               /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
-                * start in hpos, and to the "fudged earlier" vblank start in
-                * vpos.
-                */
-               stat = radeon_get_crtc_scanoutpos(rdev->ddev, work->crtc_id,
-                                                 GET_DISTANCE_TO_VBLANKSTART,
-                                                 &vpos, &hpos, NULL, NULL,
-                                                 &crtc->hwmode);
-
-               if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
-                   (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
-                   !(vpos >= 0 && hpos <= 0))
-                       break;
-
-               /* Sleep at least until estimated real start of hw vblank */
-               min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
-               if (min_udelay > vblank->framedur_ns / 2000) {
-                       /* Don't wait ridiculously long - something is wrong */
-                       repcnt = 0;
-                       break;
-               }
-               spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
-               usleep_range(min_udelay, 2 * min_udelay);
-               spin_lock_irqsave(&crtc->dev->event_lock, flags);
-       };
-
-       if (!repcnt)
-               DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
-                                "framedur %d, linedur %d, stat %d, vpos %d, "
-                                "hpos %d\n", work->crtc_id, min_udelay,
-                                vblank->framedur_ns / 1000,
-                                vblank->linedur_ns / 1000, stat, vpos, hpos);
-
        /* do the flip (mmio) */
        radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base, work->async);
 
@@ -499,10 +481,11 @@ static void radeon_flip_work_func(struct work_struct *__work)
        up_read(&rdev->exclusive_lock);
 }
 
-static int radeon_crtc_page_flip(struct drm_crtc *crtc,
-                                struct drm_framebuffer *fb,
-                                struct drm_pending_vblank_event *event,
-                                uint32_t page_flip_flags)
+static int radeon_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 drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -599,12 +582,8 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
                base &= ~7;
        }
        work->base = base;
-
-       r = drm_crtc_vblank_get(crtc);
-       if (r) {
-               DRM_ERROR("failed to get vblank before flip\n");
-               goto pflip_cleanup;
-       }
+       work->target_vblank = target - drm_crtc_vblank_count(crtc) +
+               dev->driver->get_vblank_counter(dev, work->crtc_id);
 
        /* We borrow the event spin lock for protecting flip_work */
        spin_lock_irqsave(&crtc->dev->event_lock, flags);
@@ -613,7 +592,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
                DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
                spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
                r = -EBUSY;
-               goto vblank_cleanup;
+               goto pflip_cleanup;
        }
        radeon_crtc->flip_status = RADEON_FLIP_PENDING;
        radeon_crtc->flip_work = work;
@@ -626,9 +605,6 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
        queue_work(radeon_crtc->flip_queue, &work->flip_work);
        return 0;
 
-vblank_cleanup:
-       drm_crtc_vblank_put(crtc);
-
 pflip_cleanup:
        if (unlikely(radeon_bo_reserve(new_rbo, false) != 0)) {
                DRM_ERROR("failed to reserve new rbo in error path\n");
@@ -697,7 +673,7 @@ static const struct drm_crtc_funcs radeon_crtc_funcs = {
        .gamma_set = radeon_crtc_gamma_set,
        .set_config = radeon_crtc_set_config,
        .destroy = radeon_crtc_destroy,
-       .page_flip = radeon_crtc_page_flip,
+       .page_flip_target = radeon_crtc_page_flip_target,
 };
 
 static void radeon_crtc_init(struct drm_device *dev, int index)
index db64e00..2d46564 100644 (file)
@@ -164,7 +164,6 @@ radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg
        }
 
        if (tmp & AUX_SW_RX_TIMEOUT) {
-               DRM_DEBUG_KMS("dp_aux_ch timed out\n");
                ret = -ETIMEDOUT;
                goto done;
        }
index c01a7c6..91c8f43 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/vga_switcheroo.h>
 #include <drm/drm_gem.h>
+#include <drm/drm_fb_helper.h>
 
 #include "drm_crtc_helper.h"
 #include "radeon_kfd.h"
  *   2.44.0 - SET_APPEND_CNT packet3 support
  *   2.45.0 - Allow setting shader registers using DMA/COPY packet3 on SI
  *   2.46.0 - Add PFP_SYNC_ME support on evergreen
+ *   2.47.0 - Add UVD_NO_OP register support
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       46
+#define KMS_DRIVER_MINOR       47
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
@@ -154,11 +156,6 @@ void radeon_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
 extern long radeon_kms_compat_ioctl(struct file *filp, unsigned int cmd,
                                    unsigned long arg);
 
-#if defined(CONFIG_DEBUG_FS)
-int radeon_debugfs_init(struct drm_minor *minor);
-void radeon_debugfs_cleanup(struct drm_minor *minor);
-#endif
-
 /* atpx handler */
 #if defined(CONFIG_VGA_SWITCHEROO)
 void radeon_register_atpx_handler(void);
@@ -309,6 +306,8 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 
 static struct drm_driver kms_driver;
 
+bool radeon_device_is_virtual(void);
+
 static int radeon_kick_out_firmware_fb(struct pci_dev *pdev)
 {
        struct apertures_struct *ap;
@@ -324,7 +323,7 @@ static int radeon_kick_out_firmware_fb(struct pci_dev *pdev)
 #ifdef CONFIG_X86
        primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 #endif
-       remove_conflicting_framebuffers(ap, "radeondrmfb", primary);
+       drm_fb_helper_remove_conflicting_framebuffers(ap, "radeondrmfb", primary);
        kfree(ap);
 
        return 0;
@@ -362,6 +361,17 @@ radeon_pci_remove(struct pci_dev *pdev)
        drm_put_dev(dev);
 }
 
+static void
+radeon_pci_shutdown(struct pci_dev *pdev)
+{
+       /* if we are running in a VM, make sure the device
+        * torn down properly on reboot/shutdown.
+        * unfortunately we can't detect certain
+        * hypervisors so just do this all the time.
+        */
+       radeon_pci_remove(pdev);
+}
+
 static int radeon_pmops_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -373,6 +383,14 @@ static int radeon_pmops_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+       /* GPU comes up enabled by the bios on resume */
+       if (radeon_is_px(drm_dev)) {
+               pm_runtime_disable(dev);
+               pm_runtime_set_active(dev);
+               pm_runtime_enable(dev);
+       }
+
        return radeon_resume_kms(drm_dev, true, true);
 }
 
@@ -529,10 +547,6 @@ static struct drm_driver kms_driver = {
        .disable_vblank = radeon_disable_vblank_kms,
        .get_vblank_timestamp = radeon_get_vblank_timestamp_kms,
        .get_scanout_position = radeon_get_crtc_scanoutpos,
-#if defined(CONFIG_DEBUG_FS)
-       .debugfs_init = radeon_debugfs_init,
-       .debugfs_cleanup = radeon_debugfs_cleanup,
-#endif
        .irq_preinstall = radeon_driver_irq_preinstall_kms,
        .irq_postinstall = radeon_driver_irq_postinstall_kms,
        .irq_uninstall = radeon_driver_irq_uninstall_kms,
@@ -574,6 +588,7 @@ static struct pci_driver radeon_kms_pci_driver = {
        .id_table = pciidlist,
        .probe = radeon_pci_probe,
        .remove = radeon_pci_remove,
+       .shutdown = radeon_pci_shutdown,
        .driver.pm = &radeon_pm_ops,
 };
 
index 0e3143a..0daad44 100644 (file)
@@ -25,7 +25,7 @@
  */
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/fb.h>
+#include <linux/pm_runtime.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
@@ -47,8 +47,35 @@ struct radeon_fbdev {
        struct radeon_device *rdev;
 };
 
+static int
+radeonfb_open(struct fb_info *info, int user)
+{
+       struct radeon_fbdev *rfbdev = info->par;
+       struct radeon_device *rdev = rfbdev->rdev;
+       int ret = pm_runtime_get_sync(rdev->ddev->dev);
+       if (ret < 0 && ret != -EACCES) {
+               pm_runtime_mark_last_busy(rdev->ddev->dev);
+               pm_runtime_put_autosuspend(rdev->ddev->dev);
+               return ret;
+       }
+       return 0;
+}
+
+static int
+radeonfb_release(struct fb_info *info, int user)
+{
+       struct radeon_fbdev *rfbdev = info->par;
+       struct radeon_device *rdev = rfbdev->rdev;
+
+       pm_runtime_mark_last_busy(rdev->ddev->dev);
+       pm_runtime_put_autosuspend(rdev->ddev->dev);
+       return 0;
+}
+
 static struct fb_ops radeonfb_ops = {
        .owner = THIS_MODULE,
+       .fb_open = radeonfb_open,
+       .fb_release = radeonfb_release,
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
        .fb_fillrect = drm_fb_helper_cfb_fillrect,
@@ -383,7 +410,7 @@ void radeon_fbdev_fini(struct radeon_device *rdev)
 void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state)
 {
        if (rdev->mode_info.rfbdev)
-               fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
+               drm_fb_helper_set_suspend(&rdev->mode_info.rfbdev->helper, state);
 }
 
 bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
index 9590bcd..021aa00 100644 (file)
@@ -938,10 +938,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
                         "Radeon i2c hw bus %s", name);
                i2c->adapter.algo = &radeon_i2c_algo;
                ret = i2c_add_adapter(&i2c->adapter);
-               if (ret) {
-                       DRM_ERROR("Failed to register hw i2c %s\n", name);
+               if (ret)
                        goto out_free;
-               }
        } else if (rec->hw_capable &&
                   radeon_hw_i2c &&
                   ASIC_IS_DCE3(rdev)) {
@@ -950,10 +948,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
                         "Radeon i2c hw bus %s", name);
                i2c->adapter.algo = &radeon_atom_i2c_algo;
                ret = i2c_add_adapter(&i2c->adapter);
-               if (ret) {
-                       DRM_ERROR("Failed to register hw i2c %s\n", name);
+               if (ret)
                        goto out_free;
-               }
        } else {
                /* set the radeon bit adapter */
                snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
index 835563c..4388dde 100644 (file)
@@ -641,11 +641,11 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
        if (rdev->family >= CHIP_CAYMAN) {
                struct radeon_fpriv *fpriv;
                struct radeon_vm *vm;
-               int r;
 
                fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
                if (unlikely(!fpriv)) {
-                       return -ENOMEM;
+                       r = -ENOMEM;
+                       goto out_suspend;
                }
 
                if (rdev->accel_working) {
@@ -653,14 +653,14 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
                        r = radeon_vm_init(rdev, vm);
                        if (r) {
                                kfree(fpriv);
-                               return r;
+                               goto out_suspend;
                        }
 
                        r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
                        if (r) {
                                radeon_vm_fini(rdev, vm);
                                kfree(fpriv);
-                               return r;
+                               goto out_suspend;
                        }
 
                        /* map the ib pool buffer read only into
@@ -674,15 +674,16 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
                        if (r) {
                                radeon_vm_fini(rdev, vm);
                                kfree(fpriv);
-                               return r;
+                               goto out_suspend;
                        }
                }
                file_priv->driver_priv = fpriv;
        }
 
+out_suspend:
        pm_runtime_mark_last_busy(dev->dev);
        pm_runtime_put_autosuspend(dev->dev);
-       return 0;
+       return r;
 }
 
 /**
@@ -717,6 +718,8 @@ void radeon_driver_postclose_kms(struct drm_device *dev,
                kfree(fpriv);
                file_priv->driver_priv = NULL;
        }
+       pm_runtime_mark_last_busy(dev->dev);
+       pm_runtime_put_autosuspend(dev->dev);
 }
 
 /**
@@ -733,6 +736,8 @@ void radeon_driver_preclose_kms(struct drm_device *dev,
 {
        struct radeon_device *rdev = dev->dev_private;
 
+       pm_runtime_get_sync(dev->dev);
+
        mutex_lock(&rdev->gem.mutex);
        if (rdev->hyperz_filp == file_priv)
                rdev->hyperz_filp = NULL;
index c2e0a1c..4552682 100644 (file)
@@ -237,7 +237,8 @@ static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp)
 
        if (radeon_ttm_tt_has_userptr(bo->ttm))
                return -EPERM;
-       return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp);
+       return drm_vma_node_verify_access(&rbo->gem_base.vma_node,
+                                         filp->private_data);
 }
 
 static void radeon_move_null(struct ttm_buffer_object *bo,
@@ -346,7 +347,7 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
        if (unlikely(r)) {
                goto out_cleanup;
        }
-       r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, new_mem);
+       r = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, new_mem);
 out_cleanup:
        ttm_bo_mem_put(bo, &tmp_mem);
        return r;
@@ -379,7 +380,7 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
        if (unlikely(r)) {
                return r;
        }
-       r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, &tmp_mem);
+       r = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, &tmp_mem);
        if (unlikely(r)) {
                goto out_cleanup;
        }
@@ -444,8 +445,7 @@ static int radeon_bo_move(struct ttm_buffer_object *bo,
 
        if (r) {
 memcpy:
-               r = ttm_bo_move_memcpy(bo, evict, interruptible,
-                                      no_wait_gpu, new_mem);
+               r = ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, new_mem);
                if (r) {
                        return r;
                }
index 73dfe01..0cd0e7b 100644 (file)
@@ -669,6 +669,7 @@ static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
                                return r;
                        break;
                case UVD_ENGINE_CNTL:
+               case UVD_NO_OP:
                        break;
                default:
                        DRM_ERROR("Invalid reg 0x%X!\n",
@@ -753,8 +754,10 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
        ib.ptr[3] = addr >> 32;
        ib.ptr[4] = PACKET0(UVD_GPCOM_VCPU_CMD, 0);
        ib.ptr[5] = 0;
-       for (i = 6; i < 16; ++i)
-               ib.ptr[i] = PACKET2(0);
+       for (i = 6; i < 16; i += 2) {
+               ib.ptr[i] = PACKET0(UVD_NO_OP, 0);
+               ib.ptr[i+1] = 0;
+       }
        ib.length_dw = 16;
 
        r = radeon_ib_schedule(rdev, &ib, NULL, false);
index 1c120a4..729ae58 100644 (file)
@@ -1738,7 +1738,7 @@ static void rv770_uvd_resume(struct radeon_device *rdev)
                return;
 
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
-       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0));
        if (r) {
                dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
                return;
index 9ef2064..0271f4c 100644 (file)
 #define UVD_UDEC_TILING_CONFIG                          0xef40
 #define UVD_UDEC_DB_TILING_CONFIG                       0xef44
 #define UVD_UDEC_DBW_TILING_CONFIG                      0xef48
+#define UVD_NO_OP                                      0xeffc
 
 #define        GC_USER_SHADER_PIPE_CONFIG                      0x8954
 #define                INACTIVE_QD_PIPES(x)                            ((x) << 8)
index 2523ca9..7ee9aaf 100644 (file)
@@ -1547,7 +1547,7 @@ int si_mc_load_microcode(struct radeon_device *rdev)
 {
        const __be32 *fw_data = NULL;
        const __le32 *new_fw_data = NULL;
-       u32 running, blackout = 0;
+       u32 running;
        u32 *io_mc_regs = NULL;
        const __le32 *new_io_mc_regs = NULL;
        int i, regs_size, ucode_size;
@@ -1598,11 +1598,6 @@ int si_mc_load_microcode(struct radeon_device *rdev)
        running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
 
        if (running == 0) {
-               if (running) {
-                       blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
-                       WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
-               }
-
                /* reset the engine and set to writable */
                WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
                WREG32(MC_SEQ_SUP_CNTL, 0x00000010);
@@ -1641,9 +1636,6 @@ int si_mc_load_microcode(struct radeon_device *rdev)
                                break;
                        udelay(1);
                }
-
-               if (running)
-                       WREG32(MC_SHARED_BLACKOUT_CNTL, blackout);
        }
 
        return 0;
@@ -6928,7 +6920,7 @@ static void si_uvd_resume(struct radeon_device *rdev)
                return;
 
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
-       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2);
+       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0));
        if (r) {
                dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r);
                return;
index 1f78ec2..89bdf20 100644 (file)
@@ -4112,7 +4112,7 @@ static int si_populate_smc_voltage_tables(struct radeon_device *rdev,
                                                              &rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
                                si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table);
 
-                               table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
+                               table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC_PHASE_SHEDDING] =
                                        cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);
 
                                si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
index d1a7b58..eb220ee 100644 (file)
 #define UVD_UDEC_ADDR_CONFIG                           0xEF4C
 #define UVD_UDEC_DB_ADDR_CONFIG                                0xEF50
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xEF54
+#define UVD_NO_OP                                      0xEFFC
 #define UVD_RBC_RB_RPTR                                        0xF690
 #define UVD_RBC_RB_WPTR                                        0xF694
 #define UVD_STATUS                                     0xf6bc
index 3c77983..966e3a5 100644 (file)
@@ -194,6 +194,7 @@ typedef struct SISLANDS_SMC_SWSTATE SISLANDS_SMC_SWSTATE;
 #define SISLANDS_SMC_VOLTAGEMASK_VDDC  0
 #define SISLANDS_SMC_VOLTAGEMASK_MVDD  1
 #define SISLANDS_SMC_VOLTAGEMASK_VDDCI 2
+#define SISLANDS_SMC_VOLTAGEMASK_VDDC_PHASE_SHEDDING 3
 #define SISLANDS_SMC_VOLTAGEMASK_MAX   4
 
 struct SISLANDS_SMC_VOLTAGEMASKTABLE
index 899ef7a..73c971e 100644 (file)
@@ -316,8 +316,8 @@ static int rcar_du_probe(struct platform_device *pdev)
        rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data;
 
        ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev);
-       if (!ddev)
-               return -ENOMEM;
+       if (IS_ERR(ddev))
+               return PTR_ERR(ddev);
 
        rcdu->ddev = ddev;
        ddev->dev_private = rcdu;
index f03eb55..bd9c3bb 100644 (file)
@@ -257,7 +257,8 @@ static void rcar_du_atomic_complete(struct rcar_du_commit *commit)
        /* Apply the atomic update. */
        drm_atomic_helper_commit_modeset_disables(dev, old_state);
        drm_atomic_helper_commit_modeset_enables(dev, old_state);
-       drm_atomic_helper_commit_planes(dev, old_state, true);
+       drm_atomic_helper_commit_planes(dev, old_state,
+                                       DRM_PLANE_COMMIT_ACTIVE_ONLY);
 
        drm_atomic_helper_wait_for_vblanks(dev, old_state);
 
index 05d0713..9746365 100644 (file)
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-               rockchip_drm_gem.o rockchip_drm_vop.o
+               rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
index 89aadbf..8548e82 100644 (file)
@@ -32,6 +32,7 @@
 #include <drm/bridge/analogix_dp.h>
 
 #include "rockchip_drm_drv.h"
+#include "rockchip_drm_psr.h"
 #include "rockchip_drm_vop.h"
 
 #define RK3288_GRF_SOC_CON6            0x25c
@@ -41,6 +42,8 @@
 
 #define HIWORD_UPDATE(val, mask)       (val | (mask) << 16)
 
+#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS  100
+
 #define to_dp(nm)      container_of(nm, struct rockchip_dp_device, nm)
 
 /**
@@ -68,11 +71,65 @@ struct rockchip_dp_device {
        struct regmap            *grf;
        struct reset_control     *rst;
 
+       struct work_struct       psr_work;
+       spinlock_t               psr_lock;
+       unsigned int             psr_state;
+
        const struct rockchip_dp_chip_data *data;
 
        struct analogix_dp_plat_data plat_data;
 };
 
+static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
+{
+       struct rockchip_dp_device *dp = to_dp(encoder);
+       unsigned long flags;
+
+       if (!analogix_dp_psr_supported(dp->dev))
+               return;
+
+       dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
+
+       spin_lock_irqsave(&dp->psr_lock, flags);
+       if (enabled)
+               dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
+       else
+               dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+
+       schedule_work(&dp->psr_work);
+       spin_unlock_irqrestore(&dp->psr_lock, flags);
+}
+
+static void analogix_dp_psr_work(struct work_struct *work)
+{
+       struct rockchip_dp_device *dp =
+                               container_of(work, typeof(*dp), psr_work);
+       struct drm_crtc *crtc = dp->encoder.crtc;
+       int psr_state = dp->psr_state;
+       int vact_end;
+       int ret;
+       unsigned long flags;
+
+       if (!crtc)
+               return;
+
+       vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay;
+
+       ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end,
+                                         PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
+       if (ret) {
+               dev_err(dp->dev, "line flag interrupt did not arrive\n");
+               return;
+       }
+
+       spin_lock_irqsave(&dp->psr_lock, flags);
+       if (psr_state == EDP_VSC_PSR_STATE_ACTIVE)
+               analogix_dp_enable_psr(dp->dev);
+       else
+               analogix_dp_disable_psr(dp->dev);
+       spin_unlock_irqrestore(&dp->psr_lock, flags);
+}
+
 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
 {
        reset_control_assert(dp->rst);
@@ -87,6 +144,8 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
        struct rockchip_dp_device *dp = to_dp(plat_data);
        int ret;
 
+       cancel_work_sync(&dp->psr_work);
+
        ret = clk_prepare_enable(dp->pclk);
        if (ret < 0) {
                dev_err(dp->dev, "failed to enable pclk %d\n", ret);
@@ -342,12 +401,22 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
        dp->plat_data.power_off = rockchip_dp_powerdown;
        dp->plat_data.get_modes = rockchip_dp_get_modes;
 
+       spin_lock_init(&dp->psr_lock);
+       dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+       INIT_WORK(&dp->psr_work, analogix_dp_psr_work);
+
+       rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
+
        return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
                               void *data)
 {
+       struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+       rockchip_drm_psr_unregister(&dp->encoder);
+
        return analogix_dp_unbind(dev, master, data);
 }
 
@@ -381,10 +450,8 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 
                panel = of_drm_find_panel(panel_node);
                of_node_put(panel_node);
-               if (!panel) {
-                       DRM_ERROR("failed to find panel\n");
+               if (!panel)
                        return -EPROBE_DEFER;
-               }
        }
 
        dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
@@ -445,7 +512,6 @@ static struct platform_driver rockchip_dp_driver = {
        .remove = rockchip_dp_remove,
        .driver = {
                   .name = "rockchip-dp",
-                  .owner = THIS_MODULE,
                   .pm = &rockchip_dp_pm_ops,
                   .of_match_table = of_match_ptr(rockchip_dp_dt_ids),
        },
index a822d49..8c8cbe8 100644 (file)
@@ -143,8 +143,8 @@ static int rockchip_drm_bind(struct device *dev)
        int ret;
 
        drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
-       if (!drm_dev)
-               return -ENOMEM;
+       if (IS_ERR(drm_dev))
+               return PTR_ERR(drm_dev);
 
        dev_set_drvdata(dev, drm_dev);
 
@@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev)
 
        drm_dev->dev_private = private;
 
+       INIT_LIST_HEAD(&private->psr_list);
+       spin_lock_init(&private->psr_list_lock);
+
        drm_mode_config_init(drm_dev);
 
        rockchip_drm_mode_config_init(drm_dev);
@@ -306,7 +309,7 @@ static struct drm_driver rockchip_drm_driver = {
 };
 
 #ifdef CONFIG_PM_SLEEP
-void rockchip_drm_fb_suspend(struct drm_device *drm)
+static void rockchip_drm_fb_suspend(struct drm_device *drm)
 {
        struct rockchip_drm_private *priv = drm->dev_private;
 
@@ -315,7 +318,7 @@ void rockchip_drm_fb_suspend(struct drm_device *drm)
        console_unlock();
 }
 
-void rockchip_drm_fb_resume(struct drm_device *drm)
+static void rockchip_drm_fb_resume(struct drm_device *drm)
 {
        struct rockchip_drm_private *priv = drm->dev_private;
 
index ea39329..fb6226c 100644 (file)
@@ -39,7 +39,6 @@ struct drm_connector;
 struct rockchip_crtc_funcs {
        int (*enable_vblank)(struct drm_crtc *crtc);
        void (*disable_vblank)(struct drm_crtc *crtc);
-       void (*wait_for_update)(struct drm_crtc *crtc);
 };
 
 struct rockchip_crtc_state {
@@ -61,6 +60,9 @@ struct rockchip_drm_private {
        struct drm_gem_object *fbdev_bo;
        const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
        struct drm_atomic_state *state;
+
+       struct list_head psr_list;
+       spinlock_t psr_list_lock;
 };
 
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
@@ -70,4 +72,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
                                   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
                                    struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+                               unsigned int mstimeout);
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
index 55c5273..0f6eda0 100644 (file)
@@ -22,6 +22,7 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
+#include "rockchip_drm_psr.h"
 
 #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
 
@@ -63,9 +64,20 @@ static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb,
                                     rockchip_fb->obj[0], handle);
 }
 
+static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
+                                struct drm_file *file,
+                                unsigned int flags, unsigned int color,
+                                struct drm_clip_rect *clips,
+                                unsigned int num_clips)
+{
+       rockchip_drm_psr_flush_all(fb->dev);
+       return 0;
+}
+
 static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
        .destroy        = rockchip_drm_fb_destroy,
        .create_handle  = rockchip_drm_fb_create_handle,
+       .dirty          = rockchip_drm_fb_dirty,
 };
 
 static struct rockchip_drm_fb *
@@ -162,68 +174,6 @@ static void rockchip_drm_output_poll_changed(struct drm_device *dev)
                drm_fb_helper_hotplug_event(fb_helper);
 }
 
-static void rockchip_crtc_wait_for_update(struct drm_crtc *crtc)
-{
-       struct rockchip_drm_private *priv = crtc->dev->dev_private;
-       int pipe = drm_crtc_index(crtc);
-       const struct rockchip_crtc_funcs *crtc_funcs = priv->crtc_funcs[pipe];
-
-       if (crtc_funcs && crtc_funcs->wait_for_update)
-               crtc_funcs->wait_for_update(crtc);
-}
-
-/*
- * We can't use drm_atomic_helper_wait_for_vblanks() because rk3288 and rk3066
- * have hardware counters for neither vblanks nor scanlines, which results in
- * a race where:
- *                             | <-- HW vsync irq and reg take effect
- *            plane_commit --> |
- *     get_vblank and wait --> |
- *                             | <-- handle_vblank, vblank->count + 1
- *              cleanup_fb --> |
- *             iommu crash --> |
- *                             | <-- HW vsync irq and reg take effect
- *
- * This function is equivalent but uses rockchip_crtc_wait_for_update() instead
- * of waiting for vblank_count to change.
- */
-static void
-rockchip_atomic_wait_for_complete(struct drm_device *dev, struct drm_atomic_state *old_state)
-{
-       struct drm_crtc_state *old_crtc_state;
-       struct drm_crtc *crtc;
-       int i, ret;
-
-       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
-               /* No one cares about the old state, so abuse it for tracking
-                * and store whether we hold a vblank reference (and should do a
-                * vblank wait) in the ->enable boolean.
-                */
-               old_crtc_state->enable = false;
-
-               if (!crtc->state->active)
-                       continue;
-
-               if (!drm_atomic_helper_framebuffer_changed(dev,
-                               old_state, crtc))
-                       continue;
-
-               ret = drm_crtc_vblank_get(crtc);
-               if (ret != 0)
-                       continue;
-
-               old_crtc_state->enable = true;
-       }
-
-       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
-               if (!old_crtc_state->enable)
-                       continue;
-
-               rockchip_crtc_wait_for_update(crtc);
-               drm_crtc_vblank_put(crtc);
-       }
-}
-
 static void
 rockchip_atomic_commit_tail(struct drm_atomic_state *state)
 {
@@ -233,11 +183,12 @@ rockchip_atomic_commit_tail(struct drm_atomic_state *state)
 
        drm_atomic_helper_commit_modeset_enables(dev, state);
 
-       drm_atomic_helper_commit_planes(dev, state, true);
+       drm_atomic_helper_commit_planes(dev, state,
+                                       DRM_PLANE_COMMIT_ACTIVE_ONLY);
 
        drm_atomic_helper_commit_hw_done(state);
 
-       rockchip_atomic_wait_for_complete(dev, state);
+       drm_atomic_helper_wait_for_vblanks(dev, state);
 
        drm_atomic_helper_cleanup_planes(dev, state);
 }
index 207e01d..a16c69f 100644 (file)
@@ -20,6 +20,7 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 #include "rockchip_drm_fb.h"
+#include "rockchip_drm_fbdev.h"
 
 #define PREFERRED_BPP          32
 #define to_drm_private(x) \
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
new file mode 100644 (file)
index 0000000..a553e18
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Yakir Yang <ykk@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_psr.h"
+
+#define PSR_FLUSH_TIMEOUT      msecs_to_jiffies(100)
+
+enum psr_state {
+       PSR_FLUSH,
+       PSR_ENABLE,
+       PSR_DISABLE,
+};
+
+struct psr_drv {
+       struct list_head        list;
+       struct drm_encoder      *encoder;
+
+       spinlock_t              lock;
+       bool                    active;
+       enum psr_state          state;
+
+       struct timer_list       flush_timer;
+
+       void (*set)(struct drm_encoder *encoder, bool enable);
+};
+
+static struct psr_drv *find_psr_by_crtc(struct drm_crtc *crtc)
+{
+       struct rockchip_drm_private *drm_drv = crtc->dev->dev_private;
+       struct psr_drv *psr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
+       list_for_each_entry(psr, &drm_drv->psr_list, list) {
+               if (psr->encoder->crtc == crtc)
+                       goto out;
+       }
+       psr = ERR_PTR(-ENODEV);
+
+out:
+       spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
+       return psr;
+}
+
+static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state)
+{
+       /*
+        * Allowed finite state machine:
+        *
+        *   PSR_ENABLE  < = = = = = >  PSR_FLUSH
+        *       | ^                        |
+        *       | |                        |
+        *       v |                        |
+        *   PSR_DISABLE < - - - - - - - - -
+        */
+       if (state == psr->state || !psr->active)
+               return;
+
+       /* Already disabled in flush, change the state, but not the hardware */
+       if (state == PSR_DISABLE && psr->state == PSR_FLUSH) {
+               psr->state = state;
+               return;
+       }
+
+       psr->state = state;
+
+       /* Actually commit the state change to hardware */
+       switch (psr->state) {
+       case PSR_ENABLE:
+               psr->set(psr->encoder, true);
+               break;
+
+       case PSR_DISABLE:
+       case PSR_FLUSH:
+               psr->set(psr->encoder, false);
+               break;
+       }
+}
+
+static void psr_set_state(struct psr_drv *psr, enum psr_state state)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&psr->lock, flags);
+       psr_set_state_locked(psr, state);
+       spin_unlock_irqrestore(&psr->lock, flags);
+}
+
+static void psr_flush_handler(unsigned long data)
+{
+       struct psr_drv *psr = (struct psr_drv *)data;
+       unsigned long flags;
+
+       /* If the state has changed since we initiated the flush, do nothing */
+       spin_lock_irqsave(&psr->lock, flags);
+       if (psr->state == PSR_FLUSH)
+               psr_set_state_locked(psr, PSR_ENABLE);
+       spin_unlock_irqrestore(&psr->lock, flags);
+}
+
+/**
+ * rockchip_drm_psr_activate - activate PSR on the given pipe
+ * @crtc: CRTC to obtain the PSR encoder
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int rockchip_drm_psr_activate(struct drm_crtc *crtc)
+{
+       struct psr_drv *psr = find_psr_by_crtc(crtc);
+       unsigned long flags;
+
+       if (IS_ERR(psr))
+               return PTR_ERR(psr);
+
+       spin_lock_irqsave(&psr->lock, flags);
+       psr->active = true;
+       spin_unlock_irqrestore(&psr->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(rockchip_drm_psr_activate);
+
+/**
+ * rockchip_drm_psr_deactivate - deactivate PSR on the given pipe
+ * @crtc: CRTC to obtain the PSR encoder
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int rockchip_drm_psr_deactivate(struct drm_crtc *crtc)
+{
+       struct psr_drv *psr = find_psr_by_crtc(crtc);
+       unsigned long flags;
+
+       if (IS_ERR(psr))
+               return PTR_ERR(psr);
+
+       spin_lock_irqsave(&psr->lock, flags);
+       psr->active = false;
+       spin_unlock_irqrestore(&psr->lock, flags);
+       del_timer_sync(&psr->flush_timer);
+
+       return 0;
+}
+EXPORT_SYMBOL(rockchip_drm_psr_deactivate);
+
+static void rockchip_drm_do_flush(struct psr_drv *psr)
+{
+       mod_timer(&psr->flush_timer,
+                 round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT));
+       psr_set_state(psr, PSR_FLUSH);
+}
+
+/**
+ * rockchip_drm_psr_flush - flush a single pipe
+ * @crtc: CRTC of the pipe to flush
+ *
+ * Returns:
+ * 0 on success, -errno on fail
+ */
+int rockchip_drm_psr_flush(struct drm_crtc *crtc)
+{
+       struct psr_drv *psr = find_psr_by_crtc(crtc);
+       if (IS_ERR(psr))
+               return PTR_ERR(psr);
+
+       rockchip_drm_do_flush(psr);
+       return 0;
+}
+EXPORT_SYMBOL(rockchip_drm_psr_flush);
+
+/**
+ * rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
+ * @dev: drm device
+ *
+ * Disable the PSR function for all registered encoders, and then enable the
+ * PSR function back after PSR_FLUSH_TIMEOUT. If encoder PSR state have been
+ * changed during flush time, then keep the state no change after flush
+ * timeout.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+void rockchip_drm_psr_flush_all(struct drm_device *dev)
+{
+       struct rockchip_drm_private *drm_drv = dev->dev_private;
+       struct psr_drv *psr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
+       list_for_each_entry(psr, &drm_drv->psr_list, list)
+               rockchip_drm_do_flush(psr);
+       spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
+}
+EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
+
+/**
+ * rockchip_drm_psr_register - register encoder to psr driver
+ * @encoder: encoder that obtain the PSR function
+ * @psr_set: call back to set PSR state
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int rockchip_drm_psr_register(struct drm_encoder *encoder,
+                       void (*psr_set)(struct drm_encoder *, bool enable))
+{
+       struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
+       struct psr_drv *psr;
+       unsigned long flags;
+
+       if (!encoder || !psr_set)
+               return -EINVAL;
+
+       psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
+       if (!psr)
+               return -ENOMEM;
+
+       setup_timer(&psr->flush_timer, psr_flush_handler, (unsigned long)psr);
+       spin_lock_init(&psr->lock);
+
+       psr->active = true;
+       psr->state = PSR_DISABLE;
+       psr->encoder = encoder;
+       psr->set = psr_set;
+
+       spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
+       list_add_tail(&psr->list, &drm_drv->psr_list);
+       spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(rockchip_drm_psr_register);
+
+/**
+ * rockchip_drm_psr_unregister - unregister encoder to psr driver
+ * @encoder: encoder that obtain the PSR function
+ * @psr_set: call back to set PSR state
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
+{
+       struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
+       struct psr_drv *psr, *n;
+       unsigned long flags;
+
+       spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
+       list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
+               if (psr->encoder == encoder) {
+                       del_timer(&psr->flush_timer);
+                       list_del(&psr->list);
+                       kfree(psr);
+               }
+       }
+       spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
+}
+EXPORT_SYMBOL(rockchip_drm_psr_unregister);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
new file mode 100644 (file)
index 0000000..b420cf1
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Yakir Yang <ykk@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ROCKCHIP_DRM_PSR___
+#define __ROCKCHIP_DRM_PSR___
+
+void rockchip_drm_psr_flush_all(struct drm_device *dev);
+int rockchip_drm_psr_flush(struct drm_crtc *crtc);
+
+int rockchip_drm_psr_activate(struct drm_crtc *crtc);
+int rockchip_drm_psr_deactivate(struct drm_crtc *crtc);
+
+int rockchip_drm_psr_register(struct drm_encoder *encoder,
+                       void (*psr_set)(struct drm_encoder *, bool enable));
+void rockchip_drm_psr_unregister(struct drm_encoder *encoder);
+
+#endif /* __ROCKCHIP_DRM_PSR__ */
index 91305eb..c7eba30 100644 (file)
 #include <drm/drm_atomic.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_flip_work.h>
 #include <drm/drm_plane_helper.h>
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/iopoll.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 #include "rockchip_drm_fb.h"
+#include "rockchip_drm_psr.h"
 #include "rockchip_drm_vop.h"
 
-#define __REG_SET_RELAXED(x, off, mask, shift, v) \
-               vop_mask_write_relaxed(x, off, (mask) << shift, (v) << shift)
-#define __REG_SET_NORMAL(x, off, mask, shift, v) \
-               vop_mask_write(x, off, (mask) << shift, (v) << shift)
+#define __REG_SET_RELAXED(x, off, mask, shift, v, write_mask) \
+               vop_mask_write(x, off, mask, shift, v, write_mask, true)
+
+#define __REG_SET_NORMAL(x, off, mask, shift, v, write_mask) \
+               vop_mask_write(x, off, mask, shift, v, write_mask, false)
 
 #define REG_SET(x, base, reg, v, mode) \
-               __REG_SET_##mode(x, base + reg.offset, reg.mask, reg.shift, v)
+               __REG_SET_##mode(x, base + reg.offset, \
+                                reg.mask, reg.shift, v, reg.write_mask)
 #define REG_SET_MASK(x, base, reg, mask, v, mode) \
-               __REG_SET_##mode(x, base + reg.offset, mask, reg.shift, v)
+               __REG_SET_##mode(x, base + reg.offset, \
+                                mask, reg.shift, v, reg.write_mask)
 
 #define VOP_WIN_SET(x, win, name, v) \
                REG_SET(x, win->base, win->phy->name, v, RELAXED)
 
 #define to_vop(x) container_of(x, struct vop, crtc)
 #define to_vop_win(x) container_of(x, struct vop_win, base)
-#define to_vop_plane_state(x) container_of(x, struct vop_plane_state, base)
 
-struct vop_plane_state {
-       struct drm_plane_state base;
-       int format;
-       struct drm_rect src;
-       struct drm_rect dest;
-       dma_addr_t yrgb_mst;
-       bool enable;
+enum vop_pending {
+       VOP_PENDING_FB_UNREF,
 };
 
 struct vop_win {
        struct drm_plane base;
        const struct vop_win_data *data;
        struct vop *vop;
-
-       /* protected by dev->event_lock */
-       bool enable;
-       dma_addr_t yrgb_mst;
 };
 
 struct vop {
@@ -113,11 +109,15 @@ struct vop {
        struct mutex vsync_mutex;
        bool vsync_work_pending;
        struct completion dsp_hold_completion;
-       struct completion wait_update_complete;
 
        /* protected by dev->event_lock */
        struct drm_pending_vblank_event *event;
 
+       struct drm_flip_work fb_unref_work;
+       unsigned long pending;
+
+       struct completion line_flag_completion;
+
        const struct vop_data *data;
 
        uint32_t *regsbak;
@@ -164,27 +164,25 @@ static inline uint32_t vop_read_reg(struct vop *vop, uint32_t base,
 }
 
 static inline void vop_mask_write(struct vop *vop, uint32_t offset,
-                                 uint32_t mask, uint32_t v)
+                                 uint32_t mask, uint32_t shift, uint32_t v,
+                                 bool write_mask, bool relaxed)
 {
-       if (mask) {
-               uint32_t cached_val = vop->regsbak[offset >> 2];
-
-               cached_val = (cached_val & ~mask) | v;
-               writel(cached_val, vop->regs + offset);
-               vop->regsbak[offset >> 2] = cached_val;
-       }
-}
+       if (!mask)
+               return;
 
-static inline void vop_mask_write_relaxed(struct vop *vop, uint32_t offset,
-                                         uint32_t mask, uint32_t v)
-{
-       if (mask) {
+       if (write_mask) {
+               v = ((v << shift) & 0xffff) | (mask << (shift + 16));
+       } else {
                uint32_t cached_val = vop->regsbak[offset >> 2];
 
-               cached_val = (cached_val & ~mask) | v;
-               writel_relaxed(cached_val, vop->regs + offset);
-               vop->regsbak[offset >> 2] = cached_val;
+               v = (cached_val & ~(mask << shift)) | ((v & mask) << shift);
+               vop->regsbak[offset >> 2] = v;
        }
+
+       if (relaxed)
+               writel_relaxed(v, vop->regs + offset);
+       else
+               writel(v, vop->regs + offset);
 }
 
 static inline uint32_t vop_get_intr_type(struct vop *vop,
@@ -240,7 +238,7 @@ static enum vop_data_format vop_convert_format(uint32_t format)
        case DRM_FORMAT_NV24:
                return VOP_FMT_YUV444SP;
        default:
-               DRM_ERROR("unsupport format[%08x]\n", format);
+               DRM_ERROR("unsupported format[%08x]\n", format);
                return -EINVAL;
        }
 }
@@ -317,7 +315,7 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win,
        int vskiplines = 0;
 
        if (dst_w > 3840) {
-               DRM_ERROR("Maximum destination width (3840) exceeded\n");
+               DRM_DEV_ERROR(vop->dev, "Maximum dst width (3840) exceeded\n");
                return;
        }
 
@@ -355,11 +353,11 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win,
        VOP_SCL_SET_EXT(vop, win, lb_mode, lb_mode);
        if (lb_mode == LB_RGB_3840X2) {
                if (yrgb_ver_scl_mode != SCALE_NONE) {
-                       DRM_ERROR("ERROR : not allow yrgb ver scale\n");
+                       DRM_DEV_ERROR(vop->dev, "not allow yrgb ver scale\n");
                        return;
                }
                if (cbcr_ver_scl_mode != SCALE_NONE) {
-                       DRM_ERROR("ERROR : not allow cbcr ver scale\n");
+                       DRM_DEV_ERROR(vop->dev, "not allow cbcr ver scale\n");
                        return;
                }
                vsu_mode = SCALE_UP_BIL;
@@ -411,6 +409,7 @@ static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
 
        spin_lock_irqsave(&vop->irq_lock, flags);
 
+       VOP_INTR_SET_TYPE(vop, clear, DSP_HOLD_VALID_INTR, 1);
        VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 1);
 
        spin_unlock_irqrestore(&vop->irq_lock, flags);
@@ -430,7 +429,73 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
        spin_unlock_irqrestore(&vop->irq_lock, flags);
 }
 
-static void vop_enable(struct drm_crtc *crtc)
+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ *     the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num,
+ *      to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG -------------------------------+
+ * FRAME_SYNC ----+                         |
+ *                |                         |
+ *                v                         v
+ *                | Vsync | Vbp |  Vactive  | Vfp |
+ *                        ^     ^           ^     ^
+ *                        |     |           |     |
+ *                        |     |           |     |
+ * dsp_vs_end ------------+     |           |     |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --------------+           |     |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end ----------------------------+     |   VOP_DSP_VACT_ST_END
+ * dsp_total -------------------------------------+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+       uint32_t line_flag_irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vop->irq_lock, flags);
+
+       line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+       spin_unlock_irqrestore(&vop->irq_lock, flags);
+
+       return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+       unsigned long flags;
+
+       if (WARN_ON(!vop->is_enabled))
+               return;
+
+       spin_lock_irqsave(&vop->irq_lock, flags);
+
+       VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+       VOP_INTR_SET_TYPE(vop, clear, LINE_FLAG_INTR, 1);
+       VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+       spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+       unsigned long flags;
+
+       if (WARN_ON(!vop->is_enabled))
+               return;
+
+       spin_lock_irqsave(&vop->irq_lock, flags);
+
+       VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0);
+
+       spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
+static int vop_enable(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
        int ret;
@@ -438,26 +503,20 @@ static void vop_enable(struct drm_crtc *crtc)
        ret = pm_runtime_get_sync(vop->dev);
        if (ret < 0) {
                dev_err(vop->dev, "failed to get pm runtime: %d\n", ret);
-               return;
+               goto err_put_pm_runtime;
        }
 
        ret = clk_enable(vop->hclk);
-       if (ret < 0) {
-               dev_err(vop->dev, "failed to enable hclk - %d\n", ret);
-               return;
-       }
+       if (WARN_ON(ret < 0))
+               goto err_put_pm_runtime;
 
        ret = clk_enable(vop->dclk);
-       if (ret < 0) {
-               dev_err(vop->dev, "failed to enable dclk - %d\n", ret);
+       if (WARN_ON(ret < 0))
                goto err_disable_hclk;
-       }
 
        ret = clk_enable(vop->aclk);
-       if (ret < 0) {
-               dev_err(vop->dev, "failed to enable aclk - %d\n", ret);
+       if (WARN_ON(ret < 0))
                goto err_disable_dclk;
-       }
 
        /*
         * Slave iommu shares power, irq and clock with vop.  It was associated
@@ -487,7 +546,7 @@ static void vop_enable(struct drm_crtc *crtc)
 
        drm_crtc_vblank_on(crtc);
 
-       return;
+       return 0;
 
 err_disable_aclk:
        clk_disable(vop->aclk);
@@ -495,6 +554,9 @@ err_disable_dclk:
        clk_disable(vop->dclk);
 err_disable_hclk:
        clk_disable(vop->hclk);
+err_put_pm_runtime:
+       pm_runtime_put_sync(vop->dev);
+       return ret;
 }
 
 static void vop_crtc_disable(struct drm_crtc *crtc)
@@ -504,6 +566,8 @@ static void vop_crtc_disable(struct drm_crtc *crtc)
 
        WARN_ON(vop->event);
 
+       rockchip_drm_psr_deactivate(&vop->crtc);
+
        /*
         * We need to make sure that all windows are disabled before we
         * disable that crtc. Otherwise we might try to scan from a destroyed
@@ -568,22 +632,6 @@ static void vop_plane_destroy(struct drm_plane *plane)
        drm_plane_cleanup(plane);
 }
 
-static int vop_plane_prepare_fb(struct drm_plane *plane,
-                               const struct drm_plane_state *new_state)
-{
-       if (plane->state->fb)
-               drm_framebuffer_reference(plane->state->fb);
-
-       return 0;
-}
-
-static void vop_plane_cleanup_fb(struct drm_plane *plane,
-                                const struct drm_plane_state *old_state)
-{
-       if (old_state->fb)
-               drm_framebuffer_unreference(old_state->fb);
-}
-
 static int vop_plane_atomic_check(struct drm_plane *plane,
                           struct drm_plane_state *state)
 {
@@ -591,12 +639,8 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
        struct drm_crtc_state *crtc_state;
        struct drm_framebuffer *fb = state->fb;
        struct vop_win *vop_win = to_vop_win(plane);
-       struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
        const struct vop_win_data *win = vop_win->data;
-       bool visible;
        int ret;
-       struct drm_rect *dest = &vop_plane_state->dest;
-       struct drm_rect *src = &vop_plane_state->src;
        struct drm_rect clip;
        int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
                                        DRM_PLANE_HELPER_NO_SCALING;
@@ -604,62 +648,43 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
                                        DRM_PLANE_HELPER_NO_SCALING;
 
        if (!crtc || !fb)
-               goto out_disable;
+               return 0;
 
        crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
        if (WARN_ON(!crtc_state))
                return -EINVAL;
 
-       src->x1 = state->src_x;
-       src->y1 = state->src_y;
-       src->x2 = state->src_x + state->src_w;
-       src->y2 = state->src_y + state->src_h;
-       dest->x1 = state->crtc_x;
-       dest->y1 = state->crtc_y;
-       dest->x2 = state->crtc_x + state->crtc_w;
-       dest->y2 = state->crtc_y + state->crtc_h;
-
        clip.x1 = 0;
        clip.y1 = 0;
        clip.x2 = crtc_state->adjusted_mode.hdisplay;
        clip.y2 = crtc_state->adjusted_mode.vdisplay;
 
-       ret = drm_plane_helper_check_update(plane, crtc, state->fb,
-                                           src, dest, &clip,
-                                           state->rotation,
-                                           min_scale,
-                                           max_scale,
-                                           true, true, &visible);
+       ret = drm_plane_helper_check_state(state, &clip,
+                                          min_scale, max_scale,
+                                          true, true);
        if (ret)
                return ret;
 
-       if (!visible)
-               goto out_disable;
+       if (!state->visible)
+               return 0;
 
-       vop_plane_state->format = vop_convert_format(fb->pixel_format);
-       if (vop_plane_state->format < 0)
-               return vop_plane_state->format;
+       ret = vop_convert_format(fb->pixel_format);
+       if (ret < 0)
+               return ret;
 
        /*
         * Src.x1 can be odd when do clip, but yuv plane start point
         * need align with 2 pixel.
         */
-       if (is_yuv_support(fb->pixel_format) && ((src->x1 >> 16) % 2))
+       if (is_yuv_support(fb->pixel_format) && ((state->src.x1 >> 16) % 2))
                return -EINVAL;
 
-       vop_plane_state->enable = true;
-
-       return 0;
-
-out_disable:
-       vop_plane_state->enable = false;
        return 0;
 }
 
 static void vop_plane_atomic_disable(struct drm_plane *plane,
                                     struct drm_plane_state *old_state)
 {
-       struct vop_plane_state *vop_plane_state = to_vop_plane_state(old_state);
        struct vop_win *vop_win = to_vop_win(plane);
        const struct vop_win_data *win = vop_win->data;
        struct vop *vop = to_vop(old_state->crtc);
@@ -667,18 +692,11 @@ static void vop_plane_atomic_disable(struct drm_plane *plane,
        if (!old_state->crtc)
                return;
 
-       spin_lock_irq(&plane->dev->event_lock);
-       vop_win->enable = false;
-       vop_win->yrgb_mst = 0;
-       spin_unlock_irq(&plane->dev->event_lock);
-
        spin_lock(&vop->reg_lock);
 
        VOP_WIN_SET(vop, win, enable, 0);
 
        spin_unlock(&vop->reg_lock);
-
-       vop_plane_state->enable = false;
 }
 
 static void vop_plane_atomic_update(struct drm_plane *plane,
@@ -687,21 +705,21 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
        struct drm_plane_state *state = plane->state;
        struct drm_crtc *crtc = state->crtc;
        struct vop_win *vop_win = to_vop_win(plane);
-       struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
        const struct vop_win_data *win = vop_win->data;
        struct vop *vop = to_vop(state->crtc);
        struct drm_framebuffer *fb = state->fb;
        unsigned int actual_w, actual_h;
        unsigned int dsp_stx, dsp_sty;
        uint32_t act_info, dsp_info, dsp_st;
-       struct drm_rect *src = &vop_plane_state->src;
-       struct drm_rect *dest = &vop_plane_state->dest;
+       struct drm_rect *src = &state->src;
+       struct drm_rect *dest = &state->dst;
        struct drm_gem_object *obj, *uv_obj;
        struct rockchip_gem_object *rk_obj, *rk_uv_obj;
        unsigned long offset;
        dma_addr_t dma_addr;
        uint32_t val;
        bool rb_swap;
+       int format;
 
        /*
         * can't update plane when vop is disabled.
@@ -712,7 +730,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
        if (WARN_ON(!vop->is_enabled))
                return;
 
-       if (!vop_plane_state->enable) {
+       if (!state->visible) {
                vop_plane_atomic_disable(plane, old_state);
                return;
        }
@@ -733,18 +751,15 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 
        offset = (src->x1 >> 16) * drm_format_plane_cpp(fb->pixel_format, 0);
        offset += (src->y1 >> 16) * fb->pitches[0];
-       vop_plane_state->yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
+       dma_addr = rk_obj->dma_addr + offset + fb->offsets[0];
 
-       spin_lock_irq(&plane->dev->event_lock);
-       vop_win->enable = true;
-       vop_win->yrgb_mst = vop_plane_state->yrgb_mst;
-       spin_unlock_irq(&plane->dev->event_lock);
+       format = vop_convert_format(fb->pixel_format);
 
        spin_lock(&vop->reg_lock);
 
-       VOP_WIN_SET(vop, win, format, vop_plane_state->format);
+       VOP_WIN_SET(vop, win, format, format);
        VOP_WIN_SET(vop, win, yrgb_vir, fb->pitches[0] >> 2);
-       VOP_WIN_SET(vop, win, yrgb_mst, vop_plane_state->yrgb_mst);
+       VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
        if (is_yuv_support(fb->pixel_format)) {
                int hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
                int vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
@@ -791,68 +806,18 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 }
 
 static const struct drm_plane_helper_funcs plane_helper_funcs = {
-       .prepare_fb = vop_plane_prepare_fb,
-       .cleanup_fb = vop_plane_cleanup_fb,
        .atomic_check = vop_plane_atomic_check,
        .atomic_update = vop_plane_atomic_update,
        .atomic_disable = vop_plane_atomic_disable,
 };
 
-static void vop_atomic_plane_reset(struct drm_plane *plane)
-{
-       struct vop_plane_state *vop_plane_state =
-                                       to_vop_plane_state(plane->state);
-
-       if (plane->state && plane->state->fb)
-               drm_framebuffer_unreference(plane->state->fb);
-
-       kfree(vop_plane_state);
-       vop_plane_state = kzalloc(sizeof(*vop_plane_state), GFP_KERNEL);
-       if (!vop_plane_state)
-               return;
-
-       plane->state = &vop_plane_state->base;
-       plane->state->plane = plane;
-}
-
-static struct drm_plane_state *
-vop_atomic_plane_duplicate_state(struct drm_plane *plane)
-{
-       struct vop_plane_state *old_vop_plane_state;
-       struct vop_plane_state *vop_plane_state;
-
-       if (WARN_ON(!plane->state))
-               return NULL;
-
-       old_vop_plane_state = to_vop_plane_state(plane->state);
-       vop_plane_state = kmemdup(old_vop_plane_state,
-                                 sizeof(*vop_plane_state), GFP_KERNEL);
-       if (!vop_plane_state)
-               return NULL;
-
-       __drm_atomic_helper_plane_duplicate_state(plane,
-                                                 &vop_plane_state->base);
-
-       return &vop_plane_state->base;
-}
-
-static void vop_atomic_plane_destroy_state(struct drm_plane *plane,
-                                          struct drm_plane_state *state)
-{
-       struct vop_plane_state *vop_state = to_vop_plane_state(state);
-
-       __drm_atomic_helper_plane_destroy_state(state);
-
-       kfree(vop_state);
-}
-
 static const struct drm_plane_funcs vop_plane_funcs = {
        .update_plane   = drm_atomic_helper_update_plane,
        .disable_plane  = drm_atomic_helper_disable_plane,
        .destroy = vop_plane_destroy,
-       .reset = vop_atomic_plane_reset,
-       .atomic_duplicate_state = vop_atomic_plane_duplicate_state,
-       .atomic_destroy_state = vop_atomic_plane_destroy_state,
+       .reset = drm_atomic_helper_plane_reset,
+       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
 };
 
 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
@@ -865,6 +830,7 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
 
        spin_lock_irqsave(&vop->irq_lock, flags);
 
+       VOP_INTR_SET_TYPE(vop, clear, FS_INTR, 1);
        VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 1);
 
        spin_unlock_irqrestore(&vop->irq_lock, flags);
@@ -887,18 +853,9 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
        spin_unlock_irqrestore(&vop->irq_lock, flags);
 }
 
-static void vop_crtc_wait_for_update(struct drm_crtc *crtc)
-{
-       struct vop *vop = to_vop(crtc);
-
-       reinit_completion(&vop->wait_update_complete);
-       WARN_ON(!wait_for_completion_timeout(&vop->wait_update_complete, 100));
-}
-
 static const struct rockchip_crtc_funcs private_crtc_funcs = {
        .enable_vblank = vop_crtc_enable_vblank,
        .disable_vblank = vop_crtc_disable_vblank,
-       .wait_for_update = vop_crtc_wait_for_update,
 };
 
 static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -928,11 +885,17 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
        u16 vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
        u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start;
        u16 vact_end = vact_st + vdisplay;
-       uint32_t val;
+       uint32_t pin_pol, val;
+       int ret;
 
        WARN_ON(vop->event);
 
-       vop_enable(crtc);
+       ret = vop_enable(crtc);
+       if (ret) {
+               DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret);
+               return;
+       }
+
        /*
         * If dclk rate is zero, mean that scanout is stop,
         * we don't need wait any more.
@@ -969,25 +932,31 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
                vop_dsp_hold_valid_irq_disable(vop);
        }
 
-       val = 0x8;
-       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
-       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
-       VOP_CTRL_SET(vop, pin_pol, val);
+       pin_pol = 0x8;
+       pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
+       pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
+       VOP_CTRL_SET(vop, pin_pol, pin_pol);
+
        switch (s->output_type) {
        case DRM_MODE_CONNECTOR_LVDS:
                VOP_CTRL_SET(vop, rgb_en, 1);
+               VOP_CTRL_SET(vop, rgb_pin_pol, pin_pol);
                break;
        case DRM_MODE_CONNECTOR_eDP:
+               VOP_CTRL_SET(vop, edp_pin_pol, pin_pol);
                VOP_CTRL_SET(vop, edp_en, 1);
                break;
        case DRM_MODE_CONNECTOR_HDMIA:
+               VOP_CTRL_SET(vop, hdmi_pin_pol, pin_pol);
                VOP_CTRL_SET(vop, hdmi_en, 1);
                break;
        case DRM_MODE_CONNECTOR_DSI:
+               VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol);
                VOP_CTRL_SET(vop, mipi_en, 1);
                break;
        default:
-               DRM_ERROR("unsupport connector_type[%d]\n", s->output_type);
+               DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n",
+                             s->output_type);
        }
        VOP_CTRL_SET(vop, out_mode, s->output_mode);
 
@@ -1006,12 +975,44 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
        clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
 
        VOP_CTRL_SET(vop, standby, 0);
+
+       rockchip_drm_psr_activate(&vop->crtc);
+}
+
+static bool vop_fs_irq_is_pending(struct vop *vop)
+{
+       return VOP_INTR_GET_TYPE(vop, status, FS_INTR);
+}
+
+static void vop_wait_for_irq_handler(struct vop *vop)
+{
+       bool pending;
+       int ret;
+
+       /*
+        * Spin until frame start interrupt status bit goes low, which means
+        * that interrupt handler was invoked and cleared it. The timeout of
+        * 10 msecs is really too long, but it is just a safety measure if
+        * something goes really wrong. The wait will only happen in the very
+        * unlikely case of a vblank happening exactly at the same time and
+        * shouldn't exceed microseconds range.
+        */
+       ret = readx_poll_timeout_atomic(vop_fs_irq_is_pending, vop, pending,
+                                       !pending, 0, 10 * 1000);
+       if (ret)
+               DRM_DEV_ERROR(vop->dev, "VOP vblank IRQ stuck for 10 ms\n");
+
+       synchronize_irq(vop->irq);
 }
 
 static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
                                  struct drm_crtc_state *old_crtc_state)
 {
+       struct drm_atomic_state *old_state = old_crtc_state->state;
+       struct drm_plane_state *old_plane_state;
        struct vop *vop = to_vop(crtc);
+       struct drm_plane *plane;
+       int i;
 
        if (WARN_ON(!vop->is_enabled))
                return;
@@ -1021,12 +1022,13 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
        vop_cfg_done(vop);
 
        spin_unlock(&vop->reg_lock);
-}
 
-static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
-                                 struct drm_crtc_state *old_crtc_state)
-{
-       struct vop *vop = to_vop(crtc);
+       /*
+        * There is a (rather unlikely) possiblity that a vblank interrupt
+        * fired before we set the cfg_done bit. To avoid spuriously
+        * signalling flip completion we need to wait for it to finish.
+        */
+       vop_wait_for_irq_handler(vop);
 
        spin_lock_irq(&crtc->dev->event_lock);
        if (crtc->state->event) {
@@ -1037,6 +1039,25 @@ static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
                crtc->state->event = NULL;
        }
        spin_unlock_irq(&crtc->dev->event_lock);
+
+       for_each_plane_in_state(old_state, plane, old_plane_state, i) {
+               if (!old_plane_state->fb)
+                       continue;
+
+               if (old_plane_state->fb == plane->state->fb)
+                       continue;
+
+               drm_framebuffer_reference(old_plane_state->fb);
+               drm_flip_work_queue(&vop->fb_unref_work, old_plane_state->fb);
+               set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
+               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+       }
+}
+
+static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
+                                 struct drm_crtc_state *old_crtc_state)
+{
+       rockchip_drm_psr_flush(crtc);
 }
 
 static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
@@ -1093,16 +1114,13 @@ static const struct drm_crtc_funcs vop_crtc_funcs = {
        .atomic_destroy_state = vop_crtc_destroy_state,
 };
 
-static bool vop_win_pending_is_complete(struct vop_win *vop_win)
+static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
 {
-       dma_addr_t yrgb_mst;
-
-       if (!vop_win->enable)
-               return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0;
-
-       yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data);
+       struct vop *vop = container_of(work, struct vop, fb_unref_work);
+       struct drm_framebuffer *fb = val;
 
-       return yrgb_mst == vop_win->yrgb_mst;
+       drm_crtc_vblank_put(&vop->crtc);
+       drm_framebuffer_unreference(fb);
 }
 
 static void vop_handle_vblank(struct vop *vop)
@@ -1110,25 +1128,17 @@ static void vop_handle_vblank(struct vop *vop)
        struct drm_device *drm = vop->drm_dev;
        struct drm_crtc *crtc = &vop->crtc;
        unsigned long flags;
-       int i;
-
-       for (i = 0; i < vop->data->win_size; i++) {
-               if (!vop_win_pending_is_complete(&vop->win[i]))
-                       return;
-       }
 
        spin_lock_irqsave(&drm->event_lock, flags);
        if (vop->event) {
-
                drm_crtc_send_vblank_event(crtc, vop->event);
                drm_crtc_vblank_put(crtc);
                vop->event = NULL;
-
        }
        spin_unlock_irqrestore(&drm->event_lock, flags);
 
-       if (!completion_done(&vop->wait_update_complete))
-               complete(&vop->wait_update_complete);
+       if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending))
+               drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq);
 }
 
 static irqreturn_t vop_isr(int irq, void *data)
@@ -1162,6 +1172,12 @@ static irqreturn_t vop_isr(int irq, void *data)
                ret = IRQ_HANDLED;
        }
 
+       if (active_irqs & LINE_FLAG_INTR) {
+               complete(&vop->line_flag_completion);
+               active_irqs &= ~LINE_FLAG_INTR;
+               ret = IRQ_HANDLED;
+       }
+
        if (active_irqs & FS_INTR) {
                drm_crtc_handle_vblank(crtc);
                vop_handle_vblank(vop);
@@ -1171,7 +1187,8 @@ static irqreturn_t vop_isr(int irq, void *data)
 
        /* Unhandled irqs are spurious. */
        if (active_irqs)
-               DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
+               DRM_DEV_ERROR(vop->dev, "Unknown VOP IRQs: %#02x\n",
+                             active_irqs);
 
        return ret;
 }
@@ -1206,7 +1223,8 @@ static int vop_create_crtc(struct vop *vop)
                                               win_data->phy->nformats,
                                               win_data->type, NULL);
                if (ret) {
-                       DRM_ERROR("failed to initialize plane\n");
+                       DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",
+                                     ret);
                        goto err_cleanup_planes;
                }
 
@@ -1244,7 +1262,8 @@ static int vop_create_crtc(struct vop *vop)
                                               win_data->phy->nformats,
                                               win_data->type, NULL);
                if (ret) {
-                       DRM_ERROR("failed to initialize overlay plane\n");
+                       DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",
+                                     ret);
                        goto err_cleanup_crtc;
                }
                drm_plane_helper_add(&vop_win->base, &plane_helper_funcs);
@@ -1252,14 +1271,17 @@ static int vop_create_crtc(struct vop *vop)
 
        port = of_get_child_by_name(dev->of_node, "port");
        if (!port) {
-               DRM_ERROR("no port node found in %s\n",
-                         dev->of_node->full_name);
+               DRM_DEV_ERROR(vop->dev, "no port node found in %s\n",
+                             dev->of_node->full_name);
                ret = -ENOENT;
                goto err_cleanup_crtc;
        }
 
+       drm_flip_work_init(&vop->fb_unref_work, "fb_unref",
+                          vop_fb_unref_worker);
+
        init_completion(&vop->dsp_hold_completion);
-       init_completion(&vop->wait_update_complete);
+       init_completion(&vop->line_flag_completion);
        crtc->port = port;
        rockchip_register_crtc_funcs(crtc, &private_crtc_funcs);
 
@@ -1300,6 +1322,7 @@ static void vop_destroy_crtc(struct vop *vop)
         * references the CRTC.
         */
        drm_crtc_cleanup(crtc);
+       drm_flip_work_cleanup(&vop->fb_unref_work);
 }
 
 static int vop_initial(struct vop *vop)
@@ -1416,6 +1439,49 @@ static void vop_win_init(struct vop *vop)
        }
 }
 
+/**
+ * rockchip_drm_wait_line_flag - acqiure the give line flag event
+ * @crtc: CRTC to enable line flag
+ * @line_num: interested line number
+ * @mstimeout: millisecond for timeout
+ *
+ * Driver would hold here until the interested line flag interrupt have
+ * happened or timeout to wait.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+                               unsigned int mstimeout)
+{
+       struct vop *vop = to_vop(crtc);
+       unsigned long jiffies_left;
+
+       if (!crtc || !vop->is_enabled)
+               return -ENODEV;
+
+       if (line_num > crtc->mode.vtotal || mstimeout <= 0)
+               return -EINVAL;
+
+       if (vop_line_flag_irq_is_enabled(vop))
+               return -EBUSY;
+
+       reinit_completion(&vop->line_flag_completion);
+       vop_line_flag_irq_enable(vop, line_num);
+
+       jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion,
+                                                  msecs_to_jiffies(mstimeout));
+       vop_line_flag_irq_disable(vop);
+
+       if (jiffies_left == 0) {
+               dev_err(vop->dev, "Timeout waiting for IRQ\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(rockchip_drm_wait_line_flag);
+
 static int vop_bind(struct device *dev, struct device *master, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -1481,10 +1547,15 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
 
        ret = vop_create_crtc(vop);
        if (ret)
-               return ret;
+               goto err_enable_irq;
 
        pm_runtime_enable(&pdev->dev);
+
        return 0;
+
+err_enable_irq:
+       enable_irq(vop->irq); /* To balance out the disable_irq above */
+       return ret;
 }
 
 static void vop_unbind(struct device *dev, struct device *master, void *data)
index 071ff0b..1dbc526 100644 (file)
@@ -33,6 +33,7 @@ struct vop_reg {
        uint32_t offset;
        uint32_t shift;
        uint32_t mask;
+       bool write_mask;
 };
 
 struct vop_ctrl {
@@ -48,6 +49,10 @@ struct vop_ctrl {
        struct vop_reg dither_down;
        struct vop_reg dither_up;
        struct vop_reg pin_pol;
+       struct vop_reg rgb_pin_pol;
+       struct vop_reg hdmi_pin_pol;
+       struct vop_reg edp_pin_pol;
+       struct vop_reg mipi_pin_pol;
 
        struct vop_reg htotal_pw;
        struct vop_reg hact_st_end;
@@ -56,6 +61,8 @@ struct vop_ctrl {
        struct vop_reg hpost_st_end;
        struct vop_reg vpost_st_end;
 
+       struct vop_reg line_flag_num[2];
+
        struct vop_reg cfg_done;
 };
 
index 919992c..35c51f3 100644 (file)
 #define VOP_REG(off, _mask, s) \
                {.offset = off, \
                 .mask = _mask, \
-                .shift = s,}
+                .shift = s, \
+                .write_mask = false,}
+
+#define VOP_REG_MASK(off, _mask, s) \
+               {.offset = off, \
+                .mask = _mask, \
+                .shift = s, \
+                .write_mask = true,}
 
 static const uint32_t formats_win_full[] = {
        DRM_FORMAT_XRGB8888,
@@ -50,6 +57,89 @@ static const uint32_t formats_win_lite[] = {
        DRM_FORMAT_BGR565,
 };
 
+static const struct vop_scl_regs rk3036_win_scl = {
+       .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
+       .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
+       .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
+       .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
+};
+
+static const struct vop_win_phy rk3036_win0_data = {
+       .scl = &rk3036_win_scl,
+       .data_formats = formats_win_full,
+       .nformats = ARRAY_SIZE(formats_win_full),
+       .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
+       .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
+       .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
+       .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0),
+       .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0),
+       .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0),
+       .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0),
+       .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
+       .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
+       .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16),
+};
+
+static const struct vop_win_phy rk3036_win1_data = {
+       .data_formats = formats_win_lite,
+       .nformats = ARRAY_SIZE(formats_win_lite),
+       .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
+       .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
+       .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
+       .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0),
+       .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0),
+       .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
+       .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
+       .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
+};
+
+static const struct vop_win_data rk3036_vop_win_data[] = {
+       { .base = 0x00, .phy = &rk3036_win0_data,
+         .type = DRM_PLANE_TYPE_PRIMARY },
+       { .base = 0x00, .phy = &rk3036_win1_data,
+         .type = DRM_PLANE_TYPE_CURSOR },
+};
+
+static const int rk3036_vop_intrs[] = {
+       DSP_HOLD_VALID_INTR,
+       FS_INTR,
+       LINE_FLAG_INTR,
+       BUS_ERROR_INTR,
+};
+
+static const struct vop_intr rk3036_intr = {
+       .intrs = rk3036_vop_intrs,
+       .nintrs = ARRAY_SIZE(rk3036_vop_intrs),
+       .status = VOP_REG(RK3036_INT_STATUS, 0xf, 0),
+       .enable = VOP_REG(RK3036_INT_STATUS, 0xf, 4),
+       .clear = VOP_REG(RK3036_INT_STATUS, 0xf, 8),
+};
+
+static const struct vop_ctrl rk3036_ctrl_data = {
+       .standby = VOP_REG(RK3036_SYS_CTRL, 0x1, 30),
+       .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
+       .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
+       .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
+       .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
+       .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
+       .vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0),
+       .line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12),
+       .cfg_done = VOP_REG(RK3036_REG_CFG_DONE, 0x1, 0),
+};
+
+static const struct vop_reg_data rk3036_vop_init_reg_table[] = {
+       {RK3036_DSP_CTRL1, 0x00000000},
+};
+
+static const struct vop_data rk3036_vop = {
+       .init_table = rk3036_vop_init_reg_table,
+       .table_size = ARRAY_SIZE(rk3036_vop_init_reg_table),
+       .ctrl = &rk3036_ctrl_data,
+       .intr = &rk3036_intr,
+       .win = rk3036_vop_win_data,
+       .win_size = ARRAY_SIZE(rk3036_vop_win_data),
+};
+
 static const struct vop_scl_extension rk3288_win_full_scl_ext = {
        .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
        .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
@@ -133,6 +223,7 @@ static const struct vop_ctrl rk3288_ctrl_data = {
        .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
        .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
        .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
+       .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12),
        .cfg_done = VOP_REG(RK3288_REG_CFG_DONE, 0x1, 0),
 };
 
@@ -190,93 +281,104 @@ static const struct vop_data rk3288_vop = {
        .win_size = ARRAY_SIZE(rk3288_vop_win_data),
 };
 
-static const struct vop_scl_regs rk3036_win_scl = {
-       .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
-       .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
-       .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
-       .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
-};
-
-static const struct vop_win_phy rk3036_win0_data = {
-       .scl = &rk3036_win_scl,
-       .data_formats = formats_win_full,
-       .nformats = ARRAY_SIZE(formats_win_full),
-       .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
-       .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
-       .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
-       .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0),
-       .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0),
-       .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0),
-       .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0),
-       .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
-       .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
-       .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16),
+static const struct vop_ctrl rk3399_ctrl_data = {
+       .standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22),
+       .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23),
+       .rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12),
+       .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13),
+       .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14),
+       .mipi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 15),
+       .dither_down = VOP_REG(RK3399_DSP_CTRL1, 0xf, 1),
+       .dither_up = VOP_REG(RK3399_DSP_CTRL1, 0x1, 6),
+       .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19),
+       .out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0),
+       .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
+       .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20),
+       .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24),
+       .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28),
+       .htotal_pw = VOP_REG(RK3399_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
+       .hact_st_end = VOP_REG(RK3399_DSP_HACT_ST_END, 0x1fff1fff, 0),
+       .vtotal_pw = VOP_REG(RK3399_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
+       .vact_st_end = VOP_REG(RK3399_DSP_VACT_ST_END, 0x1fff1fff, 0),
+       .hpost_st_end = VOP_REG(RK3399_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
+       .vpost_st_end = VOP_REG(RK3399_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
+       .line_flag_num[0] = VOP_REG(RK3399_LINE_FLAG, 0xffff, 0),
+       .line_flag_num[1] = VOP_REG(RK3399_LINE_FLAG, 0xffff, 16),
+       .cfg_done = VOP_REG_MASK(RK3399_REG_CFG_DONE, 0x1, 0),
 };
 
-static const struct vop_win_phy rk3036_win1_data = {
-       .data_formats = formats_win_lite,
-       .nformats = ARRAY_SIZE(formats_win_lite),
-       .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
-       .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
-       .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
-       .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0),
-       .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0),
-       .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
-       .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
-       .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
-};
-
-static const struct vop_win_data rk3036_vop_win_data[] = {
-       { .base = 0x00, .phy = &rk3036_win0_data,
-         .type = DRM_PLANE_TYPE_PRIMARY },
-       { .base = 0x00, .phy = &rk3036_win1_data,
-         .type = DRM_PLANE_TYPE_CURSOR },
-};
-
-static const int rk3036_vop_intrs[] = {
-       DSP_HOLD_VALID_INTR,
+static const int rk3399_vop_intrs[] = {
        FS_INTR,
+       0, 0,
        LINE_FLAG_INTR,
+       0,
        BUS_ERROR_INTR,
+       0, 0, 0, 0, 0, 0, 0,
+       DSP_HOLD_VALID_INTR,
 };
 
-static const struct vop_intr rk3036_intr = {
-       .intrs = rk3036_vop_intrs,
-       .nintrs = ARRAY_SIZE(rk3036_vop_intrs),
-       .status = VOP_REG(RK3036_INT_STATUS, 0xf, 0),
-       .enable = VOP_REG(RK3036_INT_STATUS, 0xf, 4),
-       .clear = VOP_REG(RK3036_INT_STATUS, 0xf, 8),
+static const struct vop_intr rk3399_vop_intr = {
+       .intrs = rk3399_vop_intrs,
+       .nintrs = ARRAY_SIZE(rk3399_vop_intrs),
+       .status = VOP_REG_MASK(RK3399_INTR_STATUS0, 0xffff, 0),
+       .enable = VOP_REG_MASK(RK3399_INTR_EN0, 0xffff, 0),
+       .clear = VOP_REG_MASK(RK3399_INTR_CLEAR0, 0xffff, 0),
 };
 
-static const struct vop_ctrl rk3036_ctrl_data = {
-       .standby = VOP_REG(RK3036_SYS_CTRL, 0x1, 30),
-       .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
-       .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
-       .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
-       .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
-       .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
-       .vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0),
-       .cfg_done = VOP_REG(RK3036_REG_CFG_DONE, 0x1, 0),
+static const struct vop_reg_data rk3399_init_reg_table[] = {
+       {RK3399_SYS_CTRL, 0x2000f800},
+       {RK3399_DSP_CTRL0, 0x00000000},
+       {RK3399_WIN0_CTRL0, 0x00000080},
+       {RK3399_WIN1_CTRL0, 0x00000080},
+       /* TODO: Win2/3 support multiple area function, but we haven't found
+        * a suitable way to use it yet, so let's just use them as other windows
+        * with only area 0 enabled.
+        */
+       {RK3399_WIN2_CTRL0, 0x00000010},
+       {RK3399_WIN3_CTRL0, 0x00000010},
 };
 
-static const struct vop_reg_data rk3036_vop_init_reg_table[] = {
-       {RK3036_DSP_CTRL1, 0x00000000},
+static const struct vop_data rk3399_vop_big = {
+       .init_table = rk3399_init_reg_table,
+       .table_size = ARRAY_SIZE(rk3399_init_reg_table),
+       .intr = &rk3399_vop_intr,
+       .ctrl = &rk3399_ctrl_data,
+       /*
+        * rk3399 vop big windows register layout is same as rk3288.
+        */
+       .win = rk3288_vop_win_data,
+       .win_size = ARRAY_SIZE(rk3288_vop_win_data),
 };
 
-static const struct vop_data rk3036_vop = {
-       .init_table = rk3036_vop_init_reg_table,
-       .table_size = ARRAY_SIZE(rk3036_vop_init_reg_table),
-       .ctrl = &rk3036_ctrl_data,
-       .intr = &rk3036_intr,
-       .win = rk3036_vop_win_data,
-       .win_size = ARRAY_SIZE(rk3036_vop_win_data),
+static const struct vop_win_data rk3399_vop_lit_win_data[] = {
+       { .base = 0x00, .phy = &rk3288_win01_data,
+         .type = DRM_PLANE_TYPE_PRIMARY },
+       { .base = 0x00, .phy = &rk3288_win23_data,
+         .type = DRM_PLANE_TYPE_CURSOR},
+};
+
+static const struct vop_data rk3399_vop_lit = {
+       .init_table = rk3399_init_reg_table,
+       .table_size = ARRAY_SIZE(rk3399_init_reg_table),
+       .intr = &rk3399_vop_intr,
+       .ctrl = &rk3399_ctrl_data,
+       /*
+        * rk3399 vop lit windows register layout is same as rk3288,
+        * but cut off the win1 and win3 windows.
+        */
+       .win = rk3399_vop_lit_win_data,
+       .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
 };
 
 static const struct of_device_id vop_driver_dt_match[] = {
-       { .compatible = "rockchip,rk3288-vop",
-         .data = &rk3288_vop },
        { .compatible = "rockchip,rk3036-vop",
          .data = &rk3036_vop },
+       { .compatible = "rockchip,rk3288-vop",
+         .data = &rk3288_vop },
+       { .compatible = "rockchip,rk3399-vop-big",
+         .data = &rk3399_vop_big },
+       { .compatible = "rockchip,rk3399-vop-lit",
+         .data = &rk3399_vop_lit },
        {},
 };
 MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
@@ -305,7 +407,6 @@ static struct platform_driver vop_platform_driver = {
        .remove = vop_remove,
        .driver = {
                .name = "rockchip-vop",
-               .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(vop_driver_dt_match),
        },
 };
index d4b46cb..cd19726 100644 (file)
 #define RK3036_HWC_LUT_ADDR            0x800
 /* rk3036 register definition end */
 
+/* rk3399 register definition */
+#define RK3399_REG_CFG_DONE            0x00000
+#define RK3399_VERSION_INFO            0x00004
+#define RK3399_SYS_CTRL                        0x00008
+#define RK3399_SYS_CTRL1               0x0000c
+#define RK3399_DSP_CTRL0               0x00010
+#define RK3399_DSP_CTRL1               0x00014
+#define RK3399_DSP_BG                  0x00018
+#define RK3399_MCU_CTRL                        0x0001c
+#define RK3399_WB_CTRL0                        0x00020
+#define RK3399_WB_CTRL1                        0x00024
+#define RK3399_WB_YRGB_MST             0x00028
+#define RK3399_WB_CBR_MST              0x0002c
+#define RK3399_WIN0_CTRL0              0x00030
+#define RK3399_WIN0_CTRL1              0x00034
+#define RK3399_WIN0_COLOR_KEY          0x00038
+#define RK3399_WIN0_VIR                        0x0003c
+#define RK3399_WIN0_YRGB_MST           0x00040
+#define RK3399_WIN0_CBR_MST            0x00044
+#define RK3399_WIN0_ACT_INFO           0x00048
+#define RK3399_WIN0_DSP_INFO           0x0004c
+#define RK3399_WIN0_DSP_ST             0x00050
+#define RK3399_WIN0_SCL_FACTOR_YRGB    0x00054
+#define RK3399_WIN0_SCL_FACTOR_CBR     0x00058
+#define RK3399_WIN0_SCL_OFFSET         0x0005c
+#define RK3399_WIN0_SRC_ALPHA_CTRL     0x00060
+#define RK3399_WIN0_DST_ALPHA_CTRL     0x00064
+#define RK3399_WIN0_FADING_CTRL                0x00068
+#define RK3399_WIN0_CTRL2              0x0006c
+#define RK3399_WIN1_CTRL0              0x00070
+#define RK3399_WIN1_CTRL1              0x00074
+#define RK3399_WIN1_COLOR_KEY          0x00078
+#define RK3399_WIN1_VIR                        0x0007c
+#define RK3399_WIN1_YRGB_MST           0x00080
+#define RK3399_WIN1_CBR_MST            0x00084
+#define RK3399_WIN1_ACT_INFO           0x00088
+#define RK3399_WIN1_DSP_INFO           0x0008c
+#define RK3399_WIN1_DSP_ST             0x00090
+#define RK3399_WIN1_SCL_FACTOR_YRGB    0x00094
+#define RK3399_WIN1_SCL_FACTOR_CBR     0x00098
+#define RK3399_WIN1_SCL_OFFSET         0x0009c
+#define RK3399_WIN1_SRC_ALPHA_CTRL     0x000a0
+#define RK3399_WIN1_DST_ALPHA_CTRL     0x000a4
+#define RK3399_WIN1_FADING_CTRL                0x000a8
+#define RK3399_WIN1_CTRL2              0x000ac
+#define RK3399_WIN2_CTRL0              0x000b0
+#define RK3399_WIN2_CTRL1              0x000b4
+#define RK3399_WIN2_VIR0_1             0x000b8
+#define RK3399_WIN2_VIR2_3             0x000bc
+#define RK3399_WIN2_MST0               0x000c0
+#define RK3399_WIN2_DSP_INFO0          0x000c4
+#define RK3399_WIN2_DSP_ST0            0x000c8
+#define RK3399_WIN2_COLOR_KEY          0x000cc
+#define RK3399_WIN2_MST1               0x000d0
+#define RK3399_WIN2_DSP_INFO1          0x000d4
+#define RK3399_WIN2_DSP_ST1            0x000d8
+#define RK3399_WIN2_SRC_ALPHA_CTRL     0x000dc
+#define RK3399_WIN2_MST2               0x000e0
+#define RK3399_WIN2_DSP_INFO2          0x000e4
+#define RK3399_WIN2_DSP_ST2            0x000e8
+#define RK3399_WIN2_DST_ALPHA_CTRL     0x000ec
+#define RK3399_WIN2_MST3               0x000f0
+#define RK3399_WIN2_DSP_INFO3          0x000f4
+#define RK3399_WIN2_DSP_ST3            0x000f8
+#define RK3399_WIN2_FADING_CTRL                0x000fc
+#define RK3399_WIN3_CTRL0              0x00100
+#define RK3399_WIN3_CTRL1              0x00104
+#define RK3399_WIN3_VIR0_1             0x00108
+#define RK3399_WIN3_VIR2_3             0x0010c
+#define RK3399_WIN3_MST0               0x00110
+#define RK3399_WIN3_DSP_INFO0          0x00114
+#define RK3399_WIN3_DSP_ST0            0x00118
+#define RK3399_WIN3_COLOR_KEY          0x0011c
+#define RK3399_WIN3_MST1               0x00120
+#define RK3399_WIN3_DSP_INFO1          0x00124
+#define RK3399_WIN3_DSP_ST1            0x00128
+#define RK3399_WIN3_SRC_ALPHA_CTRL     0x0012c
+#define RK3399_WIN3_MST2               0x00130
+#define RK3399_WIN3_DSP_INFO2          0x00134
+#define RK3399_WIN3_DSP_ST2            0x00138
+#define RK3399_WIN3_DST_ALPHA_CTRL     0x0013c
+#define RK3399_WIN3_MST3               0x00140
+#define RK3399_WIN3_DSP_INFO3          0x00144
+#define RK3399_WIN3_DSP_ST3            0x00148
+#define RK3399_WIN3_FADING_CTRL                0x0014c
+#define RK3399_HWC_CTRL0               0x00150
+#define RK3399_HWC_CTRL1               0x00154
+#define RK3399_HWC_MST                 0x00158
+#define RK3399_HWC_DSP_ST              0x0015c
+#define RK3399_HWC_SRC_ALPHA_CTRL      0x00160
+#define RK3399_HWC_DST_ALPHA_CTRL      0x00164
+#define RK3399_HWC_FADING_CTRL         0x00168
+#define RK3399_HWC_RESERVED1           0x0016c
+#define RK3399_POST_DSP_HACT_INFO      0x00170
+#define RK3399_POST_DSP_VACT_INFO      0x00174
+#define RK3399_POST_SCL_FACTOR_YRGB    0x00178
+#define RK3399_POST_RESERVED           0x0017c
+#define RK3399_POST_SCL_CTRL           0x00180
+#define RK3399_POST_DSP_VACT_INFO_F1   0x00184
+#define RK3399_DSP_HTOTAL_HS_END       0x00188
+#define RK3399_DSP_HACT_ST_END         0x0018c
+#define RK3399_DSP_VTOTAL_VS_END       0x00190
+#define RK3399_DSP_VACT_ST_END         0x00194
+#define RK3399_DSP_VS_ST_END_F1                0x00198
+#define RK3399_DSP_VACT_ST_END_F1      0x0019c
+#define RK3399_PWM_CTRL                        0x001a0
+#define RK3399_PWM_PERIOD_HPR          0x001a4
+#define RK3399_PWM_DUTY_LPR            0x001a8
+#define RK3399_PWM_CNT                 0x001ac
+#define RK3399_BCSH_COLOR_BAR          0x001b0
+#define RK3399_BCSH_BCS                        0x001b4
+#define RK3399_BCSH_H                  0x001b8
+#define RK3399_BCSH_CTRL               0x001bc
+#define RK3399_CABC_CTRL0              0x001c0
+#define RK3399_CABC_CTRL1              0x001c4
+#define RK3399_CABC_CTRL2              0x001c8
+#define RK3399_CABC_CTRL3              0x001cc
+#define RK3399_CABC_GAUSS_LINE0_0      0x001d0
+#define RK3399_CABC_GAUSS_LINE0_1      0x001d4
+#define RK3399_CABC_GAUSS_LINE1_0      0x001d8
+#define RK3399_CABC_GAUSS_LINE1_1      0x001dc
+#define RK3399_CABC_GAUSS_LINE2_0      0x001e0
+#define RK3399_CABC_GAUSS_LINE2_1      0x001e4
+#define RK3399_FRC_LOWER01_0           0x001e8
+#define RK3399_FRC_LOWER01_1           0x001ec
+#define RK3399_FRC_LOWER10_0           0x001f0
+#define RK3399_FRC_LOWER10_1           0x001f4
+#define RK3399_FRC_LOWER11_0           0x001f8
+#define RK3399_FRC_LOWER11_1           0x001fc
+#define RK3399_AFBCD0_CTRL             0x00200
+#define RK3399_AFBCD0_HDR_PTR          0x00204
+#define RK3399_AFBCD0_PIC_SIZE         0x00208
+#define RK3399_AFBCD0_STATUS           0x0020c
+#define RK3399_AFBCD1_CTRL             0x00220
+#define RK3399_AFBCD1_HDR_PTR          0x00224
+#define RK3399_AFBCD1_PIC_SIZE         0x00228
+#define RK3399_AFBCD1_STATUS           0x0022c
+#define RK3399_AFBCD2_CTRL             0x00240
+#define RK3399_AFBCD2_HDR_PTR          0x00244
+#define RK3399_AFBCD2_PIC_SIZE         0x00248
+#define RK3399_AFBCD2_STATUS           0x0024c
+#define RK3399_AFBCD3_CTRL             0x00260
+#define RK3399_AFBCD3_HDR_PTR          0x00264
+#define RK3399_AFBCD3_PIC_SIZE         0x00268
+#define RK3399_AFBCD3_STATUS           0x0026c
+#define RK3399_INTR_EN0                        0x00280
+#define RK3399_INTR_CLEAR0             0x00284
+#define RK3399_INTR_STATUS0            0x00288
+#define RK3399_INTR_RAW_STATUS0                0x0028c
+#define RK3399_INTR_EN1                        0x00290
+#define RK3399_INTR_CLEAR1             0x00294
+#define RK3399_INTR_STATUS1            0x00298
+#define RK3399_INTR_RAW_STATUS1                0x0029c
+#define RK3399_LINE_FLAG               0x002a0
+#define RK3399_VOP_STATUS              0x002a4
+#define RK3399_BLANKING_VALUE          0x002a8
+#define RK3399_MCU_BYPASS_PORT         0x002ac
+#define RK3399_WIN0_DSP_BG             0x002b0
+#define RK3399_WIN1_DSP_BG             0x002b4
+#define RK3399_WIN2_DSP_BG             0x002b8
+#define RK3399_WIN3_DSP_BG             0x002bc
+#define RK3399_YUV2YUV_WIN             0x002c0
+#define RK3399_YUV2YUV_POST            0x002c4
+#define RK3399_AUTO_GATING_EN          0x002cc
+#define RK3399_WIN0_CSC_COE            0x003a0
+#define RK3399_WIN1_CSC_COE            0x003c0
+#define RK3399_WIN2_CSC_COE            0x003e0
+#define RK3399_WIN3_CSC_COE            0x00400
+#define RK3399_HWC_CSC_COE             0x00420
+#define RK3399_BCSH_R2Y_CSC_COE                0x00440
+#define RK3399_BCSH_Y2R_CSC_COE                0x00460
+#define RK3399_POST_YUV2YUV_Y2R_COE    0x00480
+#define RK3399_POST_YUV2YUV_3X3_COE    0x004a0
+#define RK3399_POST_YUV2YUV_R2Y_COE    0x004c0
+#define RK3399_WIN0_YUV2YUV_Y2R                0x004e0
+#define RK3399_WIN0_YUV2YUV_3X3                0x00500
+#define RK3399_WIN0_YUV2YUV_R2Y                0x00520
+#define RK3399_WIN1_YUV2YUV_Y2R                0x00540
+#define RK3399_WIN1_YUV2YUV_3X3                0x00560
+#define RK3399_WIN1_YUV2YUV_R2Y                0x00580
+#define RK3399_WIN2_YUV2YUV_Y2R                0x005a0
+#define RK3399_WIN2_YUV2YUV_3X3                0x005c0
+#define RK3399_WIN2_YUV2YUV_R2Y                0x005e0
+#define RK3399_WIN3_YUV2YUV_Y2R                0x00600
+#define RK3399_WIN3_YUV2YUV_3X3                0x00620
+#define RK3399_WIN3_YUV2YUV_R2Y                0x00640
+#define RK3399_WIN2_LUT_ADDR           0x01000
+#define RK3399_WIN3_LUT_ADDR           0x01400
+#define RK3399_HWC_LUT_ADDR            0x01800
+#define RK3399_CABC_GAMMA_LUT_ADDR     0x01c00
+#define RK3399_GAMMA_LUT_ADDR          0x02000
+/* rk3399 register definition end */
+
 #endif /* _ROCKCHIP_VOP_REG_H */
index 21aed1f..3b80713 100644 (file)
@@ -50,7 +50,7 @@ static const struct file_operations savage_driver_fops = {
 
 static struct drm_driver driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_HAVE_DMA | DRIVER_PCI_DMA,
+           DRIVER_USE_AGP | DRIVER_HAVE_DMA | DRIVER_PCI_DMA | DRIVER_LEGACY,
        .dev_priv_size = sizeof(drm_savage_buf_priv_t),
        .load = savage_driver_load,
        .firstopen = savage_driver_firstopen,
index c01ad0a..3dc0d8f 100644 (file)
@@ -1001,15 +1001,9 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_
                cmdbuf->cmd_addr = kcmd_addr;
        }
        if (cmdbuf->vb_size) {
-               kvb_addr = kmalloc(cmdbuf->vb_size, GFP_KERNEL);
-               if (kvb_addr == NULL) {
-                       ret = -ENOMEM;
-                       goto done;
-               }
-
-               if (copy_from_user(kvb_addr, cmdbuf->vb_addr,
-                                      cmdbuf->vb_size)) {
-                       ret = -EFAULT;
+               kvb_addr = memdup_user(cmdbuf->vb_addr, cmdbuf->vb_size);
+               if (IS_ERR(kvb_addr)) {
+                       ret = PTR_ERR(kvb_addr);
                        goto done;
                }
                cmdbuf->vb_addr = kvb_addr;
index 79bce76..ae98398 100644 (file)
@@ -102,7 +102,7 @@ static void sis_driver_postclose(struct drm_device *dev, struct drm_file *file)
 }
 
 static struct drm_driver driver = {
-       .driver_features = DRIVER_USE_AGP,
+       .driver_features = DRIVER_USE_AGP | DRIVER_LEGACY,
        .load = sis_driver_load,
        .unload = sis_driver_unload,
        .open = sis_driver_open,
index 494ab25..acd7286 100644 (file)
@@ -1,6 +1,6 @@
 config DRM_STI
-       tristate "DRM Support for STMicroelectronics SoC stiH41x Series"
-       depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM)
+       tristate "DRM Support for STMicroelectronics SoC stiH4xx Series"
+       depends on DRM && (ARCH_STI || ARCH_MULTIPLATFORM)
        select RESET_CONTROLLER
        select DRM_KMS_HELPER
        select DRM_GEM_CMA_HELPER
@@ -9,4 +9,4 @@ config DRM_STI
        select FW_LOADER
        select SND_SOC_HDMI_CODEC if SND_SOC
        help
-         Choose this option to enable DRM on STM stiH41x chipset
+         Choose this option to enable DRM on STM stiH4xx chipset
index b805762..d20f7c0 100644 (file)
@@ -9,7 +9,6 @@ sti-drm-y := \
        sti_crtc.o \
        sti_plane.o \
        sti_hdmi.o \
-       sti_hdmi_tx3g0c55phy.o \
        sti_hdmi_tx3g4c28phy.o \
        sti_dvo.o \
        sti_awg_utils.o \
index 134201e..f62041f 100644 (file)
@@ -25,7 +25,7 @@
 /*
  * stiH407 compositor properties
  */
-struct sti_compositor_data stih407_compositor_data = {
+static const struct sti_compositor_data stih407_compositor_data = {
        .nb_subdev = 8,
        .subdev_desc = {
                        {STI_CURSOR_SUBDEV, (int)STI_CURSOR, 0x000},
@@ -39,38 +39,18 @@ struct sti_compositor_data stih407_compositor_data = {
        },
 };
 
-/*
- * stiH416 compositor properties
- * Note:
- * on stih416 MIXER_AUX has a different base address from MIXER_MAIN
- * Moreover, GDPx is different for Main and Aux Mixer. So this subdev map does
- * not fit for stiH416 if we want to enable the MIXER_AUX.
- */
-struct sti_compositor_data stih416_compositor_data = {
-       .nb_subdev = 3,
-       .subdev_desc = {
-                       {STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100},
-                       {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200},
-                       {STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00}
-       },
-};
-
-int sti_compositor_debufs_init(struct sti_compositor *compo,
-                              struct drm_minor *minor)
+int sti_compositor_debugfs_init(struct sti_compositor *compo,
+                               struct drm_minor *minor)
 {
-       int ret = 0, i;
+       unsigned int i;
 
-       for (i = 0; compo->vid[i]; i++) {
-               ret = vid_debugfs_init(compo->vid[i], minor);
-               if (ret)
-                       return ret;
-       }
+       for (i = 0; i < STI_MAX_VID; i++)
+               if (compo->vid[i])
+                       vid_debugfs_init(compo->vid[i], minor);
 
-       for (i = 0; compo->mixer[i]; i++) {
-               ret = sti_mixer_debugfs_init(compo->mixer[i], minor);
-               if (ret)
-                       return ret;
-       }
+       for (i = 0; i < STI_MAX_MIXER; i++)
+               if (compo->mixer[i])
+                       sti_mixer_debugfs_init(compo->mixer[i], minor);
 
        return 0;
 }
@@ -183,9 +163,6 @@ static const struct component_ops sti_compositor_ops = {
 
 static const struct of_device_id compositor_of_match[] = {
        {
-               .compatible = "st,stih416-compositor",
-               .data = &stih416_compositor_data,
-       }, {
                .compatible = "st,stih407-compositor",
                .data = &stih407_compositor_data,
        }, {
@@ -201,6 +178,7 @@ static int sti_compositor_probe(struct platform_device *pdev)
        struct device_node *vtg_np;
        struct sti_compositor *compo;
        struct resource *res;
+       unsigned int i;
 
        compo = devm_kzalloc(dev, sizeof(*compo), GFP_KERNEL);
        if (!compo) {
@@ -208,7 +186,8 @@ static int sti_compositor_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
        compo->dev = dev;
-       compo->vtg_vblank_nb.notifier_call = sti_crtc_vblank_cb;
+       for (i = 0; i < STI_MAX_MIXER; i++)
+               compo->vtg_vblank_nb[i].notifier_call = sti_crtc_vblank_cb;
 
        /* populate data structure depending on compatibility */
        BUG_ON(!of_match_node(compositor_of_match, np)->data);
@@ -266,12 +245,12 @@ static int sti_compositor_probe(struct platform_device *pdev)
 
        vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 0);
        if (vtg_np)
-               compo->vtg_main = of_vtg_find(vtg_np);
+               compo->vtg[STI_MIXER_MAIN] = of_vtg_find(vtg_np);
        of_node_put(vtg_np);
 
        vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 1);
        if (vtg_np)
-               compo->vtg_aux = of_vtg_find(vtg_np);
+               compo->vtg[STI_MIXER_AUX] = of_vtg_find(vtg_np);
        of_node_put(vtg_np);
 
        platform_set_drvdata(pdev, compo);
index 24444ef..2952a2d 100644 (file)
@@ -60,9 +60,8 @@ struct sti_compositor_data {
  * @rst_aux: reset control of the aux path
  * @mixer: array of mixers
  * @vid: array of vids
- * @vtg_main: vtg for main data path
- * @vtg_aux: vtg for auxillary data path
- * @vtg_vblank_nb: callback for VTG VSYNC notification
+ * @vtg: array of vtgs
+ * @vtg_vblank_nb: array of callbacks for VTG VSYNC notification
  */
 struct sti_compositor {
        struct device *dev;
@@ -76,12 +75,11 @@ struct sti_compositor {
        struct reset_control *rst_aux;
        struct sti_mixer *mixer[STI_MAX_MIXER];
        struct sti_vid *vid[STI_MAX_VID];
-       struct sti_vtg *vtg_main;
-       struct sti_vtg *vtg_aux;
-       struct notifier_block vtg_vblank_nb;
+       struct sti_vtg *vtg[STI_MAX_MIXER];
+       struct notifier_block vtg_vblank_nb[STI_MAX_MIXER];
 };
 
-int sti_compositor_debufs_init(struct sti_compositor *compo,
-                              struct drm_minor *minor);
+int sti_compositor_debugfs_init(struct sti_compositor *compo,
+                               struct drm_minor *minor);
 
 #endif
index c7d734d..e992bed 100644 (file)
@@ -86,8 +86,7 @@ sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
                goto pix_error;
        }
 
-       sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ?
-                       compo->vtg_main : compo->vtg_aux, &crtc->mode);
+       sti_vtg_set_config(compo->vtg[mixer->id], &crtc->mode);
 
        if (sti_mixer_active_video_area(mixer, &crtc->mode)) {
                DRM_ERROR("Can't set active video area\n");
@@ -166,6 +165,10 @@ static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
 
                switch (plane->status) {
                case STI_PLANE_UPDATED:
+                       /* ignore update for other CRTC */
+                       if (p->state->crtc != crtc)
+                               continue;
+
                        /* update planes tag as updated */
                        DRM_DEBUG_DRIVER("update plane %s\n",
                                         sti_plane_to_str(plane));
@@ -244,8 +247,7 @@ static int sti_crtc_set_property(struct drm_crtc *crtc,
 int sti_crtc_vblank_cb(struct notifier_block *nb,
                       unsigned long event, void *data)
 {
-       struct sti_compositor *compo =
-               container_of(nb, struct sti_compositor, vtg_vblank_nb);
+       struct sti_compositor *compo;
        struct drm_crtc *crtc = data;
        struct sti_mixer *mixer;
        unsigned long flags;
@@ -254,6 +256,7 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
 
        priv = crtc->dev->dev_private;
        pipe = drm_crtc_index(crtc);
+       compo = container_of(nb, struct sti_compositor, vtg_vblank_nb[pipe]);
        mixer = compo->mixer[pipe];
 
        if ((event != VTG_TOP_FIELD_EVENT) &&
@@ -295,14 +298,13 @@ int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
 {
        struct sti_private *dev_priv = dev->dev_private;
        struct sti_compositor *compo = dev_priv->compo;
-       struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
+       struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
        struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
+       struct sti_vtg *vtg = compo->vtg[pipe];
 
        DRM_DEBUG_DRIVER("\n");
 
-       if (sti_vtg_register_client(pipe == STI_MIXER_MAIN ?
-                       compo->vtg_main : compo->vtg_aux,
-                       vtg_vblank_nb, crtc)) {
+       if (sti_vtg_register_client(vtg, vtg_vblank_nb, crtc)) {
                DRM_ERROR("Cannot register VTG notifier\n");
                return -EINVAL;
        }
@@ -314,13 +316,13 @@ void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
 {
        struct sti_private *priv = drm_dev->dev_private;
        struct sti_compositor *compo = priv->compo;
-       struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
+       struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
        struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
+       struct sti_vtg *vtg = compo->vtg[pipe];
 
        DRM_DEBUG_DRIVER("\n");
 
-       if (sti_vtg_unregister_client(pipe == STI_MIXER_MAIN ?
-                       compo->vtg_main : compo->vtg_aux, vtg_vblank_nb))
+       if (sti_vtg_unregister_client(vtg, vtg_vblank_nb))
                DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
 
        /* free the resources of the pending requests */
@@ -336,7 +338,7 @@ static int sti_crtc_late_register(struct drm_crtc *crtc)
        struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
 
        if (drm_crtc_index(crtc) == 0)
-               return sti_compositor_debufs_init(compo, crtc->dev->primary);
+               return sti_compositor_debugfs_init(compo, crtc->dev->primary);
 
        return 0;
 }
index 3b53f7f..cca75bd 100644 (file)
@@ -309,15 +309,15 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
 {
        struct sti_plane *plane = to_sti_plane(drm_plane);
 
-       if (!drm_plane->crtc) {
+       if (!oldstate->crtc) {
                DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
                                 drm_plane->base.id);
                return;
        }
 
        DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
-                        drm_plane->crtc->base.id,
-                        sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)),
+                        oldstate->crtc->base.id,
+                        sti_mixer_to_str(to_sti_mixer(oldstate->crtc)),
                         drm_plane->base.id, sti_plane_to_str(plane));
 
        plane->status = STI_PLANE_DISABLING;
@@ -345,7 +345,7 @@ static int sti_cursor_late_register(struct drm_plane *drm_plane)
        return cursor_debugfs_init(cursor, drm_plane->dev->primary);
 }
 
-struct drm_plane_funcs sti_cursor_plane_helpers_funcs = {
+static const struct drm_plane_funcs sti_cursor_plane_helpers_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = sti_cursor_destroy,
index 96bd3d0..2784919 100644 (file)
@@ -140,7 +140,7 @@ err:
        return ret;
 }
 
-void sti_drm_dbg_cleanup(struct drm_minor *minor)
+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);
@@ -178,7 +178,7 @@ static void sti_atomic_complete(struct sti_private *private,
         */
 
        drm_atomic_helper_commit_modeset_disables(drm, state);
-       drm_atomic_helper_commit_planes(drm, state, false);
+       drm_atomic_helper_commit_planes(drm, state, 0);
        drm_atomic_helper_commit_modeset_enables(drm, state);
 
        drm_atomic_helper_wait_for_vblanks(drm, state);
@@ -282,7 +282,7 @@ static const struct file_operations sti_driver_fops = {
 };
 
 static struct drm_driver sti_driver = {
-       .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET |
+       .driver_features = DRIVER_MODESET |
            DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
        .gem_free_object_unlocked = drm_gem_cma_free_object,
        .gem_vm_ops = &drm_gem_cma_vm_ops,
@@ -365,8 +365,8 @@ static int sti_bind(struct device *dev)
        int ret;
 
        ddev = drm_dev_alloc(&sti_driver, dev);
-       if (!ddev)
-               return -ENOMEM;
+       if (IS_ERR(ddev))
+               return PTR_ERR(ddev);
 
        ddev->platformdev = to_platform_device(dev);
 
index 00881eb..e8c1ed0 100644 (file)
@@ -17,6 +17,7 @@
 #include <drm/drm_panel.h>
 
 #include "sti_awg_utils.h"
+#include "sti_drv.h"
 #include "sti_mixer.h"
 
 /* DVO registers */
@@ -106,7 +107,7 @@ struct sti_dvo_connector {
        container_of(x, struct sti_dvo_connector, drm_connector)
 
 #define BLANKING_LEVEL 16
-int dvo_awg_generate_code(struct sti_dvo *dvo, u8 *ram_size, u32 *ram_code)
+static int dvo_awg_generate_code(struct sti_dvo *dvo, u8 *ram_size, u32 *ram_code)
 {
        struct drm_display_mode *mode = &dvo->mode;
        struct dvo_config *config = dvo->config;
index b8d942c..81df309 100644 (file)
@@ -460,6 +460,7 @@ static void sti_gdp_disable(struct sti_gdp *gdp)
                clk_disable_unprepare(gdp->clk_pix);
 
        gdp->plane.status = STI_PLANE_DISABLED;
+       gdp->vtg = NULL;
 }
 
 /**
@@ -473,8 +474,8 @@ static void sti_gdp_disable(struct sti_gdp *gdp)
  * RETURNS:
  * 0 on success.
  */
-int sti_gdp_field_cb(struct notifier_block *nb,
-               unsigned long event, void *data)
+static int sti_gdp_field_cb(struct notifier_block *nb,
+                           unsigned long event, void *data)
 {
        struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb);
 
@@ -611,7 +612,6 @@ static int sti_gdp_atomic_check(struct drm_plane *drm_plane,
        struct drm_crtc *crtc = state->crtc;
        struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
        struct drm_framebuffer *fb =  state->fb;
-       bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
        struct drm_crtc_state *crtc_state;
        struct sti_mixer *mixer;
        struct drm_display_mode *mode;
@@ -628,8 +628,8 @@ static int sti_gdp_atomic_check(struct drm_plane *drm_plane,
        mode = &crtc_state->mode;
        dst_x = state->crtc_x;
        dst_y = state->crtc_y;
-       dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
-       dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+       dst_w = clamp_val(state->crtc_w, 0, mode->hdisplay - dst_x);
+       dst_h = clamp_val(state->crtc_h, 0, mode->vdisplay - dst_y);
        /* src_x are in 16.16 format */
        src_x = state->src_x >> 16;
        src_y = state->src_y >> 16;
@@ -648,10 +648,9 @@ static int sti_gdp_atomic_check(struct drm_plane *drm_plane,
                return -EINVAL;
        }
 
-       if (first_prepare) {
+       if (!gdp->vtg) {
                /* Register gdp callback */
-               gdp->vtg = mixer->id == STI_MIXER_MAIN ?
-                                       compo->vtg_main : compo->vtg_aux;
+               gdp->vtg = compo->vtg[mixer->id];
                if (sti_vtg_register_client(gdp->vtg,
                                            &gdp->vtg_field_nb, crtc)) {
                        DRM_ERROR("Cannot register VTG notifier\n");
@@ -719,7 +718,7 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
        u32 dma_updated_top;
        u32 dma_updated_btm;
        int format;
-       unsigned int depth, bpp;
+       unsigned int bpp;
        u32 ydo, xdo, yds, xds;
 
        if (!crtc || !fb)
@@ -728,8 +727,8 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
        mode = &crtc->mode;
        dst_x = state->crtc_x;
        dst_y = state->crtc_y;
-       dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
-       dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+       dst_w = clamp_val(state->crtc_w, 0, mode->hdisplay - dst_x);
+       dst_h = clamp_val(state->crtc_h, 0, mode->vdisplay - dst_y);
        /* src_x are in 16.16 format */
        src_x = state->src_x >> 16;
        src_y = state->src_y >> 16;
@@ -758,9 +757,9 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
                         (unsigned long)cma_obj->paddr);
 
        /* pixel memory location */
-       drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
+       bpp = drm_format_plane_cpp(fb->pixel_format, 0);
        top_field->gam_gdp_pml = (u32)cma_obj->paddr + fb->offsets[0];
-       top_field->gam_gdp_pml += src_x * (bpp >> 3);
+       top_field->gam_gdp_pml += src_x * bpp;
        top_field->gam_gdp_pml += src_y * fb->pitches[0];
 
        /* output parameters (clamped / cropped) */
@@ -810,7 +809,7 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
        if (!curr_list) {
                /* First update or invalid node should directly write in the
                 * hw register */
-               DRM_DEBUG_DRIVER("%s first update (or invalid node)",
+               DRM_DEBUG_DRIVER("%s first update (or invalid node)\n",
                                 sti_plane_to_str(plane));
 
                writel(gdp->is_curr_top ?
@@ -846,15 +845,15 @@ static void sti_gdp_atomic_disable(struct drm_plane *drm_plane,
 {
        struct sti_plane *plane = to_sti_plane(drm_plane);
 
-       if (!drm_plane->crtc) {
+       if (!oldstate->crtc) {
                DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
                                 drm_plane->base.id);
                return;
        }
 
        DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
-                        drm_plane->crtc->base.id,
-                        sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)),
+                        oldstate->crtc->base.id,
+                        sti_mixer_to_str(to_sti_mixer(oldstate->crtc)),
                         drm_plane->base.id, sti_plane_to_str(plane));
 
        plane->status = STI_PLANE_DISABLING;
@@ -882,7 +881,7 @@ static int sti_gdp_late_register(struct drm_plane *drm_plane)
        return gdp_debugfs_init(gdp, drm_plane->dev->primary);
 }
 
-struct drm_plane_funcs sti_gdp_plane_helpers_funcs = {
+static const struct drm_plane_funcs sti_gdp_plane_helpers_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = sti_gdp_destroy,
index 8505569..e7c243f 100644 (file)
 #define SCALE_CTRL_CR_DFLT              0x00DB0249
 
 /* Video DACs control */
-#define VIDEO_DACS_CONTROL_MASK         0x0FFF
-#define VIDEO_DACS_CONTROL_SYSCFG2535   0x085C /* for stih416 */
-#define DAC_CFG_HD_OFF_SHIFT            5
-#define DAC_CFG_HD_OFF_MASK             (0x7 << DAC_CFG_HD_OFF_SHIFT)
-#define VIDEO_DACS_CONTROL_SYSCFG5072   0x0120 /* for stih407 */
 #define DAC_CFG_HD_HZUVW_OFF_MASK       BIT(1)
 
-
 /* Upsampler values for the alternative 2X Filter */
 #define SAMPLER_COEF_NB                 8
 #define HDA_ANA_SRC_Y_CFG_ALT_2X        0x01130000
@@ -300,28 +294,14 @@ static bool hda_get_mode_idx(struct drm_display_mode mode, int *idx)
  */
 static void hda_enable_hd_dacs(struct sti_hda *hda, bool enable)
 {
-       u32 mask;
-
        if (hda->video_dacs_ctrl) {
                u32 val;
 
-               switch ((u32)hda->video_dacs_ctrl & VIDEO_DACS_CONTROL_MASK) {
-               case VIDEO_DACS_CONTROL_SYSCFG2535:
-                       mask = DAC_CFG_HD_OFF_MASK;
-                       break;
-               case VIDEO_DACS_CONTROL_SYSCFG5072:
-                       mask = DAC_CFG_HD_HZUVW_OFF_MASK;
-                       break;
-               default:
-                       DRM_INFO("Video DACS control register not supported!");
-                       return;
-               }
-
                val = readl(hda->video_dacs_ctrl);
                if (enable)
-                       val &= ~mask;
+                       val &= ~DAC_CFG_HD_HZUVW_OFF_MASK;
                else
-                       val |= mask;
+                       val |= DAC_CFG_HD_HZUVW_OFF_MASK;
 
                writel(val, hda->video_dacs_ctrl);
        }
@@ -352,24 +332,11 @@ static void hda_dbg_awg_microcode(struct seq_file *s, void __iomem *reg)
 static void hda_dbg_video_dacs_ctrl(struct seq_file *s, void __iomem *reg)
 {
        u32 val = readl(reg);
-       u32 mask;
-
-       switch ((u32)reg & VIDEO_DACS_CONTROL_MASK) {
-       case VIDEO_DACS_CONTROL_SYSCFG2535:
-               mask = DAC_CFG_HD_OFF_MASK;
-               break;
-       case VIDEO_DACS_CONTROL_SYSCFG5072:
-               mask = DAC_CFG_HD_HZUVW_OFF_MASK;
-               break;
-       default:
-               DRM_DEBUG_DRIVER("Warning: DACS ctrl register not supported!");
-               return;
-       }
 
        seq_puts(s, "\n");
        seq_printf(s, "\n  %-25s 0x%08X", "VIDEO_DACS_CONTROL", val);
        seq_puts(s, "\tHD DACs ");
-       seq_puts(s, val & mask ? "disabled" : "enabled");
+       seq_puts(s, val & DAC_CFG_HD_HZUVW_OFF_MASK ? "disabled" : "enabled");
 }
 
 static int hda_dbg_show(struct seq_file *s, void *data)
index fedc17f..376b076 100644 (file)
@@ -22,7 +22,6 @@
 
 #include "sti_hdmi.h"
 #include "sti_hdmi_tx3g4c28phy.h"
-#include "sti_hdmi_tx3g0c55phy.h"
 #include "sti_vtg.h"
 
 #define HDMI_CFG                        0x0000
@@ -203,7 +202,7 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
 
        /* Audio FIFO underrun IRQ */
        if (hdmi->irq_status & HDMI_INT_AUDIO_FIFO_XRUN)
-               DRM_INFO("Warning: audio FIFO underrun occurs!");
+               DRM_INFO("Warning: audio FIFO underrun occurs!\n");
 
        return IRQ_HANDLED;
 }
@@ -569,7 +568,7 @@ static void hdmi_swreset(struct sti_hdmi *hdmi)
 
        /* Wait reset completed */
        wait_event_interruptible_timeout(hdmi->wait_event,
-                                        hdmi->event_received == true,
+                                        hdmi->event_received,
                                         msecs_to_jiffies
                                         (HDMI_TIMEOUT_SWRESET));
 
@@ -1054,6 +1053,7 @@ static int sti_hdmi_late_register(struct drm_connector *connector)
 }
 
 static const struct drm_connector_funcs sti_hdmi_connector_funcs = {
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_hdmi_connector_detect,
        .destroy = drm_connector_cleanup,
@@ -1181,7 +1181,7 @@ static void hdmi_audio_shutdown(struct device *dev, void *data)
                    HDMI_AUD_CFG_ONE_BIT_INVALID;
        hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG);
 
-       hdmi->audio.enabled = 0;
+       hdmi->audio.enabled = false;
        hdmi_audio_infoframe_config(hdmi);
 }
 
@@ -1213,7 +1213,7 @@ static int hdmi_audio_hw_params(struct device *dev,
                return -EINVAL;
        }
 
-       audio.enabled = 1;
+       audio.enabled = true;
 
        ret = hdmi_audio_configure(hdmi, &audio);
        if (ret < 0)
@@ -1265,7 +1265,7 @@ static int sti_hdmi_register_audio_driver(struct device *dev,
 
        DRM_DEBUG_DRIVER("\n");
 
-       hdmi->audio.enabled = 0;
+       hdmi->audio.enabled = false;
 
        hdmi->audio_pdev = platform_device_register_data(
                dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
@@ -1373,9 +1373,6 @@ static const struct component_ops sti_hdmi_ops = {
 
 static const struct of_device_id hdmi_of_match[] = {
        {
-               .compatible = "st,stih416-hdmi",
-               .data = &tx3g0c55phy_ops,
-       }, {
                .compatible = "st,stih407-hdmi",
                .data = &tx3g4c28phy_ops,
        }, {
@@ -1422,22 +1419,6 @@ static int sti_hdmi_probe(struct platform_device *pdev)
                goto release_adapter;
        }
 
-       if (of_device_is_compatible(np, "st,stih416-hdmi")) {
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                                  "syscfg");
-               if (!res) {
-                       DRM_ERROR("Invalid syscfg resource\n");
-                       ret = -ENOMEM;
-                       goto release_adapter;
-               }
-               hdmi->syscfg = devm_ioremap_nocache(dev, res->start,
-                                                   resource_size(res));
-               if (!hdmi->syscfg) {
-                       ret = -ENOMEM;
-                       goto release_adapter;
-               }
-       }
-
        hdmi->phy_ops = (struct hdmi_phy_ops *)
                of_match_node(hdmi_of_match, np)->data;
 
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c
deleted file mode 100644 (file)
index 49ae8e4..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics SA 2014
- * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
- * License terms:  GNU General Public License (GPL), version 2
- */
-
-#include "sti_hdmi_tx3g0c55phy.h"
-
-#define HDMI_SRZ_PLL_CFG                0x0504
-#define HDMI_SRZ_TAP_1                  0x0508
-#define HDMI_SRZ_TAP_2                  0x050C
-#define HDMI_SRZ_TAP_3                  0x0510
-#define HDMI_SRZ_CTRL                   0x0514
-
-#define HDMI_SRZ_PLL_CFG_POWER_DOWN     BIT(0)
-#define HDMI_SRZ_PLL_CFG_VCOR_SHIFT     1
-#define HDMI_SRZ_PLL_CFG_VCOR_425MHZ    0
-#define HDMI_SRZ_PLL_CFG_VCOR_850MHZ    1
-#define HDMI_SRZ_PLL_CFG_VCOR_1700MHZ   2
-#define HDMI_SRZ_PLL_CFG_VCOR_3000MHZ   3
-#define HDMI_SRZ_PLL_CFG_VCOR_MASK      3
-#define HDMI_SRZ_PLL_CFG_VCOR(x)        (x << HDMI_SRZ_PLL_CFG_VCOR_SHIFT)
-#define HDMI_SRZ_PLL_CFG_NDIV_SHIFT     8
-#define HDMI_SRZ_PLL_CFG_NDIV_MASK      (0x1F << HDMI_SRZ_PLL_CFG_NDIV_SHIFT)
-#define HDMI_SRZ_PLL_CFG_MODE_SHIFT     16
-#define HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ  0x1
-#define HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ  0x4
-#define HDMI_SRZ_PLL_CFG_MODE_27_MHZ    0x5
-#define HDMI_SRZ_PLL_CFG_MODE_33_75_MHZ 0x6
-#define HDMI_SRZ_PLL_CFG_MODE_40_5_MHZ  0x7
-#define HDMI_SRZ_PLL_CFG_MODE_54_MHZ    0x8
-#define HDMI_SRZ_PLL_CFG_MODE_67_5_MHZ  0x9
-#define HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ 0xA
-#define HDMI_SRZ_PLL_CFG_MODE_81_MHZ    0xB
-#define HDMI_SRZ_PLL_CFG_MODE_82_5_MHZ  0xC
-#define HDMI_SRZ_PLL_CFG_MODE_108_MHZ   0xD
-#define HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ 0xE
-#define HDMI_SRZ_PLL_CFG_MODE_165_MHZ   0xF
-#define HDMI_SRZ_PLL_CFG_MODE_MASK      0xF
-#define HDMI_SRZ_PLL_CFG_MODE(x)        (x << HDMI_SRZ_PLL_CFG_MODE_SHIFT)
-
-#define HDMI_SRZ_CTRL_POWER_DOWN        (1 << 0)
-#define HDMI_SRZ_CTRL_EXTERNAL_DATA_EN  (1 << 1)
-
-/* sysconf registers */
-#define HDMI_REJECTION_PLL_CONFIGURATION 0x0858        /* SYSTEM_CONFIG2534 */
-#define HDMI_REJECTION_PLL_STATUS        0x0948        /* SYSTEM_CONFIG2594 */
-
-#define REJECTION_PLL_HDMI_ENABLE_SHIFT 0
-#define REJECTION_PLL_HDMI_ENABLE_MASK  (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT)
-#define REJECTION_PLL_HDMI_PDIV_SHIFT   24
-#define REJECTION_PLL_HDMI_PDIV_MASK    (0x7 << REJECTION_PLL_HDMI_PDIV_SHIFT)
-#define REJECTION_PLL_HDMI_NDIV_SHIFT   16
-#define REJECTION_PLL_HDMI_NDIV_MASK    (0xFF << REJECTION_PLL_HDMI_NDIV_SHIFT)
-#define REJECTION_PLL_HDMI_MDIV_SHIFT   8
-#define REJECTION_PLL_HDMI_MDIV_MASK    (0xFF << REJECTION_PLL_HDMI_MDIV_SHIFT)
-
-#define REJECTION_PLL_HDMI_REJ_PLL_LOCK BIT(0)
-
-#define HDMI_TIMEOUT_PLL_LOCK  50   /*milliseconds */
-
-/**
- * pll mode structure
- *
- * A pointer to an array of these structures is passed to a TMDS (HDMI) output
- * via the control interface to provide board and SoC specific
- * configurations of the HDMI PHY. Each entry in the array specifies a hardware
- * specific configuration for a given TMDS clock frequency range. The array
- * should be terminated with an entry that has all fields set to zero.
- *
- * @min: Lower bound of TMDS clock frequency this entry applies to
- * @max: Upper bound of TMDS clock frequency this entry applies to
- * @mode: SoC specific register configuration
- */
-struct pllmode {
-       u32 min;
-       u32 max;
-       u32 mode;
-};
-
-#define NB_PLL_MODE 7
-static struct pllmode pllmodes[NB_PLL_MODE] = {
-       {13500000, 13513500, HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ},
-       {25174800, 25200000, HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ},
-       {27000000, 27027000, HDMI_SRZ_PLL_CFG_MODE_27_MHZ},
-       {54000000, 54054000, HDMI_SRZ_PLL_CFG_MODE_54_MHZ},
-       {72000000, 74250000, HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ},
-       {108000000, 108108000, HDMI_SRZ_PLL_CFG_MODE_108_MHZ},
-       {148351648, 297000000, HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ}
-};
-
-#define NB_HDMI_PHY_CONFIG 5
-static struct hdmi_phy_config hdmiphy_config[NB_HDMI_PHY_CONFIG] = {
-       {0, 40000000, {0x00101010, 0x00101010, 0x00101010, 0x02} },
-       {40000000, 140000000, {0x00111111, 0x00111111, 0x00111111, 0x02} },
-       {140000000, 160000000, {0x00131313, 0x00101010, 0x00101010, 0x02} },
-       {160000000, 250000000, {0x00131313, 0x00111111, 0x00111111, 0x03FE} },
-       {250000000, 300000000, {0x00151515, 0x00101010, 0x00101010, 0x03FE} },
-};
-
-#define PLL_CHANGE_DELAY       1 /* ms */
-
-/**
- * Disable the pll rejection
- *
- * @hdmi: pointer on the hdmi internal structure
- *
- * return true if the pll has been disabled
- */
-static bool disable_pll_rejection(struct sti_hdmi *hdmi)
-{
-       u32 val;
-
-       DRM_DEBUG_DRIVER("\n");
-
-       val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
-       val &= ~REJECTION_PLL_HDMI_ENABLE_MASK;
-       writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
-
-       msleep(PLL_CHANGE_DELAY);
-       val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS);
-
-       return !(val & REJECTION_PLL_HDMI_REJ_PLL_LOCK);
-}
-
-/**
- * Enable the old BCH/rejection PLL is now reused to provide the CLKPXPLL
- * clock input to the new PHY PLL that generates the serializer clock
- * (TMDS*10) and the TMDS clock which is now fed back into the HDMI
- * formatter instead of the TMDS clock line from ClockGenB.
- *
- * @hdmi: pointer on the hdmi internal structure
- *
- * return true if pll has been correctly set
- */
-static bool enable_pll_rejection(struct sti_hdmi *hdmi)
-{
-       unsigned int inputclock;
-       u32 mdiv, ndiv, pdiv, val;
-
-       DRM_DEBUG_DRIVER("\n");
-
-       if (!disable_pll_rejection(hdmi))
-               return false;
-
-       inputclock = hdmi->mode.clock * 1000;
-
-       DRM_DEBUG_DRIVER("hdmi rejection pll input clock = %dHz\n", inputclock);
-
-
-       /* Power up the HDMI rejection PLL
-        * Note: On this SoC (stiH416) we are forced to have the input clock
-        * be equal to the HDMI pixel clock.
-        *
-        * The values here have been suggested by validation however they are
-        * still provisional and subject to change.
-        *
-        * PLLout = (Fin*Mdiv) / ((2 * Ndiv) / 2^Pdiv)
-        */
-       if (inputclock < 50000000) {
-               /*
-                * For slower clocks we need to multiply more to keep the
-                * internal VCO frequency within the physical specification
-                * of the PLL.
-                */
-               pdiv = 4;
-               ndiv = 240;
-               mdiv = 30;
-       } else {
-               pdiv = 2;
-               ndiv = 60;
-               mdiv = 30;
-       }
-
-       val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
-
-       val &= ~(REJECTION_PLL_HDMI_PDIV_MASK |
-               REJECTION_PLL_HDMI_NDIV_MASK |
-               REJECTION_PLL_HDMI_MDIV_MASK |
-               REJECTION_PLL_HDMI_ENABLE_MASK);
-
-       val |=  (pdiv << REJECTION_PLL_HDMI_PDIV_SHIFT) |
-               (ndiv << REJECTION_PLL_HDMI_NDIV_SHIFT) |
-               (mdiv << REJECTION_PLL_HDMI_MDIV_SHIFT) |
-               (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT);
-
-       writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
-
-       msleep(PLL_CHANGE_DELAY);
-       val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS);
-
-       return (val & REJECTION_PLL_HDMI_REJ_PLL_LOCK);
-}
-
-/**
- * Start hdmi phy macro cell tx3g0c55
- *
- * @hdmi: pointer on the hdmi internal structure
- *
- * Return false if an error occur
- */
-static bool sti_hdmi_tx3g0c55phy_start(struct sti_hdmi *hdmi)
-{
-       u32 ckpxpll = hdmi->mode.clock * 1000;
-       u32 val, tmdsck, freqvco, pllctrl = 0;
-       unsigned int i;
-
-       if (!enable_pll_rejection(hdmi))
-               return false;
-
-       DRM_DEBUG_DRIVER("ckpxpll = %dHz\n", ckpxpll);
-
-       /* Assuming no pixel repetition and 24bits color */
-       tmdsck = ckpxpll;
-       pllctrl = 2 << HDMI_SRZ_PLL_CFG_NDIV_SHIFT;
-
-       /*
-        * Setup the PLL mode parameter based on the ckpxpll. If we haven't got
-        * a clock frequency supported by one of the specific PLL modes then we
-        * will end up using the generic mode (0) which only supports a 10x
-        * multiplier, hence only 24bit color.
-        */
-       for (i = 0; i < NB_PLL_MODE; i++) {
-               if (ckpxpll >= pllmodes[i].min && ckpxpll <= pllmodes[i].max)
-                       pllctrl |= HDMI_SRZ_PLL_CFG_MODE(pllmodes[i].mode);
-       }
-
-       freqvco = tmdsck * 10;
-       if (freqvco <= 425000000UL)
-               pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_425MHZ);
-       else if (freqvco <= 850000000UL)
-               pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_850MHZ);
-       else if (freqvco <= 1700000000UL)
-               pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_1700MHZ);
-       else if (freqvco <= 2970000000UL)
-               pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_3000MHZ);
-       else {
-               DRM_ERROR("PHY serializer clock out of range\n");
-               goto err;
-       }
-
-       /*
-        * Configure and power up the PHY PLL
-        */
-       hdmi->event_received = false;
-       DRM_DEBUG_DRIVER("pllctrl = 0x%x\n", pllctrl);
-       hdmi_write(hdmi, pllctrl, HDMI_SRZ_PLL_CFG);
-
-       /* wait PLL interrupt */
-       wait_event_interruptible_timeout(hdmi->wait_event,
-                                        hdmi->event_received == true,
-                                        msecs_to_jiffies
-                                        (HDMI_TIMEOUT_PLL_LOCK));
-
-       if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) == 0) {
-               DRM_ERROR("hdmi phy pll not locked\n");
-               goto err;
-       }
-
-       DRM_DEBUG_DRIVER("got PHY PLL Lock\n");
-
-       /*
-        * To configure the source termination and pre-emphasis appropriately
-        * for different high speed TMDS clock frequencies a phy configuration
-        * table must be provided, tailored to the SoC and board combination.
-        */
-       for (i = 0; i < NB_HDMI_PHY_CONFIG; i++) {
-               if ((hdmiphy_config[i].min_tmds_freq <= tmdsck) &&
-                   (hdmiphy_config[i].max_tmds_freq >= tmdsck)) {
-                       val = hdmiphy_config[i].config[0];
-                       hdmi_write(hdmi, val, HDMI_SRZ_TAP_1);
-                       val = hdmiphy_config[i].config[1];
-                       hdmi_write(hdmi, val, HDMI_SRZ_TAP_2);
-                       val = hdmiphy_config[i].config[2];
-                       hdmi_write(hdmi, val, HDMI_SRZ_TAP_3);
-                       val = hdmiphy_config[i].config[3];
-                       val |= HDMI_SRZ_CTRL_EXTERNAL_DATA_EN;
-                       val &= ~HDMI_SRZ_CTRL_POWER_DOWN;
-                       hdmi_write(hdmi, val, HDMI_SRZ_CTRL);
-
-                       DRM_DEBUG_DRIVER("serializer cfg 0x%x 0x%x 0x%x 0x%x\n",
-                                        hdmiphy_config[i].config[0],
-                                        hdmiphy_config[i].config[1],
-                                        hdmiphy_config[i].config[2],
-                                        hdmiphy_config[i].config[3]);
-                       return true;
-               }
-       }
-
-       /*
-        * Default, power up the serializer with no pre-emphasis or source
-        * termination.
-        */
-       hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_1);
-       hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_2);
-       hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_3);
-       hdmi_write(hdmi, HDMI_SRZ_CTRL_EXTERNAL_DATA_EN, HDMI_SRZ_CTRL);
-
-       return true;
-
-err:
-       disable_pll_rejection(hdmi);
-
-       return false;
-}
-
-/**
- * Stop hdmi phy macro cell tx3g0c55
- *
- * @hdmi: pointer on the hdmi internal structure
- */
-static void sti_hdmi_tx3g0c55phy_stop(struct sti_hdmi *hdmi)
-{
-       DRM_DEBUG_DRIVER("\n");
-
-       hdmi->event_received = false;
-
-       hdmi_write(hdmi, HDMI_SRZ_CTRL_POWER_DOWN, HDMI_SRZ_CTRL);
-       hdmi_write(hdmi, HDMI_SRZ_PLL_CFG_POWER_DOWN, HDMI_SRZ_PLL_CFG);
-
-       /* wait PLL interrupt */
-       wait_event_interruptible_timeout(hdmi->wait_event,
-                                        hdmi->event_received == true,
-                                        msecs_to_jiffies
-                                        (HDMI_TIMEOUT_PLL_LOCK));
-
-       if (hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK)
-               DRM_ERROR("hdmi phy pll not well disabled\n");
-
-       disable_pll_rejection(hdmi);
-}
-
-struct hdmi_phy_ops tx3g0c55phy_ops = {
-       .start = sti_hdmi_tx3g0c55phy_start,
-       .stop = sti_hdmi_tx3g0c55phy_stop,
-};
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h
deleted file mode 100644 (file)
index 068237b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics SA 2014
- * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
- * License terms:  GNU General Public License (GPL), version 2
- */
-
-#ifndef _STI_HDMI_TX3G0C55PHY_H_
-#define _STI_HDMI_TX3G0C55PHY_H_
-
-#include "sti_hdmi.h"
-
-extern struct hdmi_phy_ops tx3g0c55phy_ops;
-
-#endif
index b5ee783..f88130f 100644 (file)
@@ -17,6 +17,7 @@
 #include "sti_hqvdp_lut.h"
 #include "sti_plane.h"
 #include "sti_vtg.h"
+#include "sti_drv.h"
 
 /* Firmware name */
 #define HQVDP_FMW_NAME          "hqvdp-stih407.bin"
@@ -770,6 +771,7 @@ static void sti_hqvdp_disable(struct sti_hqvdp *hqvdp)
                DRM_ERROR("XP70 could not revert to idle\n");
 
        hqvdp->plane.status = STI_PLANE_DISABLED;
+       hqvdp->xp70_initialized = false;
 }
 
 /**
@@ -783,7 +785,7 @@ static void sti_hqvdp_disable(struct sti_hqvdp *hqvdp)
  * RETURNS:
  * 0 on success.
  */
-int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
+static int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
 {
        struct sti_hqvdp *hqvdp = container_of(nb, struct sti_hqvdp, vtg_nb);
        int btm_cmd_offset, top_cmd_offest;
@@ -1012,7 +1014,6 @@ static int sti_hqvdp_atomic_check(struct drm_plane *drm_plane,
        struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
        struct drm_crtc *crtc = state->crtc;
        struct drm_framebuffer *fb = state->fb;
-       bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
        struct drm_crtc_state *crtc_state;
        struct drm_display_mode *mode;
        int dst_x, dst_y, dst_w, dst_h;
@@ -1026,8 +1027,8 @@ static int sti_hqvdp_atomic_check(struct drm_plane *drm_plane,
        mode = &crtc_state->mode;
        dst_x = state->crtc_x;
        dst_y = state->crtc_y;
-       dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
-       dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+       dst_w = clamp_val(state->crtc_w, 0, mode->hdisplay - dst_x);
+       dst_h = clamp_val(state->crtc_h, 0, mode->vdisplay - dst_y);
        /* src_x are in 16.16 format */
        src_x = state->src_x >> 16;
        src_y = state->src_y >> 16;
@@ -1063,7 +1064,7 @@ static int sti_hqvdp_atomic_check(struct drm_plane *drm_plane,
                return -EINVAL;
        }
 
-       if (first_prepare) {
+       if (!hqvdp->xp70_initialized) {
                /* Start HQVDP XP70 coprocessor */
                sti_hqvdp_start_xp70(hqvdp);
 
@@ -1115,8 +1116,8 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
        mode = &crtc->mode;
        dst_x = state->crtc_x;
        dst_y = state->crtc_y;
-       dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
-       dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+       dst_w = clamp_val(state->crtc_w, 0, mode->hdisplay - dst_x);
+       dst_h = clamp_val(state->crtc_h, 0, mode->vdisplay - dst_y);
        /* src_x are in 16.16 format */
        src_x = state->src_x >> 16;
        src_y = state->src_y >> 16;
@@ -1214,15 +1215,15 @@ static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane,
 {
        struct sti_plane *plane = to_sti_plane(drm_plane);
 
-       if (!drm_plane->crtc) {
+       if (!oldstate->crtc) {
                DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
                                 drm_plane->base.id);
                return;
        }
 
        DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
-                        drm_plane->crtc->base.id,
-                        sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)),
+                        oldstate->crtc->base.id,
+                        sti_mixer_to_str(to_sti_mixer(oldstate->crtc)),
                         drm_plane->base.id, sti_plane_to_str(plane));
 
        plane->status = STI_PLANE_DISABLING;
@@ -1250,7 +1251,7 @@ static int sti_hqvdp_late_register(struct drm_plane *drm_plane)
        return hqvdp_debugfs_init(hqvdp, drm_plane->dev->primary);
 }
 
-struct drm_plane_funcs sti_hqvdp_plane_helpers_funcs = {
+static const struct drm_plane_funcs sti_hqvdp_plane_helpers_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = sti_hqvdp_destroy,
@@ -1289,7 +1290,7 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
        return &hqvdp->plane.drm_plane;
 }
 
-int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
+static int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
 {
        struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
index 7d9aea8..4ddc58f 100644 (file)
@@ -16,12 +16,6 @@ static unsigned int bkg_color = 0x000000;
 MODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB");
 module_param_named(bkgcolor, bkg_color, int, 0644);
 
-/* Identity: G=Y , B=Cb , R=Cr */
-static const u32 mixerColorSpaceMatIdentity[] = {
-       0x10000000, 0x00000000, 0x10000000, 0x00001000,
-       0x00000000, 0x00000000, 0x00000000, 0x00000000
-};
-
 /* regs offset */
 #define GAM_MIXER_CTL      0x00
 #define GAM_MIXER_BKC      0x04
@@ -358,22 +352,12 @@ int sti_mixer_set_plane_status(struct sti_mixer *mixer,
        return 0;
 }
 
-void sti_mixer_set_matrix(struct sti_mixer *mixer)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(mixerColorSpaceMatIdentity); i++)
-               sti_mixer_reg_write(mixer, GAM_MIXER_MX0 + (i * 4),
-                                   mixerColorSpaceMatIdentity[i]);
-}
-
 struct sti_mixer *sti_mixer_create(struct device *dev,
                                   struct drm_device *drm_dev,
                                   int id,
                                   void __iomem *baseaddr)
 {
        struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
-       struct device_node *np = dev->of_node;
 
        dev_dbg(dev, "%s\n", __func__);
        if (!mixer) {
@@ -384,9 +368,6 @@ struct sti_mixer *sti_mixer_create(struct device *dev,
        mixer->dev = dev;
        mixer->id = id;
 
-       if (of_device_is_compatible(np, "st,stih416-compositor"))
-               sti_mixer_set_matrix(mixer);
-
        DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
                         sti_mixer_to_str(mixer), mixer->regs);
 
index e25995b..ad46d35 100644 (file)
@@ -18,6 +18,7 @@
 #include <drm/drm_crtc_helper.h>
 
 #include "sti_crtc.h"
+#include "sti_drv.h"
 #include "sti_vtg.h"
 
 /* glue registers */
@@ -209,13 +210,11 @@ static void tvout_vip_set_rnd(struct sti_tvout *tvout, int reg, u32 rnd)
  * @tvout: tvout structure
  * @reg: register to set
  * @main_path: main or auxiliary path
- * @sel_input_logic_inverted: need to invert the logic
  * @sel_input: selected_input (main/aux + conv)
  */
 static void tvout_vip_set_sel_input(struct sti_tvout *tvout,
                                    int reg,
                                    bool main_path,
-                                   bool sel_input_logic_inverted,
                                    enum sti_tvout_video_out_type video_out)
 {
        u32 sel_input;
@@ -236,8 +235,7 @@ static void tvout_vip_set_sel_input(struct sti_tvout *tvout,
        }
 
        /* on stih407 chip the sel_input bypass mode logic is inverted */
-       if (sel_input_logic_inverted)
-               sel_input = sel_input ^ TVO_VIP_SEL_INPUT_BYPASS_MASK;
+       sel_input = sel_input ^ TVO_VIP_SEL_INPUT_BYPASS_MASK;
 
        val &= ~TVO_VIP_SEL_INPUT_MASK;
        val |= sel_input;
@@ -295,8 +293,6 @@ static void tvout_preformatter_set_matrix(struct sti_tvout *tvout,
  */
 static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path)
 {
-       struct device_node *node = tvout->dev->of_node;
-       bool sel_input_logic_inverted = false;
        u32 tvo_in_vid_format;
        int val, tmp;
 
@@ -334,16 +330,11 @@ static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path)
        /* Set round mode (rounded to 8-bit per component) */
        tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED);
 
-       if (of_device_is_compatible(node, "st,stih407-tvout")) {
-               /* Set input video format */
-               tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format,
-                                        TVO_IN_FMT_SIGNED);
-               sel_input_logic_inverted = true;
-       }
+       /* Set input video format */
+       tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, TVO_IN_FMT_SIGNED);
 
        /* Input selection */
        tvout_vip_set_sel_input(tvout, TVO_VIP_DVO, main_path,
-                               sel_input_logic_inverted,
                                STI_TVOUT_VIDEO_OUT_RGB);
 }
 
@@ -356,8 +347,6 @@ static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path)
  */
 static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path)
 {
-       struct device_node *node = tvout->dev->of_node;
-       bool sel_input_logic_inverted = false;
        u32 tvo_in_vid_format;
 
        dev_dbg(tvout->dev, "%s\n", __func__);
@@ -390,16 +379,12 @@ static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path)
        /* set round mode (rounded to 8-bit per component) */
        tvout_vip_set_rnd(tvout, TVO_VIP_HDMI, TVO_VIP_RND_8BIT_ROUNDED);
 
-       if (of_device_is_compatible(node, "st,stih407-tvout")) {
-               /* set input video format */
-               tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format,
-                                       TVO_IN_FMT_SIGNED);
-               sel_input_logic_inverted = true;
-       }
+       /* set input video format */
+       tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, TVO_IN_FMT_SIGNED);
 
        /* input selection */
        tvout_vip_set_sel_input(tvout, TVO_VIP_HDMI, main_path,
-                       sel_input_logic_inverted, STI_TVOUT_VIDEO_OUT_RGB);
+                               STI_TVOUT_VIDEO_OUT_RGB);
 }
 
 /**
@@ -411,8 +396,6 @@ static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path)
  */
 static void tvout_hda_start(struct sti_tvout *tvout, bool main_path)
 {
-       struct device_node *node = tvout->dev->of_node;
-       bool sel_input_logic_inverted = false;
        u32 tvo_in_vid_format;
        int val;
 
@@ -448,16 +431,11 @@ static void tvout_hda_start(struct sti_tvout *tvout, bool main_path)
        /* set round mode (rounded to 10-bit per component) */
        tvout_vip_set_rnd(tvout, TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED);
 
-       if (of_device_is_compatible(node, "st,stih407-tvout")) {
-               /* set input video format */
-               tvout_vip_set_in_vid_fmt(tvout,
-                       tvo_in_vid_format, TVO_IN_FMT_SIGNED);
-               sel_input_logic_inverted = true;
-       }
+       /* Set input video format */
+       tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, TVO_IN_FMT_SIGNED);
 
        /* Input selection */
        tvout_vip_set_sel_input(tvout, TVO_VIP_HDF, main_path,
-                               sel_input_logic_inverted,
                                STI_TVOUT_VIDEO_OUT_YUV);
 
        /* power up HD DAC */
@@ -905,7 +883,6 @@ static int sti_tvout_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id tvout_of_match[] = {
-       { .compatible = "st,stih416-tvout", },
        { .compatible = "st,stih407-tvout", },
        { /* end node */ }
 };
index 47634a0..2ad5989 100644 (file)
@@ -142,8 +142,8 @@ void sti_vid_commit(struct sti_vid *vid,
        struct drm_display_mode *mode = &crtc->mode;
        int dst_x = state->crtc_x;
        int dst_y = state->crtc_y;
-       int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
-       int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+       int dst_w = clamp_val(state->crtc_w, 0, mode->hdisplay - dst_x);
+       int dst_h = clamp_val(state->crtc_h, 0, mode->vdisplay - dst_y);
        int src_h = state->src_h >> 16;
        u32 val, ydo, xdo, yds, xds;
 
index b1eb0d7..cf7fe8a 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <drm/drmP.h>
 
+#include "sti_drv.h"
+
 /* registers offset */
 #define VTAC_CONFIG                     0x00
 #define VTAC_RX_FIFO_CONFIG             0x04
index 0bdc385..a8882bd 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <drm/drmP.h>
 
+#include "sti_drv.h"
 #include "sti_vtg.h"
 
 #define VTG_MODE_MASTER         0
@@ -72,7 +73,7 @@
 #define AWG_DELAY_ED        (-8)
 #define AWG_DELAY_SD        (-7)
 
-LIST_HEAD(vtg_lookup);
+static LIST_HEAD(vtg_lookup);
 
 /*
  * STI VTG register offset structure
index 58cd551..d625a82 100644 (file)
@@ -9,5 +9,5 @@ sun4i-tcon-y += sun4i_dotclock.o
 
 obj-$(CONFIG_DRM_SUN4I)                += sun4i-drm.o sun4i-tcon.o
 obj-$(CONFIG_DRM_SUN4I)                += sun4i_backend.o
-
+obj-$(CONFIG_DRM_SUN4I)                += sun6i_drc.o
 obj-$(CONFIG_DRM_SUN4I)                += sun4i_tv.o
index 3ab5604..32c0584 100644 (file)
@@ -83,8 +83,13 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 }
 EXPORT_SYMBOL(sun4i_backend_layer_enable);
 
-static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode)
+static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
+                                            u32 format, u32 *mode)
 {
+       if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
+           (format == DRM_FORMAT_ARGB8888))
+               format = DRM_FORMAT_XRGB8888;
+
        switch (format) {
        case DRM_FORMAT_ARGB8888:
                *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888;
@@ -164,7 +169,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
        DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
                         interlaced ? "on" : "off");
 
-       ret = sun4i_backend_drm_format_to_layer(fb->pixel_format, &val);
+       ret = sun4i_backend_drm_format_to_layer(plane, fb->pixel_format, &val);
        if (ret) {
                DRM_DEBUG_DRIVER("Invalid format\n");
                return val;
@@ -217,6 +222,51 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 }
 EXPORT_SYMBOL(sun4i_backend_update_layer_buffer);
 
+static int sun4i_backend_init_sat(struct device *dev) {
+       struct sun4i_backend *backend = dev_get_drvdata(dev);
+       int ret;
+
+       backend->sat_reset = devm_reset_control_get(dev, "sat");
+       if (IS_ERR(backend->sat_reset)) {
+               dev_err(dev, "Couldn't get the SAT reset line\n");
+               return PTR_ERR(backend->sat_reset);
+       }
+
+       ret = reset_control_deassert(backend->sat_reset);
+       if (ret) {
+               dev_err(dev, "Couldn't deassert the SAT reset line\n");
+               return ret;
+       }
+
+       backend->sat_clk = devm_clk_get(dev, "sat");
+       if (IS_ERR(backend->sat_clk)) {
+               dev_err(dev, "Couldn't get our SAT clock\n");
+               ret = PTR_ERR(backend->sat_clk);
+               goto err_assert_reset;
+       }
+
+       ret = clk_prepare_enable(backend->sat_clk);
+       if (ret) {
+               dev_err(dev, "Couldn't enable the SAT clock\n");
+               return ret;
+       }
+
+       return 0;
+
+err_assert_reset:
+       reset_control_assert(backend->sat_reset);
+       return ret;
+}
+
+static int sun4i_backend_free_sat(struct device *dev) {
+       struct sun4i_backend *backend = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(backend->sat_clk);
+       reset_control_assert(backend->sat_reset);
+
+       return 0;
+}
+
 static struct regmap_config sun4i_backend_regmap_config = {
        .reg_bits       = 32,
        .val_bits       = 32,
@@ -243,10 +293,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        regs = devm_ioremap_resource(dev, res);
-       if (IS_ERR(regs)) {
-               dev_err(dev, "Couldn't map the backend registers\n");
+       if (IS_ERR(regs))
                return PTR_ERR(regs);
-       }
 
        backend->regs = devm_regmap_init_mmio(dev, regs,
                                              &sun4i_backend_regmap_config);
@@ -291,6 +339,15 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
        }
        clk_prepare_enable(backend->ram_clk);
 
+       if (of_device_is_compatible(dev->of_node,
+                                   "allwinner,sun8i-a33-display-backend")) {
+               ret = sun4i_backend_init_sat(dev);
+               if (ret) {
+                       dev_err(dev, "Couldn't init SAT resources\n");
+                       goto err_disable_ram_clk;
+               }
+       }
+
        /* Reset the registers */
        for (i = 0x800; i < 0x1000; i += 4)
                regmap_write(backend->regs, i, 0);
@@ -306,6 +363,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 
        return 0;
 
+err_disable_ram_clk:
+       clk_disable_unprepare(backend->ram_clk);
 err_disable_mod_clk:
        clk_disable_unprepare(backend->mod_clk);
 err_disable_bus_clk:
@@ -320,6 +379,10 @@ static void sun4i_backend_unbind(struct device *dev, struct device *master,
 {
        struct sun4i_backend *backend = dev_get_drvdata(dev);
 
+       if (of_device_is_compatible(dev->of_node,
+                                   "allwinner,sun8i-a33-display-backend"))
+               sun4i_backend_free_sat(dev);
+
        clk_disable_unprepare(backend->ram_clk);
        clk_disable_unprepare(backend->mod_clk);
        clk_disable_unprepare(backend->bus_clk);
@@ -345,6 +408,7 @@ static int sun4i_backend_remove(struct platform_device *pdev)
 
 static const struct of_device_id sun4i_backend_of_table[] = {
        { .compatible = "allwinner,sun5i-a13-display-backend" },
+       { .compatible = "allwinner,sun8i-a33-display-backend" },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);
index 7070bb3..83e63cc 100644 (file)
@@ -52,8 +52,8 @@
 #define SUN4I_BACKEND_LAYFB_L32ADD_REG(l)      (0x850 + (0x4 * (l)))
 
 #define SUN4I_BACKEND_LAYFB_H4ADD_REG          0x860
-#define SUN4I_BACKEND_LAYFB_H4ADD_MSK(l)               GENMASK(3 + ((l) * 8), 0)
-#define SUN4I_BACKEND_LAYFB_H4ADD(l, val)                      ((val) << ((l) * 8))
+#define SUN4I_BACKEND_LAYFB_H4ADD_MSK(l)               GENMASK(3 + ((l) * 8), (l) * 8)
+#define SUN4I_BACKEND_LAYFB_H4ADD(l, val)              ((val) << ((l) * 8))
 
 #define SUN4I_BACKEND_REGBUFFCTL_REG           0x870
 #define SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS          BIT(1)
@@ -146,6 +146,9 @@ struct sun4i_backend {
        struct clk              *bus_clk;
        struct clk              *mod_clk;
        struct clk              *ram_clk;
+
+       struct clk              *sat_clk;
+       struct reset_control    *sat_reset;
 };
 
 void sun4i_backend_apply_color_correction(struct sun4i_backend *backend);
index 5b34631..d401156 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/regmap.h>
 
 #include "sun4i_tcon.h"
+#include "sun4i_dotclock.h"
 
 struct sun4i_dclk {
        struct clk_hw   hw;
@@ -61,7 +62,7 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
        regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val);
 
        val >>= SUN4I_TCON0_DCLK_DIV_SHIFT;
-       val &= SUN4I_TCON0_DCLK_DIV_WIDTH;
+       val &= (1 << SUN4I_TCON0_DCLK_DIV_WIDTH) - 1;
 
        if (!val)
                val = 1;
@@ -76,7 +77,7 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
        u8 best_div = 1;
        int i;
 
-       for (i = 6; i < 127; i++) {
+       for (i = 6; i <= 127; i++) {
                unsigned long ideal = rate * i;
                unsigned long rounded;
 
@@ -89,7 +90,8 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
                        goto out;
                }
 
-               if ((rounded < ideal) && (rounded > best_parent)) {
+               if (abs(rate - rounded / i) <
+                   abs(rate - best_parent / best_div)) {
                        best_parent = rounded;
                        best_div = i;
                }
index 7092daa..0da9862 100644 (file)
@@ -17,6 +17,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_helper.h>
 
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
@@ -109,7 +110,7 @@ static void sun4i_remove_framebuffers(void)
        ap->ranges[0].base = 0;
        ap->ranges[0].size = ~0;
 
-       remove_conflicting_framebuffers(ap, "sun4i-drm-fb", false);
+       drm_fb_helper_remove_conflicting_framebuffers(ap, "sun4i-drm-fb", false);
        kfree(ap);
 }
 
@@ -120,8 +121,8 @@ static int sun4i_drv_bind(struct device *dev)
        int ret;
 
        drm = drm_dev_alloc(&sun4i_drv_driver, dev);
-       if (!drm)
-               return -ENOMEM;
+       if (IS_ERR(drm))
+               return PTR_ERR(drm);
 
        drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
        if (!drv) {
@@ -199,13 +200,14 @@ static const struct component_master_ops sun4i_drv_master_ops = {
 
 static bool sun4i_drv_node_is_frontend(struct device_node *node)
 {
-       return of_device_is_compatible(node,
-                                      "allwinner,sun5i-a13-display-frontend");
+       return of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") ||
+               of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend");
 }
 
 static bool sun4i_drv_node_is_tcon(struct device_node *node)
 {
-       return of_device_is_compatible(node, "allwinner,sun5i-a13-tcon");
+       return of_device_is_compatible(node, "allwinner,sun5i-a13-tcon") ||
+               of_device_is_compatible(node, "allwinner,sun8i-a33-tcon");
 }
 
 static int compare_of(struct device *dev, void *data)
@@ -257,8 +259,8 @@ static int sun4i_drv_add_endpoints(struct device *dev,
                }
 
                /*
-                * If the node is our TCON, the first port is used for our
-                * panel, and will not be part of the
+                * If the node is our TCON, the first port is used for
+                * panel or bridges, and will not be part of the
                 * component framework.
                 */
                if (sun4i_drv_node_is_tcon(node)) {
@@ -320,6 +322,7 @@ static int sun4i_drv_remove(struct platform_device *pdev)
 
 static const struct of_device_id sun4i_drv_of_table[] = {
        { .compatible = "allwinner,sun5i-a13-display-engine" },
+       { .compatible = "allwinner,sun8i-a33-display-engine" },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun4i_drv_of_table);
index 70688fe..8b6ce61 100644 (file)
@@ -15,6 +15,7 @@
 #include <drm/drmP.h>
 
 #include "sun4i_drv.h"
+#include "sun4i_framebuffer.h"
 
 static void sun4i_de_output_poll_changed(struct drm_device *drm)
 {
index 068ab80..f0035bf 100644 (file)
 #include "sun4i_drv.h"
 #include "sun4i_layer.h"
 
-#define SUN4I_NUM_LAYERS       2
+struct sun4i_plane_desc {
+              enum drm_plane_type     type;
+              u8                      pipe;
+              const uint32_t          *formats;
+              uint32_t                nformats;
+};
 
 static int sun4i_backend_layer_atomic_check(struct drm_plane *plane,
                                            struct drm_plane_state *state)
@@ -65,14 +70,35 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
        .update_plane           = drm_atomic_helper_update_plane,
 };
 
-static const uint32_t sun4i_backend_layer_formats[] = {
+static const uint32_t sun4i_backend_layer_formats_primary[] = {
        DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_RGB888,
        DRM_FORMAT_XRGB8888,
+};
+
+static const uint32_t sun4i_backend_layer_formats_overlay[] = {
+       DRM_FORMAT_ARGB8888,
        DRM_FORMAT_RGB888,
+       DRM_FORMAT_XRGB8888,
+};
+
+static const struct sun4i_plane_desc sun4i_backend_planes[] = {
+       {
+               .type = DRM_PLANE_TYPE_PRIMARY,
+               .pipe = 0,
+               .formats = sun4i_backend_layer_formats_primary,
+               .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_primary),
+       },
+       {
+               .type = DRM_PLANE_TYPE_OVERLAY,
+               .pipe = 1,
+               .formats = sun4i_backend_layer_formats_overlay,
+               .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_overlay),
+       },
 };
 
 static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
-                                               enum drm_plane_type type)
+                                               const struct sun4i_plane_desc *plane)
 {
        struct sun4i_drv *drv = drm->dev_private;
        struct sun4i_layer *layer;
@@ -84,10 +110,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
 
        ret = drm_universal_plane_init(drm, &layer->plane, BIT(0),
                                       &sun4i_backend_layer_funcs,
-                                      sun4i_backend_layer_formats,
-                                      ARRAY_SIZE(sun4i_backend_layer_formats),
-                                      type,
-                                      NULL);
+                                      plane->formats, plane->nformats,
+                                      plane->type, NULL);
        if (ret) {
                dev_err(drm->dev, "Couldn't initialize layer\n");
                return ERR_PTR(ret);
@@ -97,7 +121,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
                             &sun4i_backend_layer_helper_funcs);
        layer->drv = drv;
 
-       if (type == DRM_PLANE_TYPE_PRIMARY)
+       if (plane->type == DRM_PLANE_TYPE_PRIMARY)
                drv->primary = &layer->plane;
 
        return layer;
@@ -109,8 +133,8 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
        struct sun4i_layer **layers;
        int i;
 
-       layers = devm_kcalloc(drm->dev, SUN4I_NUM_LAYERS, sizeof(**layers),
-                             GFP_KERNEL);
+       layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes),
+                             sizeof(**layers), GFP_KERNEL);
        if (!layers)
                return ERR_PTR(-ENOMEM);
 
@@ -135,13 +159,11 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
         * SoCs that support it, sprites could fill the need for more
         * layers.
         */
-       for (i = 0; i < SUN4I_NUM_LAYERS; i++) {
-               enum drm_plane_type type = (i == 0)
-                                        ? DRM_PLANE_TYPE_PRIMARY
-                                        : DRM_PLANE_TYPE_OVERLAY;
+       for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
+               const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
                struct sun4i_layer *layer = layers[i];
 
-               layer = sun4i_layer_init_one(drm, type);
+               layer = sun4i_layer_init_one(drm, plane);
                if (IS_ERR(layer)) {
                        dev_err(drm->dev, "Couldn't initialize %s plane\n",
                                i ? "overlay" : "primary");
@@ -149,10 +171,10 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
                };
 
                DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
-                                i ? "overlay" : "primary", i);
+                                i ? "overlay" : "primary", plane->pipe);
                regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
                                   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
-                                  SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(i));
+                                  SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
 
                layer->id = i;
        };
index f5bbac6..c3ff10f 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "sun4i_drv.h"
 #include "sun4i_tcon.h"
+#include "sun4i_rgb.h"
 
 struct sun4i_rgb {
        struct drm_connector    connector;
@@ -151,7 +152,14 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
 
        DRM_DEBUG_DRIVER("Enabling RGB output\n");
 
-       drm_panel_enable(tcon->panel);
+       if (!IS_ERR(tcon->panel)) {
+               drm_panel_prepare(tcon->panel);
+               drm_panel_enable(tcon->panel);
+       }
+
+       /* encoder->bridge can be NULL; drm_bridge_enable checks for it */
+       drm_bridge_enable(encoder->bridge);
+
        sun4i_tcon_channel_enable(tcon, 0);
 }
 
@@ -164,7 +172,14 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
        DRM_DEBUG_DRIVER("Disabling RGB output\n");
 
        sun4i_tcon_channel_disable(tcon, 0);
-       drm_panel_disable(tcon->panel);
+
+       /* encoder->bridge can be NULL; drm_bridge_disable checks for it */
+       drm_bridge_disable(encoder->bridge);
+
+       if (!IS_ERR(tcon->panel)) {
+               drm_panel_disable(tcon->panel);
+               drm_panel_unprepare(tcon->panel);
+       }
 }
 
 static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
@@ -203,17 +218,22 @@ int sun4i_rgb_init(struct drm_device *drm)
 {
        struct sun4i_drv *drv = drm->dev_private;
        struct sun4i_tcon *tcon = drv->tcon;
+       struct drm_encoder *encoder;
        struct sun4i_rgb *rgb;
        int ret;
 
-       /* If we don't have a panel, there's no point in going on */
-       if (IS_ERR(tcon->panel))
-               return -ENODEV;
-
        rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL);
        if (!rgb)
                return -ENOMEM;
        rgb->drv = drv;
+       encoder = &rgb->encoder;
+
+       tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
+       encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
+       if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
+               dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
+               return 0;
+       }
 
        drm_encoder_helper_add(&rgb->encoder,
                               &sun4i_rgb_enc_helper_funcs);
@@ -230,19 +250,38 @@ int sun4i_rgb_init(struct drm_device *drm)
        /* The RGB encoder can only work with the TCON channel 0 */
        rgb->encoder.possible_crtcs = BIT(0);
 
-       drm_connector_helper_add(&rgb->connector,
-                                &sun4i_rgb_con_helper_funcs);
-       ret = drm_connector_init(drm, &rgb->connector,
-                                &sun4i_rgb_con_funcs,
-                                DRM_MODE_CONNECTOR_Unknown);
-       if (ret) {
-               dev_err(drm->dev, "Couldn't initialise the rgb connector\n");
-               goto err_cleanup_connector;
+       if (!IS_ERR(tcon->panel)) {
+               drm_connector_helper_add(&rgb->connector,
+                                        &sun4i_rgb_con_helper_funcs);
+               ret = drm_connector_init(drm, &rgb->connector,
+                                        &sun4i_rgb_con_funcs,
+                                        DRM_MODE_CONNECTOR_Unknown);
+               if (ret) {
+                       dev_err(drm->dev, "Couldn't initialise the rgb connector\n");
+                       goto err_cleanup_connector;
+               }
+
+               drm_mode_connector_attach_encoder(&rgb->connector,
+                                                 &rgb->encoder);
+
+               ret = drm_panel_attach(tcon->panel, &rgb->connector);
+               if (ret) {
+                       dev_err(drm->dev, "Couldn't attach our panel\n");
+                       goto err_cleanup_connector;
+               }
        }
 
-       drm_mode_connector_attach_encoder(&rgb->connector, &rgb->encoder);
+       if (!IS_ERR(encoder->bridge)) {
+               encoder->bridge->encoder = &rgb->encoder;
 
-       drm_panel_attach(tcon->panel, &rgb->connector);
+               ret = drm_bridge_attach(drm, encoder->bridge);
+               if (ret) {
+                       dev_err(drm->dev, "Couldn't attach our bridge\n");
+                       goto err_cleanup_connector;
+               }
+       } else {
+               encoder->bridge = NULL;
+       }
 
        return 0;
 
index 652385f..cadacb5 100644 (file)
@@ -59,11 +59,13 @@ void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel)
                regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
                                   SUN4I_TCON0_CTL_TCON_ENABLE, 0);
                clk_disable_unprepare(tcon->dclk);
-       } else if (channel == 1) {
-               regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
-                                  SUN4I_TCON1_CTL_TCON_ENABLE, 0);
-               clk_disable_unprepare(tcon->sclk1);
+               return;
        }
+
+       WARN_ON(!tcon->has_channel_1);
+       regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
+                          SUN4I_TCON1_CTL_TCON_ENABLE, 0);
+       clk_disable_unprepare(tcon->sclk1);
 }
 EXPORT_SYMBOL(sun4i_tcon_channel_disable);
 
@@ -75,12 +77,14 @@ void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel)
                                   SUN4I_TCON0_CTL_TCON_ENABLE,
                                   SUN4I_TCON0_CTL_TCON_ENABLE);
                clk_prepare_enable(tcon->dclk);
-       } else if (channel == 1) {
-               regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
-                                  SUN4I_TCON1_CTL_TCON_ENABLE,
-                                  SUN4I_TCON1_CTL_TCON_ENABLE);
-               clk_prepare_enable(tcon->sclk1);
+               return;
        }
+
+       WARN_ON(!tcon->has_channel_1);
+       regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
+                          SUN4I_TCON1_CTL_TCON_ENABLE,
+                          SUN4I_TCON1_CTL_TCON_ENABLE);
+       clk_prepare_enable(tcon->sclk1);
 }
 EXPORT_SYMBOL(sun4i_tcon_channel_enable);
 
@@ -198,6 +202,8 @@ void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
        u8 clk_delay;
        u32 val;
 
+       WARN_ON(!tcon->has_channel_1);
+
        /* Adjust clock delay */
        clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
        regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
@@ -321,10 +327,12 @@ static int sun4i_tcon_init_clocks(struct device *dev,
                return PTR_ERR(tcon->sclk0);
        }
 
-       tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");
-       if (IS_ERR(tcon->sclk1)) {
-               dev_err(dev, "Couldn't get the TCON channel 1 clock\n");
-               return PTR_ERR(tcon->sclk1);
+       if (tcon->has_channel_1) {
+               tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");
+               if (IS_ERR(tcon->sclk1)) {
+                       dev_err(dev, "Couldn't get the TCON channel 1 clock\n");
+                       return PTR_ERR(tcon->sclk1);
+               }
        }
 
        return sun4i_dclk_create(dev, tcon);
@@ -374,10 +382,8 @@ static int sun4i_tcon_init_regmap(struct device *dev,
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        regs = devm_ioremap_resource(dev, res);
-       if (IS_ERR(regs)) {
-               dev_err(dev, "Couldn't map the TCON registers\n");
+       if (IS_ERR(regs))
                return PTR_ERR(regs);
-       }
 
        tcon->regs = devm_regmap_init_mmio(dev, regs,
                                           &sun4i_tcon_regmap_config);
@@ -398,7 +404,7 @@ static int sun4i_tcon_init_regmap(struct device *dev,
        return 0;
 }
 
-static struct drm_panel *sun4i_tcon_find_panel(struct device_node *node)
+struct drm_panel *sun4i_tcon_find_panel(struct device_node *node)
 {
        struct device_node *port, *remote, *child;
        struct device_node *end_node = NULL;
@@ -432,6 +438,40 @@ static struct drm_panel *sun4i_tcon_find_panel(struct device_node *node)
        return of_drm_find_panel(remote) ?: ERR_PTR(-EPROBE_DEFER);
 }
 
+struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node)
+{
+       struct device_node *port, *remote, *child;
+       struct device_node *end_node = NULL;
+
+       /* Inputs are listed first, then outputs */
+       port = of_graph_get_port_by_id(node, 1);
+
+       /*
+        * Our first output is the RGB interface where the panel will
+        * be connected.
+        */
+       for_each_child_of_node(port, child) {
+               u32 reg;
+
+               of_property_read_u32(child, "reg", &reg);
+               if (reg == 0)
+                       end_node = child;
+       }
+
+       if (!end_node) {
+               DRM_DEBUG_DRIVER("Missing bridge endpoint\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       remote = of_graph_get_remote_port_parent(end_node);
+       if (!remote) {
+               DRM_DEBUG_DRIVER("Enable to parse remote node\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       return of_drm_find_bridge(remote) ?: ERR_PTR(-EPROBE_DEFER);
+}
+
 static int sun4i_tcon_bind(struct device *dev, struct device *master,
                           void *data)
 {
@@ -446,9 +486,15 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
        dev_set_drvdata(dev, tcon);
        drv->tcon = tcon;
        tcon->drm = drm;
+       tcon->dev = dev;
 
-       if (of_device_is_compatible(dev->of_node, "allwinner,sun5i-a13-tcon"))
+       if (of_device_is_compatible(dev->of_node, "allwinner,sun5i-a13-tcon")) {
                tcon->has_mux = true;
+               tcon->has_channel_1 = true;
+       } else {
+               tcon->has_mux = false;
+               tcon->has_channel_1 = false;
+       }
 
        tcon->lcd_rst = devm_reset_control_get(dev, "lcd");
        if (IS_ERR(tcon->lcd_rst)) {
@@ -484,12 +530,6 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
                goto err_free_clocks;
        }
 
-       tcon->panel = sun4i_tcon_find_panel(dev->of_node);
-       if (IS_ERR(tcon->panel)) {
-               dev_info(dev, "No panel found... RGB output disabled\n");
-               return 0;
-       }
-
        ret = sun4i_rgb_init(drm);
        if (ret < 0)
                goto err_free_clocks;
@@ -519,19 +559,22 @@ static struct component_ops sun4i_tcon_ops = {
 static int sun4i_tcon_probe(struct platform_device *pdev)
 {
        struct device_node *node = pdev->dev.of_node;
+       struct drm_bridge *bridge;
        struct drm_panel *panel;
 
        /*
-        * The panel is not ready.
+        * Neither the bridge or the panel is ready.
         * Defer the probe.
         */
        panel = sun4i_tcon_find_panel(node);
+       bridge = sun4i_tcon_find_bridge(node);
 
        /*
         * If we don't have a panel endpoint, just go on
         */
-       if (PTR_ERR(panel) == -EPROBE_DEFER) {
-               DRM_DEBUG_DRIVER("Still waiting for our panel. Deferring...\n");
+       if ((PTR_ERR(panel) == -EPROBE_DEFER) &&
+           (PTR_ERR(bridge) == -EPROBE_DEFER)) {
+               DRM_DEBUG_DRIVER("Still waiting for our panel/bridge. Deferring...\n");
                return -EPROBE_DEFER;
        }
 
@@ -547,6 +590,7 @@ static int sun4i_tcon_remove(struct platform_device *pdev)
 
 static const struct of_device_id sun4i_tcon_of_table[] = {
        { .compatible = "allwinner,sun5i-a13-tcon" },
+       { .compatible = "allwinner,sun8i-a33-tcon" },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
index 0e0b11d..12bd489 100644 (file)
 #define SUN4I_TCON_MAX_CHANNELS                2
 
 struct sun4i_tcon {
+       struct device                   *dev;
        struct drm_device               *drm;
        struct regmap                   *regs;
 
@@ -163,8 +164,13 @@ struct sun4i_tcon {
        bool                            has_mux;
 
        struct drm_panel                *panel;
+
+       bool                            has_channel_1;
 };
 
+struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
+struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
+
 /* Global Control */
 void sun4i_tcon_disable(struct sun4i_tcon *tcon);
 void sun4i_tcon_enable(struct sun4i_tcon *tcon);
index b841478..1dd3d9e 100644 (file)
@@ -161,10 +161,10 @@ struct tv_mode {
        bool            dac3_en;
        bool            dac_bit25_en;
 
-       struct color_gains              *color_gains;
-       struct burst_levels             *burst_levels;
-       struct video_levels             *video_levels;
-       struct resync_parameters        *resync_params;
+       const struct color_gains        *color_gains;
+       const struct burst_levels       *burst_levels;
+       const struct video_levels       *video_levels;
+       const struct resync_parameters  *resync_params;
 };
 
 struct sun4i_tv {
@@ -178,39 +178,39 @@ struct sun4i_tv {
        struct sun4i_drv        *drv;
 };
 
-struct video_levels ntsc_video_levels = {
+static const struct video_levels ntsc_video_levels = {
        .black = 282,   .blank = 240,
 };
 
-struct video_levels pal_video_levels = {
+static const struct video_levels pal_video_levels = {
        .black = 252,   .blank = 252,
 };
 
-struct burst_levels ntsc_burst_levels = {
+static const struct burst_levels ntsc_burst_levels = {
        .cb = 79,       .cr = 0,
 };
 
-struct burst_levels pal_burst_levels = {
+static const struct burst_levels pal_burst_levels = {
        .cb = 40,       .cr = 40,
 };
 
-struct color_gains ntsc_color_gains = {
+static const struct color_gains ntsc_color_gains = {
        .cb = 160,      .cr = 160,
 };
 
-struct color_gains pal_color_gains = {
+static const struct color_gains pal_color_gains = {
        .cb = 224,      .cr = 224,
 };
 
-struct resync_parameters ntsc_resync_parameters = {
+static const struct resync_parameters ntsc_resync_parameters = {
        .field = false, .line = 14,     .pixel = 12,
 };
 
-struct resync_parameters pal_resync_parameters = {
+static const struct resync_parameters pal_resync_parameters = {
        .field = true,  .line = 13,     .pixel = 12,
 };
 
-struct tv_mode tv_modes[] = {
+static const struct tv_mode tv_modes[] = {
        {
                .name           = "NTSC",
                .mode           = SUN4I_TVE_CFG0_RES_480i,
@@ -289,13 +289,13 @@ drm_connector_to_sun4i_tv(struct drm_connector *connector)
  * So far, it doesn't seem to be preserved when the mode is passed by
  * to mode_set for some reason.
  */
-static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode)
+static const struct tv_mode *sun4i_tv_find_tv_by_mode(const struct drm_display_mode *mode)
 {
        int i;
 
        /* First try to identify the mode by name */
        for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
-               struct tv_mode *tv_mode = &tv_modes[i];
+               const struct tv_mode *tv_mode = &tv_modes[i];
 
                DRM_DEBUG_DRIVER("Comparing mode %s vs %s",
                                 mode->name, tv_mode->name);
@@ -306,7 +306,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode)
 
        /* Then by number of lines */
        for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
-               struct tv_mode *tv_mode = &tv_modes[i];
+               const struct tv_mode *tv_mode = &tv_modes[i];
 
                DRM_DEBUG_DRIVER("Comparing mode %s vs %s (X: %d vs %d)",
                                 mode->name, tv_mode->name,
@@ -319,7 +319,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode)
        return NULL;
 }
 
-static void sun4i_tv_mode_to_drm_mode(struct tv_mode *tv_mode,
+static void sun4i_tv_mode_to_drm_mode(const struct tv_mode *tv_mode,
                                      struct drm_display_mode *mode)
 {
        DRM_DEBUG_DRIVER("Creating mode %s\n", mode->name);
@@ -386,7 +386,7 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
        struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
        struct sun4i_drv *drv = tv->drv;
        struct sun4i_tcon *tcon = drv->tcon;
-       struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
+       const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
 
        sun4i_tcon1_mode_set(tcon, mode);
 
@@ -507,8 +507,14 @@ static int sun4i_tv_comp_get_modes(struct drm_connector *connector)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
-               struct drm_display_mode *mode = drm_mode_create(connector->dev);
-               struct tv_mode *tv_mode = &tv_modes[i];
+               struct drm_display_mode *mode;
+               const struct tv_mode *tv_mode = &tv_modes[i];
+
+               mode = drm_mode_create(connector->dev);
+               if (!mode) {
+                       DRM_ERROR("Failed to create a new display mode\n");
+                       return 0;
+               }
 
                strcpy(mode->name, tv_mode->name);
 
diff --git a/drivers/gpu/drm/sun4i/sun6i_drc.c b/drivers/gpu/drm/sun4i/sun6i_drc.c
new file mode 100644 (file)
index 0000000..bf6d846
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+struct sun6i_drc {
+       struct clk              *bus_clk;
+       struct clk              *mod_clk;
+       struct reset_control    *reset;
+};
+
+static int sun6i_drc_bind(struct device *dev, struct device *master,
+                        void *data)
+{
+       struct sun6i_drc *drc;
+       int ret;
+
+       drc = devm_kzalloc(dev, sizeof(*drc), GFP_KERNEL);
+       if (!drc)
+               return -ENOMEM;
+       dev_set_drvdata(dev, drc);
+
+       drc->reset = devm_reset_control_get(dev, NULL);
+       if (IS_ERR(drc->reset)) {
+               dev_err(dev, "Couldn't get our reset line\n");
+               return PTR_ERR(drc->reset);
+       }
+
+       ret = reset_control_deassert(drc->reset);
+       if (ret) {
+               dev_err(dev, "Couldn't deassert our reset line\n");
+               return ret;
+       }
+
+       drc->bus_clk = devm_clk_get(dev, "ahb");
+       if (IS_ERR(drc->bus_clk)) {
+               dev_err(dev, "Couldn't get our bus clock\n");
+               ret = PTR_ERR(drc->bus_clk);
+               goto err_assert_reset;
+       }
+       clk_prepare_enable(drc->bus_clk);
+
+       drc->mod_clk = devm_clk_get(dev, "mod");
+       if (IS_ERR(drc->mod_clk)) {
+               dev_err(dev, "Couldn't get our mod clock\n");
+               ret = PTR_ERR(drc->mod_clk);
+               goto err_disable_bus_clk;
+       }
+       clk_prepare_enable(drc->mod_clk);
+
+       return 0;
+
+err_disable_bus_clk:
+       clk_disable_unprepare(drc->bus_clk);
+err_assert_reset:
+       reset_control_assert(drc->reset);
+       return ret;
+}
+
+static void sun6i_drc_unbind(struct device *dev, struct device *master,
+                           void *data)
+{
+       struct sun6i_drc *drc = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(drc->mod_clk);
+       clk_disable_unprepare(drc->bus_clk);
+       reset_control_assert(drc->reset);
+}
+
+static struct component_ops sun6i_drc_ops = {
+       .bind   = sun6i_drc_bind,
+       .unbind = sun6i_drc_unbind,
+};
+
+static int sun6i_drc_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &sun6i_drc_ops);
+}
+
+static int sun6i_drc_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &sun6i_drc_ops);
+
+       return 0;
+}
+
+static const struct of_device_id sun6i_drc_of_table[] = {
+       { .compatible = "allwinner,sun8i-a33-drc" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sun6i_drc_of_table);
+
+static struct platform_driver sun6i_drc_platform_driver = {
+       .probe          = sun6i_drc_probe,
+       .remove         = sun6i_drc_remove,
+       .driver         = {
+               .name           = "sun6i-drc",
+               .of_match_table = sun6i_drc_of_table,
+       },
+};
+module_platform_driver(sun6i_drc_platform_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 Dynamic Range Control (DRC) Driver");
+MODULE_LICENSE("GPL");
index fab5ebc..f418892 100644 (file)
@@ -56,6 +56,7 @@ static const struct file_operations tdfx_driver_fops = {
 };
 
 static struct drm_driver driver = {
+       .driver_features = DRIVER_LEGACY,
        .set_busid = drm_pci_set_busid,
        .fops = &tdfx_driver_fops,
        .name = DRIVER_NAME,
index 8495bd0..4010d69 100644 (file)
@@ -480,17 +480,6 @@ static const struct drm_plane_funcs tegra_primary_plane_funcs = {
        .atomic_destroy_state = tegra_plane_atomic_destroy_state,
 };
 
-static int tegra_plane_prepare_fb(struct drm_plane *plane,
-                                 const struct drm_plane_state *new_state)
-{
-       return 0;
-}
-
-static void tegra_plane_cleanup_fb(struct drm_plane *plane,
-                                  const struct drm_plane_state *old_fb)
-{
-}
-
 static int tegra_plane_state_add(struct tegra_plane *plane,
                                 struct drm_plane_state *state)
 {
@@ -591,7 +580,14 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
                struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
 
                window.base[i] = bo->paddr + fb->offsets[i];
-               window.stride[i] = fb->pitches[i];
+
+               /*
+                * Tegra uses a shared stride for UV planes. Framebuffers are
+                * already checked for this in the tegra_plane_atomic_check()
+                * function, so it's safe to ignore the V-plane pitch here.
+                */
+               if (i < 2)
+                       window.stride[i] = fb->pitches[i];
        }
 
        tegra_dc_setup_window(dc, p->index, &window);
@@ -624,8 +620,6 @@ static void tegra_plane_atomic_disable(struct drm_plane *plane,
 }
 
 static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = {
-       .prepare_fb = tegra_plane_prepare_fb,
-       .cleanup_fb = tegra_plane_cleanup_fb,
        .atomic_check = tegra_plane_atomic_check,
        .atomic_update = tegra_plane_atomic_update,
        .atomic_disable = tegra_plane_atomic_disable,
@@ -796,8 +790,6 @@ static const struct drm_plane_funcs tegra_cursor_plane_funcs = {
 };
 
 static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
-       .prepare_fb = tegra_plane_prepare_fb,
-       .cleanup_fb = tegra_plane_cleanup_fb,
        .atomic_check = tegra_cursor_atomic_check,
        .atomic_update = tegra_cursor_atomic_update,
        .atomic_disable = tegra_cursor_atomic_disable,
@@ -866,8 +858,6 @@ static const uint32_t tegra_overlay_plane_formats[] = {
 };
 
 static const struct drm_plane_helper_funcs tegra_overlay_plane_helper_funcs = {
-       .prepare_fb = tegra_plane_prepare_fb,
-       .cleanup_fb = tegra_plane_cleanup_fb,
        .atomic_check = tegra_plane_atomic_check,
        .atomic_update = tegra_plane_atomic_update,
        .atomic_disable = tegra_plane_atomic_disable,
index 755264d..8ab47b5 100644 (file)
@@ -57,7 +57,8 @@ static void tegra_atomic_complete(struct tegra_drm *tegra,
 
        drm_atomic_helper_commit_modeset_disables(drm, state);
        drm_atomic_helper_commit_modeset_enables(drm, state);
-       drm_atomic_helper_commit_planes(drm, state, true);
+       drm_atomic_helper_commit_planes(drm, state,
+                                       DRM_PLANE_COMMIT_ACTIVE_ONLY);
 
        drm_atomic_helper_wait_for_vblanks(drm, state);
 
@@ -982,8 +983,8 @@ static int host1x_drm_probe(struct host1x_device *dev)
        int err;
 
        drm = drm_dev_alloc(driver, &dev->dev);
-       if (!drm)
-               return -ENOMEM;
+       if (IS_ERR(drm))
+               return PTR_ERR(drm);
 
        dev_set_drvdata(&dev->dev, drm);
 
index aa60d99..95e622e 100644 (file)
@@ -613,7 +613,7 @@ struct dma_buf *tegra_gem_prime_export(struct drm_device *drm,
        exp_info.flags = flags;
        exp_info.priv = gem;
 
-       return dma_buf_export(&exp_info);
+       return drm_gem_dmabuf_export(drm, &exp_info);
 }
 
 struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm,
index deeca48..6f67517 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_DRM_TILCDC_SLAVE_COMPAT) += tilcdc_slave_compat.o \
                                         tilcdc_slave_compat.dtb.o
 
 tilcdc-y := \
+       tilcdc_plane.o \
        tilcdc_crtc.o \
        tilcdc_tfp410.o \
        tilcdc_panel.o \
index 107c8bd..52ebe8f 100644 (file)
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "drm_flip_work.h"
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_flip_work.h>
 #include <drm/drm_plane_helper.h>
+#include <linux/workqueue.h>
 
 #include "tilcdc_drv.h"
 #include "tilcdc_regs.h"
 struct tilcdc_crtc {
        struct drm_crtc base;
 
+       struct drm_plane primary;
        const struct tilcdc_panel_info *info;
        struct drm_pending_vblank_event *event;
-       int dpms;
+       bool enabled;
        wait_queue_head_t frame_done_wq;
        bool frame_done;
        spinlock_t irq_lock;
 
+       unsigned int lcd_fck_rate;
+
        ktime_t last_vblank;
 
        struct drm_framebuffer *curr_fb;
@@ -67,6 +74,7 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
        struct drm_gem_cma_object *gem;
        unsigned int depth, bpp;
        dma_addr_t start, end;
+       u64 dma_base_and_ceiling;
 
        drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
        gem = drm_fb_cma_get_gem_obj(fb, 0);
@@ -77,8 +85,13 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
 
        end = start + (crtc->mode.vdisplay * fb->pitches[0]);
 
-       tilcdc_write(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, start);
-       tilcdc_write(dev, LCDC_DMA_FB_CEILING_ADDR_0_REG, end);
+       /* Write LCDC_DMA_FB_BASE_ADDR_0_REG and LCDC_DMA_FB_CEILING_ADDR_0_REG
+        * with a single insruction, if available. This should make it more
+        * unlikely that LCDC would fetch the DMA addresses in the middle of
+        * an update.
+        */
+       dma_base_and_ceiling = (u64)(end - 1) << 32 | start;
+       tilcdc_write64(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, dma_base_and_ceiling);
 
        if (tilcdc_crtc->curr_fb)
                drm_flip_work_queue(&tilcdc_crtc->unref_work,
@@ -87,6 +100,43 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
        tilcdc_crtc->curr_fb = fb;
 }
 
+static void tilcdc_crtc_enable_irqs(struct drm_device *dev)
+{
+       struct tilcdc_drm_private *priv = dev->dev_private;
+
+       tilcdc_clear_irqstatus(dev, 0xffffffff);
+
+       if (priv->rev == 1) {
+               tilcdc_set(dev, LCDC_RASTER_CTRL_REG,
+                       LCDC_V1_UNDERFLOW_INT_ENA);
+               tilcdc_set(dev, LCDC_DMA_CTRL_REG,
+                       LCDC_V1_END_OF_FRAME_INT_ENA);
+       } else {
+               tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG,
+                       LCDC_V2_UNDERFLOW_INT_ENA |
+                       LCDC_V2_END_OF_FRAME0_INT_ENA |
+                       LCDC_FRAME_DONE | LCDC_SYNC_LOST);
+       }
+}
+
+static void tilcdc_crtc_disable_irqs(struct drm_device *dev)
+{
+       struct tilcdc_drm_private *priv = dev->dev_private;
+
+       /* disable irqs that we might have enabled: */
+       if (priv->rev == 1) {
+               tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
+                       LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA);
+               tilcdc_clear(dev, LCDC_DMA_CTRL_REG,
+                       LCDC_V1_END_OF_FRAME_INT_ENA);
+       } else {
+               tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
+                       LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA |
+                       LCDC_V2_END_OF_FRAME0_INT_ENA |
+                       LCDC_FRAME_DONE | LCDC_SYNC_LOST);
+       }
+}
+
 static void reset(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -100,66 +150,112 @@ static void reset(struct drm_crtc *crtc)
        tilcdc_clear(dev, LCDC_CLK_RESET_REG, LCDC_CLK_MAIN_RESET);
 }
 
-static void start(struct drm_crtc *crtc)
+static void tilcdc_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
+       struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
+
+       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+
+       if (tilcdc_crtc->enabled)
+               return;
+
+       pm_runtime_get_sync(dev->dev);
 
        reset(crtc);
 
+       tilcdc_crtc_enable_irqs(dev);
+
        tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE);
        tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_PALETTE_LOAD_MODE(DATA_ONLY));
        tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
+
+       drm_crtc_vblank_on(crtc);
+
+       tilcdc_crtc->enabled = true;
 }
 
-static void stop(struct drm_crtc *crtc)
+void tilcdc_crtc_disable(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;
+
+       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+
+       if (!tilcdc_crtc->enabled)
+               return;
 
+       tilcdc_crtc->frame_done = false;
        tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
+
+       /*
+        * if necessary wait for framedone irq which will still come
+        * before putting things to sleep..
+        */
+       if (priv->rev == 2) {
+               int ret = wait_event_timeout(tilcdc_crtc->frame_done_wq,
+                                            tilcdc_crtc->frame_done,
+                                            msecs_to_jiffies(500));
+               if (ret == 0)
+                       dev_err(dev->dev, "%s: timeout waiting for framedone\n",
+                               __func__);
+       }
+
+       drm_crtc_vblank_off(crtc);
+
+       tilcdc_crtc_disable_irqs(dev);
+
+       pm_runtime_put_sync(dev->dev);
+
+       if (tilcdc_crtc->next_fb) {
+               drm_flip_work_queue(&tilcdc_crtc->unref_work,
+                                   tilcdc_crtc->next_fb);
+               tilcdc_crtc->next_fb = NULL;
+       }
+
+       if (tilcdc_crtc->curr_fb) {
+               drm_flip_work_queue(&tilcdc_crtc->unref_work,
+                                   tilcdc_crtc->curr_fb);
+               tilcdc_crtc->curr_fb = NULL;
+       }
+
+       drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
+       tilcdc_crtc->last_vblank = ktime_set(0, 0);
+
+       tilcdc_crtc->enabled = false;
+}
+
+static bool tilcdc_crtc_is_on(struct drm_crtc *crtc)
+{
+       return crtc->state && crtc->state->enable && crtc->state->active;
 }
 
 static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
 {
        struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
+       struct tilcdc_drm_private *priv = crtc->dev->dev_private;
+
+       drm_modeset_lock_crtc(crtc, NULL);
+       tilcdc_crtc_disable(crtc);
+       drm_modeset_unlock_crtc(crtc);
 
-       tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       flush_workqueue(priv->wq);
 
        of_node_put(crtc->port);
        drm_crtc_cleanup(crtc);
        drm_flip_work_cleanup(&tilcdc_crtc->unref_work);
 }
 
-static int tilcdc_verify_fb(struct drm_crtc *crtc, struct drm_framebuffer *fb)
-{
-       struct drm_device *dev = crtc->dev;
-       unsigned int depth, bpp;
-
-       drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
-
-       if (fb->pitches[0] != crtc->mode.hdisplay * bpp / 8) {
-               dev_err(dev->dev,
-                       "Invalid pitch: fb and crtc widths must be the same");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int tilcdc_crtc_page_flip(struct drm_crtc *crtc,
+int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
                struct drm_framebuffer *fb,
-               struct drm_pending_vblank_event *event,
-               uint32_t page_flip_flags)
+               struct drm_pending_vblank_event *event)
 {
        struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
        struct drm_device *dev = crtc->dev;
-       int r;
        unsigned long flags;
-       s64 tdiff;
-       ktime_t next_vblank;
 
-       r = tilcdc_verify_fb(crtc, fb);
-       if (r)
-               return r;
+       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
 
        if (tilcdc_crtc->event) {
                dev_err(dev->dev, "already pending page flip!\n");
@@ -170,82 +266,31 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc,
 
        crtc->primary->fb = fb;
 
-       pm_runtime_get_sync(dev->dev);
-
        spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
 
-       next_vblank = ktime_add_us(tilcdc_crtc->last_vblank,
-               1000000 / crtc->hwmode.vrefresh);
+       if (crtc->hwmode.vrefresh && ktime_to_ns(tilcdc_crtc->last_vblank)) {
+               ktime_t next_vblank;
+               s64 tdiff;
+
+               next_vblank = ktime_add_us(tilcdc_crtc->last_vblank,
+                       1000000 / crtc->hwmode.vrefresh);
 
-       tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get()));
+               tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get()));
 
-       if (tdiff >= TILCDC_VBLANK_SAFETY_THRESHOLD_US)
+               if (tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US)
+                       tilcdc_crtc->next_fb = fb;
+       }
+
+       if (tilcdc_crtc->next_fb != fb)
                set_scanout(crtc, fb);
-       else
-               tilcdc_crtc->next_fb = fb;
 
        tilcdc_crtc->event = event;
 
        spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags);
 
-       pm_runtime_put_sync(dev->dev);
-
        return 0;
 }
 
-void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
-       struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
-       struct drm_device *dev = crtc->dev;
-       struct tilcdc_drm_private *priv = dev->dev_private;
-
-       /* we really only care about on or off: */
-       if (mode != DRM_MODE_DPMS_ON)
-               mode = DRM_MODE_DPMS_OFF;
-
-       if (tilcdc_crtc->dpms == mode)
-               return;
-
-       tilcdc_crtc->dpms = mode;
-
-       if (mode == DRM_MODE_DPMS_ON) {
-               pm_runtime_get_sync(dev->dev);
-               start(crtc);
-       } else {
-               tilcdc_crtc->frame_done = false;
-               stop(crtc);
-
-               /*
-                * if necessary wait for framedone irq which will still come
-                * before putting things to sleep..
-                */
-               if (priv->rev == 2) {
-                       int ret = wait_event_timeout(
-                                       tilcdc_crtc->frame_done_wq,
-                                       tilcdc_crtc->frame_done,
-                                       msecs_to_jiffies(50));
-                       if (ret == 0)
-                               dev_err(dev->dev, "timeout waiting for framedone\n");
-               }
-
-               pm_runtime_put_sync(dev->dev);
-
-               if (tilcdc_crtc->next_fb) {
-                       drm_flip_work_queue(&tilcdc_crtc->unref_work,
-                                           tilcdc_crtc->next_fb);
-                       tilcdc_crtc->next_fb = NULL;
-               }
-
-               if (tilcdc_crtc->curr_fb) {
-                       drm_flip_work_queue(&tilcdc_crtc->unref_work,
-                                           tilcdc_crtc->curr_fb);
-                       tilcdc_crtc->curr_fb = NULL;
-               }
-
-               drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
-       }
-}
-
 static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc,
                const struct drm_display_mode *mode,
                struct drm_display_mode *adjusted_mode)
@@ -275,41 +320,54 @@ static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc,
        return true;
 }
 
-static void tilcdc_crtc_prepare(struct drm_crtc *crtc)
+static void tilcdc_crtc_set_clk(struct drm_crtc *crtc)
 {
-       tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-}
+       struct drm_device *dev = crtc->dev;
+       struct tilcdc_drm_private *priv = dev->dev_private;
+       struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
+       const unsigned clkdiv = 2; /* using a fixed divider of 2 */
+       int ret;
 
-static void tilcdc_crtc_commit(struct drm_crtc *crtc)
-{
-       tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+       /* mode.clock is in KHz, set_rate wants parameter in Hz */
+       ret = clk_set_rate(priv->clk, crtc->mode.clock * 1000 * clkdiv);
+       if (ret < 0) {
+               dev_err(dev->dev, "failed to set display clock rate to: %d\n",
+                       crtc->mode.clock);
+               return;
+       }
+
+       tilcdc_crtc->lcd_fck_rate = clk_get_rate(priv->clk);
+
+       DBG("lcd_clk=%u, mode clock=%d, div=%u",
+           tilcdc_crtc->lcd_fck_rate, crtc->mode.clock, clkdiv);
+
+       /* Configure the LCD clock divisor. */
+       tilcdc_write(dev, LCDC_CTRL_REG, LCDC_CLK_DIVISOR(clkdiv) |
+                    LCDC_RASTER_MODE);
+
+       if (priv->rev == 2)
+               tilcdc_set(dev, LCDC_CLK_ENABLE_REG,
+                               LCDC_V2_DMA_CLK_EN | LCDC_V2_LIDD_CLK_EN |
+                               LCDC_V2_CORE_CLK_EN);
 }
 
-static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
-               struct drm_display_mode *mode,
-               struct drm_display_mode *adjusted_mode,
-               int x, int y,
-               struct drm_framebuffer *old_fb)
+static void tilcdc_crtc_mode_set_nofb(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;
        const struct tilcdc_panel_info *info = tilcdc_crtc->info;
        uint32_t reg, hbp, hfp, hsw, vbp, vfp, vsw;
-       int ret;
+       struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+       struct drm_framebuffer *fb = crtc->primary->state->fb;
 
-       ret = tilcdc_crtc_mode_valid(crtc, mode);
-       if (WARN_ON(ret))
-               return ret;
+       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
 
        if (WARN_ON(!info))
-               return -EINVAL;
-
-       ret = tilcdc_verify_fb(crtc, crtc->primary->fb);
-       if (ret)
-               return ret;
+               return;
 
-       pm_runtime_get_sync(dev->dev);
+       if (WARN_ON(!fb))
+               return;
 
        /* Configure the Burst Size and fifo threshold of DMA: */
        reg = tilcdc_read(dev, LCDC_DMA_CTRL_REG) & ~0x00000770;
@@ -330,7 +388,8 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
                reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_16);
                break;
        default:
-               return -EINVAL;
+               dev_err(dev->dev, "invalid burst size\n");
+               return;
        }
        reg |= (info->fifo_th << 8);
        tilcdc_write(dev, LCDC_DMA_CTRL_REG, reg);
@@ -344,9 +403,9 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
        vsw = mode->vsync_end - mode->vsync_start;
 
        DBG("%dx%d, hbp=%u, hfp=%u, hsw=%u, vbp=%u, vfp=%u, vsw=%u",
-                       mode->hdisplay, mode->vdisplay, hbp, hfp, hsw, vbp, vfp, vsw);
+           mode->hdisplay, mode->vdisplay, hbp, hfp, hsw, vbp, vfp, vsw);
 
-       /* Configure the AC Bias Period and Number of Transitions per Interrupt: */
+       /* Set AC Bias Period and Number of Transitions per Interrupt: */
        reg = tilcdc_read(dev, LCDC_RASTER_TIMING_2_REG) & ~0x000fff00;
        reg |= LCDC_AC_BIAS_FREQUENCY(info->ac_bias) |
                LCDC_AC_BIAS_TRANSITIONS_PER_INT(info->ac_bias_intrpt);
@@ -381,7 +440,7 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
        /*
         * be sure to set Bit 10 for the V2 LCDC controller,
         * otherwise limited to 1024 pixels width, stopping
-        * 1920x1080 being suppoted.
+        * 1920x1080 being supported.
         */
        if (priv->rev == 2) {
                if ((mode->vdisplay - 1) & 0x400) {
@@ -396,14 +455,15 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
        /* Configure display type: */
        reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG) &
                ~(LCDC_TFT_MODE | LCDC_MONO_8BIT_MODE | LCDC_MONOCHROME_MODE |
-                       LCDC_V2_TFT_24BPP_MODE | LCDC_V2_TFT_24BPP_UNPACK | 0x000ff000);
+                 LCDC_V2_TFT_24BPP_MODE | LCDC_V2_TFT_24BPP_UNPACK |
+                 0x000ff000 /* Palette Loading Delay bits */);
        reg |= LCDC_TFT_MODE; /* no monochrome/passive support */
        if (info->tft_alt_mode)
                reg |= LCDC_TFT_ALT_ENABLE;
        if (priv->rev == 2) {
                unsigned int depth, bpp;
 
-               drm_fb_get_bpp_depth(crtc->primary->fb->pixel_format, &depth, &bpp);
+               drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
                switch (bpp) {
                case 16:
                        break;
@@ -415,7 +475,7 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
                        break;
                default:
                        dev_err(dev->dev, "invalid pixel format\n");
-                       return -EINVAL;
+                       return;
                }
        }
        reg |= info->fdd < 12;
@@ -436,12 +496,7 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
        else
                tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE);
 
-       /*
-        * use value from adjusted_mode here as this might have been
-        * changed as part of the fixup for slave encoders to solve the
-        * issue where tilcdc timings are not VESA compliant
-        */
-       if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
                tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC);
        else
                tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC);
@@ -456,51 +511,56 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
        else
                tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER);
 
-       drm_framebuffer_reference(crtc->primary->fb);
-
-       set_scanout(crtc, crtc->primary->fb);
+       drm_framebuffer_reference(fb);
 
-       tilcdc_crtc_update_clk(crtc);
+       set_scanout(crtc, fb);
 
-       pm_runtime_put_sync(dev->dev);
+       tilcdc_crtc_set_clk(crtc);
 
-       return 0;
+       crtc->hwmode = crtc->state->adjusted_mode;
 }
 
-static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-               struct drm_framebuffer *old_fb)
+static int tilcdc_crtc_atomic_check(struct drm_crtc *crtc,
+                                   struct drm_crtc_state *state)
 {
-       struct drm_device *dev = crtc->dev;
-       int r;
-
-       r = tilcdc_verify_fb(crtc, crtc->primary->fb);
-       if (r)
-               return r;
-
-       drm_framebuffer_reference(crtc->primary->fb);
+       struct drm_display_mode *mode = &state->mode;
+       int ret;
 
-       pm_runtime_get_sync(dev->dev);
+       /* If we are not active we don't care */
+       if (!state->active)
+               return 0;
 
-       set_scanout(crtc, crtc->primary->fb);
+       if (state->state->planes[0].ptr != crtc->primary ||
+           state->state->planes[0].state == NULL ||
+           state->state->planes[0].state->crtc != crtc) {
+               dev_dbg(crtc->dev->dev, "CRTC primary plane must be present");
+               return -EINVAL;
+       }
 
-       pm_runtime_put_sync(dev->dev);
+       ret = tilcdc_crtc_mode_valid(crtc, mode);
+       if (ret) {
+               dev_dbg(crtc->dev->dev, "Mode \"%s\" not valid", mode->name);
+               return -EINVAL;
+       }
 
        return 0;
 }
 
 static const struct drm_crtc_funcs tilcdc_crtc_funcs = {
-               .destroy        = tilcdc_crtc_destroy,
-               .set_config     = drm_crtc_helper_set_config,
-               .page_flip      = tilcdc_crtc_page_flip,
+       .destroy        = tilcdc_crtc_destroy,
+       .set_config     = drm_atomic_helper_set_config,
+       .page_flip      = drm_atomic_helper_page_flip,
+       .reset          = drm_atomic_helper_crtc_reset,
+       .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 };
 
 static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = {
-               .dpms           = tilcdc_crtc_dpms,
                .mode_fixup     = tilcdc_crtc_mode_fixup,
-               .prepare        = tilcdc_crtc_prepare,
-               .commit         = tilcdc_crtc_commit,
-               .mode_set       = tilcdc_crtc_mode_set,
-               .mode_set_base  = tilcdc_crtc_mode_set_base,
+               .enable         = tilcdc_crtc_enable,
+               .disable        = tilcdc_crtc_disable,
+               .atomic_check   = tilcdc_crtc_atomic_check,
+               .mode_set_nofb  = tilcdc_crtc_mode_set_nofb,
 };
 
 int tilcdc_crtc_max_width(struct drm_crtc *crtc)
@@ -622,46 +682,23 @@ void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
 
 void tilcdc_crtc_update_clk(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;
-       int dpms = tilcdc_crtc->dpms;
-       unsigned long lcd_clk;
-       const unsigned clkdiv = 2; /* using a fixed divider of 2 */
-       int ret;
+       struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 
-       pm_runtime_get_sync(dev->dev);
+       drm_modeset_lock_crtc(crtc, NULL);
+       if (tilcdc_crtc->lcd_fck_rate != clk_get_rate(priv->clk)) {
+               if (tilcdc_crtc_is_on(crtc)) {
+                       pm_runtime_get_sync(dev->dev);
+                       tilcdc_crtc_disable(crtc);
 
-       if (dpms == DRM_MODE_DPMS_ON)
-               tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+                       tilcdc_crtc_set_clk(crtc);
 
-       /* mode.clock is in KHz, set_rate wants parameter in Hz */
-       ret = clk_set_rate(priv->clk, crtc->mode.clock * 1000 * clkdiv);
-       if (ret < 0) {
-               dev_err(dev->dev, "failed to set display clock rate to: %d\n",
-                               crtc->mode.clock);
-               goto out;
+                       tilcdc_crtc_enable(crtc);
+                       pm_runtime_put_sync(dev->dev);
+               }
        }
-
-       lcd_clk = clk_get_rate(priv->clk);
-
-       DBG("lcd_clk=%lu, mode clock=%d, div=%u",
-               lcd_clk, crtc->mode.clock, clkdiv);
-
-       /* Configure the LCD clock divisor. */
-       tilcdc_write(dev, LCDC_CTRL_REG, LCDC_CLK_DIVISOR(clkdiv) |
-                       LCDC_RASTER_MODE);
-
-       if (priv->rev == 2)
-               tilcdc_set(dev, LCDC_CLK_ENABLE_REG,
-                               LCDC_V2_DMA_CLK_EN | LCDC_V2_LIDD_CLK_EN |
-                               LCDC_V2_CORE_CLK_EN);
-
-       if (dpms == DRM_MODE_DPMS_ON)
-               tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
-
-out:
-       pm_runtime_put_sync(dev->dev);
+       drm_modeset_unlock_crtc(crtc);
 }
 
 #define SYNC_LOST_COUNT_LIMIT 50
@@ -718,30 +755,34 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
                        tilcdc_crtc->frame_intact = true;
        }
 
+       if (stat & LCDC_FIFO_UNDERFLOW)
+               dev_err_ratelimited(dev->dev, "%s(0x%08x): FIFO underfow",
+                                   __func__, stat);
+
+       /* For revision 2 only */
        if (priv->rev == 2) {
                if (stat & LCDC_FRAME_DONE) {
                        tilcdc_crtc->frame_done = true;
                        wake_up(&tilcdc_crtc->frame_done_wq);
                }
-               tilcdc_write(dev, LCDC_END_OF_INT_IND_REG, 0);
-       }
 
-       if (stat & LCDC_SYNC_LOST) {
-               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, disabling the interrupt",
-                               __func__, stat);
-                       tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
-                                    LCDC_SYNC_LOST);
+               if (stat & LCDC_SYNC_LOST) {
+                       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, disabling the interrupt", __func__, stat);
+                               tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
+                                            LCDC_SYNC_LOST);
+                       }
                }
-       }
 
-       if (stat & LCDC_FIFO_UNDERFLOW)
-               dev_err_ratelimited(dev->dev, "%s(0x%08x): FIFO underfow",
-                                   __func__, stat);
+               /* Indicate to LCDC that the interrupt service routine has
+                * completed, see 13.3.6.1.6 in AM335x TRM.
+                */
+               tilcdc_write(dev, LCDC_END_OF_INT_IND_REG, 0);
+       }
 
        return IRQ_HANDLED;
 }
@@ -761,7 +802,10 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
 
        crtc = &tilcdc_crtc->base;
 
-       tilcdc_crtc->dpms = DRM_MODE_DPMS_OFF;
+       ret = tilcdc_plane_init(dev, &tilcdc_crtc->primary);
+       if (ret < 0)
+               goto fail;
+
        init_waitqueue_head(&tilcdc_crtc->frame_done_wq);
 
        drm_flip_work_init(&tilcdc_crtc->unref_work,
@@ -769,7 +813,11 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
 
        spin_lock_init(&tilcdc_crtc->irq_lock);
 
-       ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs);
+       ret = drm_crtc_init_with_planes(dev, crtc,
+                                       &tilcdc_crtc->primary,
+                                       NULL,
+                                       &tilcdc_crtc_funcs,
+                                       "tilcdc crtc");
        if (ret < 0)
                goto fail;
 
index d278093..a694977 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/component.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/suspend.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 
 #include "tilcdc_drv.h"
 #include "tilcdc_regs.h"
 
 static LIST_HEAD(module_list);
 
+static const u32 tilcdc_rev1_formats[] = { DRM_FORMAT_RGB565 };
+
+static const u32 tilcdc_straight_formats[] = { DRM_FORMAT_RGB565,
+                                              DRM_FORMAT_BGR888,
+                                              DRM_FORMAT_XBGR8888 };
+
+static const u32 tilcdc_crossed_formats[] = { DRM_FORMAT_BGR565,
+                                             DRM_FORMAT_RGB888,
+                                             DRM_FORMAT_XRGB8888 };
+
+static const u32 tilcdc_legacy_formats[] = { DRM_FORMAT_RGB565,
+                                            DRM_FORMAT_RGB888,
+                                            DRM_FORMAT_XRGB8888 };
+
 void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
                const struct tilcdc_module_ops *funcs)
 {
@@ -59,9 +75,84 @@ static void tilcdc_fb_output_poll_changed(struct drm_device *dev)
        drm_fbdev_cma_hotplug_event(priv->fbdev);
 }
 
+static int tilcdc_atomic_check(struct drm_device *dev,
+                              struct drm_atomic_state *state)
+{
+       int ret;
+
+       ret = drm_atomic_helper_check_modeset(dev, state);
+       if (ret)
+               return ret;
+
+       ret = drm_atomic_helper_check_planes(dev, state);
+       if (ret)
+               return ret;
+
+       /*
+        * tilcdc ->atomic_check can update ->mode_changed if pixel format
+        * changes, hence will we check modeset changes again.
+        */
+       ret = drm_atomic_helper_check_modeset(dev, state);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static int tilcdc_commit(struct drm_device *dev,
+                 struct drm_atomic_state *state,
+                 bool async)
+{
+       int ret;
+
+       ret = drm_atomic_helper_prepare_planes(dev, state);
+       if (ret)
+               return ret;
+
+       drm_atomic_helper_swap_state(state, true);
+
+       /*
+        * Everything below can be run asynchronously without the need to grab
+        * any modeset locks at all under one condition: It must be guaranteed
+        * that the asynchronous work has either been cancelled (if the driver
+        * supports it, which at least requires that the framebuffers get
+        * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
+        * before the new state gets committed on the software side with
+        * drm_atomic_helper_swap_state().
+        *
+        * This scheme allows new atomic state updates to be prepared and
+        * checked in parallel to the asynchronous completion of the previous
+        * update. Which is important since compositors need to figure out the
+        * composition of the next frame right after having submitted the
+        * current layout.
+        */
+
+       /* Keep HW on while we commit the state. */
+       pm_runtime_get_sync(dev->dev);
+
+       drm_atomic_helper_commit_modeset_disables(dev, state);
+
+       drm_atomic_helper_commit_planes(dev, state, 0);
+
+       drm_atomic_helper_commit_modeset_enables(dev, state);
+
+       /* Now HW should remain on if need becase the crtc is enabled */
+       pm_runtime_put_sync(dev->dev);
+
+       drm_atomic_helper_wait_for_vblanks(dev, state);
+
+       drm_atomic_helper_cleanup_planes(dev, state);
+
+       drm_atomic_state_free(state);
+
+       return 0;
+}
+
 static const struct drm_mode_config_funcs mode_config_funcs = {
        .fb_create = tilcdc_fb_create,
        .output_poll_changed = tilcdc_fb_output_poll_changed,
+       .atomic_check = tilcdc_atomic_check,
+       .atomic_commit = tilcdc_commit,
 };
 
 static int modeset_init(struct drm_device *dev)
@@ -93,12 +184,9 @@ static int cpufreq_transition(struct notifier_block *nb,
 {
        struct tilcdc_drm_private *priv = container_of(nb,
                        struct tilcdc_drm_private, freq_transition);
-       if (val == CPUFREQ_POSTCHANGE) {
-               if (priv->lcd_fck_rate != clk_get_rate(priv->clk)) {
-                       priv->lcd_fck_rate = clk_get_rate(priv->clk);
-                       tilcdc_crtc_update_clk(priv->crtc);
-               }
-       }
+
+       if (val == CPUFREQ_POSTCHANGE)
+               tilcdc_crtc_update_clk(priv->crtc);
 
        return 0;
 }
@@ -112,8 +200,6 @@ static int tilcdc_unload(struct drm_device *dev)
 {
        struct tilcdc_drm_private *priv = dev->dev_private;
 
-       tilcdc_crtc_dpms(priv->crtc, DRM_MODE_DPMS_OFF);
-
        tilcdc_remove_external_encoders(dev);
 
        drm_fbdev_cma_fini(priv->fbdev);
@@ -121,9 +207,7 @@ static int tilcdc_unload(struct drm_device *dev)
        drm_mode_config_cleanup(dev);
        drm_vblank_cleanup(dev);
 
-       pm_runtime_get_sync(dev->dev);
        drm_irq_uninstall(dev);
-       pm_runtime_put_sync(dev->dev);
 
 #ifdef CONFIG_CPU_FREQ
        cpufreq_unregister_notifier(&priv->freq_transition,
@@ -146,24 +230,17 @@ static int tilcdc_unload(struct drm_device *dev)
        return 0;
 }
 
-static size_t tilcdc_num_regs(void);
-
 static int tilcdc_load(struct drm_device *dev, unsigned long flags)
 {
        struct platform_device *pdev = dev->platformdev;
        struct device_node *node = pdev->dev.of_node;
        struct tilcdc_drm_private *priv;
-       struct tilcdc_module *mod;
        struct resource *res;
        u32 bpp = 0;
        int ret;
 
        priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
-       if (priv)
-               priv->saved_register =
-                       devm_kcalloc(dev->dev, tilcdc_num_regs(),
-                                    sizeof(*priv->saved_register), GFP_KERNEL);
-       if (!priv || !priv->saved_register) {
+       if (!priv) {
                dev_err(dev->dev, "failed to allocate private data\n");
                return -ENOMEM;
        }
@@ -201,7 +278,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
        }
 
 #ifdef CONFIG_CPU_FREQ
-       priv->lcd_fck_rate = clk_get_rate(priv->clk);
        priv->freq_transition.notifier_call = cpufreq_transition;
        ret = cpufreq_register_notifier(&priv->freq_transition,
                        CPUFREQ_TRANSITION_NOTIFIER);
@@ -249,6 +325,37 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
 
        pm_runtime_put_sync(dev->dev);
 
+       if (priv->rev == 1) {
+               DBG("Revision 1 LCDC supports only RGB565 format");
+               priv->pixelformats = tilcdc_rev1_formats;
+               priv->num_pixelformats = ARRAY_SIZE(tilcdc_rev1_formats);
+               bpp = 16;
+       } else {
+               const char *str = "\0";
+
+               of_property_read_string(node, "blue-and-red-wiring", &str);
+               if (0 == strcmp(str, "crossed")) {
+                       DBG("Configured for crossed blue and red wires");
+                       priv->pixelformats = tilcdc_crossed_formats;
+                       priv->num_pixelformats =
+                               ARRAY_SIZE(tilcdc_crossed_formats);
+                       bpp = 32; /* Choose bpp with RGB support for fbdef */
+               } else if (0 == strcmp(str, "straight")) {
+                       DBG("Configured for straight blue and red wires");
+                       priv->pixelformats = tilcdc_straight_formats;
+                       priv->num_pixelformats =
+                               ARRAY_SIZE(tilcdc_straight_formats);
+                       bpp = 16; /* Choose bpp with RGB support for fbdef */
+               } else {
+                       DBG("Blue and red wiring '%s' unknown, use legacy mode",
+                           str);
+                       priv->pixelformats = tilcdc_legacy_formats;
+                       priv->num_pixelformats =
+                               ARRAY_SIZE(tilcdc_legacy_formats);
+                       bpp = 16; /* This is just a guess */
+               }
+       }
+
        ret = modeset_init(dev);
        if (ret < 0) {
                dev_err(dev->dev, "failed to initialize mode setting\n");
@@ -262,7 +369,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
                if (ret < 0)
                        goto fail_mode_config_cleanup;
 
-               ret = tilcdc_add_external_encoders(dev, &bpp);
+               ret = tilcdc_add_external_encoders(dev);
                if (ret < 0)
                        goto fail_component_cleanup;
        }
@@ -279,22 +386,14 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
                goto fail_external_cleanup;
        }
 
-       pm_runtime_get_sync(dev->dev);
        ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
-       pm_runtime_put_sync(dev->dev);
        if (ret < 0) {
                dev_err(dev->dev, "failed to install IRQ handler\n");
                goto fail_vblank_cleanup;
        }
 
-       list_for_each_entry(mod, &module_list, list) {
-               DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp);
-               bpp = mod->preferred_bpp;
-               if (bpp > 0)
-                       break;
-       }
+       drm_mode_config_reset(dev);
 
-       drm_helper_disable_unused_functions(dev);
        priv->fbdev = drm_fbdev_cma_init(dev, bpp,
                        dev->mode_config.num_crtc,
                        dev->mode_config.num_connector);
@@ -308,20 +407,18 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
        return 0;
 
 fail_irq_uninstall:
-       pm_runtime_get_sync(dev->dev);
        drm_irq_uninstall(dev);
-       pm_runtime_put_sync(dev->dev);
 
 fail_vblank_cleanup:
        drm_vblank_cleanup(dev);
 
-fail_mode_config_cleanup:
-       drm_mode_config_cleanup(dev);
-
 fail_component_cleanup:
        if (priv->is_componentized)
                component_unbind_all(dev->dev, dev);
 
+fail_mode_config_cleanup:
+       drm_mode_config_cleanup(dev);
+
 fail_external_cleanup:
        tilcdc_remove_external_encoders(dev);
 
@@ -361,45 +458,6 @@ static irqreturn_t tilcdc_irq(int irq, void *arg)
        return tilcdc_crtc_irq(priv->crtc);
 }
 
-static void tilcdc_irq_preinstall(struct drm_device *dev)
-{
-       tilcdc_clear_irqstatus(dev, 0xffffffff);
-}
-
-static int tilcdc_irq_postinstall(struct drm_device *dev)
-{
-       struct tilcdc_drm_private *priv = dev->dev_private;
-
-       /* enable FIFO underflow irq: */
-       if (priv->rev == 1) {
-               tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_V1_UNDERFLOW_INT_ENA);
-       } else {
-               tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG,
-                          LCDC_V2_UNDERFLOW_INT_ENA |
-                          LCDC_V2_END_OF_FRAME0_INT_ENA |
-                          LCDC_FRAME_DONE | LCDC_SYNC_LOST);
-       }
-
-       return 0;
-}
-
-static void tilcdc_irq_uninstall(struct drm_device *dev)
-{
-       struct tilcdc_drm_private *priv = dev->dev_private;
-
-       /* disable irqs that we might have enabled: */
-       if (priv->rev == 1) {
-               tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
-                               LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA);
-               tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_V1_END_OF_FRAME_INT_ENA);
-       } else {
-               tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
-                       LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA |
-                       LCDC_V2_END_OF_FRAME0_INT_ENA |
-                       LCDC_FRAME_DONE | LCDC_SYNC_LOST);
-       }
-}
-
 static int tilcdc_enable_vblank(struct drm_device *dev, unsigned int pipe)
 {
        return 0;
@@ -410,7 +468,7 @@ static void tilcdc_disable_vblank(struct drm_device *dev, unsigned int pipe)
        return;
 }
 
-#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PM_SLEEP)
+#if defined(CONFIG_DEBUG_FS)
 static const struct {
        const char *name;
        uint8_t  rev;
@@ -441,15 +499,6 @@ static const struct {
 #undef REG
 };
 
-static size_t tilcdc_num_regs(void)
-{
-       return ARRAY_SIZE(registers);
-}
-#else
-static size_t tilcdc_num_regs(void)
-{
-       return 0;
-}
 #endif
 
 #ifdef CONFIG_DEBUG_FS
@@ -537,14 +586,11 @@ static const struct file_operations fops = {
 
 static struct drm_driver tilcdc_driver = {
        .driver_features    = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET |
-                              DRIVER_PRIME),
+                              DRIVER_PRIME | DRIVER_ATOMIC),
        .load               = tilcdc_load,
        .unload             = tilcdc_unload,
        .lastclose          = tilcdc_lastclose,
        .irq_handler        = tilcdc_irq,
-       .irq_preinstall     = tilcdc_irq_preinstall,
-       .irq_postinstall    = tilcdc_irq_postinstall,
-       .irq_uninstall      = tilcdc_irq_uninstall,
        .get_vblank_counter = drm_vblank_no_hw_counter,
        .enable_vblank      = tilcdc_enable_vblank,
        .disable_vblank     = tilcdc_disable_vblank,
@@ -584,28 +630,12 @@ static int tilcdc_pm_suspend(struct device *dev)
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct tilcdc_drm_private *priv = ddev->dev_private;
-       unsigned i, n = 0;
 
-       drm_kms_helper_poll_disable(ddev);
+       priv->saved_state = drm_atomic_helper_suspend(ddev);
 
        /* Select sleep pin state */
        pinctrl_pm_select_sleep_state(dev);
 
-       if (pm_runtime_suspended(dev)) {
-               priv->ctx_valid = false;
-               return 0;
-       }
-
-       /* Disable the LCDC controller, to avoid locking up the PRCM */
-       tilcdc_crtc_dpms(priv->crtc, DRM_MODE_DPMS_OFF);
-
-       /* Save register state: */
-       for (i = 0; i < ARRAY_SIZE(registers); i++)
-               if (registers[i].save && (priv->rev >= registers[i].rev))
-                       priv->saved_register[n++] = tilcdc_read(ddev, registers[i].reg);
-
-       priv->ctx_valid = true;
-
        return 0;
 }
 
@@ -613,23 +643,15 @@ static int tilcdc_pm_resume(struct device *dev)
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct tilcdc_drm_private *priv = ddev->dev_private;
-       unsigned i, n = 0;
+       int ret = 0;
 
        /* Select default pin state */
        pinctrl_pm_select_default_state(dev);
 
-       if (priv->ctx_valid == true) {
-               /* Restore register state: */
-               for (i = 0; i < ARRAY_SIZE(registers); i++)
-                       if (registers[i].save &&
-                           (priv->rev >= registers[i].rev))
-                               tilcdc_write(ddev, registers[i].reg,
-                                            priv->saved_register[n++]);
-       }
-
-       drm_kms_helper_poll_enable(ddev);
+       if (priv->saved_state)
+               ret = drm_atomic_helper_resume(ddev, priv->saved_state);
 
-       return 0;
+       return ret;
 }
 #endif
 
@@ -648,6 +670,12 @@ static int tilcdc_bind(struct device *dev)
 
 static void tilcdc_unbind(struct device *dev)
 {
+       struct drm_device *ddev = dev_get_drvdata(dev);
+
+       /* Check if a subcomponent has already triggered the unloading. */
+       if (!ddev->dev_private)
+               return;
+
        drm_put_dev(dev_get_drvdata(dev));
 }
 
@@ -680,17 +708,15 @@ static int tilcdc_pdev_probe(struct platform_device *pdev)
 
 static int tilcdc_pdev_remove(struct platform_device *pdev)
 {
-       struct drm_device *ddev = dev_get_drvdata(&pdev->dev);
-       struct tilcdc_drm_private *priv = ddev->dev_private;
-
-       /* Check if a subcomponent has already triggered the unloading. */
-       if (!priv)
-               return 0;
+       int ret;
 
-       if (priv->is_componentized)
-               component_master_del(&pdev->dev, &tilcdc_comp_ops);
-       else
+       ret = tilcdc_get_external_components(&pdev->dev, NULL);
+       if (ret < 0)
+               return ret;
+       else if (ret == 0)
                drm_put_dev(platform_get_drvdata(pdev));
+       else
+               component_master_del(&pdev->dev, &tilcdc_comp_ops);
 
        return 0;
 }
index c1de18b..9780c37 100644 (file)
@@ -65,13 +65,15 @@ struct tilcdc_drm_private {
         */
        uint32_t max_width;
 
-       /* register contents saved across suspend/resume: */
-       u32 *saved_register;
-       bool ctx_valid;
+       /* Supported pixel formats */
+       const uint32_t *pixelformats;
+       uint32_t num_pixelformats;
+
+       /* The context for pm susped/resume cycle is stored here */
+       struct drm_atomic_state *saved_state;
 
 #ifdef CONFIG_CPU_FREQ
        struct notifier_block freq_transition;
-       unsigned int lcd_fck_rate;
 #endif
 
        struct workqueue_struct *wq;
@@ -113,7 +115,6 @@ struct tilcdc_module {
        const char *name;
        struct list_head list;
        const struct tilcdc_module_ops *funcs;
-       unsigned int preferred_bpp;
 };
 
 void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
@@ -171,6 +172,11 @@ void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
                                        bool simulate_vesa_sync);
 int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode);
 int tilcdc_crtc_max_width(struct drm_crtc *crtc);
-void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode);
+void tilcdc_crtc_disable(struct drm_crtc *crtc);
+int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
+               struct drm_framebuffer *fb,
+               struct drm_pending_vblank_event *event);
+
+int tilcdc_plane_init(struct drm_device *dev, struct drm_plane *plane);
 
 #endif /* __TILCDC_DRV_H__ */
index 03acb4f..68e8950 100644 (file)
@@ -52,7 +52,7 @@ static int tilcdc_external_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
-static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
+static int tilcdc_add_external_encoder(struct drm_device *dev,
                                       struct drm_connector *connector)
 {
        struct tilcdc_drm_private *priv = dev->dev_private;
@@ -64,7 +64,6 @@ static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
        /* Only tda998x is supported at the moment. */
        tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true);
        tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
-       *bpp = panel_info_tda998x.bpp;
 
        connector_funcs = devm_kzalloc(dev->dev, sizeof(*connector_funcs),
                                       GFP_KERNEL);
@@ -94,7 +93,7 @@ static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
        return 0;
 }
 
-int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp)
+int tilcdc_add_external_encoders(struct drm_device *dev)
 {
        struct tilcdc_drm_private *priv = dev->dev_private;
        struct drm_connector *connector;
@@ -108,7 +107,7 @@ int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp)
                        if (connector == priv->connectors[i])
                                found = true;
                if (!found) {
-                       ret = tilcdc_add_external_encoder(dev, bpp, connector);
+                       ret = tilcdc_add_external_encoder(dev, connector);
                        if (ret)
                                return ret;
                }
@@ -138,14 +137,23 @@ static int dev_match_of(struct device *dev, void *data)
 int tilcdc_get_external_components(struct device *dev,
                                   struct component_match **match)
 {
+       struct device_node *node;
        struct device_node *ep = NULL;
        int count = 0;
 
-       while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) {
-               struct device_node *node;
+       /* Avoid error print by of_graph_get_next_endpoint() if there
+        * is no ports present.
+        */
+       node = of_get_child_by_name(dev->of_node, "ports");
+       if (!node)
+               node = of_get_child_by_name(dev->of_node, "port");
+       if (!node)
+               return 0;
+       of_node_put(node);
 
+       while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) {
                node = of_graph_get_remote_port_parent(ep);
-               if (!node && !of_device_is_available(node)) {
+               if (!node || !of_device_is_available(node)) {
                        of_node_put(node);
                        continue;
                }
index 6aabe27..c700e0c 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __TILCDC_EXTERNAL_H__
 #define __TILCDC_EXTERNAL_H__
 
-int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp);
+int tilcdc_add_external_encoders(struct drm_device *dev);
 void tilcdc_remove_external_encoders(struct drm_device *dev);
 int tilcdc_get_external_components(struct device *dev,
                                   struct component_match **match);
index ff7774c..2134bb2 100644 (file)
 #include <video/display_timing.h>
 #include <video/of_display_timing.h>
 #include <video/videomode.h>
+#include <drm/drm_atomic_helper.h>
 
 #include "tilcdc_drv.h"
+#include "tilcdc_panel.h"
 
 struct panel_module {
        struct tilcdc_module base;
@@ -64,9 +66,7 @@ static void panel_encoder_dpms(struct drm_encoder *encoder, int mode)
 
 static void panel_encoder_prepare(struct drm_encoder *encoder)
 {
-       struct panel_encoder *panel_encoder = to_panel_encoder(encoder);
        panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-       tilcdc_crtc_set_panel_info(encoder->crtc, panel_encoder->mod->info);
 }
 
 static void panel_encoder_commit(struct drm_encoder *encoder)
@@ -196,9 +196,12 @@ static struct drm_encoder *panel_connector_best_encoder(
 
 static const struct drm_connector_funcs panel_connector_funcs = {
        .destroy            = panel_connector_destroy,
-       .dpms               = drm_helper_connector_dpms,
+       .dpms               = drm_atomic_helper_connector_dpms,
        .detect             = panel_connector_detect,
        .fill_modes         = drm_helper_probe_single_connector_modes,
+       .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 const struct drm_connector_helper_funcs panel_connector_helper_funcs = {
@@ -268,6 +271,9 @@ static int panel_modeset_init(struct tilcdc_module *mod, struct drm_device *dev)
        priv->encoders[priv->num_encoders++] = encoder;
        priv->connectors[priv->num_connectors++] = connector;
 
+       tilcdc_crtc_set_panel_info(priv->crtc,
+                                  to_panel_encoder(encoder)->mod->info);
+
        return 0;
 }
 
@@ -392,8 +398,6 @@ static int panel_probe(struct platform_device *pdev)
                goto fail_timings;
        }
 
-       mod->preferred_bpp = panel_mod->info->bpp;
-
        return 0;
 
 fail_timings:
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc/tilcdc_plane.c
new file mode 100644 (file)
index 0000000..74c65fa
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 Texas Instruments
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drmP.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <uapi/drm/drm_fourcc.h>
+
+#include "tilcdc_drv.h"
+
+static struct drm_plane_funcs tilcdc_plane_funcs = {
+       .update_plane   = drm_atomic_helper_update_plane,
+       .disable_plane  = drm_atomic_helper_disable_plane,
+       .destroy        = drm_plane_cleanup,
+       .set_property   = drm_atomic_helper_plane_set_property,
+       .reset          = drm_atomic_helper_plane_reset,
+       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static int tilcdc_plane_atomic_check(struct drm_plane *plane,
+                                    struct drm_plane_state *state)
+{
+       struct drm_crtc_state *crtc_state;
+       struct drm_plane_state *old_state = plane->state;
+       unsigned int depth, bpp;
+
+       if (!state->crtc)
+               return 0;
+
+       if (WARN_ON(!state->fb))
+               return -EINVAL;
+
+       if (state->crtc_x || state->crtc_y) {
+               dev_err(plane->dev->dev, "%s: crtc position must be zero.",
+                       __func__);
+               return -EINVAL;
+       }
+
+       crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+                                                       state->crtc);
+       /* we should have a crtc state if the plane is attached to a crtc */
+       if (WARN_ON(!crtc_state))
+               return 0;
+
+       if (crtc_state->mode.hdisplay != state->crtc_w ||
+           crtc_state->mode.vdisplay != state->crtc_h) {
+               dev_err(plane->dev->dev,
+                       "%s: Size must match mode (%dx%d == %dx%d)", __func__,
+                       crtc_state->mode.hdisplay, crtc_state->mode.vdisplay,
+                       state->crtc_w, state->crtc_h);
+               return -EINVAL;
+       }
+
+       drm_fb_get_bpp_depth(state->fb->pixel_format, &depth, &bpp);
+       if (state->fb->pitches[0] != crtc_state->mode.hdisplay * bpp / 8) {
+               dev_err(plane->dev->dev,
+                       "Invalid pitch: fb and crtc widths must be the same");
+               return -EINVAL;
+       }
+
+       if (state->fb && old_state->fb &&
+           state->fb->pixel_format != old_state->fb->pixel_format) {
+               dev_dbg(plane->dev->dev,
+                       "%s(): pixel format change requires mode_change\n",
+                       __func__);
+               crtc_state->mode_changed = true;
+       }
+
+       return 0;
+}
+
+static void tilcdc_plane_atomic_update(struct drm_plane *plane,
+                                      struct drm_plane_state *old_state)
+{
+       struct drm_plane_state *state = plane->state;
+
+       if (!state->crtc)
+               return;
+
+       if (WARN_ON(!state->fb || !state->crtc->state))
+               return;
+
+       tilcdc_crtc_update_fb(state->crtc,
+                             state->fb,
+                             state->crtc->state->event);
+}
+
+static const struct drm_plane_helper_funcs plane_helper_funcs = {
+       .atomic_check = tilcdc_plane_atomic_check,
+       .atomic_update = tilcdc_plane_atomic_update,
+};
+
+int tilcdc_plane_init(struct drm_device *dev,
+                     struct drm_plane *plane)
+{
+       struct tilcdc_drm_private *priv = dev->dev_private;
+       int ret;
+
+       ret = drm_plane_init(dev, plane, 1,
+                            &tilcdc_plane_funcs,
+                            priv->pixelformats,
+                            priv->num_pixelformats,
+                            true);
+       if (ret) {
+               dev_err(dev->dev, "Failed to initialize plane: %d\n", ret);
+               return ret;
+       }
+
+       drm_plane_helper_add(plane, &plane_helper_funcs);
+
+       return 0;
+}
index 1bf5e25..f57c0d6 100644 (file)
@@ -119,6 +119,20 @@ static inline void tilcdc_write(struct drm_device *dev, u32 reg, u32 data)
        iowrite32(data, priv->mmio + reg);
 }
 
+static inline void tilcdc_write64(struct drm_device *dev, u32 reg, u64 data)
+{
+       struct tilcdc_drm_private *priv = dev->dev_private;
+       volatile void __iomem *addr = priv->mmio + reg;
+
+#ifdef iowrite64
+       iowrite64(data, addr);
+#else
+       __iowmb();
+       /* This compiles to strd (=64-bit write) on ARM7 */
+       *(volatile u64 __force *)addr = __cpu_to_le64(data);
+#endif
+}
+
 static inline u32 tilcdc_read(struct drm_device *dev, u32 reg)
 {
        struct tilcdc_drm_private *priv = dev->dev_private;
index f9c79da..623a914 100644 (file)
@@ -139,7 +139,7 @@ static void __init tilcdc_node_disable(struct device_node *node)
        of_update_property(node, prop);
 }
 
-struct device_node * __init tilcdc_get_overlay(struct kfree_table *kft)
+static struct device_node * __init tilcdc_get_overlay(struct kfree_table *kft)
 {
        const int size = __dtb_tilcdc_slave_compat_end -
                __dtb_tilcdc_slave_compat_begin;
@@ -195,7 +195,7 @@ static const char * const tilcdc_slave_props[] __initconst = {
        NULL
 };
 
-void __init tilcdc_convert_slave_node(void)
+static void __init tilcdc_convert_slave_node(void)
 {
        struct device_node *slave = NULL, *lcdc = NULL;
        struct device_node *i2c = NULL, *fragment = NULL;
@@ -207,7 +207,7 @@ void __init tilcdc_convert_slave_node(void)
        int ret;
 
        if (kfree_table_init(&kft))
-               goto out;
+               return;
 
        lcdc = of_find_matching_node(NULL, tilcdc_of_match);
        slave = of_find_matching_node(NULL, tilcdc_slave_of_match);
@@ -261,7 +261,7 @@ out:
        of_node_put(fragment);
 }
 
-int __init tilcdc_slave_compat_init(void)
+static int __init tilcdc_slave_compat_init(void)
 {
        tilcdc_convert_slave_node();
        return 0;
index 6b8c5b3..458043a 100644 (file)
 #include <linux/of_gpio.h>
 #include <linux/pinctrl/pinmux.h>
 #include <linux/pinctrl/consumer.h>
+#include <drm/drm_atomic_helper.h>
 
 #include "tilcdc_drv.h"
+#include "tilcdc_tfp410.h"
 
 struct tfp410_module {
        struct tilcdc_module base;
@@ -75,7 +77,6 @@ static void tfp410_encoder_dpms(struct drm_encoder *encoder, int mode)
 static void tfp410_encoder_prepare(struct drm_encoder *encoder)
 {
        tfp410_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-       tilcdc_crtc_set_panel_info(encoder->crtc, &dvi_info);
 }
 
 static void tfp410_encoder_commit(struct drm_encoder *encoder)
@@ -201,9 +202,12 @@ static struct drm_encoder *tfp410_connector_best_encoder(
 
 static const struct drm_connector_funcs tfp410_connector_funcs = {
        .destroy            = tfp410_connector_destroy,
-       .dpms               = drm_helper_connector_dpms,
+       .dpms               = drm_atomic_helper_connector_dpms,
        .detect             = tfp410_connector_detect,
        .fill_modes         = drm_helper_probe_single_connector_modes,
+       .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 const struct drm_connector_helper_funcs tfp410_connector_helper_funcs = {
@@ -276,6 +280,7 @@ static int tfp410_modeset_init(struct tilcdc_module *mod, struct drm_device *dev
        priv->encoders[priv->num_encoders++] = encoder;
        priv->connectors[priv->num_connectors++] = connector;
 
+       tilcdc_crtc_set_panel_info(priv->crtc, &dvi_info);
        return 0;
 }
 
@@ -323,8 +328,6 @@ static int tfp410_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       mod->preferred_bpp = dvi_info.bpp;
-
        i2c_node = of_find_node_by_phandle(i2c_phandle);
        if (!i2c_node) {
                dev_err(&pdev->dev, "could not get i2c bus node\n");
index 42c074a..fc6217d 100644 (file)
@@ -57,14 +57,14 @@ static struct attribute ttm_bo_count = {
 static inline int ttm_mem_type_from_place(const struct ttm_place *place,
                                          uint32_t *mem_type)
 {
-       int i;
+       int pos;
 
-       for (i = 0; i <= TTM_PL_PRIV5; i++)
-               if (place->flags & (1 << i)) {
-                       *mem_type = i;
-                       return 0;
-               }
-       return -EINVAL;
+       pos = ffs(place->flags & TTM_PL_MASK_MEM);
+       if (unlikely(!pos))
+               return -EINVAL;
+
+       *mem_type = pos - 1;
+       return 0;
 }
 
 static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type)
@@ -354,14 +354,12 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
 
        if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
            !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))
-               ret = ttm_bo_move_ttm(bo, evict, interruptible, no_wait_gpu,
-                                     mem);
+               ret = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, mem);
        else if (bdev->driver->move)
                ret = bdev->driver->move(bo, evict, interruptible,
                                         no_wait_gpu, mem);
        else
-               ret = ttm_bo_move_memcpy(bo, evict, interruptible,
-                                        no_wait_gpu, mem);
+               ret = ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, mem);
 
        if (ret) {
                if (bdev->driver->move_notify) {
index f157a9e..bf6e216 100644 (file)
@@ -45,8 +45,8 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
 }
 
 int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
-                   bool evict, bool interruptible,
-                   bool no_wait_gpu, struct ttm_mem_reg *new_mem)
+                   bool interruptible, bool no_wait_gpu,
+                   struct ttm_mem_reg *new_mem)
 {
        struct ttm_tt *ttm = bo->ttm;
        struct ttm_mem_reg *old_mem = &bo->mem;
@@ -329,8 +329,7 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
 }
 
 int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
-                      bool evict, bool interruptible,
-                      bool no_wait_gpu,
+                      bool interruptible, bool no_wait_gpu,
                       struct ttm_mem_reg *new_mem)
 {
        struct ttm_bo_device *bdev = bo->bdev;
index a1803fb..29855be 100644 (file)
@@ -600,3 +600,9 @@ size_t ttm_round_pot(size_t size)
        return 0;
 }
 EXPORT_SYMBOL(ttm_round_pot);
+
+uint64_t ttm_get_kernel_zone_memory_size(struct ttm_mem_global *glob)
+{
+       return glob->zone_kernel->max_mem;
+}
+EXPORT_SYMBOL(ttm_get_kernel_zone_memory_size);
index bef9f6f..cec4b4b 100644 (file)
@@ -858,7 +858,6 @@ static int ttm_dma_pool_get_pages(struct dma_pool *pool,
        if (count) {
                d_page = list_first_entry(&pool->free_list, struct dma_page, page_list);
                ttm->pages[index] = d_page->p;
-               ttm_dma->cpu_address[index] = d_page->vaddr;
                ttm_dma->dma_address[index] = d_page->dma;
                list_move_tail(&d_page->page_list, &ttm_dma->pages_list);
                r = 0;
@@ -989,7 +988,6 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
        INIT_LIST_HEAD(&ttm_dma->pages_list);
        for (i = 0; i < ttm->num_pages; i++) {
                ttm->pages[i] = NULL;
-               ttm_dma->cpu_address[i] = 0;
                ttm_dma->dma_address[i] = 0;
        }
 
index bc5aa57..aee3c00 100644 (file)
@@ -57,10 +57,8 @@ static void ttm_dma_tt_alloc_page_directory(struct ttm_dma_tt *ttm)
 {
        ttm->ttm.pages = drm_calloc_large(ttm->ttm.num_pages,
                                          sizeof(*ttm->ttm.pages) +
-                                         sizeof(*ttm->dma_address) +
-                                         sizeof(*ttm->cpu_address));
-       ttm->cpu_address = (void *) (ttm->ttm.pages + ttm->ttm.num_pages);
-       ttm->dma_address = (void *) (ttm->cpu_address + ttm->ttm.num_pages);
+                                         sizeof(*ttm->dma_address));
+       ttm->dma_address = (void *) (ttm->ttm.pages + ttm->ttm.num_pages);
 }
 
 #ifdef CONFIG_X86
@@ -244,7 +242,6 @@ void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma)
 
        drm_free_large(ttm->pages);
        ttm->pages = NULL;
-       ttm_dma->cpu_address = NULL;
        ttm_dma->dma_address = NULL;
 }
 EXPORT_SYMBOL(ttm_dma_tt_fini);
index 4709b54..d2f57c5 100644 (file)
@@ -150,8 +150,5 @@ int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder)
        drm_connector_register(connector);
        drm_mode_connector_attach_encoder(connector, encoder);
 
-       drm_object_attach_property(&connector->base,
-                                     dev->mode_config.dirty_info_property,
-                                     1);
        return 0;
 }
index e2243ed..ac90ffd 100644 (file)
@@ -209,7 +209,7 @@ struct dma_buf *udl_gem_prime_export(struct drm_device *dev,
        exp_info.flags = flags;
        exp_info.priv = obj;
 
-       return dma_buf_export(&exp_info);
+       return drm_gem_dmabuf_export(dev, &exp_info);
 }
 
 static int udl_prime_create(struct drm_device *dev,
index 17d34e0..cc45d98 100644 (file)
@@ -16,6 +16,20 @@ static int udl_driver_set_busid(struct drm_device *d, struct drm_master *m)
        return 0;
 }
 
+static int udl_usb_suspend(struct usb_interface *interface,
+                          pm_message_t message)
+{
+       return 0;
+}
+
+static int udl_usb_resume(struct usb_interface *interface)
+{
+       struct drm_device *dev = usb_get_intfdata(interface);
+
+       udl_modeset_restore(dev);
+       return 0;
+}
+
 static const struct vm_operations_struct udl_gem_vm_ops = {
        .fault = udl_gem_fault,
        .open = drm_gem_vm_open,
@@ -72,8 +86,8 @@ static int udl_usb_probe(struct usb_interface *interface,
        int r;
 
        dev = drm_dev_alloc(&driver, &interface->dev);
-       if (!dev)
-               return -ENOMEM;
+       if (IS_ERR(dev))
+               return PTR_ERR(dev);
 
        r = drm_dev_register(dev, (unsigned long)udev);
        if (r)
@@ -122,6 +136,8 @@ static struct usb_driver udl_driver = {
        .name = "udl",
        .probe = udl_usb_probe,
        .disconnect = udl_usb_disconnect,
+       .suspend = udl_usb_suspend,
+       .resume = udl_usb_resume,
        .id_table = id_table,
 };
 module_usb_driver(udl_driver);
index 0b03d34..f338a57 100644 (file)
@@ -52,6 +52,7 @@ struct udl_device {
        struct device *dev;
        struct drm_device *ddev;
        struct usb_device *udev;
+       struct drm_crtc *crtc;
 
        int sku_pixel_limit;
 
@@ -87,6 +88,7 @@ struct udl_framebuffer {
 
 /* modeset */
 int udl_modeset_init(struct drm_device *dev);
+void udl_modeset_restore(struct drm_device *dev);
 void udl_modeset_cleanup(struct drm_device *dev);
 int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder);
 
index 33dbfb2..29f0207 100644 (file)
@@ -16,6 +16,8 @@
 /* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
 #define BULK_SIZE 512
 
+#define NR_USB_REQUEST_CHANNEL 0x12
+
 #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
 #define WRITES_IN_FLIGHT (4)
 #define MAX_VENDOR_DESCRIPTOR_SIZE 256
@@ -90,6 +92,26 @@ success:
        return true;
 }
 
+/*
+ * Need to ensure a channel is selected before submitting URBs
+ */
+static int udl_select_std_channel(struct udl_device *udl)
+{
+       int ret;
+       u8 set_def_chn[] = {0x57, 0xCD, 0xDC, 0xA7,
+                           0x1C, 0x88, 0x5E, 0x15,
+                           0x60, 0xFE, 0xC6, 0x97,
+                           0x16, 0x3D, 0x47, 0xF2};
+
+       ret = usb_control_msg(udl->udev,
+                             usb_sndctrlpipe(udl->udev, 0),
+                             NR_USB_REQUEST_CHANNEL,
+                             (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
+                             set_def_chn, sizeof(set_def_chn),
+                             USB_CTRL_SET_TIMEOUT);
+       return ret < 0 ? ret : 0;
+}
+
 static void udl_release_urb_work(struct work_struct *work)
 {
        struct urb_node *unode = container_of(work, struct urb_node,
@@ -301,6 +323,9 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags)
                goto err;
        }
 
+       if (udl_select_std_channel(udl))
+               DRM_ERROR("Selecting channel failed\n");
+
        if (!udl_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
                DRM_ERROR("udl_alloc_urb_list failed\n");
                goto err;
index f92ea95..f2b2481 100644 (file)
@@ -309,6 +309,8 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
        char *wrptr;
        int color_depth = 0;
 
+       udl->crtc = crtc;
+
        buf = (char *)udl->mode_buf;
 
        /* for now we just clip 24 -> 16 - if we fix that fix this */
@@ -441,8 +443,6 @@ int udl_modeset_init(struct drm_device *dev)
 
        dev->mode_config.funcs = &udl_mode_funcs;
 
-       drm_mode_create_dirty_info_property(dev);
-
        udl_crtc_init(dev);
 
        encoder = udl_encoder_init(dev);
@@ -452,6 +452,18 @@ int udl_modeset_init(struct drm_device *dev)
        return 0;
 }
 
+void udl_modeset_restore(struct drm_device *dev)
+{
+       struct udl_device *udl = dev->dev_private;
+       struct udl_framebuffer *ufb;
+
+       if (!udl->crtc || !udl->crtc->primary->fb)
+               return;
+       udl_crtc_commit(udl->crtc);
+       ufb = to_udl_fb(udl->crtc->primary->fb);
+       udl_handle_damage(ufb, 0, 0, ufb->base.width, ufb->base.height);
+}
+
 void udl_modeset_cleanup(struct drm_device *dev)
 {
        drm_mode_config_cleanup(dev);
index 8fc2b73..7f08d68 100644 (file)
@@ -163,14 +163,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
        int vblank_lines;
        int ret = 0;
 
-       /*
-        * XXX Doesn't work well in interlaced mode yet, partially due
-        * to problems in vc4 kms or drm core interlaced mode handling,
-        * so disable for now in interlaced mode.
-        */
-       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-               return ret;
-
        /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
 
        /* Get optional system timestamp before query. */
@@ -191,10 +183,15 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
 
        /* Vertical position of hvs composed scanline. */
        *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);
+       *hpos = 0;
 
-       /* No hpos info available. */
-       if (hpos)
-               *hpos = 0;
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               *vpos /= 2;
+
+               /* Use hpos to correct for field offset in interlaced mode. */
+               if (VC4_GET_FIELD(val, SCALER_DISPSTATX_FRAME_COUNT) % 2)
+                       *hpos += mode->crtc_htotal / 2;
+       }
 
        /* This is the offset we need for translating hvs -> pv scanout pos. */
        fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay;
@@ -217,8 +214,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
                 * position of the PV.
                 */
                *vpos -= fifo_lines + 1;
-               if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-                       *vpos /= 2;
 
                ret |= DRM_SCANOUTPOS_ACCURATE;
                return ret;
@@ -234,7 +229,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
         * and need to make things up in a approximative but consistent way.
         */
        ret |= DRM_SCANOUTPOS_IN_VBLANK;
-       vblank_lines = mode->crtc_vtotal - mode->crtc_vdisplay;
+       vblank_lines = mode->vtotal - mode->vdisplay;
 
        if (flags & DRM_CALLED_FROM_VBLIRQ) {
                /*
@@ -383,7 +378,7 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
        struct drm_crtc_state *state = crtc->state;
        struct drm_display_mode *mode = &state->adjusted_mode;
        bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
-       u32 vactive = (mode->vdisplay >> (interlace ? 1 : 0));
+       u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
        u32 format = PV_CONTROL_FORMAT_24;
        bool debug_dump_regs = false;
        int clock_select = vc4_get_clock_select(crtc);
@@ -399,47 +394,65 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
        CRTC_WRITE(PV_CONTROL, 0);
 
        CRTC_WRITE(PV_HORZA,
-                  VC4_SET_FIELD(mode->htotal - mode->hsync_end,
+                  VC4_SET_FIELD((mode->htotal -
+                                 mode->hsync_end) * pixel_rep,
                                 PV_HORZA_HBP) |
-                  VC4_SET_FIELD(mode->hsync_end - mode->hsync_start,
+                  VC4_SET_FIELD((mode->hsync_end -
+                                 mode->hsync_start) * pixel_rep,
                                 PV_HORZA_HSYNC));
        CRTC_WRITE(PV_HORZB,
-                  VC4_SET_FIELD(mode->hsync_start - mode->hdisplay,
+                  VC4_SET_FIELD((mode->hsync_start -
+                                 mode->hdisplay) * pixel_rep,
                                 PV_HORZB_HFP) |
-                  VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE));
+                  VC4_SET_FIELD(mode->hdisplay * pixel_rep, PV_HORZB_HACTIVE));
 
        CRTC_WRITE(PV_VERTA,
-                  VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
+                  VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
                                 PV_VERTA_VBP) |
-                  VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
+                  VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
                                 PV_VERTA_VSYNC));
        CRTC_WRITE(PV_VERTB,
-                  VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
+                  VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
                                 PV_VERTB_VFP) |
-                  VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE));
+                  VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
 
        if (interlace) {
                CRTC_WRITE(PV_VERTA_EVEN,
-                          VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1,
+                          VC4_SET_FIELD(mode->crtc_vtotal -
+                                        mode->crtc_vsync_end - 1,
                                         PV_VERTA_VBP) |
-                          VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
+                          VC4_SET_FIELD(mode->crtc_vsync_end -
+                                        mode->crtc_vsync_start,
                                         PV_VERTA_VSYNC));
                CRTC_WRITE(PV_VERTB_EVEN,
-                          VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
+                          VC4_SET_FIELD(mode->crtc_vsync_start -
+                                        mode->crtc_vdisplay,
                                         PV_VERTB_VFP) |
-                          VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE));
+                          VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
+
+               /* We set up first field even mode for HDMI.  VEC's
+                * NTSC mode would want first field odd instead, once
+                * we support it (to do so, set ODD_FIRST and put the
+                * delay in VSYNCD_EVEN instead).
+                */
+               CRTC_WRITE(PV_V_CONTROL,
+                          PV_VCONTROL_CONTINUOUS |
+                          PV_VCONTROL_INTERLACE |
+                          VC4_SET_FIELD(mode->htotal * pixel_rep / 2,
+                                        PV_VCONTROL_ODD_DELAY));
+               CRTC_WRITE(PV_VSYNCD_EVEN, 0);
+       } else {
+               CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS);
        }
 
-       CRTC_WRITE(PV_HACT_ACT, mode->hdisplay);
+       CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
 
-       CRTC_WRITE(PV_V_CONTROL,
-                  PV_VCONTROL_CONTINUOUS |
-                  (interlace ? PV_VCONTROL_INTERLACE : 0));
 
        CRTC_WRITE(PV_CONTROL,
                   VC4_SET_FIELD(format, PV_CONTROL_FORMAT) |
                   VC4_SET_FIELD(vc4_get_fifo_full_level(format),
                                 PV_CONTROL_FIFO_LEVEL) |
+                  VC4_SET_FIELD(pixel_rep - 1, PV_CONTROL_PIXEL_REP) |
                   PV_CONTROL_CLR_AT_START |
                   PV_CONTROL_TRIGGER_UNDERFLOW |
                   PV_CONTROL_WAIT_HSTART |
@@ -480,6 +493,9 @@ static void vc4_crtc_disable(struct drm_crtc *crtc)
        int ret;
        require_hvs_enabled(dev);
 
+       /* Disable vblank irq handling before crtc is disabled. */
+       drm_crtc_vblank_off(crtc);
+
        CRTC_WRITE(PV_V_CONTROL,
                   CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN);
        ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1);
@@ -530,6 +546,23 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
        /* Turn on the pixel valve, which will emit the vstart signal. */
        CRTC_WRITE(PV_V_CONTROL,
                   CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
+
+       /* Enable vblank irq handling after crtc is started. */
+       drm_crtc_vblank_on(crtc);
+}
+
+static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
+                               const struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       /* Do not allow doublescan modes from user space */
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) {
+               DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
+                             crtc->base.id);
+               return false;
+       }
+
+       return true;
 }
 
 static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
@@ -819,6 +852,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
        .mode_set_nofb = vc4_crtc_mode_set_nofb,
        .disable = vc4_crtc_disable,
        .enable = vc4_crtc_enable,
+       .mode_fixup = vc4_crtc_mode_fixup,
        .atomic_check = vc4_crtc_atomic_check,
        .atomic_flush = vc4_crtc_atomic_flush,
 };
index 275fedb..1e1f6b8 100644 (file)
@@ -340,9 +340,20 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder)
        }
 }
 
+static bool vc4_dpi_encoder_mode_fixup(struct drm_encoder *encoder,
+                                      const struct drm_display_mode *mode,
+                                      struct drm_display_mode *adjusted_mode)
+{
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+               return false;
+
+       return true;
+}
+
 static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = {
        .disable = vc4_dpi_encoder_disable,
        .enable = vc4_dpi_encoder_enable,
+       .mode_fixup = vc4_dpi_encoder_mode_fixup,
 };
 
 static const struct of_device_id vc4_dpi_dt_match[] = {
index 9ecef93..8703f56 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include "drm_fb_cma_helper.h"
+#include <drm/drm_fb_helper.h>
 
 #include "uapi/drm/vc4_drm.h"
 #include "vc4_drv.h"
@@ -214,7 +215,7 @@ static void vc4_kick_out_firmware_fb(void)
        ap->ranges[0].base = 0;
        ap->ranges[0].size = ~0;
 
-       remove_conflicting_framebuffers(ap, "vc4drmfb", false);
+       drm_fb_helper_remove_conflicting_framebuffers(ap, "vc4drmfb", false);
        kfree(ap);
 }
 
@@ -232,8 +233,8 @@ static int vc4_drm_bind(struct device *dev)
                return -ENOMEM;
 
        drm = drm_dev_alloc(&vc4_drm_driver, dev);
-       if (!drm)
-               return -ENOMEM;
+       if (IS_ERR(drm))
+               return PTR_ERR(drm);
        platform_set_drvdata(pdev, drm);
        vc4->dev = drm;
        drm->dev_private = vc4;
index 428e249..7c1e4d9 100644 (file)
@@ -122,9 +122,16 @@ to_vc4_dev(struct drm_device *dev)
 struct vc4_bo {
        struct drm_gem_cma_object base;
 
-       /* seqno of the last job to render to this BO. */
+       /* seqno of the last job to render using this BO. */
        uint64_t seqno;
 
+       /* seqno of the last job to use the RCL to write to this BO.
+        *
+        * Note that this doesn't include binner overflow memory
+        * writes.
+        */
+       uint64_t write_seqno;
+
        /* List entry for the BO's position in either
         * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list
         */
@@ -216,6 +223,9 @@ struct vc4_exec_info {
        /* Sequence number for this bin/render job. */
        uint64_t seqno;
 
+       /* Latest write_seqno of any BO that binning depends on. */
+       uint64_t bin_dep_seqno;
+
        /* Last current addresses the hardware was processing when the
         * hangcheck timer checked on us.
         */
@@ -230,6 +240,13 @@ struct vc4_exec_info {
        struct drm_gem_cma_object **bo;
        uint32_t bo_count;
 
+       /* List of BOs that are being written by the RCL.  Other than
+        * the binner temporary storage, this is all the BOs written
+        * by the job.
+        */
+       struct drm_gem_cma_object *rcl_write_bo[4];
+       uint32_t rcl_write_bo_count;
+
        /* Pointers for our position in vc4->job_list */
        struct list_head head;
 
@@ -307,18 +324,15 @@ struct vc4_exec_info {
 static inline struct vc4_exec_info *
 vc4_first_bin_job(struct vc4_dev *vc4)
 {
-       if (list_empty(&vc4->bin_job_list))
-               return NULL;
-       return list_first_entry(&vc4->bin_job_list, struct vc4_exec_info, head);
+       return list_first_entry_or_null(&vc4->bin_job_list,
+                                       struct vc4_exec_info, head);
 }
 
 static inline struct vc4_exec_info *
 vc4_first_render_job(struct vc4_dev *vc4)
 {
-       if (list_empty(&vc4->render_job_list))
-               return NULL;
-       return list_first_entry(&vc4->render_job_list,
-                               struct vc4_exec_info, head);
+       return list_first_entry_or_null(&vc4->render_job_list,
+                                       struct vc4_exec_info, head);
 }
 
 static inline struct vc4_exec_info *
index b262c5c..47a095f 100644 (file)
@@ -419,10 +419,6 @@ again:
 
        vc4_flush_caches(dev);
 
-       /* Disable the binner's pre-loaded overflow memory address */
-       V3D_WRITE(V3D_BPOA, 0);
-       V3D_WRITE(V3D_BPOS, 0);
-
        /* Either put the job in the binner if it uses the binner, or
         * immediately move it to the to-be-rendered queue.
         */
@@ -471,6 +467,11 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
        list_for_each_entry(bo, &exec->unref_list, unref_head) {
                bo->seqno = seqno;
        }
+
+       for (i = 0; i < exec->rcl_write_bo_count; i++) {
+               bo = to_vc4_bo(&exec->rcl_write_bo[i]->base);
+               bo->write_seqno = seqno;
+       }
 }
 
 /* Queues a struct vc4_exec_info for execution.  If no job is
@@ -673,6 +674,14 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
                goto fail;
 
        ret = vc4_validate_shader_recs(dev, exec);
+       if (ret)
+               goto fail;
+
+       /* Block waiting on any previous rendering into the CS's VBO,
+        * IB, or textures, so that pixels are actually written by the
+        * time we try to read them.
+        */
+       ret = vc4_wait_for_seqno(dev, exec->bin_dep_seqno, ~0ull, true);
 
 fail:
        drm_free_large(temp);
index 4452f36..c4cb2e2 100644 (file)
@@ -62,6 +62,8 @@ struct vc4_hdmi {
 struct vc4_hdmi_encoder {
        struct vc4_encoder base;
        bool hdmi_monitor;
+       bool limited_rgb_range;
+       bool rgb_range_selectable;
 };
 
 static inline struct vc4_hdmi_encoder *
@@ -174,6 +176,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
                        return connector_status_disconnected;
        }
 
+       if (drm_probe_ddc(vc4->hdmi->ddc))
+               return connector_status_connected;
+
        if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
                return connector_status_connected;
        else
@@ -202,6 +207,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
                return -ENODEV;
 
        vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+
+       if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
+               vc4_encoder->rgb_range_selectable =
+                       drm_rgb_quant_range_selectable(edid);
+       }
+
        drm_mode_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
 
@@ -246,7 +257,7 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev,
        connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
                             DRM_CONNECTOR_POLL_DISCONNECT);
 
-       connector->interlace_allowed = 0;
+       connector->interlace_allowed = 1;
        connector->doublescan_allowed = 0;
 
        drm_mode_connector_attach_encoder(connector, encoder);
@@ -269,25 +280,143 @@ static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = {
        .destroy = vc4_hdmi_encoder_destroy,
 };
 
+static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
+                               enum hdmi_infoframe_type type)
+{
+       struct drm_device *dev = encoder->dev;
+       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       u32 packet_id = type - 0x80;
+
+       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
+                  HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
+
+       return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
+                         BIT(packet_id)), 100);
+}
+
+static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
+                                    union hdmi_infoframe *frame)
+{
+       struct drm_device *dev = encoder->dev;
+       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       u32 packet_id = frame->any.type - 0x80;
+       u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id;
+       uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
+       ssize_t len, i;
+       int ret;
+
+       WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
+                   VC4_HDMI_RAM_PACKET_ENABLE),
+                 "Packet RAM has to be on to store the packet.");
+
+       len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
+       if (len < 0)
+               return;
+
+       ret = vc4_hdmi_stop_packet(encoder, frame->any.type);
+       if (ret) {
+               DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
+               return;
+       }
+
+       for (i = 0; i < len; i += 7) {
+               HDMI_WRITE(packet_reg,
+                          buffer[i + 0] << 0 |
+                          buffer[i + 1] << 8 |
+                          buffer[i + 2] << 16);
+               packet_reg += 4;
+
+               HDMI_WRITE(packet_reg,
+                          buffer[i + 3] << 0 |
+                          buffer[i + 4] << 8 |
+                          buffer[i + 5] << 16 |
+                          buffer[i + 6] << 24);
+               packet_reg += 4;
+       }
+
+       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
+                  HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
+       ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
+                       BIT(packet_id)), 100);
+       if (ret)
+               DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
+}
+
+static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+{
+       struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
+       struct drm_crtc *crtc = encoder->crtc;
+       const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+       union hdmi_infoframe frame;
+       int ret;
+
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
+       if (ret < 0) {
+               DRM_ERROR("couldn't fill AVI infoframe\n");
+               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;
+               }
+       }
+
+       vc4_hdmi_write_infoframe(encoder, &frame);
+}
+
+static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
+{
+       union hdmi_infoframe frame;
+       int ret;
+
+       ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore");
+       if (ret < 0) {
+               DRM_ERROR("couldn't fill SPD infoframe\n");
+               return;
+       }
+
+       frame.spd.sdi = HDMI_SPD_SDI_PC;
+
+       vc4_hdmi_write_infoframe(encoder, &frame);
+}
+
+static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
+{
+       vc4_hdmi_set_avi_infoframe(encoder);
+       vc4_hdmi_set_spd_infoframe(encoder);
+}
+
 static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
                                      struct drm_display_mode *unadjusted_mode,
                                      struct drm_display_mode *mode)
 {
+       struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
        struct drm_device *dev = encoder->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        bool debug_dump_regs = false;
        bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
        bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
-       u32 vactive = (mode->vdisplay >>
-                      ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0));
-       u32 verta = (VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
+       bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
+       u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
+       u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
                                   VC4_HDMI_VERTA_VSP) |
-                    VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
+                    VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
                                   VC4_HDMI_VERTA_VFP) |
-                    VC4_SET_FIELD(vactive, VC4_HDMI_VERTA_VAL));
+                    VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL));
        u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
-                    VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
+                    VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
                                   VC4_HDMI_VERTB_VBP));
+       u32 vertb_even = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
+                         VC4_SET_FIELD(mode->crtc_vtotal -
+                                       mode->crtc_vsync_end -
+                                       interlaced,
+                                       VC4_HDMI_VERTB_VBP));
+       u32 csc_ctl;
 
        if (debug_dump_regs) {
                DRM_INFO("HDMI regs before:\n");
@@ -296,7 +425,8 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
 
        HD_WRITE(VC4_HD_VID_CTL, 0);
 
-       clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000);
+       clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000 *
+                    ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1));
 
        HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
                   HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
@@ -306,29 +436,62 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        HDMI_WRITE(VC4_HDMI_HORZA,
                   (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) |
                   (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) |
-                  VC4_SET_FIELD(mode->hdisplay, VC4_HDMI_HORZA_HAP));
+                  VC4_SET_FIELD(mode->hdisplay * pixel_rep,
+                                VC4_HDMI_HORZA_HAP));
 
        HDMI_WRITE(VC4_HDMI_HORZB,
-                  VC4_SET_FIELD(mode->htotal - mode->hsync_end,
+                  VC4_SET_FIELD((mode->htotal -
+                                 mode->hsync_end) * pixel_rep,
                                 VC4_HDMI_HORZB_HBP) |
-                  VC4_SET_FIELD(mode->hsync_end - mode->hsync_start,
+                  VC4_SET_FIELD((mode->hsync_end -
+                                 mode->hsync_start) * pixel_rep,
                                 VC4_HDMI_HORZB_HSP) |
-                  VC4_SET_FIELD(mode->hsync_start - mode->hdisplay,
+                  VC4_SET_FIELD((mode->hsync_start -
+                                 mode->hdisplay) * pixel_rep,
                                 VC4_HDMI_HORZB_HFP));
 
        HDMI_WRITE(VC4_HDMI_VERTA0, verta);
        HDMI_WRITE(VC4_HDMI_VERTA1, verta);
 
-       HDMI_WRITE(VC4_HDMI_VERTB0, vertb);
+       HDMI_WRITE(VC4_HDMI_VERTB0, vertb_even);
        HDMI_WRITE(VC4_HDMI_VERTB1, vertb);
 
        HD_WRITE(VC4_HD_VID_CTL,
                 (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
                 (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
 
+       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) {
+               /* 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
+                * to 16-235.  The matrix here is:
+                *
+                * [ 0      0      0.8594 16]
+                * [ 0      0.8594 0      16]
+                * [ 0.8594 0      0      16]
+                * [ 0      0      0       1]
+                */
+               csc_ctl |= VC4_HD_CSC_CTL_ENABLE;
+               csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC;
+               csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
+                                        VC4_HD_CSC_CTL_MODE);
+
+               HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000);
+               HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0);
+               HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000);
+               HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
+               HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
+               HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
+               vc4_encoder->limited_rgb_range = true;
+       } else {
+               vc4_encoder->limited_rgb_range = false;
+       }
+
        /* The RGB order applies even when CSC is disabled. */
-       HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
-                                              VC4_HD_CSC_CTL_ORDER));
+       HD_WRITE(VC4_HD_CSC_CTL, csc_ctl);
 
        HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
 
@@ -343,6 +506,8 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
        struct drm_device *dev = encoder->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
 
+       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
+
        HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
        HD_WRITE(VC4_HD_VID_CTL,
                 HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
@@ -369,7 +534,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
                           VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
 
                ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
-                              VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1);
+                              VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
                WARN_ONCE(ret, "Timeout waiting for "
                          "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
        } else {
@@ -381,7 +546,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
                           ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
 
                ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
-                                VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1);
+                                VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
                WARN_ONCE(ret, "Timeout waiting for "
                          "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
        }
@@ -395,9 +560,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
                           HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
                           VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
 
-               /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set
-                * up the infoframe.
-                */
+               HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
+                          VC4_HDMI_RAM_PACKET_ENABLE);
+
+               vc4_hdmi_set_infoframes(encoder);
 
                drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
                drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
index 4ac894d..c1f65c6 100644 (file)
@@ -44,7 +44,7 @@ vc4_atomic_complete_commit(struct vc4_commit *c)
 
        drm_atomic_helper_commit_modeset_disables(dev, state);
 
-       drm_atomic_helper_commit_planes(dev, state, false);
+       drm_atomic_helper_commit_planes(dev, state, 0);
 
        drm_atomic_helper_commit_modeset_enables(dev, state);
 
index 29e4b40..881bf48 100644 (file)
@@ -735,8 +735,6 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
 }
 
 static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
-       .prepare_fb = NULL,
-       .cleanup_fb = NULL,
        .atomic_check = vc4_plane_atomic_check,
        .atomic_update = vc4_plane_atomic_update,
 };
index 160942a..1aa44c2 100644 (file)
 # define PV_CONTROL_CLR_AT_START               BIT(14)
 # define PV_CONTROL_TRIGGER_UNDERFLOW          BIT(13)
 # define PV_CONTROL_WAIT_HSTART                        BIT(12)
+# define PV_CONTROL_PIXEL_REP_MASK             VC4_MASK(5, 4)
+# define PV_CONTROL_PIXEL_REP_SHIFT            4
 # define PV_CONTROL_CLK_SELECT_DSI_VEC         0
 # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI    1
 # define PV_CONTROL_CLK_SELECT_MASK            VC4_MASK(3, 2)
 # define PV_CONTROL_EN                         BIT(0)
 
 #define PV_V_CONTROL                           0x04
+# define PV_VCONTROL_ODD_DELAY_MASK            VC4_MASK(22, 6)
+# define PV_VCONTROL_ODD_DELAY_SHIFT           6
+# define PV_VCONTROL_ODD_FIRST                 BIT(5)
 # define PV_VCONTROL_INTERLACE                 BIT(4)
 # define PV_VCONTROL_CONTINUOUS                        BIT(1)
 # define PV_VCONTROL_VIDEN                     BIT(0)
 #define VC4_HDMI_RAM_PACKET_CONFIG             0x0a0
 # define VC4_HDMI_RAM_PACKET_ENABLE            BIT(16)
 
+#define VC4_HDMI_RAM_PACKET_STATUS             0x0a4
+
 #define VC4_HDMI_HORZA                         0x0c4
 # define VC4_HDMI_HORZA_VPOS                   BIT(14)
 # define VC4_HDMI_HORZA_HPOS                   BIT(13)
 
 #define VC4_HDMI_TX_PHY_RESET_CTL              0x2c0
 
+#define VC4_HDMI_GCP_0                         0x400
+#define VC4_HDMI_PACKET_STRIDE                 0x24
+
 #define VC4_HD_M_CTL                           0x00c
 # define VC4_HD_M_REGISTER_FILE_STANDBY                (3 << 6)
 # define VC4_HD_M_RAM_STANDBY                  (3 << 4)
 # define VC4_HD_CSC_CTL_MODE_SHIFT             2
 # define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB   0
 # define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB   1
-# define VC4_HD_CSC_CTL_MODE_CUSTOM            2
+# define VC4_HD_CSC_CTL_MODE_CUSTOM            3
 # define VC4_HD_CSC_CTL_RGB2YCC                        BIT(1)
 # define VC4_HD_CSC_CTL_ENABLE                 BIT(0)
 
+#define VC4_HD_CSC_12_11                       0x044
+#define VC4_HD_CSC_14_13                       0x048
+#define VC4_HD_CSC_22_21                       0x04c
+#define VC4_HD_CSC_24_23                       0x050
+#define VC4_HD_CSC_32_31                       0x054
+#define VC4_HD_CSC_34_33                       0x058
+
 #define VC4_HD_FRAME_COUNT                     0x068
 
 /* HVS display list information. */
index 0f12418..08886a3 100644 (file)
@@ -45,6 +45,8 @@ struct vc4_rcl_setup {
 
        struct drm_gem_cma_object *rcl;
        u32 next_offset;
+
+       u32 next_write_bo_index;
 };
 
 static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val)
@@ -407,6 +409,8 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
        if (!*obj)
                return -EINVAL;
 
+       exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj;
+
        if (surf->offset & 0xf) {
                DRM_ERROR("MSAA write must be 16b aligned.\n");
                return -EINVAL;
@@ -417,7 +421,8 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
 
 static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
                                 struct drm_gem_cma_object **obj,
-                                struct drm_vc4_submit_rcl_surface *surf)
+                                struct drm_vc4_submit_rcl_surface *surf,
+                                bool is_write)
 {
        uint8_t tiling = VC4_GET_FIELD(surf->bits,
                                       VC4_LOADSTORE_TILE_BUFFER_TILING);
@@ -440,6 +445,9 @@ static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
        if (!*obj)
                return -EINVAL;
 
+       if (is_write)
+               exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj;
+
        if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
                if (surf == &exec->args->zs_write) {
                        DRM_ERROR("general zs write may not be a full-res.\n");
@@ -542,6 +550,8 @@ vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec,
        if (!*obj)
                return -EINVAL;
 
+       exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj;
+
        if (tiling > VC4_TILING_FORMAT_LT) {
                DRM_ERROR("Bad tiling format\n");
                return -EINVAL;
@@ -599,15 +609,18 @@ int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec)
        if (ret)
                return ret;
 
-       ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
+       ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read,
+                                   false);
        if (ret)
                return ret;
 
-       ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read);
+       ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read,
+                                   false);
        if (ret)
                return ret;
 
-       ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write);
+       ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write,
+                                   true);
        if (ret)
                return ret;
 
index 9ce1d0a..26503e3 100644 (file)
@@ -267,6 +267,9 @@ validate_indexed_prim_list(VALIDATE_ARGS)
        if (!ib)
                return -EINVAL;
 
+       exec->bin_dep_seqno = max(exec->bin_dep_seqno,
+                                 to_vc4_bo(&ib->base)->write_seqno);
+
        if (offset > ib->base.size ||
            (ib->base.size - offset) / index_size < length) {
                DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n",
@@ -555,8 +558,7 @@ static bool
 reloc_tex(struct vc4_exec_info *exec,
          void *uniform_data_u,
          struct vc4_texture_sample_info *sample,
-         uint32_t texture_handle_index)
-
+         uint32_t texture_handle_index, bool is_cs)
 {
        struct drm_gem_cma_object *tex;
        uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]);
@@ -714,6 +716,11 @@ reloc_tex(struct vc4_exec_info *exec,
 
        *validated_p0 = tex->paddr + p0;
 
+       if (is_cs) {
+               exec->bin_dep_seqno = max(exec->bin_dep_seqno,
+                                         to_vc4_bo(&tex->base)->write_seqno);
+       }
+
        return true;
  fail:
        DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0);
@@ -835,7 +842,8 @@ validate_gl_shader_rec(struct drm_device *dev,
                        if (!reloc_tex(exec,
                                       uniform_data_u,
                                       &validated_shader->texture_samples[tex],
-                                      texture_handles_u[tex])) {
+                                      texture_handles_u[tex],
+                                      i == 2)) {
                                return -EINVAL;
                        }
                }
@@ -867,6 +875,9 @@ validate_gl_shader_rec(struct drm_device *dev,
                uint32_t stride = *(uint8_t *)(pkt_u + o + 5);
                uint32_t max_index;
 
+               exec->bin_dep_seqno = max(exec->bin_dep_seqno,
+                                         to_vc4_bo(&vbo->base)->write_seqno);
+
                if (state->addr & 0x8)
                        stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff;
 
index c15bafb..f36c147 100644 (file)
@@ -334,8 +334,8 @@ static int __init vgem_init(void)
        int ret;
 
        vgem_device = drm_dev_alloc(&vgem_driver, NULL);
-       if (!vgem_device) {
-               ret = -ENOMEM;
+       if (IS_ERR(vgem_device)) {
+               ret = PTR_ERR(vgem_device);
                goto out;
        }
 
index ed8aa8f..e5582ba 100644 (file)
@@ -72,7 +72,7 @@ static const struct file_operations via_driver_fops = {
 
 static struct drm_driver driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_HAVE_IRQ |
+           DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_LEGACY |
            DRIVER_IRQ_SHARED,
        .load = via_driver_load,
        .unload = via_driver_unload,
index 4e192aa..7cf3678 100644 (file)
@@ -338,7 +338,8 @@ static void vgdev_atomic_commit_tail(struct drm_atomic_state *state)
 
        drm_atomic_helper_commit_modeset_disables(dev, state);
        drm_atomic_helper_commit_modeset_enables(dev, state);
-       drm_atomic_helper_commit_planes(dev, state, true);
+       drm_atomic_helper_commit_planes(dev, state,
+                                       DRM_PLANE_COMMIT_ACTIVE_ONLY);
 
        drm_atomic_helper_commit_hw_done(state);
 
index 7f0e93f..49e5996 100644 (file)
  */
 
 #include <linux/pci.h>
+#include <drm/drm_fb_helper.h>
 
 #include "virtgpu_drv.h"
 
+int drm_virtio_set_busid(struct drm_device *dev, struct drm_master *master)
+{
+       struct pci_dev *pdev = dev->pdev;
+
+       if (pdev) {
+               return drm_pci_set_busid(dev, master);
+       }
+       return 0;
+}
+
 static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev)
 {
        struct apertures_struct *ap;
@@ -42,7 +53,7 @@ static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev)
        primary = pci_dev->resource[PCI_ROM_RESOURCE].flags
                & IORESOURCE_ROM_SHADOW;
 
-       remove_conflicting_framebuffers(ap, "virtiodrmfb", primary);
+       drm_fb_helper_remove_conflicting_framebuffers(ap, "virtiodrmfb", primary);
 
        kfree(ap);
 }
@@ -53,8 +64,8 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
        int ret;
 
        dev = drm_dev_alloc(driver, &vdev->dev);
-       if (!dev)
-               return -ENOMEM;
+       if (IS_ERR(dev))
+               return PTR_ERR(dev);
        dev->virtdev = vdev;
        vdev->priv = dev;
 
index c13f70c..5820b70 100644 (file)
@@ -117,6 +117,7 @@ static const struct file_operations virtio_gpu_driver_fops = {
 
 static struct drm_driver driver = {
        .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC,
+       .set_busid = drm_virtio_set_busid,
        .load = virtio_gpu_driver_load,
        .unload = virtio_gpu_driver_unload,
        .open = virtio_gpu_driver_open,
index b18ef31..ae59080 100644 (file)
@@ -49,6 +49,7 @@
 #define DRIVER_PATCHLEVEL 1
 
 /* virtgpu_drm_bus.c */
+int drm_virtio_set_busid(struct drm_device *dev, struct drm_master *master);
 int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev);
 
 struct virtio_gpu_object {
@@ -75,6 +76,7 @@ typedef void (*virtio_gpu_resp_cb)(struct virtio_gpu_device *vgdev,
 struct virtio_gpu_fence_driver {
        atomic64_t       last_seq;
        uint64_t         sync_seq;
+       uint64_t         context;
        struct list_head fences;
        spinlock_t       lock;
 };
index cf44187..f3f70fa 100644 (file)
@@ -89,7 +89,7 @@ int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev,
        (*fence)->drv = drv;
        (*fence)->seq = ++drv->sync_seq;
        fence_init(&(*fence)->f, &virtio_fence_ops, &drv->lock,
-                  0, (*fence)->seq);
+                  drv->context, (*fence)->seq);
        fence_get(&(*fence)->f);
        list_add_tail(&(*fence)->node, &drv->fences);
        spin_unlock_irqrestore(&drv->lock, irq_flags);
index c046903..818478b 100644 (file)
@@ -89,10 +89,16 @@ static void virtio_gpu_unref_list(struct list_head *head)
        }
 }
 
-static int virtio_gpu_execbuffer(struct drm_device *dev,
-                                struct drm_virtgpu_execbuffer *exbuf,
+/*
+ * Usage of execbuffer:
+ * Relocations need to take into account the full VIRTIO_GPUDrawable size.
+ * However, the command as passed from user space must *not* contain the initial
+ * VIRTIO_GPUReleaseInfo struct (first XXX bytes)
+ */
+static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
                                 struct drm_file *drm_file)
 {
+       struct drm_virtgpu_execbuffer *exbuf = data;
        struct virtio_gpu_device *vgdev = dev->dev_private;
        struct virtio_gpu_fpriv *vfpriv = drm_file->driver_priv;
        struct drm_gem_object *gobj;
@@ -152,15 +158,10 @@ static int virtio_gpu_execbuffer(struct drm_device *dev,
        if (ret)
                goto out_free;
 
-       buf = kmalloc(exbuf->size, GFP_KERNEL);
-       if (!buf) {
-               ret = -ENOMEM;
-               goto out_unresv;
-       }
-       if (copy_from_user(buf, (void __user *)(uintptr_t)exbuf->command,
-                          exbuf->size)) {
-               kfree(buf);
-               ret = -EFAULT;
+       buf = memdup_user((void __user *)(uintptr_t)exbuf->command,
+                         exbuf->size);
+       if (IS_ERR(buf)) {
+               ret = PTR_ERR(buf);
                goto out_unresv;
        }
        virtio_gpu_cmd_submit(vgdev, buf, exbuf->size,
@@ -182,20 +183,6 @@ out_free:
        return ret;
 }
 
-/*
- * Usage of execbuffer:
- * Relocations need to take into account the full VIRTIO_GPUDrawable size.
- * However, the command as passed from user space must *not* contain the initial
- * VIRTIO_GPUReleaseInfo struct (first XXX bytes)
- */
-static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
-                                      struct drm_file *file_priv)
-{
-       struct drm_virtgpu_execbuffer *execbuffer = data;
-       return virtio_gpu_execbuffer(dev, execbuffer, file_priv);
-}
-
-
 static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data,
                                     struct drm_file *file_priv)
 {
index 4150873..036b0fb 100644 (file)
@@ -159,6 +159,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
        virtio_gpu_init_vq(&vgdev->ctrlq, virtio_gpu_dequeue_ctrl_func);
        virtio_gpu_init_vq(&vgdev->cursorq, virtio_gpu_dequeue_cursor_func);
 
+       vgdev->fence_drv.context = fence_context_alloc(1);
        spin_lock_init(&vgdev->fence_drv.lock);
        INIT_LIST_HEAD(&vgdev->fence_drv.fences);
        INIT_LIST_HEAD(&vgdev->cap_cache);
index 925ca25..ba28c0f 100644 (file)
@@ -76,7 +76,8 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
                output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
        if (old_state->crtc)
                output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
-       WARN_ON(!output);
+       if (WARN_ON(!output))
+               return;
 
        if (plane->state->fb) {
                vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
@@ -129,7 +130,8 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
                output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
        if (old_state->crtc)
                output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
-       WARN_ON(!output);
+       if (WARN_ON(!output))
+               return;
 
        if (plane->state->fb) {
                vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
index b49445d..fb7b82a 100644 (file)
@@ -6,6 +6,7 @@ config DRM_VMWGFX
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        select DRM_TTM
+       select FB
        # Only needed for the transitional use of drm_crtc_init - can be removed
        # again once vmwgfx sets up the primary plane itself.
        select DRM_KMS_HELPER
index 74304b0..070d750 100644 (file)
                        VMWGFX_NUM_GB_SURFACE +\
                        VMWGFX_NUM_GB_SCREEN_TARGET)
 
-#define VMW_PL_GMR TTM_PL_PRIV0
-#define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0
-#define VMW_PL_MOB TTM_PL_PRIV1
-#define VMW_PL_FLAG_MOB TTM_PL_FLAG_PRIV1
+#define VMW_PL_GMR (TTM_PL_PRIV + 0)
+#define VMW_PL_FLAG_GMR (TTM_PL_FLAG_PRIV << 0)
+#define VMW_PL_MOB (TTM_PL_PRIV + 1)
+#define VMW_PL_FLAG_MOB (TTM_PL_FLAG_PRIV << 1)
 
 #define VMW_RES_CONTEXT ttm_driver_type0
 #define VMW_RES_SURFACE ttm_driver_type1
index 63ccd98..23ec673 100644 (file)
@@ -376,9 +376,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
 
        drm_mode_crtc_set_gamma_size(crtc, 256);
 
-       drm_object_attach_property(&connector->base,
-                                  dev->mode_config.dirty_info_property,
-                                  1);
        drm_object_attach_property(&connector->base,
                                   dev_priv->hotplug_mode_update_property, 1);
        drm_object_attach_property(&connector->base,
@@ -421,10 +418,6 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
        if (ret != 0)
                goto err_free;
 
-       ret = drm_mode_create_dirty_info_property(dev);
-       if (ret != 0)
-               goto err_vblank_cleanup;
-
        vmw_kms_create_implicit_placement_property(dev_priv, true);
 
        if (dev_priv->capabilities & SVGA_CAP_MULTIMON)
@@ -439,8 +432,6 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
 
        return 0;
 
-err_vblank_cleanup:
-       drm_vblank_cleanup(dev);
 err_free:
        kfree(dev_priv->ldu_priv);
        dev_priv->ldu_priv = NULL;
index b74eae2..f423590 100644 (file)
@@ -537,9 +537,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
 
        drm_mode_crtc_set_gamma_size(crtc, 256);
 
-       drm_object_attach_property(&connector->base,
-                                  dev->mode_config.dirty_info_property,
-                                  1);
        drm_object_attach_property(&connector->base,
                                   dev_priv->hotplug_mode_update_property, 1);
        drm_object_attach_property(&connector->base,
@@ -574,10 +571,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
        if (unlikely(ret != 0))
                return ret;
 
-       ret = drm_mode_create_dirty_info_property(dev);
-       if (unlikely(ret != 0))
-               goto err_vblank_cleanup;
-
        vmw_kms_create_implicit_placement_property(dev_priv, false);
 
        for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
@@ -588,10 +581,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
        DRM_INFO("Screen Objects Display Unit initialized\n");
 
        return 0;
-
-err_vblank_cleanup:
-       drm_vblank_cleanup(dev);
-       return ret;
 }
 
 int vmw_kms_sou_close_display(struct vmw_private *dev_priv)
index 41932a7..94ad8d2 100644 (file)
@@ -1130,9 +1130,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
 
        drm_mode_crtc_set_gamma_size(crtc, 256);
 
-       drm_object_attach_property(&connector->base,
-                                  dev->mode_config.dirty_info_property,
-                                  1);
        drm_object_attach_property(&connector->base,
                                   dev_priv->hotplug_mode_update_property, 1);
        drm_object_attach_property(&connector->base,
@@ -1202,10 +1199,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
        if (unlikely(ret != 0))
                return ret;
 
-       ret = drm_mode_create_dirty_info_property(dev);
-       if (unlikely(ret != 0))
-               goto err_vblank_cleanup;
-
        dev_priv->active_display_unit = vmw_du_screen_target;
 
        vmw_kms_create_implicit_placement_property(dev_priv, false);
index 107ec23..5f96141 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
 
 imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
-               ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o
+               ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-image-convert.o \
+               ipu-smfc.o ipu-vdi.o
index 99dcacf..b9539f7 100644 (file)
@@ -45,6 +45,12 @@ static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
        writel(value, ipu->cm_reg + offset);
 }
 
+int ipu_get_num(struct ipu_soc *ipu)
+{
+       return ipu->id;
+}
+EXPORT_SYMBOL_GPL(ipu_get_num);
+
 void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
 {
        u32 val;
@@ -724,6 +730,137 @@ void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
 }
 EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
 
+
+/* Frame Synchronization Unit Channel Linking */
+
+struct fsu_link_reg_info {
+       int chno;
+       u32 reg;
+       u32 mask;
+       u32 val;
+};
+
+struct fsu_link_info {
+       struct fsu_link_reg_info src;
+       struct fsu_link_reg_info sink;
+};
+
+static const struct fsu_link_info fsu_link_info[] = {
+       {
+               .src  = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
+                         FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC },
+               .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
+                         FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC },
+       }, {
+               .src =  { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
+                         FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
+               .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
+                         FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
+       }, {
+               .src =  { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
+                         FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
+               .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
+                         FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
+       }, {
+               .src =  { IPUV3_CHANNEL_CSI_DIRECT, 0 },
+               .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
+                         FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
+       },
+};
+
+static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
+               if (src == fsu_link_info[i].src.chno &&
+                   sink == fsu_link_info[i].sink.chno)
+                       return &fsu_link_info[i];
+       }
+
+       return NULL;
+}
+
+/*
+ * Links a source channel to a sink channel in the FSU.
+ */
+int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
+{
+       const struct fsu_link_info *link;
+       u32 src_reg, sink_reg;
+       unsigned long flags;
+
+       link = find_fsu_link_info(src_ch, sink_ch);
+       if (!link)
+               return -EINVAL;
+
+       spin_lock_irqsave(&ipu->lock, flags);
+
+       if (link->src.mask) {
+               src_reg = ipu_cm_read(ipu, link->src.reg);
+               src_reg &= ~link->src.mask;
+               src_reg |= link->src.val;
+               ipu_cm_write(ipu, src_reg, link->src.reg);
+       }
+
+       if (link->sink.mask) {
+               sink_reg = ipu_cm_read(ipu, link->sink.reg);
+               sink_reg &= ~link->sink.mask;
+               sink_reg |= link->sink.val;
+               ipu_cm_write(ipu, sink_reg, link->sink.reg);
+       }
+
+       spin_unlock_irqrestore(&ipu->lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_fsu_link);
+
+/*
+ * Unlinks source and sink channels in the FSU.
+ */
+int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
+{
+       const struct fsu_link_info *link;
+       u32 src_reg, sink_reg;
+       unsigned long flags;
+
+       link = find_fsu_link_info(src_ch, sink_ch);
+       if (!link)
+               return -EINVAL;
+
+       spin_lock_irqsave(&ipu->lock, flags);
+
+       if (link->src.mask) {
+               src_reg = ipu_cm_read(ipu, link->src.reg);
+               src_reg &= ~link->src.mask;
+               ipu_cm_write(ipu, src_reg, link->src.reg);
+       }
+
+       if (link->sink.mask) {
+               sink_reg = ipu_cm_read(ipu, link->sink.reg);
+               sink_reg &= ~link->sink.mask;
+               ipu_cm_write(ipu, sink_reg, link->sink.reg);
+       }
+
+       spin_unlock_irqrestore(&ipu->lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_fsu_unlink);
+
+/* Link IDMAC channels in the FSU */
+int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink)
+{
+       return ipu_fsu_link(src->ipu, src->num, sink->num);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_link);
+
+/* Unlink IDMAC channels in the FSU */
+int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink)
+{
+       return ipu_fsu_unlink(src->ipu, src->num, sink->num);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_unlink);
+
 struct ipu_devtype {
        const char *name;
        unsigned long cm_ofs;
@@ -833,6 +970,20 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
                goto err_ic;
        }
 
+       ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
+                          IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
+                          IPU_CONF_IC_INPUT);
+       if (ret) {
+               unit = "vdi";
+               goto err_vdi;
+       }
+
+       ret = ipu_image_convert_init(ipu, dev);
+       if (ret) {
+               unit = "image_convert";
+               goto err_image_convert;
+       }
+
        ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
                          IPU_CONF_DI0_EN, ipu_clk);
        if (ret) {
@@ -887,6 +1038,10 @@ err_dc:
 err_di_1:
        ipu_di_exit(ipu, 0);
 err_di_0:
+       ipu_image_convert_exit(ipu);
+err_image_convert:
+       ipu_vdi_exit(ipu);
+err_vdi:
        ipu_ic_exit(ipu);
 err_ic:
        ipu_csi_exit(ipu, 1);
@@ -971,6 +1126,8 @@ static void ipu_submodules_exit(struct ipu_soc *ipu)
        ipu_dc_exit(ipu);
        ipu_di_exit(ipu, 1);
        ipu_di_exit(ipu, 0);
+       ipu_image_convert_exit(ipu);
+       ipu_vdi_exit(ipu);
        ipu_ic_exit(ipu);
        ipu_csi_exit(ipu, 1);
        ipu_csi_exit(ipu, 0);
@@ -1004,14 +1161,14 @@ static struct ipu_platform_reg client_reg[] = {
                        .dma[0] = IPUV3_CHANNEL_CSI0,
                        .dma[1] = -EINVAL,
                },
-               .name = "imx-ipuv3-camera",
+               .name = "imx-ipuv3-csi",
        }, {
                .pdata = {
                        .csi = 1,
                        .dma[0] = IPUV3_CHANNEL_CSI1,
                        .dma[1] = -EINVAL,
                },
-               .name = "imx-ipuv3-camera",
+               .name = "imx-ipuv3-csi",
        }, {
                .pdata = {
                        .di = 0,
@@ -1207,15 +1364,16 @@ EXPORT_SYMBOL_GPL(ipu_dump);
 
 static int ipu_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *of_id =
-                       of_match_device(imx_ipu_dt_ids, &pdev->dev);
+       struct device_node *np = pdev->dev.of_node;
        struct ipu_soc *ipu;
        struct resource *res;
        unsigned long ipu_base;
        int i, ret, irq_sync, irq_err;
        const struct ipu_devtype *devtype;
 
-       devtype = of_id->data;
+       devtype = of_device_get_match_data(&pdev->dev);
+       if (!devtype)
+               return -EINVAL;
 
        irq_sync = platform_get_irq(pdev, 0);
        irq_err = platform_get_irq(pdev, 1);
@@ -1237,6 +1395,7 @@ static int ipu_probe(struct platform_device *pdev)
                ipu->channel[i].ipu = ipu;
        ipu->devtype = devtype;
        ipu->ipu_type = devtype->type;
+       ipu->id = of_alias_get_id(np, "ipu");
 
        spin_lock_init(&ipu->lock);
        mutex_init(&ipu->channel_lock);
index 6494a4d..fcb7dc8 100644 (file)
@@ -253,6 +253,13 @@ void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
 
+void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
+{
+       ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
+       ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
+
 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
 {
        ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
@@ -268,6 +275,12 @@ void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
 
+int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
+{
+       return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
+
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
 {
        ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
index 06631ac..d6e5ded 100644 (file)
@@ -258,12 +258,8 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
                cfg->data_width = IPU_CSI_DATA_WIDTH_8;
                break;
        case MEDIA_BUS_FMT_UYVY8_1X16:
-               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
-               cfg->mipi_dt = MIPI_DT_YUV422;
-               cfg->data_width = IPU_CSI_DATA_WIDTH_16;
-               break;
        case MEDIA_BUS_FMT_YUYV8_1X16:
-               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
                cfg->mipi_dt = MIPI_DT_YUV422;
                cfg->data_width = IPU_CSI_DATA_WIDTH_16;
                break;
@@ -365,10 +361,14 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
 {
        struct ipu_csi_bus_config cfg;
        unsigned long flags;
-       u32 data = 0;
+       u32 width, height, data = 0;
 
        fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
 
+       /* set default sensor frame width and height */
+       width = mbus_fmt->width;
+       height = mbus_fmt->height;
+
        /* Set the CSI_SENS_CONF register remaining fields */
        data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
                cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
@@ -386,11 +386,6 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
 
        ipu_csi_write(csi, data, CSI_SENS_CONF);
 
-       /* Setup sensor frame size */
-       ipu_csi_write(csi,
-                     (mbus_fmt->width - 1) | ((mbus_fmt->height - 1) << 16),
-                     CSI_SENS_FRM_SIZE);
-
        /* Set CCIR registers */
 
        switch (cfg.clk_mode) {
@@ -408,11 +403,12 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
                         * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
                         * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
                         */
+                       height = 625; /* framelines for PAL */
+
                        ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
                                          CSI_CCIR_CODE_1);
                        ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
                        ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
-
                } else if (mbus_fmt->width == 720 && mbus_fmt->height == 480) {
                        /*
                         * NTSC case
@@ -422,6 +418,8 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
                         * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
                         * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
                         */
+                       height = 525; /* framelines for NTSC */
+
                        ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
                                          CSI_CCIR_CODE_1);
                        ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
@@ -447,6 +445,10 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
                break;
        }
 
+       /* Setup sensor frame size */
+       ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
+                     CSI_SENS_FRM_SIZE);
+
        dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
                ipu_csi_read(csi, CSI_SENS_CONF));
        dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
index 42705bb..a40f211 100644 (file)
@@ -123,20 +123,6 @@ int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
 }
 EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
 
-static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv)
-{
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-       while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) {
-               if (time_after(jiffies, timeout)) {
-                       dev_warn(priv->dev,
-                                "Timeout waiting for DMFC FIFOs to clear\n");
-                       break;
-               }
-               cpu_relax();
-       }
-}
-
 void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
 {
        struct ipu_dmfc_priv *priv = dmfc->priv;
@@ -145,10 +131,8 @@ void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
 
        priv->use_count--;
 
-       if (!priv->use_count) {
-               ipu_dmfc_wait_fifos(priv);
+       if (!priv->use_count)
                ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
-       }
 
        if (priv->use_count < 0)
                priv->use_count = 0;
index 1dcb96c..321eb98 100644 (file)
@@ -160,6 +160,7 @@ struct ipu_ic_priv {
        spinlock_t lock;
        struct ipu_soc *ipu;
        int use_count;
+       int irt_use_count;
        struct ipu_ic task[IC_NUM_TASKS];
 };
 
@@ -379,8 +380,6 @@ void ipu_ic_task_disable(struct ipu_ic *ic)
 
        ipu_ic_write(ic, ic_conf, IC_CONF);
 
-       ic->rotation = ic->graphics = false;
-
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
@@ -620,7 +619,7 @@ int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
        ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
        ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
 
-       if (rot >= IPU_ROTATE_90_RIGHT)
+       if (ipu_rot_mode_is_irt(rot))
                ic->rotation = true;
 
 unlock:
@@ -629,22 +628,41 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
 
+static void ipu_irt_enable(struct ipu_ic *ic)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+
+       if (!priv->irt_use_count)
+               ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
+
+       priv->irt_use_count++;
+}
+
+static void ipu_irt_disable(struct ipu_ic *ic)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+
+       if (priv->irt_use_count) {
+               if (!--priv->irt_use_count)
+                       ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
+       }
+}
+
 int ipu_ic_enable(struct ipu_ic *ic)
 {
        struct ipu_ic_priv *priv = ic->priv;
        unsigned long flags;
-       u32 module = IPU_CONF_IC_EN;
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       if (ic->rotation)
-               module |= IPU_CONF_ROT_EN;
-
        if (!priv->use_count)
-               ipu_module_enable(priv->ipu, module);
+               ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
 
        priv->use_count++;
 
+       if (ic->rotation)
+               ipu_irt_enable(ic);
+
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
@@ -655,18 +673,22 @@ int ipu_ic_disable(struct ipu_ic *ic)
 {
        struct ipu_ic_priv *priv = ic->priv;
        unsigned long flags;
-       u32 module = IPU_CONF_IC_EN | IPU_CONF_ROT_EN;
 
        spin_lock_irqsave(&priv->lock, flags);
 
        priv->use_count--;
 
        if (!priv->use_count)
-               ipu_module_disable(priv->ipu, module);
+               ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
 
        if (priv->use_count < 0)
                priv->use_count = 0;
 
+       if (ic->rotation)
+               ipu_irt_disable(ic);
+
+       ic->rotation = ic->graphics = false;
+
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c
new file mode 100644 (file)
index 0000000..2ba7d43
--- /dev/null
@@ -0,0 +1,1709 @@
+/*
+ * Copyright (C) 2012-2016 Mentor Graphics Inc.
+ *
+ * Queued image conversion support, with tiling and rotation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <video/imx-ipu-image-convert.h>
+#include "ipu-prv.h"
+
+/*
+ * The IC Resizer has a restriction that the output frame from the
+ * resizer must be 1024 or less in both width (pixels) and height
+ * (lines).
+ *
+ * The image converter attempts to split up a conversion when
+ * the desired output (converted) frame resolution exceeds the
+ * IC resizer limit of 1024 in either dimension.
+ *
+ * If either dimension of the output frame exceeds the limit, the
+ * dimension is split into 1, 2, or 4 equal stripes, for a maximum
+ * of 4*4 or 16 tiles. A conversion is then carried out for each
+ * tile (but taking care to pass the full frame stride length to
+ * the DMA channel's parameter memory!). IDMA double-buffering is used
+ * to convert each tile back-to-back when possible (see note below
+ * when double_buffering boolean is set).
+ *
+ * Note that the input frame must be split up into the same number
+ * of tiles as the output frame.
+ *
+ * FIXME: at this point there is no attempt to deal with visible seams
+ * at the tile boundaries when upscaling. The seams are caused by a reset
+ * of the bilinear upscale interpolation when starting a new tile. The
+ * seams are barely visible for small upscale factors, but become
+ * increasingly visible as the upscale factor gets larger, since more
+ * interpolated pixels get thrown out at the tile boundaries. A possilble
+ * fix might be to overlap tiles of different sizes, but this must be done
+ * while also maintaining the IDMAC dma buffer address alignment and 8x8 IRT
+ * alignment restrictions of each tile.
+ */
+
+#define MAX_STRIPES_W    4
+#define MAX_STRIPES_H    4
+#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
+
+#define MIN_W     16
+#define MIN_H     8
+#define MAX_W     4096
+#define MAX_H     4096
+
+enum ipu_image_convert_type {
+       IMAGE_CONVERT_IN = 0,
+       IMAGE_CONVERT_OUT,
+};
+
+struct ipu_image_convert_dma_buf {
+       void          *virt;
+       dma_addr_t    phys;
+       unsigned long len;
+};
+
+struct ipu_image_convert_dma_chan {
+       int in;
+       int out;
+       int rot_in;
+       int rot_out;
+       int vdi_in_p;
+       int vdi_in;
+       int vdi_in_n;
+};
+
+/* dimensions of one tile */
+struct ipu_image_tile {
+       u32 width;
+       u32 height;
+       /* size and strides are in bytes */
+       u32 size;
+       u32 stride;
+       u32 rot_stride;
+       /* start Y or packed offset of this tile */
+       u32 offset;
+       /* offset from start to tile in U plane, for planar formats */
+       u32 u_off;
+       /* offset from start to tile in V plane, for planar formats */
+       u32 v_off;
+};
+
+struct ipu_image_convert_image {
+       struct ipu_image base;
+       enum ipu_image_convert_type type;
+
+       const struct ipu_image_pixfmt *fmt;
+       unsigned int stride;
+
+       /* # of rows (horizontal stripes) if dest height is > 1024 */
+       unsigned int num_rows;
+       /* # of columns (vertical stripes) if dest width is > 1024 */
+       unsigned int num_cols;
+
+       struct ipu_image_tile tile[MAX_TILES];
+};
+
+struct ipu_image_pixfmt {
+       u32     fourcc;        /* V4L2 fourcc */
+       int     bpp;           /* total bpp */
+       int     uv_width_dec;  /* decimation in width for U/V planes */
+       int     uv_height_dec; /* decimation in height for U/V planes */
+       bool    planar;        /* planar format */
+       bool    uv_swapped;    /* U and V planes are swapped */
+       bool    uv_packed;     /* partial planar (U and V in same plane) */
+};
+
+struct ipu_image_convert_ctx;
+struct ipu_image_convert_chan;
+struct ipu_image_convert_priv;
+
+struct ipu_image_convert_ctx {
+       struct ipu_image_convert_chan *chan;
+
+       ipu_image_convert_cb_t complete;
+       void *complete_context;
+
+       /* Source/destination image data and rotation mode */
+       struct ipu_image_convert_image in;
+       struct ipu_image_convert_image out;
+       enum ipu_rotate_mode rot_mode;
+
+       /* intermediate buffer for rotation */
+       struct ipu_image_convert_dma_buf rot_intermediate[2];
+
+       /* current buffer number for double buffering */
+       int cur_buf_num;
+
+       bool aborting;
+       struct completion aborted;
+
+       /* can we use double-buffering for this conversion operation? */
+       bool double_buffering;
+       /* num_rows * num_cols */
+       unsigned int num_tiles;
+       /* next tile to process */
+       unsigned int next_tile;
+       /* where to place converted tile in dest image */
+       unsigned int out_tile_map[MAX_TILES];
+
+       struct list_head list;
+};
+
+struct ipu_image_convert_chan {
+       struct ipu_image_convert_priv *priv;
+
+       enum ipu_ic_task ic_task;
+       const struct ipu_image_convert_dma_chan *dma_ch;
+
+       struct ipu_ic *ic;
+       struct ipuv3_channel *in_chan;
+       struct ipuv3_channel *out_chan;
+       struct ipuv3_channel *rotation_in_chan;
+       struct ipuv3_channel *rotation_out_chan;
+
+       /* the IPU end-of-frame irqs */
+       int out_eof_irq;
+       int rot_out_eof_irq;
+
+       spinlock_t irqlock;
+
+       /* list of convert contexts */
+       struct list_head ctx_list;
+       /* queue of conversion runs */
+       struct list_head pending_q;
+       /* queue of completed runs */
+       struct list_head done_q;
+
+       /* the current conversion run */
+       struct ipu_image_convert_run *current_run;
+};
+
+struct ipu_image_convert_priv {
+       struct ipu_image_convert_chan chan[IC_NUM_TASKS];
+       struct ipu_soc *ipu;
+};
+
+static const struct ipu_image_convert_dma_chan
+image_convert_dma_chan[IC_NUM_TASKS] = {
+       [IC_TASK_VIEWFINDER] = {
+               .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
+               .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
+               .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
+               .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
+               .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
+               .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
+               .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
+       },
+       [IC_TASK_POST_PROCESSOR] = {
+               .in = IPUV3_CHANNEL_MEM_IC_PP,
+               .out = IPUV3_CHANNEL_IC_PP_MEM,
+               .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
+               .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
+       },
+};
+
+static const struct ipu_image_pixfmt image_convert_formats[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_RGB565,
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_RGB24,
+               .bpp    = 24,
+       }, {
+               .fourcc = V4L2_PIX_FMT_BGR24,
+               .bpp    = 24,
+       }, {
+               .fourcc = V4L2_PIX_FMT_RGB32,
+               .bpp    = 32,
+       }, {
+               .fourcc = V4L2_PIX_FMT_BGR32,
+               .bpp    = 32,
+       }, {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .bpp    = 16,
+               .uv_width_dec = 2,
+               .uv_height_dec = 1,
+       }, {
+               .fourcc = V4L2_PIX_FMT_UYVY,
+               .bpp    = 16,
+               .uv_width_dec = 2,
+               .uv_height_dec = 1,
+       }, {
+               .fourcc = V4L2_PIX_FMT_YUV420,
+               .bpp    = 12,
+               .planar = true,
+               .uv_width_dec = 2,
+               .uv_height_dec = 2,
+       }, {
+               .fourcc = V4L2_PIX_FMT_YVU420,
+               .bpp    = 12,
+               .planar = true,
+               .uv_width_dec = 2,
+               .uv_height_dec = 2,
+               .uv_swapped = true,
+       }, {
+               .fourcc = V4L2_PIX_FMT_NV12,
+               .bpp    = 12,
+               .planar = true,
+               .uv_width_dec = 2,
+               .uv_height_dec = 2,
+               .uv_packed = true,
+       }, {
+               .fourcc = V4L2_PIX_FMT_YUV422P,
+               .bpp    = 16,
+               .planar = true,
+               .uv_width_dec = 2,
+               .uv_height_dec = 1,
+       }, {
+               .fourcc = V4L2_PIX_FMT_NV16,
+               .bpp    = 16,
+               .planar = true,
+               .uv_width_dec = 2,
+               .uv_height_dec = 1,
+               .uv_packed = true,
+       },
+};
+
+static const struct ipu_image_pixfmt *get_format(u32 fourcc)
+{
+       const struct ipu_image_pixfmt *ret = NULL;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
+               if (image_convert_formats[i].fourcc == fourcc) {
+                       ret = &image_convert_formats[i];
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static void dump_format(struct ipu_image_convert_ctx *ctx,
+                       struct ipu_image_convert_image *ic_image)
+{
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+
+       dev_dbg(priv->ipu->dev,
+               "task %u: ctx %p: %s format: %dx%d (%dx%d tiles of size %dx%d), %c%c%c%c\n",
+               chan->ic_task, ctx,
+               ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
+               ic_image->base.pix.width, ic_image->base.pix.height,
+               ic_image->num_cols, ic_image->num_rows,
+               ic_image->tile[0].width, ic_image->tile[0].height,
+               ic_image->fmt->fourcc & 0xff,
+               (ic_image->fmt->fourcc >> 8) & 0xff,
+               (ic_image->fmt->fourcc >> 16) & 0xff,
+               (ic_image->fmt->fourcc >> 24) & 0xff);
+}
+
+int ipu_image_convert_enum_format(int index, u32 *fourcc)
+{
+       const struct ipu_image_pixfmt *fmt;
+
+       if (index >= (int)ARRAY_SIZE(image_convert_formats))
+               return -EINVAL;
+
+       /* Format found */
+       fmt = &image_convert_formats[index];
+       *fourcc = fmt->fourcc;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
+
+static void free_dma_buf(struct ipu_image_convert_priv *priv,
+                        struct ipu_image_convert_dma_buf *buf)
+{
+       if (buf->virt)
+               dma_free_coherent(priv->ipu->dev,
+                                 buf->len, buf->virt, buf->phys);
+       buf->virt = NULL;
+       buf->phys = 0;
+}
+
+static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
+                        struct ipu_image_convert_dma_buf *buf,
+                        int size)
+{
+       buf->len = PAGE_ALIGN(size);
+       buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
+                                      GFP_DMA | GFP_KERNEL);
+       if (!buf->virt) {
+               dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static inline int num_stripes(int dim)
+{
+       if (dim <= 1024)
+               return 1;
+       else if (dim <= 2048)
+               return 2;
+       else
+               return 4;
+}
+
+static void calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
+                                struct ipu_image_convert_image *image)
+{
+       int i;
+
+       for (i = 0; i < ctx->num_tiles; i++) {
+               struct ipu_image_tile *tile = &image->tile[i];
+
+               tile->height = image->base.pix.height / image->num_rows;
+               tile->width = image->base.pix.width / image->num_cols;
+               tile->size = ((tile->height * image->fmt->bpp) >> 3) *
+                       tile->width;
+
+               if (image->fmt->planar) {
+                       tile->stride = tile->width;
+                       tile->rot_stride = tile->height;
+               } else {
+                       tile->stride =
+                               (image->fmt->bpp * tile->width) >> 3;
+                       tile->rot_stride =
+                               (image->fmt->bpp * tile->height) >> 3;
+               }
+       }
+}
+
+/*
+ * Use the rotation transformation to find the tile coordinates
+ * (row, col) of a tile in the destination frame that corresponds
+ * to the given tile coordinates of a source frame. The destination
+ * coordinate is then converted to a tile index.
+ */
+static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
+                               int src_row, int src_col)
+{
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       struct ipu_image_convert_image *s_image = &ctx->in;
+       struct ipu_image_convert_image *d_image = &ctx->out;
+       int dst_row, dst_col;
+
+       /* with no rotation it's a 1:1 mapping */
+       if (ctx->rot_mode == IPU_ROTATE_NONE)
+               return src_row * s_image->num_cols + src_col;
+
+       /*
+        * before doing the transform, first we have to translate
+        * source row,col for an origin in the center of s_image
+        */
+       src_row = src_row * 2 - (s_image->num_rows - 1);
+       src_col = src_col * 2 - (s_image->num_cols - 1);
+
+       /* do the rotation transform */
+       if (ctx->rot_mode & IPU_ROT_BIT_90) {
+               dst_col = -src_row;
+               dst_row = src_col;
+       } else {
+               dst_col = src_col;
+               dst_row = src_row;
+       }
+
+       /* apply flip */
+       if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
+               dst_col = -dst_col;
+       if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
+               dst_row = -dst_row;
+
+       dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
+               chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
+
+       /*
+        * finally translate dest row,col using an origin in upper
+        * left of d_image
+        */
+       dst_row += d_image->num_rows - 1;
+       dst_col += d_image->num_cols - 1;
+       dst_row /= 2;
+       dst_col /= 2;
+
+       return dst_row * d_image->num_cols + dst_col;
+}
+
+/*
+ * Fill the out_tile_map[] with transformed destination tile indeces.
+ */
+static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
+{
+       struct ipu_image_convert_image *s_image = &ctx->in;
+       unsigned int row, col, tile = 0;
+
+       for (row = 0; row < s_image->num_rows; row++) {
+               for (col = 0; col < s_image->num_cols; col++) {
+                       ctx->out_tile_map[tile] =
+                               transform_tile_index(ctx, row, col);
+                       tile++;
+               }
+       }
+}
+
+static void calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
+                                    struct ipu_image_convert_image *image)
+{
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       const struct ipu_image_pixfmt *fmt = image->fmt;
+       unsigned int row, col, tile = 0;
+       u32 H, w, h, y_stride, uv_stride;
+       u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
+       u32 y_row_off, y_col_off, y_off;
+       u32 y_size, uv_size;
+
+       /* setup some convenience vars */
+       H = image->base.pix.height;
+
+       y_stride = image->stride;
+       uv_stride = y_stride / fmt->uv_width_dec;
+       if (fmt->uv_packed)
+               uv_stride *= 2;
+
+       y_size = H * y_stride;
+       uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
+
+       for (row = 0; row < image->num_rows; row++) {
+               w = image->tile[tile].width;
+               h = image->tile[tile].height;
+               y_row_off = row * h * y_stride;
+               uv_row_off = (row * h * uv_stride) / fmt->uv_height_dec;
+
+               for (col = 0; col < image->num_cols; col++) {
+                       y_col_off = col * w;
+                       uv_col_off = y_col_off / fmt->uv_width_dec;
+                       if (fmt->uv_packed)
+                               uv_col_off *= 2;
+
+                       y_off = y_row_off + y_col_off;
+                       uv_off = uv_row_off + uv_col_off;
+
+                       u_off = y_size - y_off + uv_off;
+                       v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
+                       if (fmt->uv_swapped) {
+                               tmp = u_off;
+                               u_off = v_off;
+                               v_off = tmp;
+                       }
+
+                       image->tile[tile].offset = y_off;
+                       image->tile[tile].u_off = u_off;
+                       image->tile[tile++].v_off = v_off;
+
+                       dev_dbg(priv->ipu->dev,
+                               "task %u: ctx %p: %s@[%d,%d]: y_off %08x, u_off %08x, v_off %08x\n",
+                               chan->ic_task, ctx,
+                               image->type == IMAGE_CONVERT_IN ?
+                               "Input" : "Output", row, col,
+                               y_off, u_off, v_off);
+               }
+       }
+}
+
+static void calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
+                                    struct ipu_image_convert_image *image)
+{
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       const struct ipu_image_pixfmt *fmt = image->fmt;
+       unsigned int row, col, tile = 0;
+       u32 w, h, bpp, stride;
+       u32 row_off, col_off;
+
+       /* setup some convenience vars */
+       stride = image->stride;
+       bpp = fmt->bpp;
+
+       for (row = 0; row < image->num_rows; row++) {
+               w = image->tile[tile].width;
+               h = image->tile[tile].height;
+               row_off = row * h * stride;
+
+               for (col = 0; col < image->num_cols; col++) {
+                       col_off = (col * w * bpp) >> 3;
+
+                       image->tile[tile].offset = row_off + col_off;
+                       image->tile[tile].u_off = 0;
+                       image->tile[tile++].v_off = 0;
+
+                       dev_dbg(priv->ipu->dev,
+                               "task %u: ctx %p: %s@[%d,%d]: phys %08x\n",
+                               chan->ic_task, ctx,
+                               image->type == IMAGE_CONVERT_IN ?
+                               "Input" : "Output", row, col,
+                               row_off + col_off);
+               }
+       }
+}
+
+static void calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
+                             struct ipu_image_convert_image *image)
+{
+       if (image->fmt->planar)
+               calc_tile_offsets_planar(ctx, image);
+       else
+               calc_tile_offsets_packed(ctx, image);
+}
+
+/*
+ * return the number of runs in given queue (pending_q or done_q)
+ * for this context. hold irqlock when calling.
+ */
+static int get_run_count(struct ipu_image_convert_ctx *ctx,
+                        struct list_head *q)
+{
+       struct ipu_image_convert_run *run;
+       int count = 0;
+
+       lockdep_assert_held(&ctx->chan->irqlock);
+
+       list_for_each_entry(run, q, list) {
+               if (run->ctx == ctx)
+                       count++;
+       }
+
+       return count;
+}
+
+static void convert_stop(struct ipu_image_convert_run *run)
+{
+       struct ipu_image_convert_ctx *ctx = run->ctx;
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+
+       dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
+               __func__, chan->ic_task, ctx, run);
+
+       /* disable IC tasks and the channels */
+       ipu_ic_task_disable(chan->ic);
+       ipu_idmac_disable_channel(chan->in_chan);
+       ipu_idmac_disable_channel(chan->out_chan);
+
+       if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               ipu_idmac_disable_channel(chan->rotation_in_chan);
+               ipu_idmac_disable_channel(chan->rotation_out_chan);
+               ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
+       }
+
+       ipu_ic_disable(chan->ic);
+}
+
+static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
+                              struct ipuv3_channel *channel,
+                              struct ipu_image_convert_image *image,
+                              enum ipu_rotate_mode rot_mode,
+                              bool rot_swap_width_height)
+{
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       unsigned int burst_size;
+       u32 width, height, stride;
+       dma_addr_t addr0, addr1 = 0;
+       struct ipu_image tile_image;
+       unsigned int tile_idx[2];
+
+       if (image->type == IMAGE_CONVERT_OUT) {
+               tile_idx[0] = ctx->out_tile_map[0];
+               tile_idx[1] = ctx->out_tile_map[1];
+       } else {
+               tile_idx[0] = 0;
+               tile_idx[1] = 1;
+       }
+
+       if (rot_swap_width_height) {
+               width = image->tile[0].height;
+               height = image->tile[0].width;
+               stride = image->tile[0].rot_stride;
+               addr0 = ctx->rot_intermediate[0].phys;
+               if (ctx->double_buffering)
+                       addr1 = ctx->rot_intermediate[1].phys;
+       } else {
+               width = image->tile[0].width;
+               height = image->tile[0].height;
+               stride = image->stride;
+               addr0 = image->base.phys0 +
+                       image->tile[tile_idx[0]].offset;
+               if (ctx->double_buffering)
+                       addr1 = image->base.phys0 +
+                               image->tile[tile_idx[1]].offset;
+       }
+
+       ipu_cpmem_zero(channel);
+
+       memset(&tile_image, 0, sizeof(tile_image));
+       tile_image.pix.width = tile_image.rect.width = width;
+       tile_image.pix.height = tile_image.rect.height = height;
+       tile_image.pix.bytesperline = stride;
+       tile_image.pix.pixelformat =  image->fmt->fourcc;
+       tile_image.phys0 = addr0;
+       tile_image.phys1 = addr1;
+       ipu_cpmem_set_image(channel, &tile_image);
+
+       if (image->fmt->planar && !rot_swap_width_height)
+               ipu_cpmem_set_uv_offset(channel,
+                                       image->tile[tile_idx[0]].u_off,
+                                       image->tile[tile_idx[0]].v_off);
+
+       if (rot_mode)
+               ipu_cpmem_set_rotation(channel, rot_mode);
+
+       if (channel == chan->rotation_in_chan ||
+           channel == chan->rotation_out_chan) {
+               burst_size = 8;
+               ipu_cpmem_set_block_mode(channel);
+       } else
+               burst_size = (width % 16) ? 8 : 16;
+
+       ipu_cpmem_set_burstsize(channel, burst_size);
+
+       ipu_ic_task_idma_init(chan->ic, channel, width, height,
+                             burst_size, rot_mode);
+
+       ipu_cpmem_set_axi_id(channel, 1);
+
+       ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
+}
+
+static int convert_start(struct ipu_image_convert_run *run)
+{
+       struct ipu_image_convert_ctx *ctx = run->ctx;
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       struct ipu_image_convert_image *s_image = &ctx->in;
+       struct ipu_image_convert_image *d_image = &ctx->out;
+       enum ipu_color_space src_cs, dest_cs;
+       unsigned int dest_width, dest_height;
+       int ret;
+
+       dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p\n",
+               __func__, chan->ic_task, ctx, run);
+
+       src_cs = ipu_pixelformat_to_colorspace(s_image->fmt->fourcc);
+       dest_cs = ipu_pixelformat_to_colorspace(d_image->fmt->fourcc);
+
+       if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               /* swap width/height for resizer */
+               dest_width = d_image->tile[0].height;
+               dest_height = d_image->tile[0].width;
+       } else {
+               dest_width = d_image->tile[0].width;
+               dest_height = d_image->tile[0].height;
+       }
+
+       /* setup the IC resizer and CSC */
+       ret = ipu_ic_task_init(chan->ic,
+                              s_image->tile[0].width,
+                              s_image->tile[0].height,
+                              dest_width,
+                              dest_height,
+                              src_cs, dest_cs);
+       if (ret) {
+               dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
+               return ret;
+       }
+
+       /* init the source MEM-->IC PP IDMAC channel */
+       init_idmac_channel(ctx, chan->in_chan, s_image,
+                          IPU_ROTATE_NONE, false);
+
+       if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               /* init the IC PP-->MEM IDMAC channel */
+               init_idmac_channel(ctx, chan->out_chan, d_image,
+                                  IPU_ROTATE_NONE, true);
+
+               /* init the MEM-->IC PP ROT IDMAC channel */
+               init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
+                                  ctx->rot_mode, true);
+
+               /* init the destination IC PP ROT-->MEM IDMAC channel */
+               init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
+                                  IPU_ROTATE_NONE, false);
+
+               /* now link IC PP-->MEM to MEM-->IC PP ROT */
+               ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
+       } else {
+               /* init the destination IC PP-->MEM IDMAC channel */
+               init_idmac_channel(ctx, chan->out_chan, d_image,
+                                  ctx->rot_mode, false);
+       }
+
+       /* enable the IC */
+       ipu_ic_enable(chan->ic);
+
+       /* set buffers ready */
+       ipu_idmac_select_buffer(chan->in_chan, 0);
+       ipu_idmac_select_buffer(chan->out_chan, 0);
+       if (ipu_rot_mode_is_irt(ctx->rot_mode))
+               ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
+       if (ctx->double_buffering) {
+               ipu_idmac_select_buffer(chan->in_chan, 1);
+               ipu_idmac_select_buffer(chan->out_chan, 1);
+               if (ipu_rot_mode_is_irt(ctx->rot_mode))
+                       ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
+       }
+
+       /* enable the channels! */
+       ipu_idmac_enable_channel(chan->in_chan);
+       ipu_idmac_enable_channel(chan->out_chan);
+       if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               ipu_idmac_enable_channel(chan->rotation_in_chan);
+               ipu_idmac_enable_channel(chan->rotation_out_chan);
+       }
+
+       ipu_ic_task_enable(chan->ic);
+
+       ipu_cpmem_dump(chan->in_chan);
+       ipu_cpmem_dump(chan->out_chan);
+       if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               ipu_cpmem_dump(chan->rotation_in_chan);
+               ipu_cpmem_dump(chan->rotation_out_chan);
+       }
+
+       ipu_dump(priv->ipu);
+
+       return 0;
+}
+
+/* hold irqlock when calling */
+static int do_run(struct ipu_image_convert_run *run)
+{
+       struct ipu_image_convert_ctx *ctx = run->ctx;
+       struct ipu_image_convert_chan *chan = ctx->chan;
+
+       lockdep_assert_held(&chan->irqlock);
+
+       ctx->in.base.phys0 = run->in_phys;
+       ctx->out.base.phys0 = run->out_phys;
+
+       ctx->cur_buf_num = 0;
+       ctx->next_tile = 1;
+
+       /* remove run from pending_q and set as current */
+       list_del(&run->list);
+       chan->current_run = run;
+
+       return convert_start(run);
+}
+
+/* hold irqlock when calling */
+static void run_next(struct ipu_image_convert_chan *chan)
+{
+       struct ipu_image_convert_priv *priv = chan->priv;
+       struct ipu_image_convert_run *run, *tmp;
+       int ret;
+
+       lockdep_assert_held(&chan->irqlock);
+
+       list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
+               /* skip contexts that are aborting */
+               if (run->ctx->aborting) {
+                       dev_dbg(priv->ipu->dev,
+                               "%s: task %u: skipping aborting ctx %p run %p\n",
+                               __func__, chan->ic_task, run->ctx, run);
+                       continue;
+               }
+
+               ret = do_run(run);
+               if (!ret)
+                       break;
+
+               /*
+                * something went wrong with start, add the run
+                * to done q and continue to the next run in the
+                * pending q.
+                */
+               run->status = ret;
+               list_add_tail(&run->list, &chan->done_q);
+               chan->current_run = NULL;
+       }
+}
+
+static void empty_done_q(struct ipu_image_convert_chan *chan)
+{
+       struct ipu_image_convert_priv *priv = chan->priv;
+       struct ipu_image_convert_run *run;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->irqlock, flags);
+
+       while (!list_empty(&chan->done_q)) {
+               run = list_entry(chan->done_q.next,
+                                struct ipu_image_convert_run,
+                                list);
+
+               list_del(&run->list);
+
+               dev_dbg(priv->ipu->dev,
+                       "%s: task %u: completing ctx %p run %p with %d\n",
+                       __func__, chan->ic_task, run->ctx, run, run->status);
+
+               /* call the completion callback and free the run */
+               spin_unlock_irqrestore(&chan->irqlock, flags);
+               run->ctx->complete(run, run->ctx->complete_context);
+               spin_lock_irqsave(&chan->irqlock, flags);
+       }
+
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+}
+
+/*
+ * the bottom half thread clears out the done_q, calling the
+ * completion handler for each.
+ */
+static irqreturn_t do_bh(int irq, void *dev_id)
+{
+       struct ipu_image_convert_chan *chan = dev_id;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       struct ipu_image_convert_ctx *ctx;
+       unsigned long flags;
+
+       dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
+               chan->ic_task);
+
+       empty_done_q(chan);
+
+       spin_lock_irqsave(&chan->irqlock, flags);
+
+       /*
+        * the done_q is cleared out, signal any contexts
+        * that are aborting that abort can complete.
+        */
+       list_for_each_entry(ctx, &chan->ctx_list, list) {
+               if (ctx->aborting) {
+                       dev_dbg(priv->ipu->dev,
+                               "%s: task %u: signaling abort for ctx %p\n",
+                               __func__, chan->ic_task, ctx);
+                       complete(&ctx->aborted);
+               }
+       }
+
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+
+       dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
+               chan->ic_task);
+
+       return IRQ_HANDLED;
+}
+
+/* hold irqlock when calling */
+static irqreturn_t do_irq(struct ipu_image_convert_run *run)
+{
+       struct ipu_image_convert_ctx *ctx = run->ctx;
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_tile *src_tile, *dst_tile;
+       struct ipu_image_convert_image *s_image = &ctx->in;
+       struct ipu_image_convert_image *d_image = &ctx->out;
+       struct ipuv3_channel *outch;
+       unsigned int dst_idx;
+
+       lockdep_assert_held(&chan->irqlock);
+
+       outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
+               chan->rotation_out_chan : chan->out_chan;
+
+       /*
+        * It is difficult to stop the channel DMA before the channels
+        * enter the paused state. Without double-buffering the channels
+        * are always in a paused state when the EOF irq occurs, so it
+        * is safe to stop the channels now. For double-buffering we
+        * just ignore the abort until the operation completes, when it
+        * is safe to shut down.
+        */
+       if (ctx->aborting && !ctx->double_buffering) {
+               convert_stop(run);
+               run->status = -EIO;
+               goto done;
+       }
+
+       if (ctx->next_tile == ctx->num_tiles) {
+               /*
+                * the conversion is complete
+                */
+               convert_stop(run);
+               run->status = 0;
+               goto done;
+       }
+
+       /*
+        * not done, place the next tile buffers.
+        */
+       if (!ctx->double_buffering) {
+
+               src_tile = &s_image->tile[ctx->next_tile];
+               dst_idx = ctx->out_tile_map[ctx->next_tile];
+               dst_tile = &d_image->tile[dst_idx];
+
+               ipu_cpmem_set_buffer(chan->in_chan, 0,
+                                    s_image->base.phys0 + src_tile->offset);
+               ipu_cpmem_set_buffer(outch, 0,
+                                    d_image->base.phys0 + dst_tile->offset);
+               if (s_image->fmt->planar)
+                       ipu_cpmem_set_uv_offset(chan->in_chan,
+                                               src_tile->u_off,
+                                               src_tile->v_off);
+               if (d_image->fmt->planar)
+                       ipu_cpmem_set_uv_offset(outch,
+                                               dst_tile->u_off,
+                                               dst_tile->v_off);
+
+               ipu_idmac_select_buffer(chan->in_chan, 0);
+               ipu_idmac_select_buffer(outch, 0);
+
+       } else if (ctx->next_tile < ctx->num_tiles - 1) {
+
+               src_tile = &s_image->tile[ctx->next_tile + 1];
+               dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
+               dst_tile = &d_image->tile[dst_idx];
+
+               ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
+                                    s_image->base.phys0 + src_tile->offset);
+               ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
+                                    d_image->base.phys0 + dst_tile->offset);
+
+               ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
+               ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
+
+               ctx->cur_buf_num ^= 1;
+       }
+
+       ctx->next_tile++;
+       return IRQ_HANDLED;
+done:
+       list_add_tail(&run->list, &chan->done_q);
+       chan->current_run = NULL;
+       run_next(chan);
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t norotate_irq(int irq, void *data)
+{
+       struct ipu_image_convert_chan *chan = data;
+       struct ipu_image_convert_ctx *ctx;
+       struct ipu_image_convert_run *run;
+       unsigned long flags;
+       irqreturn_t ret;
+
+       spin_lock_irqsave(&chan->irqlock, flags);
+
+       /* get current run and its context */
+       run = chan->current_run;
+       if (!run) {
+               ret = IRQ_NONE;
+               goto out;
+       }
+
+       ctx = run->ctx;
+
+       if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               /* this is a rotation operation, just ignore */
+               spin_unlock_irqrestore(&chan->irqlock, flags);
+               return IRQ_HANDLED;
+       }
+
+       ret = do_irq(run);
+out:
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+       return ret;
+}
+
+static irqreturn_t rotate_irq(int irq, void *data)
+{
+       struct ipu_image_convert_chan *chan = data;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       struct ipu_image_convert_ctx *ctx;
+       struct ipu_image_convert_run *run;
+       unsigned long flags;
+       irqreturn_t ret;
+
+       spin_lock_irqsave(&chan->irqlock, flags);
+
+       /* get current run and its context */
+       run = chan->current_run;
+       if (!run) {
+               ret = IRQ_NONE;
+               goto out;
+       }
+
+       ctx = run->ctx;
+
+       if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               /* this was NOT a rotation operation, shouldn't happen */
+               dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
+               spin_unlock_irqrestore(&chan->irqlock, flags);
+               return IRQ_HANDLED;
+       }
+
+       ret = do_irq(run);
+out:
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+       return ret;
+}
+
+/*
+ * try to force the completion of runs for this ctx. Called when
+ * abort wait times out in ipu_image_convert_abort().
+ */
+static void force_abort(struct ipu_image_convert_ctx *ctx)
+{
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_run *run;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->irqlock, flags);
+
+       run = chan->current_run;
+       if (run && run->ctx == ctx) {
+               convert_stop(run);
+               run->status = -EIO;
+               list_add_tail(&run->list, &chan->done_q);
+               chan->current_run = NULL;
+               run_next(chan);
+       }
+
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+
+       empty_done_q(chan);
+}
+
+static void release_ipu_resources(struct ipu_image_convert_chan *chan)
+{
+       if (chan->out_eof_irq >= 0)
+               free_irq(chan->out_eof_irq, chan);
+       if (chan->rot_out_eof_irq >= 0)
+               free_irq(chan->rot_out_eof_irq, chan);
+
+       if (!IS_ERR_OR_NULL(chan->in_chan))
+               ipu_idmac_put(chan->in_chan);
+       if (!IS_ERR_OR_NULL(chan->out_chan))
+               ipu_idmac_put(chan->out_chan);
+       if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
+               ipu_idmac_put(chan->rotation_in_chan);
+       if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
+               ipu_idmac_put(chan->rotation_out_chan);
+       if (!IS_ERR_OR_NULL(chan->ic))
+               ipu_ic_put(chan->ic);
+
+       chan->in_chan = chan->out_chan = chan->rotation_in_chan =
+               chan->rotation_out_chan = NULL;
+       chan->out_eof_irq = chan->rot_out_eof_irq = -1;
+}
+
+static int get_ipu_resources(struct ipu_image_convert_chan *chan)
+{
+       const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       int ret;
+
+       /* get IC */
+       chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
+       if (IS_ERR(chan->ic)) {
+               dev_err(priv->ipu->dev, "could not acquire IC\n");
+               ret = PTR_ERR(chan->ic);
+               goto err;
+       }
+
+       /* get IDMAC channels */
+       chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
+       chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
+       if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
+               dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
+               ret = -EBUSY;
+               goto err;
+       }
+
+       chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
+       chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
+       if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
+               dev_err(priv->ipu->dev,
+                       "could not acquire idmac rotation channels\n");
+               ret = -EBUSY;
+               goto err;
+       }
+
+       /* acquire the EOF interrupts */
+       chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
+                                                 chan->out_chan,
+                                                 IPU_IRQ_EOF);
+
+       ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
+                                  0, "ipu-ic", chan);
+       if (ret < 0) {
+               dev_err(priv->ipu->dev, "could not acquire irq %d\n",
+                        chan->out_eof_irq);
+               chan->out_eof_irq = -1;
+               goto err;
+       }
+
+       chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
+                                                    chan->rotation_out_chan,
+                                                    IPU_IRQ_EOF);
+
+       ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
+                                  0, "ipu-ic", chan);
+       if (ret < 0) {
+               dev_err(priv->ipu->dev, "could not acquire irq %d\n",
+                       chan->rot_out_eof_irq);
+               chan->rot_out_eof_irq = -1;
+               goto err;
+       }
+
+       return 0;
+err:
+       release_ipu_resources(chan);
+       return ret;
+}
+
+static int fill_image(struct ipu_image_convert_ctx *ctx,
+                     struct ipu_image_convert_image *ic_image,
+                     struct ipu_image *image,
+                     enum ipu_image_convert_type type)
+{
+       struct ipu_image_convert_priv *priv = ctx->chan->priv;
+
+       ic_image->base = *image;
+       ic_image->type = type;
+
+       ic_image->fmt = get_format(image->pix.pixelformat);
+       if (!ic_image->fmt) {
+               dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
+                       type == IMAGE_CONVERT_OUT ? "Output" : "Input");
+               return -EINVAL;
+       }
+
+       if (ic_image->fmt->planar)
+               ic_image->stride = ic_image->base.pix.width;
+       else
+               ic_image->stride  = ic_image->base.pix.bytesperline;
+
+       calc_tile_dimensions(ctx, ic_image);
+       calc_tile_offsets(ctx, ic_image);
+
+       return 0;
+}
+
+/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
+static unsigned int clamp_align(unsigned int x, unsigned int min,
+                               unsigned int max, unsigned int align)
+{
+       /* Bits that must be zero to be aligned */
+       unsigned int mask = ~((1 << align) - 1);
+
+       /* Clamp to aligned min and max */
+       x = clamp(x, (min + ~mask) & mask, max & mask);
+
+       /* Round to nearest aligned value */
+       if (align)
+               x = (x + (1 << (align - 1))) & mask;
+
+       return x;
+}
+
+/*
+ * We have to adjust the tile width such that the tile physaddrs and
+ * U and V plane offsets are multiples of 8 bytes as required by
+ * the IPU DMA Controller. For the planar formats, this corresponds
+ * to a pixel alignment of 16 (but use a more formal equation since
+ * the variables are available). For all the packed formats, 8 is
+ * good enough.
+ */
+static inline u32 tile_width_align(const struct ipu_image_pixfmt *fmt)
+{
+       return fmt->planar ? 8 * fmt->uv_width_dec : 8;
+}
+
+/*
+ * For tile height alignment, we have to ensure that the output tile
+ * heights are multiples of 8 lines if the IRT is required by the
+ * given rotation mode (the IRT performs rotations on 8x8 blocks
+ * at a time). If the IRT is not used, or for input image tiles,
+ * 2 lines are good enough.
+ */
+static inline u32 tile_height_align(enum ipu_image_convert_type type,
+                                   enum ipu_rotate_mode rot_mode)
+{
+       return (type == IMAGE_CONVERT_OUT &&
+               ipu_rot_mode_is_irt(rot_mode)) ? 8 : 2;
+}
+
+/* Adjusts input/output images to IPU restrictions */
+void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
+                             enum ipu_rotate_mode rot_mode)
+{
+       const struct ipu_image_pixfmt *infmt, *outfmt;
+       unsigned int num_in_rows, num_in_cols;
+       unsigned int num_out_rows, num_out_cols;
+       u32 w_align, h_align;
+
+       infmt = get_format(in->pix.pixelformat);
+       outfmt = get_format(out->pix.pixelformat);
+
+       /* set some default pixel formats if needed */
+       if (!infmt) {
+               in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
+               infmt = get_format(V4L2_PIX_FMT_RGB24);
+       }
+       if (!outfmt) {
+               out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
+               outfmt = get_format(V4L2_PIX_FMT_RGB24);
+       }
+
+       /* image converter does not handle fields */
+       in->pix.field = out->pix.field = V4L2_FIELD_NONE;
+
+       /* resizer cannot downsize more than 4:1 */
+       if (ipu_rot_mode_is_irt(rot_mode)) {
+               out->pix.height = max_t(__u32, out->pix.height,
+                                       in->pix.width / 4);
+               out->pix.width = max_t(__u32, out->pix.width,
+                                      in->pix.height / 4);
+       } else {
+               out->pix.width = max_t(__u32, out->pix.width,
+                                      in->pix.width / 4);
+               out->pix.height = max_t(__u32, out->pix.height,
+                                       in->pix.height / 4);
+       }
+
+       /* get tiling rows/cols from output format */
+       num_out_rows = num_stripes(out->pix.height);
+       num_out_cols = num_stripes(out->pix.width);
+       if (ipu_rot_mode_is_irt(rot_mode)) {
+               num_in_rows = num_out_cols;
+               num_in_cols = num_out_rows;
+       } else {
+               num_in_rows = num_out_rows;
+               num_in_cols = num_out_cols;
+       }
+
+       /* align input width/height */
+       w_align = ilog2(tile_width_align(infmt) * num_in_cols);
+       h_align = ilog2(tile_height_align(IMAGE_CONVERT_IN, rot_mode) *
+                       num_in_rows);
+       in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W, w_align);
+       in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H, h_align);
+
+       /* align output width/height */
+       w_align = ilog2(tile_width_align(outfmt) * num_out_cols);
+       h_align = ilog2(tile_height_align(IMAGE_CONVERT_OUT, rot_mode) *
+                       num_out_rows);
+       out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W, w_align);
+       out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H, h_align);
+
+       /* set input/output strides and image sizes */
+       in->pix.bytesperline = (in->pix.width * infmt->bpp) >> 3;
+       in->pix.sizeimage = in->pix.height * in->pix.bytesperline;
+       out->pix.bytesperline = (out->pix.width * outfmt->bpp) >> 3;
+       out->pix.sizeimage = out->pix.height * out->pix.bytesperline;
+}
+EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
+
+/*
+ * this is used by ipu_image_convert_prepare() to verify set input and
+ * output images are valid before starting the conversion. Clients can
+ * also call it before calling ipu_image_convert_prepare().
+ */
+int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
+                            enum ipu_rotate_mode rot_mode)
+{
+       struct ipu_image testin, testout;
+
+       testin = *in;
+       testout = *out;
+
+       ipu_image_convert_adjust(&testin, &testout, rot_mode);
+
+       if (testin.pix.width != in->pix.width ||
+           testin.pix.height != in->pix.height ||
+           testout.pix.width != out->pix.width ||
+           testout.pix.height != out->pix.height)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
+
+/*
+ * Call ipu_image_convert_prepare() to prepare for the conversion of
+ * given images and rotation mode. Returns a new conversion context.
+ */
+struct ipu_image_convert_ctx *
+ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+                         struct ipu_image *in, struct ipu_image *out,
+                         enum ipu_rotate_mode rot_mode,
+                         ipu_image_convert_cb_t complete,
+                         void *complete_context)
+{
+       struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
+       struct ipu_image_convert_image *s_image, *d_image;
+       struct ipu_image_convert_chan *chan;
+       struct ipu_image_convert_ctx *ctx;
+       unsigned long flags;
+       bool get_res;
+       int ret;
+
+       if (!in || !out || !complete ||
+           (ic_task != IC_TASK_VIEWFINDER &&
+            ic_task != IC_TASK_POST_PROCESSOR))
+               return ERR_PTR(-EINVAL);
+
+       /* verify the in/out images before continuing */
+       ret = ipu_image_convert_verify(in, out, rot_mode);
+       if (ret) {
+               dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
+                       __func__);
+               return ERR_PTR(ret);
+       }
+
+       chan = &priv->chan[ic_task];
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return ERR_PTR(-ENOMEM);
+
+       dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
+               chan->ic_task, ctx);
+
+       ctx->chan = chan;
+       init_completion(&ctx->aborted);
+
+       s_image = &ctx->in;
+       d_image = &ctx->out;
+
+       /* set tiling and rotation */
+       d_image->num_rows = num_stripes(out->pix.height);
+       d_image->num_cols = num_stripes(out->pix.width);
+       if (ipu_rot_mode_is_irt(rot_mode)) {
+               s_image->num_rows = d_image->num_cols;
+               s_image->num_cols = d_image->num_rows;
+       } else {
+               s_image->num_rows = d_image->num_rows;
+               s_image->num_cols = d_image->num_cols;
+       }
+
+       ctx->num_tiles = d_image->num_cols * d_image->num_rows;
+       ctx->rot_mode = rot_mode;
+
+       ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
+       if (ret)
+               goto out_free;
+       ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
+       if (ret)
+               goto out_free;
+
+       calc_out_tile_map(ctx);
+
+       dump_format(ctx, s_image);
+       dump_format(ctx, d_image);
+
+       ctx->complete = complete;
+       ctx->complete_context = complete_context;
+
+       /*
+        * Can we use double-buffering for this operation? If there is
+        * only one tile (the whole image can be converted in a single
+        * operation) there's no point in using double-buffering. Also,
+        * the IPU's IDMAC channels allow only a single U and V plane
+        * offset shared between both buffers, but these offsets change
+        * for every tile, and therefore would have to be updated for
+        * each buffer which is not possible. So double-buffering is
+        * impossible when either the source or destination images are
+        * a planar format (YUV420, YUV422P, etc.).
+        */
+       ctx->double_buffering = (ctx->num_tiles > 1 &&
+                                !s_image->fmt->planar &&
+                                !d_image->fmt->planar);
+
+       if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
+                                   d_image->tile[0].size);
+               if (ret)
+                       goto out_free;
+               if (ctx->double_buffering) {
+                       ret = alloc_dma_buf(priv,
+                                           &ctx->rot_intermediate[1],
+                                           d_image->tile[0].size);
+                       if (ret)
+                               goto out_free_dmabuf0;
+               }
+       }
+
+       spin_lock_irqsave(&chan->irqlock, flags);
+
+       get_res = list_empty(&chan->ctx_list);
+
+       list_add_tail(&ctx->list, &chan->ctx_list);
+
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+
+       if (get_res) {
+               ret = get_ipu_resources(chan);
+               if (ret)
+                       goto out_free_dmabuf1;
+       }
+
+       return ctx;
+
+out_free_dmabuf1:
+       free_dma_buf(priv, &ctx->rot_intermediate[1]);
+       spin_lock_irqsave(&chan->irqlock, flags);
+       list_del(&ctx->list);
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+out_free_dmabuf0:
+       free_dma_buf(priv, &ctx->rot_intermediate[0]);
+out_free:
+       kfree(ctx);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
+
+/*
+ * Carry out a single image conversion run. Only the physaddr's of the input
+ * and output image buffers are needed. The conversion context must have
+ * been created previously with ipu_image_convert_prepare().
+ */
+int ipu_image_convert_queue(struct ipu_image_convert_run *run)
+{
+       struct ipu_image_convert_chan *chan;
+       struct ipu_image_convert_priv *priv;
+       struct ipu_image_convert_ctx *ctx;
+       unsigned long flags;
+       int ret = 0;
+
+       if (!run || !run->ctx || !run->in_phys || !run->out_phys)
+               return -EINVAL;
+
+       ctx = run->ctx;
+       chan = ctx->chan;
+       priv = chan->priv;
+
+       dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
+               chan->ic_task, ctx, run);
+
+       INIT_LIST_HEAD(&run->list);
+
+       spin_lock_irqsave(&chan->irqlock, flags);
+
+       if (ctx->aborting) {
+               ret = -EIO;
+               goto unlock;
+       }
+
+       list_add_tail(&run->list, &chan->pending_q);
+
+       if (!chan->current_run) {
+               ret = do_run(run);
+               if (ret)
+                       chan->current_run = NULL;
+       }
+unlock:
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
+
+/* Abort any active or pending conversions for this context */
+void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
+{
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       struct ipu_image_convert_run *run, *active_run, *tmp;
+       unsigned long flags;
+       int run_count, ret;
+       bool need_abort;
+
+       reinit_completion(&ctx->aborted);
+
+       spin_lock_irqsave(&chan->irqlock, flags);
+
+       /* move all remaining pending runs in this context to done_q */
+       list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
+               if (run->ctx != ctx)
+                       continue;
+               run->status = -EIO;
+               list_move_tail(&run->list, &chan->done_q);
+       }
+
+       run_count = get_run_count(ctx, &chan->done_q);
+       active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
+               chan->current_run : NULL;
+
+       need_abort = (run_count || active_run);
+
+       ctx->aborting = need_abort;
+
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+
+       if (!need_abort) {
+               dev_dbg(priv->ipu->dev,
+                       "%s: task %u: no abort needed for ctx %p\n",
+                       __func__, chan->ic_task, ctx);
+               return;
+       }
+
+       dev_dbg(priv->ipu->dev,
+               "%s: task %u: wait for completion: %d runs, active run %p\n",
+               __func__, chan->ic_task, run_count, active_run);
+
+       ret = wait_for_completion_timeout(&ctx->aborted,
+                                         msecs_to_jiffies(10000));
+       if (ret == 0) {
+               dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
+               force_abort(ctx);
+       }
+
+       ctx->aborting = false;
+}
+EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
+
+/* Unprepare image conversion context */
+void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
+{
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       unsigned long flags;
+       bool put_res;
+
+       /* make sure no runs are hanging around */
+       ipu_image_convert_abort(ctx);
+
+       dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
+               chan->ic_task, ctx);
+
+       spin_lock_irqsave(&chan->irqlock, flags);
+
+       list_del(&ctx->list);
+
+       put_res = list_empty(&chan->ctx_list);
+
+       spin_unlock_irqrestore(&chan->irqlock, flags);
+
+       if (put_res)
+               release_ipu_resources(chan);
+
+       free_dma_buf(priv, &ctx->rot_intermediate[1]);
+       free_dma_buf(priv, &ctx->rot_intermediate[0]);
+
+       kfree(ctx);
+}
+EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
+
+/*
+ * "Canned" asynchronous single image conversion. Allocates and returns
+ * a new conversion run.  On successful return the caller must free the
+ * run and call ipu_image_convert_unprepare() after conversion completes.
+ */
+struct ipu_image_convert_run *
+ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+                 struct ipu_image *in, struct ipu_image *out,
+                 enum ipu_rotate_mode rot_mode,
+                 ipu_image_convert_cb_t complete,
+                 void *complete_context)
+{
+       struct ipu_image_convert_ctx *ctx;
+       struct ipu_image_convert_run *run;
+       int ret;
+
+       ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
+                                       complete, complete_context);
+       if (IS_ERR(ctx))
+               return ERR_PTR(PTR_ERR(ctx));
+
+       run = kzalloc(sizeof(*run), GFP_KERNEL);
+       if (!run) {
+               ipu_image_convert_unprepare(ctx);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       run->ctx = ctx;
+       run->in_phys = in->phys0;
+       run->out_phys = out->phys0;
+
+       ret = ipu_image_convert_queue(run);
+       if (ret) {
+               ipu_image_convert_unprepare(ctx);
+               kfree(run);
+               return ERR_PTR(ret);
+       }
+
+       return run;
+}
+EXPORT_SYMBOL_GPL(ipu_image_convert);
+
+/* "Canned" synchronous single image conversion */
+static void image_convert_sync_complete(struct ipu_image_convert_run *run,
+                                       void *data)
+{
+       struct completion *comp = data;
+
+       complete(comp);
+}
+
+int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+                          struct ipu_image *in, struct ipu_image *out,
+                          enum ipu_rotate_mode rot_mode)
+{
+       struct ipu_image_convert_run *run;
+       struct completion comp;
+       int ret;
+
+       init_completion(&comp);
+
+       run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
+                               image_convert_sync_complete, &comp);
+       if (IS_ERR(run))
+               return PTR_ERR(run);
+
+       ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
+       ret = (ret == 0) ? -ETIMEDOUT : 0;
+
+       ipu_image_convert_unprepare(run->ctx);
+       kfree(run);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
+
+int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
+{
+       struct ipu_image_convert_priv *priv;
+       int i;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       ipu->image_convert_priv = priv;
+       priv->ipu = ipu;
+
+       for (i = 0; i < IC_NUM_TASKS; i++) {
+               struct ipu_image_convert_chan *chan = &priv->chan[i];
+
+               chan->ic_task = i;
+               chan->priv = priv;
+               chan->dma_ch = &image_convert_dma_chan[i];
+               chan->out_eof_irq = -1;
+               chan->rot_out_eof_irq = -1;
+
+               spin_lock_init(&chan->irqlock);
+               INIT_LIST_HEAD(&chan->ctx_list);
+               INIT_LIST_HEAD(&chan->pending_q);
+               INIT_LIST_HEAD(&chan->done_q);
+       }
+
+       return 0;
+}
+
+void ipu_image_convert_exit(struct ipu_soc *ipu)
+{
+}
index bfb1e8a..22e47b6 100644 (file)
@@ -75,6 +75,33 @@ struct ipu_soc;
 #define IPU_INT_CTRL(n)                IPU_CM_REG(0x003C + 4 * (n))
 #define IPU_INT_STAT(n)                IPU_CM_REG(0x0200 + 4 * (n))
 
+/* FS_PROC_FLOW1 */
+#define FS_PRPENC_ROT_SRC_SEL_MASK     (0xf << 0)
+#define FS_PRPENC_ROT_SRC_SEL_ENC              (0x7 << 0)
+#define FS_PRPVF_ROT_SRC_SEL_MASK      (0xf << 8)
+#define FS_PRPVF_ROT_SRC_SEL_VF                        (0x8 << 8)
+#define FS_PP_SRC_SEL_MASK             (0xf << 12)
+#define FS_PP_ROT_SRC_SEL_MASK         (0xf << 16)
+#define FS_PP_ROT_SRC_SEL_PP                   (0x5 << 16)
+#define FS_VDI1_SRC_SEL_MASK           (0x3 << 20)
+#define FS_VDI3_SRC_SEL_MASK           (0x3 << 20)
+#define FS_PRP_SRC_SEL_MASK            (0xf << 24)
+#define FS_VDI_SRC_SEL_MASK            (0x3 << 28)
+#define FS_VDI_SRC_SEL_CSI_DIRECT              (0x1 << 28)
+#define FS_VDI_SRC_SEL_VDOA                    (0x2 << 28)
+
+/* FS_PROC_FLOW2 */
+#define FS_PRP_ENC_DEST_SEL_MASK       (0xf << 0)
+#define FS_PRP_ENC_DEST_SEL_IRT_ENC            (0x1 << 0)
+#define FS_PRPVF_DEST_SEL_MASK         (0xf << 4)
+#define FS_PRPVF_DEST_SEL_IRT_VF               (0x1 << 4)
+#define FS_PRPVF_ROT_DEST_SEL_MASK     (0xf << 8)
+#define FS_PP_DEST_SEL_MASK            (0xf << 12)
+#define FS_PP_DEST_SEL_IRT_PP                  (0x3 << 12)
+#define FS_PP_ROT_DEST_SEL_MASK                (0xf << 16)
+#define FS_PRPENC_ROT_DEST_SEL_MASK    (0xf << 20)
+#define FS_PRP_DEST_SEL_MASK           (0xf << 24)
+
 #define IPU_DI0_COUNTER_RELEASE                        (1 << 24)
 #define IPU_DI1_COUNTER_RELEASE                        (1 << 25)
 
@@ -138,6 +165,8 @@ struct ipu_dc_priv;
 struct ipu_dmfc_priv;
 struct ipu_di;
 struct ipu_ic_priv;
+struct ipu_vdi;
+struct ipu_image_convert_priv;
 struct ipu_smfc_priv;
 
 struct ipu_devtype;
@@ -152,6 +181,7 @@ struct ipu_soc {
        void __iomem            *cm_reg;
        void __iomem            *idmac_reg;
 
+       int                     id;
        int                     usecount;
 
        struct clk              *clk;
@@ -169,6 +199,8 @@ struct ipu_soc {
        struct ipu_di           *di_priv[2];
        struct ipu_csi          *csi_priv[2];
        struct ipu_ic_priv      *ic_priv;
+       struct ipu_vdi          *vdi_priv;
+       struct ipu_image_convert_priv *image_convert_priv;
        struct ipu_smfc_priv    *smfc_priv;
 };
 
@@ -199,6 +231,13 @@ int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
                unsigned long base, unsigned long tpmem_base);
 void ipu_ic_exit(struct ipu_soc *ipu);
 
+int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
+                unsigned long base, u32 module);
+void ipu_vdi_exit(struct ipu_soc *ipu);
+
+int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev);
+void ipu_image_convert_exit(struct ipu_soc *ipu);
+
 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
                unsigned long base, u32 module, struct clk *ipu_clk);
 void ipu_di_exit(struct ipu_soc *ipu, int id);
diff --git a/drivers/gpu/ipu-v3/ipu-vdi.c b/drivers/gpu/ipu-v3/ipu-vdi.c
new file mode 100644 (file)
index 0000000..f27bf5a
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2012-2016 Mentor Graphics Inc.
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include <linux/io.h>
+#include "ipu-prv.h"
+
+struct ipu_vdi {
+       void __iomem *base;
+       u32 module;
+       spinlock_t lock;
+       int use_count;
+       struct ipu_soc *ipu;
+};
+
+
+/* VDI Register Offsets */
+#define VDI_FSIZE 0x0000
+#define VDI_C     0x0004
+
+/* VDI Register Fields */
+#define VDI_C_CH_420             (0 << 1)
+#define VDI_C_CH_422             (1 << 1)
+#define VDI_C_MOT_SEL_MASK       (0x3 << 2)
+#define VDI_C_MOT_SEL_FULL       (2 << 2)
+#define VDI_C_MOT_SEL_LOW        (1 << 2)
+#define VDI_C_MOT_SEL_MED        (0 << 2)
+#define VDI_C_BURST_SIZE1_4      (3 << 4)
+#define VDI_C_BURST_SIZE2_4      (3 << 8)
+#define VDI_C_BURST_SIZE3_4      (3 << 12)
+#define VDI_C_BURST_SIZE_MASK    0xF
+#define VDI_C_BURST_SIZE1_OFFSET 4
+#define VDI_C_BURST_SIZE2_OFFSET 8
+#define VDI_C_BURST_SIZE3_OFFSET 12
+#define VDI_C_VWM1_SET_1         (0 << 16)
+#define VDI_C_VWM1_SET_2         (1 << 16)
+#define VDI_C_VWM1_CLR_2         (1 << 19)
+#define VDI_C_VWM3_SET_1         (0 << 22)
+#define VDI_C_VWM3_SET_2         (1 << 22)
+#define VDI_C_VWM3_CLR_2         (1 << 25)
+#define VDI_C_TOP_FIELD_MAN_1    (1 << 30)
+#define VDI_C_TOP_FIELD_AUTO_1   (1 << 31)
+
+static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
+{
+       return readl(vdi->base + offset);
+}
+
+static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
+                                unsigned int offset)
+{
+       writel(value, vdi->base + offset);
+}
+
+void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
+{
+       bool top_field_0 = false;
+       unsigned long flags;
+       u32 reg;
+
+       switch (field) {
+       case V4L2_FIELD_INTERLACED_TB:
+       case V4L2_FIELD_SEQ_TB:
+       case V4L2_FIELD_TOP:
+               top_field_0 = true;
+               break;
+       case V4L2_FIELD_INTERLACED_BT:
+       case V4L2_FIELD_SEQ_BT:
+       case V4L2_FIELD_BOTTOM:
+               top_field_0 = false;
+               break;
+       default:
+               top_field_0 = (std & V4L2_STD_525_60) ? true : false;
+               break;
+       }
+
+       spin_lock_irqsave(&vdi->lock, flags);
+
+       reg = ipu_vdi_read(vdi, VDI_C);
+       if (top_field_0)
+               reg &= ~VDI_C_TOP_FIELD_MAN_1;
+       else
+               reg |= VDI_C_TOP_FIELD_MAN_1;
+       ipu_vdi_write(vdi, reg, VDI_C);
+
+       spin_unlock_irqrestore(&vdi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
+
+void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
+{
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&vdi->lock, flags);
+
+       reg = ipu_vdi_read(vdi, VDI_C);
+
+       reg &= ~VDI_C_MOT_SEL_MASK;
+
+       switch (motion_sel) {
+       case MED_MOTION:
+               reg |= VDI_C_MOT_SEL_MED;
+               break;
+       case HIGH_MOTION:
+               reg |= VDI_C_MOT_SEL_FULL;
+               break;
+       default:
+               reg |= VDI_C_MOT_SEL_LOW;
+               break;
+       }
+
+       ipu_vdi_write(vdi, reg, VDI_C);
+
+       spin_unlock_irqrestore(&vdi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
+
+void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
+{
+       unsigned long flags;
+       u32 pixel_fmt, reg;
+
+       spin_lock_irqsave(&vdi->lock, flags);
+
+       reg = ((yres - 1) << 16) | (xres - 1);
+       ipu_vdi_write(vdi, reg, VDI_FSIZE);
+
+       /*
+        * Full motion, only vertical filter is used.
+        * Burst size is 4 accesses
+        */
+       if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
+           code == MEDIA_BUS_FMT_UYVY8_1X16 ||
+           code == MEDIA_BUS_FMT_YUYV8_2X8 ||
+           code == MEDIA_BUS_FMT_YUYV8_1X16)
+               pixel_fmt = VDI_C_CH_422;
+       else
+               pixel_fmt = VDI_C_CH_420;
+
+       reg = ipu_vdi_read(vdi, VDI_C);
+       reg |= pixel_fmt;
+       reg |= VDI_C_BURST_SIZE2_4;
+       reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
+       reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
+       ipu_vdi_write(vdi, reg, VDI_C);
+
+       spin_unlock_irqrestore(&vdi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_vdi_setup);
+
+void ipu_vdi_unsetup(struct ipu_vdi *vdi)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&vdi->lock, flags);
+       ipu_vdi_write(vdi, 0, VDI_FSIZE);
+       ipu_vdi_write(vdi, 0, VDI_C);
+       spin_unlock_irqrestore(&vdi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
+
+int ipu_vdi_enable(struct ipu_vdi *vdi)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&vdi->lock, flags);
+
+       if (!vdi->use_count)
+               ipu_module_enable(vdi->ipu, vdi->module);
+
+       vdi->use_count++;
+
+       spin_unlock_irqrestore(&vdi->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_vdi_enable);
+
+int ipu_vdi_disable(struct ipu_vdi *vdi)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&vdi->lock, flags);
+
+       if (vdi->use_count) {
+               if (!--vdi->use_count)
+                       ipu_module_disable(vdi->ipu, vdi->module);
+       }
+
+       spin_unlock_irqrestore(&vdi->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_vdi_disable);
+
+struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
+{
+       return ipu->vdi_priv;
+}
+EXPORT_SYMBOL_GPL(ipu_vdi_get);
+
+void ipu_vdi_put(struct ipu_vdi *vdi)
+{
+}
+EXPORT_SYMBOL_GPL(ipu_vdi_put);
+
+int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
+                unsigned long base, u32 module)
+{
+       struct ipu_vdi *vdi;
+
+       vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
+       if (!vdi)
+               return -ENOMEM;
+
+       ipu->vdi_priv = vdi;
+
+       spin_lock_init(&vdi->lock);
+       vdi->module = module;
+       vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
+       if (!vdi->base)
+               return -ENOMEM;
+
+       dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
+       vdi->ipu = ipu;
+
+       return 0;
+}
+
+void ipu_vdi_exit(struct ipu_soc *ipu)
+{
+}
index f17cb04..1887f19 100644 (file)
@@ -131,7 +131,24 @@ static struct vga_device *vgadev_find(struct pci_dev *pdev)
        return NULL;
 }
 
-/* Returns the default VGA device (vgacon's babe) */
+/**
+ * vga_default_device - return the default VGA device, for vgacon
+ *
+ * This can be defined by the platform. The default implementation
+ * is rather dumb and will probably only work properly on single
+ * vga card setups and/or x86 platforms.
+ *
+ * If your VGA default device is not PCI, you'll have to return
+ * NULL here. In this case, I assume it will not conflict with
+ * any PCI card. If this is not true, I'll have to define two archs
+ * hooks for enabling/disabling the VGA default device if that is
+ * possible. This may be a problem with real _ISA_ VGA cards, in
+ * addition to a PCI one. I don't know at this point how to deal
+ * with that card. Can theirs IOs be disabled at all ? If not, then
+ * I suppose it's a matter of having the proper arch hook telling
+ * us about it, so we basically never allow anybody to succeed a
+ * vga_get()...
+ */
 struct pci_dev *vga_default_device(void)
 {
        return vga_default;
@@ -356,6 +373,40 @@ static void __vga_put(struct vga_device *vgadev, unsigned int rsrc)
                wake_up_all(&vga_wait_queue);
 }
 
+/**
+ * vga_get - acquire & locks VGA resources
+ * @pdev: pci device of the VGA card or NULL for the system default
+ * @rsrc: bit mask of resources to acquire and lock
+ * @interruptible: blocking should be interruptible by signals ?
+ *
+ * This function acquires VGA resources for the given card and mark those
+ * resources locked. If the resource requested are "normal" (and not legacy)
+ * resources, the arbiter will first check whether the card is doing legacy
+ * decoding for that type of resource. If yes, the lock is "converted" into a
+ * legacy resource lock.
+ *
+ * The arbiter will first look for all VGA cards that might conflict and disable
+ * their IOs and/or Memory access, including VGA forwarding on P2P bridges if
+ * necessary, so that the requested resources can be used. Then, the card is
+ * marked as locking these resources and the IO and/or Memory accesses are
+ * enabled on the card (including VGA forwarding on parent P2P bridges if any).
+ *
+ * This function will block if some conflicting card is already locking one of
+ * the required resources (or any resource on a different bus segment, since P2P
+ * bridges don't differentiate VGA memory and IO afaik). You can indicate
+ * whether this blocking should be interruptible by a signal (for userland
+ * interface) or not.
+ *
+ * Must not be called at interrupt time or in atomic context.  If the card
+ * already owns the resources, the function succeeds.  Nested calls are
+ * supported (a per-resource counter is maintained)
+ *
+ * On success, release the VGA resource again with vga_put().
+ *
+ * Returns:
+ *
+ * 0 on success, negative error code on failure.
+ */
 int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible)
 {
        struct vga_device *vgadev, *conflict;
@@ -408,6 +459,21 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible)
 }
 EXPORT_SYMBOL(vga_get);
 
+/**
+ * vga_tryget - try to acquire & lock legacy VGA resources
+ * @pdev: pci devivce of VGA card or NULL for system default
+ * @rsrc: bit mask of resources to acquire and lock
+ *
+ * This function performs the same operation as vga_get(), but will return an
+ * error (-EBUSY) instead of blocking if the resources are already locked by
+ * another card. It can be called in any context
+ *
+ * On success, release the VGA resource again with vga_put().
+ *
+ * Returns:
+ *
+ * 0 on success, negative error code on failure.
+ */
 int vga_tryget(struct pci_dev *pdev, unsigned int rsrc)
 {
        struct vga_device *vgadev;
@@ -435,6 +501,16 @@ bail:
 }
 EXPORT_SYMBOL(vga_tryget);
 
+/**
+ * vga_put - release lock on legacy VGA resources
+ * @pdev: pci device of VGA card or NULL for system default
+ * @rsrc: but mask of resource to release
+ *
+ * This fuction releases resources previously locked by vga_get() or
+ * vga_tryget(). The resources aren't disabled right away, so that a subsequence
+ * vga_get() on the same card will succeed immediately. Resources have a
+ * counter, so locks are only released if the counter reaches 0.
+ */
 void vga_put(struct pci_dev *pdev, unsigned int rsrc)
 {
        struct vga_device *vgadev;
@@ -716,7 +792,37 @@ void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes)
 }
 EXPORT_SYMBOL(vga_set_legacy_decoding);
 
-/* call with NULL to unregister */
+/**
+ * vga_client_register - register or unregister a VGA arbitration client
+ * @pdev: pci device of the VGA client
+ * @cookie: client cookie to be used in callbacks
+ * @irq_set_state: irq state change callback
+ * @set_vga_decode: vga decode change callback
+ *
+ * Clients have two callback mechanisms they can use.
+ *
+ * @irq_set_state callback: If a client can't disable its GPUs VGA
+ * resources, then we need to be able to ask it to turn off its irqs when we
+ * turn off its mem and io decoding.
+ *
+ * @set_vga_decode callback: If a client can disable its GPU VGA resource, it
+ * will get a callback from this to set the encode/decode state.
+ *
+ * Rationale: we cannot disable VGA decode resources unconditionally some single
+ * GPU laptops seem to require ACPI or BIOS access to the VGA registers to
+ * control things like backlights etc.  Hopefully newer multi-GPU laptops do
+ * something saner, and desktops won't have any special ACPI for this. The
+ * driver will get a callback when VGA arbitration is first used by userspace
+ * since some older X servers have issues.
+ *
+ * This function does not check whether a client for @pdev has been registered
+ * already.
+ *
+ * To unregister just call this function with @irq_set_state and @set_vga_decode
+ * both set to NULL for the same @pdev as originally used to register them.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
 int vga_client_register(struct pci_dev *pdev, void *cookie,
                        void (*irq_set_state)(void *cookie, bool state),
                        unsigned int (*set_vga_decode)(void *cookie,
index 261b86d..f6f0c06 100644 (file)
@@ -38,6 +38,10 @@ struct analogix_dp_plat_data {
                         struct drm_connector *);
 };
 
+int analogix_dp_psr_supported(struct device *dev);
+int analogix_dp_enable_psr(struct device *dev);
+int analogix_dp_disable_psr(struct device *dev);
+
 int analogix_dp_resume(struct device *dev);
 int analogix_dp_suspend(struct device *dev);
 
index d377865..6726440 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/platform_device.h>
 #include <linux/poll.h>
 #include <linux/ratelimit.h>
+#include <linux/rbtree.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -127,6 +128,7 @@ struct dma_buf_attachment;
  * run-time by echoing the debug value in its sysfs node:
  *   # echo 0xf > /sys/module/drm/parameters/debug
  */
+#define DRM_UT_NONE            0x00
 #define DRM_UT_CORE            0x01
 #define DRM_UT_DRIVER          0x02
 #define DRM_UT_KMS             0x04
@@ -134,11 +136,14 @@ struct dma_buf_attachment;
 #define DRM_UT_ATOMIC          0x10
 #define DRM_UT_VBL             0x20
 
-extern __printf(2, 3)
-void drm_ut_debug_printk(const char *function_name,
-                        const char *format, ...);
-extern __printf(1, 2)
-void drm_err(const char *format, ...);
+extern __printf(6, 7)
+void drm_dev_printk(const struct device *dev, const char *level,
+                   unsigned int category, const char *function_name,
+                   const char *prefix, const char *format, ...);
+
+extern __printf(3, 4)
+void drm_printk(const char *level, unsigned int category,
+               const char *format, ...);
 
 /***********************************************************************/
 /** \name DRM template customization defaults */
@@ -146,6 +151,7 @@ void drm_err(const char *format, ...);
 
 /* driver capabilities and requirements mask */
 #define DRIVER_USE_AGP                 0x1
+#define DRIVER_LEGACY                  0x2
 #define DRIVER_PCI_DMA                 0x8
 #define DRIVER_SG                      0x10
 #define DRIVER_HAVE_DMA                        0x20
@@ -162,14 +168,37 @@ void drm_err(const char *format, ...);
 /** \name Macros to make printk easier */
 /*@{*/
 
+#define _DRM_PRINTK(once, level, fmt, ...)                             \
+       do {                                                            \
+               printk##once(KERN_##level "[" DRM_NAME "] " fmt,        \
+                            ##__VA_ARGS__);                            \
+       } while (0)
+
+#define DRM_INFO(fmt, ...)                                             \
+       _DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__)
+#define DRM_NOTE(fmt, ...)                                             \
+       _DRM_PRINTK(, NOTICE, fmt, ##__VA_ARGS__)
+#define DRM_WARN(fmt, ...)                                             \
+       _DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__)
+
+#define DRM_INFO_ONCE(fmt, ...)                                                \
+       _DRM_PRINTK(_once, INFO, fmt, ##__VA_ARGS__)
+#define DRM_NOTE_ONCE(fmt, ...)                                                \
+       _DRM_PRINTK(_once, NOTICE, fmt, ##__VA_ARGS__)
+#define DRM_WARN_ONCE(fmt, ...)                                                \
+       _DRM_PRINTK(_once, WARNING, fmt, ##__VA_ARGS__)
+
 /**
  * Error output.
  *
  * \param fmt printf() like format string.
  * \param arg arguments
  */
-#define DRM_ERROR(fmt, ...)                            \
-       drm_err(fmt, ##__VA_ARGS__)
+#define DRM_DEV_ERROR(dev, fmt, ...)                                   \
+       drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\
+                      fmt, ##__VA_ARGS__)
+#define DRM_ERROR(fmt, ...)                                            \
+       drm_printk(KERN_ERR, DRM_UT_NONE, fmt,  ##__VA_ARGS__)
 
 /**
  * Rate limited error output.  Like DRM_ERROR() but won't flood the log.
@@ -177,21 +206,30 @@ void drm_err(const char *format, ...);
  * \param fmt printf() like format string.
  * \param arg arguments
  */
-#define DRM_ERROR_RATELIMITED(fmt, ...)                                \
+#define DRM_DEV_ERROR_RATELIMITED(dev, fmt, ...)                       \
 ({                                                                     \
        static DEFINE_RATELIMIT_STATE(_rs,                              \
                                      DEFAULT_RATELIMIT_INTERVAL,       \
                                      DEFAULT_RATELIMIT_BURST);         \
                                                                        \
        if (__ratelimit(&_rs))                                          \
-               drm_err(fmt, ##__VA_ARGS__);                            \
+               DRM_DEV_ERROR(dev, fmt, ##__VA_ARGS__);                 \
 })
+#define DRM_ERROR_RATELIMITED(fmt, ...)                                        \
+       DRM_DEV_ERROR_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
 
-#define DRM_INFO(fmt, ...)                             \
-       printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
+#define DRM_DEV_INFO(dev, fmt, ...)                                    \
+       drm_dev_printk(dev, KERN_INFO, DRM_UT_NONE, __func__, "", fmt,  \
+                      ##__VA_ARGS__)
 
-#define DRM_INFO_ONCE(fmt, ...)                                \
-       printk_once(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
+#define DRM_DEV_INFO_ONCE(dev, fmt, ...)                               \
+({                                                                     \
+       static bool __print_once __read_mostly;                         \
+       if (!__print_once) {                                            \
+               __print_once = true;                                    \
+               DRM_DEV_INFO(dev, fmt, ##__VA_ARGS__);                  \
+       }                                                               \
+})
 
 /**
  * Debug output.
@@ -199,37 +237,74 @@ void drm_err(const char *format, ...);
  * \param fmt printf() like format string.
  * \param arg arguments
  */
-#define DRM_DEBUG(fmt, args...)                                                \
-       do {                                                            \
-               if (unlikely(drm_debug & DRM_UT_CORE))                  \
-                       drm_ut_debug_printk(__func__, fmt, ##args);     \
-       } while (0)
+#define DRM_DEV_DEBUG(dev, fmt, args...)                               \
+       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \
+                      ##args)
+#define DRM_DEBUG(fmt, ...)                                            \
+       drm_printk(KERN_DEBUG, DRM_UT_CORE, fmt, ##__VA_ARGS__)
+
+#define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...)                                \
+       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "",    \
+                      fmt, ##args)
+#define DRM_DEBUG_DRIVER(fmt, ...)                                     \
+       drm_printk(KERN_DEBUG, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
+
+#define DRM_DEV_DEBUG_KMS(dev, fmt, args...)                           \
+       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt,  \
+                      ##args)
+#define DRM_DEBUG_KMS(fmt, ...)                                        \
+       drm_printk(KERN_DEBUG, DRM_UT_KMS, fmt, ##__VA_ARGS__)
+
+#define DRM_DEV_DEBUG_PRIME(dev, fmt, args...)                         \
+       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "",     \
+                      fmt, ##args)
+#define DRM_DEBUG_PRIME(fmt, ...)                                      \
+       drm_printk(KERN_DEBUG, DRM_UT_PRIME, fmt, ##__VA_ARGS__)
+
+#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...)                                \
+       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "",    \
+                      fmt, ##args)
+#define DRM_DEBUG_ATOMIC(fmt, ...)                                     \
+       drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
+
+#define DRM_DEV_DEBUG_VBL(dev, fmt, args...)                           \
+       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt,  \
+                      ##args)
+#define DRM_DEBUG_VBL(fmt, ...)                                        \
+       drm_printk(KERN_DEBUG, DRM_UT_VBL, fmt, ##__VA_ARGS__)
+
+#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...)    \
+({                                                                     \
+       static DEFINE_RATELIMIT_STATE(_rs,                              \
+                                     DEFAULT_RATELIMIT_INTERVAL,       \
+                                     DEFAULT_RATELIMIT_BURST);         \
+       if (__ratelimit(&_rs))                                          \
+               drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ ## level,       \
+                              __func__, "", fmt, ##args);              \
+})
 
-#define DRM_DEBUG_DRIVER(fmt, args...)                                 \
-       do {                                                            \
-               if (unlikely(drm_debug & DRM_UT_DRIVER))                \
-                       drm_ut_debug_printk(__func__, fmt, ##args);     \
-       } while (0)
-#define DRM_DEBUG_KMS(fmt, args...)                                    \
-       do {                                                            \
-               if (unlikely(drm_debug & DRM_UT_KMS))                   \
-                       drm_ut_debug_printk(__func__, fmt, ##args);     \
-       } while (0)
-#define DRM_DEBUG_PRIME(fmt, args...)                                  \
-       do {                                                            \
-               if (unlikely(drm_debug & DRM_UT_PRIME))                 \
-                       drm_ut_debug_printk(__func__, fmt, ##args);     \
-       } while (0)
-#define DRM_DEBUG_ATOMIC(fmt, args...)                                 \
-       do {                                                            \
-               if (unlikely(drm_debug & DRM_UT_ATOMIC))                \
-                       drm_ut_debug_printk(__func__, fmt, ##args);     \
-       } while (0)
-#define DRM_DEBUG_VBL(fmt, args...)                                    \
-       do {                                                            \
-               if (unlikely(drm_debug & DRM_UT_VBL))                   \
-                       drm_ut_debug_printk(__func__, fmt, ##args);     \
-       } while (0)
+/**
+ * Rate limited debug output. Like DRM_DEBUG() but won't flood the log.
+ *
+ * \param fmt printf() like format string.
+ * \param arg arguments
+ */
+#define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, args...)                   \
+       DEV__DRM_DEFINE_DEBUG_RATELIMITED(dev, CORE, fmt, ##args)
+#define DRM_DEBUG_RATELIMITED(fmt, args...)                            \
+       DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##args)
+#define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, args...)            \
+       _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRIVER, fmt, ##args)
+#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, args...)                     \
+       DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##args)
+#define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, args...)               \
+       _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, KMS, fmt, ##args)
+#define DRM_DEBUG_KMS_RATELIMITED(fmt, args...)                                \
+       DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##args)
+#define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, args...)             \
+       _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, PRIME, fmt, ##args)
+#define DRM_DEBUG_PRIME_RATELIMITED(fmt, args...)                      \
+       DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##args)
 
 /*@}*/
 
@@ -295,10 +370,10 @@ struct drm_pending_event {
                      we deliver the event, for tracing only */
 };
 
-/* initial implementaton using a linked list - todo hashtab */
 struct drm_prime_file_private {
-       struct list_head head;
        struct mutex lock;
+       struct rb_root dmabufs;
+       struct rb_root handles;
 };
 
 /** File private data */
@@ -320,7 +395,6 @@ struct drm_file {
        unsigned is_master:1;
 
        struct pid *pid;
-       kuid_t uid;
        drm_magic_t magic;
        struct list_head lhead;
        struct drm_minor *minor;
@@ -642,7 +716,7 @@ struct drm_driver {
 };
 
 enum drm_minor_type {
-       DRM_MINOR_LEGACY,
+       DRM_MINOR_PRIMARY,
        DRM_MINOR_CONTROL,
        DRM_MINOR_RENDER,
        DRM_MINOR_CNT,
@@ -856,7 +930,7 @@ static inline bool drm_is_control_client(const struct drm_file *file_priv)
 
 static inline bool drm_is_primary_client(const struct drm_file *file_priv)
 {
-       return file_priv->minor->type == DRM_MINOR_LEGACY;
+       return file_priv->minor->type == DRM_MINOR_PRIMARY;
 }
 
 /******************************************************************/
@@ -937,8 +1011,11 @@ static inline int drm_debugfs_remove_files(const struct drm_info_list *files,
 }
 #endif
 
+struct dma_buf_export_info;
+
 extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
-               struct drm_gem_object *obj, int flags);
+                                           struct drm_gem_object *obj,
+                                           int flags);
 extern int drm_gem_prime_handle_to_fd(struct drm_device *dev,
                struct drm_file *file_priv, uint32_t handle, uint32_t flags,
                int *prime_fd);
@@ -946,6 +1023,8 @@ extern struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
                struct dma_buf *dma_buf);
 extern int drm_gem_prime_fd_to_handle(struct drm_device *dev,
                struct drm_file *file_priv, int prime_fd, uint32_t *handle);
+struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
+                                     struct dma_buf_export_info *exp_info);
 extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
 
 extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
index 856a9c8..9701f2d 100644 (file)
 
 #include <drm/drm_crtc.h>
 
+/**
+ * struct drm_crtc_commit - track modeset commits on a CRTC
+ *
+ * This structure is used to track pending modeset changes and atomic commit on
+ * a per-CRTC basis. Since updating the list should never block this structure
+ * is reference counted to allow waiters to safely wait on an event to complete,
+ * without holding any locks.
+ *
+ * It has 3 different events in total to allow a fine-grained synchronization
+ * between outstanding updates::
+ *
+ *     atomic commit thread                    hardware
+ *
+ *     write new state into hardware   ---->   ...
+ *     signal hw_done
+ *                                             switch to new state on next
+ *     ...                                     v/hblank
+ *
+ *     wait for buffers to show up             ...
+ *
+ *     ...                                     send completion irq
+ *                                             irq handler signals flip_done
+ *     cleanup old buffers
+ *
+ *     signal cleanup_done
+ *
+ *     wait for flip_done              <----
+ *     clean up atomic state
+ *
+ * The important bit to know is that cleanup_done is the terminal event, but the
+ * ordering between flip_done and hw_done is entirely up to the specific driver
+ * and modeset state change.
+ *
+ * For an implementation of how to use this look at
+ * drm_atomic_helper_setup_commit() from the atomic helper library.
+ */
+struct drm_crtc_commit {
+       /**
+        * @crtc:
+        *
+        * DRM CRTC for this commit.
+        */
+       struct drm_crtc *crtc;
+
+       /**
+        * @ref:
+        *
+        * Reference count for this structure. Needed to allow blocking on
+        * completions without the risk of the completion disappearing
+        * meanwhile.
+        */
+       struct kref ref;
+
+       /**
+        * @flip_done:
+        *
+        * Will be signaled when the hardware has flipped to the new set of
+        * buffers. Signals at the same time as when the drm event for this
+        * commit is sent to userspace, or when an out-fence is singalled. Note
+        * that for most hardware, in most cases this happens after @hw_done is
+        * signalled.
+        */
+       struct completion flip_done;
+
+       /**
+        * @hw_done:
+        *
+        * Will be signalled when all hw register changes for this commit have
+        * been written out. Especially when disabling a pipe this can be much
+        * later than than @flip_done, since that can signal already when the
+        * screen goes black, whereas to fully shut down a pipe more register
+        * I/O is required.
+        *
+        * Note that this does not need to include separately reference-counted
+        * resources like backing storage buffer pinning, or runtime pm
+        * management.
+        */
+       struct completion hw_done;
+
+       /**
+        * @cleanup_done:
+        *
+        * Will be signalled after old buffers have been cleaned up by calling
+        * drm_atomic_helper_cleanup_planes(). Since this can only happen after
+        * a vblank wait completed it might be a bit later. This completion is
+        * useful to throttle updates and avoid hardware updates getting ahead
+        * of the buffer cleanup too much.
+        */
+       struct completion cleanup_done;
+
+       /**
+        * @commit_entry:
+        *
+        * Entry on the per-CRTC commit_list. Protected by crtc->commit_lock.
+        */
+       struct list_head commit_entry;
+
+       /**
+        * @event:
+        *
+        * &drm_pending_vblank_event pointer to clean up private events.
+        */
+       struct drm_pending_vblank_event *event;
+};
+
+struct __drm_planes_state {
+       struct drm_plane *ptr;
+       struct drm_plane_state *state;
+};
+
+struct __drm_crtcs_state {
+       struct drm_crtc *ptr;
+       struct drm_crtc_state *state;
+       struct drm_crtc_commit *commit;
+};
+
+struct __drm_connnectors_state {
+       struct drm_connector *ptr;
+       struct drm_connector_state *state;
+};
+
+/**
+ * struct drm_atomic_state - the global state object for atomic updates
+ * @dev: parent DRM device
+ * @allow_modeset: allow full modeset
+ * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics
+ * @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL.
+ * @planes: pointer to array of structures with per-plane data
+ * @crtcs: pointer to array of CRTC pointers
+ * @num_connector: size of the @connectors and @connector_states arrays
+ * @connectors: pointer to array of structures with per-connector data
+ * @acquire_ctx: acquire context for this atomic modeset state update
+ */
+struct drm_atomic_state {
+       struct drm_device *dev;
+       bool allow_modeset : 1;
+       bool legacy_cursor_update : 1;
+       bool legacy_set_config : 1;
+       struct __drm_planes_state *planes;
+       struct __drm_crtcs_state *crtcs;
+       int num_connector;
+       struct __drm_connnectors_state *connectors;
+
+       struct drm_modeset_acquire_ctx *acquire_ctx;
+
+       /**
+        * @commit_work:
+        *
+        * Work item which can be used by the driver or helpers to execute the
+        * commit without blocking.
+        */
+       struct work_struct commit_work;
+};
+
 void drm_crtc_commit_put(struct drm_crtc_commit *commit);
 static inline void drm_crtc_commit_get(struct drm_crtc_commit *commit)
 {
index d86ae5d..7ff92b0 100644 (file)
@@ -29,6 +29,8 @@
 #define DRM_ATOMIC_HELPER_H_
 
 #include <drm/drm_crtc.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_modeset_helper.h>
 
 struct drm_atomic_state;
 
@@ -43,8 +45,9 @@ int drm_atomic_helper_commit(struct drm_device *dev,
                             struct drm_atomic_state *state,
                             bool nonblock);
 
-void drm_atomic_helper_wait_for_fences(struct drm_device *dev,
-                                       struct drm_atomic_state *state);
+int drm_atomic_helper_wait_for_fences(struct drm_device *dev,
+                                       struct drm_atomic_state *state,
+                                       bool pre_swap);
 bool drm_atomic_helper_framebuffer_changed(struct drm_device *dev,
                                           struct drm_atomic_state *old_state,
                                           struct drm_crtc *crtc);
@@ -63,14 +66,19 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 
 int drm_atomic_helper_prepare_planes(struct drm_device *dev,
                                     struct drm_atomic_state *state);
+
+#define DRM_PLANE_COMMIT_ACTIVE_ONLY                   BIT(0)
+#define DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET      BIT(1)
+
 void drm_atomic_helper_commit_planes(struct drm_device *dev,
                                     struct drm_atomic_state *state,
-                                    bool active_only);
+                                    uint32_t flags);
 void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
                                      struct drm_atomic_state *old_state);
 void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state);
-void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
-                                             bool atomic);
+void
+drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state,
+                                        bool atomic);
 
 void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
                                  bool stall);
diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h
new file mode 100644 (file)
index 0000000..36baa17
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_BLEND_H__
+#define __DRM_BLEND_H__
+
+#include <linux/list.h>
+#include <linux/ctype.h>
+
+struct drm_device;
+struct drm_atomic_state;
+
+/*
+ * Rotation property bits. DRM_ROTATE_<degrees> rotates the image by the
+ * specified amount in degrees in counter clockwise direction. DRM_REFLECT_X and
+ * DRM_REFLECT_Y reflects the image along the specified axis prior to rotation
+ *
+ * WARNING: These defines are UABI since they're exposed in the rotation
+ * property.
+ */
+#define DRM_ROTATE_0   BIT(0)
+#define DRM_ROTATE_90  BIT(1)
+#define DRM_ROTATE_180 BIT(2)
+#define DRM_ROTATE_270 BIT(3)
+#define DRM_ROTATE_MASK (DRM_ROTATE_0   | DRM_ROTATE_90 | \
+                        DRM_ROTATE_180 | DRM_ROTATE_270)
+#define DRM_REFLECT_X  BIT(4)
+#define DRM_REFLECT_Y  BIT(5)
+#define DRM_REFLECT_MASK (DRM_REFLECT_X | DRM_REFLECT_Y)
+
+struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
+                                                      unsigned int supported_rotations);
+unsigned int drm_rotation_simplify(unsigned int rotation,
+                                  unsigned int supported_rotations);
+
+int drm_plane_create_zpos_property(struct drm_plane *plane,
+                                  unsigned int zpos,
+                                  unsigned int min, unsigned int max);
+int drm_plane_create_zpos_immutable_property(struct drm_plane *plane,
+                                            unsigned int zpos);
+int drm_atomic_normalize_zpos(struct drm_device *dev,
+                             struct drm_atomic_state *state);
+#endif
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
new file mode 100644 (file)
index 0000000..530a1d6
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_BRIDGE_H__
+#define __DRM_BRIDGE_H__
+
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <drm/drm_mode_object.h>
+#include <drm/drm_modes.h>
+
+struct drm_bridge;
+
+/**
+ * struct drm_bridge_funcs - drm_bridge control functions
+ */
+struct drm_bridge_funcs {
+       /**
+        * @attach:
+        *
+        * This callback is invoked whenever our bridge is being attached to a
+        * &drm_encoder.
+        *
+        * The attach callback is optional.
+        *
+        * RETURNS:
+        *
+        * Zero on success, error code on failure.
+        */
+       int (*attach)(struct drm_bridge *bridge);
+
+       /**
+        * @detach:
+        *
+        * This callback is invoked whenever our bridge is being detached from a
+        * &drm_encoder.
+        *
+        * The detach callback is optional.
+        */
+       void (*detach)(struct drm_bridge *bridge);
+
+       /**
+        * @mode_fixup:
+        *
+        * This callback is used to validate and adjust a mode. The paramater
+        * mode is the display mode that should be fed to the next element in
+        * the display chain, either the final &drm_connector or the next
+        * &drm_bridge. The parameter adjusted_mode is the input mode the bridge
+        * requires. It can be modified by this callback and does not need to
+        * match mode.
+        *
+        * This is the only hook that allows a bridge to reject a modeset. If
+        * this function passes all other callbacks must succeed for this
+        * configuration.
+        *
+        * The mode_fixup callback is optional.
+        *
+        * NOTE:
+        *
+        * This function is called in the check phase of atomic modesets, which
+        * can be aborted for any reason (including on userspace's request to
+        * just check whether a configuration would be possible). Drivers MUST
+        * NOT touch any persistent state (hardware or software) or data
+        * structures except the passed in @state parameter.
+        *
+        * RETURNS:
+        *
+        * True if an acceptable configuration is possible, false if the modeset
+        * operation should be rejected.
+        */
+       bool (*mode_fixup)(struct drm_bridge *bridge,
+                          const struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode);
+       /**
+        * @disable:
+        *
+        * This callback should disable the bridge. It is called right before
+        * the preceding element in the display pipe is disabled. If the
+        * preceding element is a bridge this means it's called before that
+        * bridge's ->disable() function. If the preceding element is a
+        * &drm_encoder it's called right before the encoder's ->disable(),
+        * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_funcs.
+        *
+        * The bridge can assume that the display pipe (i.e. clocks and timing
+        * signals) feeding it is still running when this callback is called.
+        *
+        * The disable callback is optional.
+        */
+       void (*disable)(struct drm_bridge *bridge);
+
+       /**
+        * @post_disable:
+        *
+        * This callback should disable the bridge. It is called right after
+        * the preceding element in the display pipe is disabled. If the
+        * preceding element is a bridge this means it's called after that
+        * bridge's ->post_disable() function. If the preceding element is a
+        * &drm_encoder it's called right after the encoder's ->disable(),
+        * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_funcs.
+        *
+        * The bridge must assume that the display pipe (i.e. clocks and timing
+        * singals) feeding it is no longer running when this callback is
+        * called.
+        *
+        * The post_disable callback is optional.
+        */
+       void (*post_disable)(struct drm_bridge *bridge);
+
+       /**
+        * @mode_set:
+        *
+        * This callback should set the given mode on the bridge. It is called
+        * after the ->mode_set() callback for the preceding element in the
+        * display pipeline has been called already. The display pipe (i.e.
+        * clocks and timing signals) is off when this function is called.
+        */
+       void (*mode_set)(struct drm_bridge *bridge,
+                        struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode);
+       /**
+        * @pre_enable:
+        *
+        * This callback should enable the bridge. It is called right before
+        * the preceding element in the display pipe is enabled. If the
+        * preceding element is a bridge this means it's called before that
+        * bridge's ->pre_enable() function. If the preceding element is a
+        * &drm_encoder it's called right before the encoder's ->enable(),
+        * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs.
+        *
+        * The display pipe (i.e. clocks and timing signals) feeding this bridge
+        * will not yet be running when this callback is called. The bridge must
+        * not enable the display link feeding the next bridge in the chain (if
+        * there is one) when this callback is called.
+        *
+        * The pre_enable callback is optional.
+        */
+       void (*pre_enable)(struct drm_bridge *bridge);
+
+       /**
+        * @enable:
+        *
+        * This callback should enable the bridge. It is called right after
+        * the preceding element in the display pipe is enabled. If the
+        * preceding element is a bridge this means it's called after that
+        * bridge's ->enable() function. If the preceding element is a
+        * &drm_encoder it's called right after the encoder's ->enable(),
+        * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs.
+        *
+        * The bridge can assume that the display pipe (i.e. clocks and timing
+        * signals) feeding it is running when this callback is called. This
+        * callback must enable the display link feeding the next bridge in the
+        * chain if there is one.
+        *
+        * The enable callback is optional.
+        */
+       void (*enable)(struct drm_bridge *bridge);
+};
+
+/**
+ * struct drm_bridge - central DRM bridge control structure
+ * @dev: DRM device this bridge belongs to
+ * @encoder: encoder to which this bridge is connected
+ * @next: the next bridge in the encoder chain
+ * @of_node: device node pointer to the bridge
+ * @list: to keep track of all added bridges
+ * @funcs: control functions
+ * @driver_private: pointer to the bridge driver's internal context
+ */
+struct drm_bridge {
+       struct drm_device *dev;
+       struct drm_encoder *encoder;
+       struct drm_bridge *next;
+#ifdef CONFIG_OF
+       struct device_node *of_node;
+#endif
+       struct list_head list;
+
+       const struct drm_bridge_funcs *funcs;
+       void *driver_private;
+};
+
+int drm_bridge_add(struct drm_bridge *bridge);
+void drm_bridge_remove(struct drm_bridge *bridge);
+struct drm_bridge *of_drm_find_bridge(struct device_node *np);
+int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
+void drm_bridge_detach(struct drm_bridge *bridge);
+
+bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
+                       const struct drm_display_mode *mode,
+                       struct drm_display_mode *adjusted_mode);
+void drm_bridge_disable(struct drm_bridge *bridge);
+void drm_bridge_post_disable(struct drm_bridge *bridge);
+void drm_bridge_mode_set(struct drm_bridge *bridge,
+                       struct drm_display_mode *mode,
+                       struct drm_display_mode *adjusted_mode);
+void drm_bridge_pre_enable(struct drm_bridge *bridge);
+void drm_bridge_enable(struct drm_bridge *bridge);
+
+#endif
diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h
new file mode 100644 (file)
index 0000000..c767238
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_COLOR_MGMT_H__
+#define __DRM_COLOR_MGMT_H__
+
+#include <linux/ctype.h>
+
+void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
+                               uint degamma_lut_size,
+                               bool has_ctm,
+                               uint gamma_lut_size);
+
+int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
+                                int gamma_size);
+
+/**
+ * drm_color_lut_extract - clamp&round LUT entries
+ * @user_input: input value
+ * @bit_precision: number of bits the hw LUT supports
+ *
+ * Extract a degamma/gamma LUT value provided by user (in the form of
+ * &drm_color_lut entries) and round it to the precision supported by the
+ * hardware.
+ */
+static inline uint32_t drm_color_lut_extract(uint32_t user_input,
+                                            uint32_t bit_precision)
+{
+       uint32_t val = user_input;
+       uint32_t max = 0xffff >> (16 - bit_precision);
+
+       /* Round only if we're not using full precision. */
+       if (bit_precision < 16) {
+               val += 1UL << (16 - bit_precision - 1);
+               val >>= 16 - bit_precision;
+       }
+
+       return clamp_val(val, 0, max);
+}
+
+
+#endif
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
new file mode 100644 (file)
index 0000000..ac9d7d8
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_CONNECTOR_H__
+#define __DRM_CONNECTOR_H__
+
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <drm/drm_mode_object.h>
+
+#include <uapi/drm/drm_mode.h>
+
+struct drm_device;
+
+struct drm_connector_helper_funcs;
+struct drm_device;
+struct drm_crtc;
+struct drm_encoder;
+struct drm_property;
+struct drm_property_blob;
+struct edid;
+
+enum drm_connector_force {
+       DRM_FORCE_UNSPECIFIED,
+       DRM_FORCE_OFF,
+       DRM_FORCE_ON,         /* force on analog part normally */
+       DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */
+};
+
+/**
+ * enum drm_connector_status - status for a &drm_connector
+ *
+ * This enum is used to track the connector status. There are no separate
+ * #defines for the uapi!
+ */
+enum drm_connector_status {
+       /**
+        * @connector_status_connected: The connector is definitely connected to
+        * a sink device, and can be enabled.
+        */
+       connector_status_connected = 1,
+       /**
+        * @connector_status_disconnected: The connector isn't connected to a
+        * sink device which can be autodetect. For digital outputs like DP or
+        * HDMI (which can be realiable probed) this means there's really
+        * nothing there. It is driver-dependent whether a connector with this
+        * status can be lit up or not.
+        */
+       connector_status_disconnected = 2,
+       /**
+        * @connector_status_unknown: The connector's status could not be
+        * reliably detected. This happens when probing would either cause
+        * flicker (like load-detection when the connector is in use), or when a
+        * hardware resource isn't available (like when load-detection needs a
+        * free CRTC). It should be possible to light up the connector with one
+        * of the listed fallback modes. For default configuration userspace
+        * should only try to light up connectors with unknown status when
+        * there's not connector with @connector_status_connected.
+        */
+       connector_status_unknown = 3,
+};
+
+enum subpixel_order {
+       SubPixelUnknown = 0,
+       SubPixelHorizontalRGB,
+       SubPixelHorizontalBGR,
+       SubPixelVerticalRGB,
+       SubPixelVerticalBGR,
+       SubPixelNone,
+};
+
+/**
+ * struct drm_display_info - runtime data about the connected sink
+ *
+ * Describes a given display (e.g. CRT or flat panel) and its limitations. For
+ * fixed display sinks like built-in panels there's not much difference between
+ * this and struct &drm_connector. But for sinks with a real cable this
+ * structure is meant to describe all the things at the other end of the cable.
+ *
+ * For sinks which provide an EDID this can be filled out by calling
+ * drm_add_edid_modes().
+ */
+struct drm_display_info {
+       /**
+        * @name: Name of the display.
+        */
+       char name[DRM_DISPLAY_INFO_LEN];
+
+       /**
+        * @width_mm: Physical width in mm.
+        */
+        unsigned int width_mm;
+       /**
+        * @height_mm: Physical height in mm.
+        */
+       unsigned int height_mm;
+
+       /**
+        * @pixel_clock: Maximum pixel clock supported by the sink, in units of
+        * 100Hz. This mismatches the clok in &drm_display_mode (which is in
+        * kHZ), because that's what the EDID uses as base unit.
+        */
+       unsigned int pixel_clock;
+       /**
+        * @bpc: Maximum bits per color channel. Used by HDMI and DP outputs.
+        */
+       unsigned int bpc;
+
+       /**
+        * @subpixel_order: Subpixel order of LCD panels.
+        */
+       enum subpixel_order subpixel_order;
+
+#define DRM_COLOR_FORMAT_RGB444                (1<<0)
+#define DRM_COLOR_FORMAT_YCRCB444      (1<<1)
+#define DRM_COLOR_FORMAT_YCRCB422      (1<<2)
+
+       /**
+        * @color_formats: HDMI Color formats, selects between RGB and YCrCb
+        * modes. Used DRM_COLOR_FORMAT\_ defines, which are _not_ the same ones
+        * as used to describe the pixel format in framebuffers, and also don't
+        * match the formats in @bus_formats which are shared with v4l.
+        */
+       u32 color_formats;
+
+       /**
+        * @bus_formats: Pixel data format on the wire, somewhat redundant with
+        * @color_formats. Array of size @num_bus_formats encoded using
+        * MEDIA_BUS_FMT\_ defines shared with v4l and media drivers.
+        */
+       const u32 *bus_formats;
+       /**
+        * @num_bus_formats: Size of @bus_formats array.
+        */
+       unsigned int num_bus_formats;
+
+#define DRM_BUS_FLAG_DE_LOW            (1<<0)
+#define DRM_BUS_FLAG_DE_HIGH           (1<<1)
+/* drive data on pos. edge */
+#define DRM_BUS_FLAG_PIXDATA_POSEDGE   (1<<2)
+/* drive data on neg. edge */
+#define DRM_BUS_FLAG_PIXDATA_NEGEDGE   (1<<3)
+
+       /**
+        * @bus_flags: Additional information (like pixel signal polarity) for
+        * the pixel data on the bus, using DRM_BUS_FLAGS\_ defines.
+        */
+       u32 bus_flags;
+
+       /**
+        * @max_tmds_clock: Maximum TMDS clock rate supported by the
+        * sink in kHz. 0 means undefined.
+        */
+       int max_tmds_clock;
+
+       /**
+        * @dvi_dual: Dual-link DVI sink?
+        */
+       bool dvi_dual;
+
+       /**
+        * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even
+        * more stuff redundant with @bus_formats.
+        */
+       u8 edid_hdmi_dc_modes;
+
+       /**
+        * @cea_rev: CEA revision of the HDMI sink.
+        */
+       u8 cea_rev;
+};
+
+int drm_display_info_set_bus_formats(struct drm_display_info *info,
+                                    const u32 *formats,
+                                    unsigned int num_formats);
+
+/**
+ * struct drm_connector_state - mutable connector state
+ * @connector: backpointer to the connector
+ * @best_encoder: can be used by helpers and drivers to select the encoder
+ * @state: backpointer to global drm_atomic_state
+ */
+struct drm_connector_state {
+       struct drm_connector *connector;
+
+       /**
+        * @crtc: CRTC to connect connector to, NULL if disabled.
+        *
+        * Do not change this directly, use drm_atomic_set_crtc_for_connector()
+        * instead.
+        */
+       struct drm_crtc *crtc;
+
+       struct drm_encoder *best_encoder;
+
+       struct drm_atomic_state *state;
+};
+
+/**
+ * struct drm_connector_funcs - control connectors on a given device
+ *
+ * Each CRTC may have one or more connectors attached to it.  The functions
+ * below allow the core DRM code to control connectors, enumerate available modes,
+ * etc.
+ */
+struct drm_connector_funcs {
+       /**
+        * @dpms:
+        *
+        * Legacy entry point to set the per-connector DPMS state. Legacy DPMS
+        * is exposed as a standard property on the connector, but diverted to
+        * this callback in the drm core. Note that atomic drivers don't
+        * implement the 4 level DPMS support on the connector any more, but
+        * instead only have an on/off "ACTIVE" property on the CRTC object.
+        *
+        * Drivers implementing atomic modeset should use
+        * drm_atomic_helper_connector_dpms() to implement this hook.
+        *
+        * RETURNS:
+        *
+        * 0 on success or a negative error code on failure.
+        */
+       int (*dpms)(struct drm_connector *connector, int mode);
+
+       /**
+        * @reset:
+        *
+        * Reset connector hardware and software state to off. This function isn't
+        * called by the core directly, only through drm_mode_config_reset().
+        * It's not a helper hook only for historical reasons.
+        *
+        * Atomic drivers can use drm_atomic_helper_connector_reset() to reset
+        * atomic state using this hook.
+        */
+       void (*reset)(struct drm_connector *connector);
+
+       /**
+        * @detect:
+        *
+        * Check to see if anything is attached to the connector. The parameter
+        * force is set to false whilst polling, true when checking the
+        * connector due to a user request. force can be used by the driver to
+        * avoid expensive, destructive operations during automated probing.
+        *
+        * FIXME:
+        *
+        * Note that this hook is only called by the probe helper. It's not in
+        * the helper library vtable purely for historical reasons. The only DRM
+        * core entry point to probe connector state is @fill_modes.
+        *
+        * RETURNS:
+        *
+        * drm_connector_status indicating the connector's status.
+        */
+       enum drm_connector_status (*detect)(struct drm_connector *connector,
+                                           bool force);
+
+       /**
+        * @force:
+        *
+        * This function is called to update internal encoder state when the
+        * connector is forced to a certain state by userspace, either through
+        * the sysfs interfaces or on the kernel cmdline. In that case the
+        * @detect callback isn't called.
+        *
+        * FIXME:
+        *
+        * Note that this hook is only called by the probe helper. It's not in
+        * the helper library vtable purely for historical reasons. The only DRM
+        * core entry point to probe connector state is @fill_modes.
+        */
+       void (*force)(struct drm_connector *connector);
+
+       /**
+        * @fill_modes:
+        *
+        * Entry point for output detection and basic mode validation. The
+        * driver should reprobe the output if needed (e.g. when hotplug
+        * handling is unreliable), add all detected modes to connector->modes
+        * and filter out any the device can't support in any configuration. It
+        * also needs to filter out any modes wider or higher than the
+        * parameters max_width and max_height indicate.
+        *
+        * The drivers must also prune any modes no longer valid from
+        * connector->modes. Furthermore it must update connector->status and
+        * connector->edid.  If no EDID has been received for this output
+        * connector->edid must be NULL.
+        *
+        * Drivers using the probe helpers should use
+        * drm_helper_probe_single_connector_modes() or
+        * drm_helper_probe_single_connector_modes_nomerge() to implement this
+        * function.
+        *
+        * RETURNS:
+        *
+        * The number of modes detected and filled into connector->modes.
+        */
+       int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
+
+       /**
+        * @set_property:
+        *
+        * This is the legacy entry point to update a property attached to the
+        * connector.
+        *
+        * Drivers implementing atomic modeset should use
+        * drm_atomic_helper_connector_set_property() to implement this hook.
+        *
+        * This callback is optional if the driver does not support any legacy
+        * driver-private properties.
+        *
+        * RETURNS:
+        *
+        * 0 on success or a negative error code on failure.
+        */
+       int (*set_property)(struct drm_connector *connector, struct drm_property *property,
+                            uint64_t val);
+
+       /**
+        * @late_register:
+        *
+        * This optional hook can be used to register additional userspace
+        * interfaces attached to the connector, light backlight control, i2c,
+        * DP aux or similar interfaces. It is called late in the driver load
+        * sequence from drm_connector_register() when registering all the
+        * core drm connector interfaces. Everything added from this callback
+        * should be unregistered in the early_unregister callback.
+        *
+        * Returns:
+        *
+        * 0 on success, or a negative error code on failure.
+        */
+       int (*late_register)(struct drm_connector *connector);
+
+       /**
+        * @early_unregister:
+        *
+        * This optional hook should be used to unregister the additional
+        * userspace interfaces attached to the connector from
+        * late_register(). It is called from drm_connector_unregister(),
+        * early in the driver unload sequence to disable userspace access
+        * before data structures are torndown.
+        */
+       void (*early_unregister)(struct drm_connector *connector);
+
+       /**
+        * @destroy:
+        *
+        * Clean up connector resources. This is called at driver unload time
+        * through drm_mode_config_cleanup(). It can also be called at runtime
+        * when a connector is being hot-unplugged for drivers that support
+        * connector hotplugging (e.g. DisplayPort MST).
+        */
+       void (*destroy)(struct drm_connector *connector);
+
+       /**
+        * @atomic_duplicate_state:
+        *
+        * Duplicate the current atomic state for this connector and return it.
+        * The core and helpers guarantee that any atomic state duplicated with
+        * this hook and still owned by the caller (i.e. not transferred to the
+        * driver by calling ->atomic_commit() from struct
+        * &drm_mode_config_funcs) will be cleaned up by calling the
+        * @atomic_destroy_state hook in this structure.
+        *
+        * Atomic drivers which don't subclass struct &drm_connector_state should use
+        * drm_atomic_helper_connector_duplicate_state(). Drivers that subclass the
+        * state structure to extend it with driver-private state should use
+        * __drm_atomic_helper_connector_duplicate_state() to make sure shared state is
+        * duplicated in a consistent fashion across drivers.
+        *
+        * It is an error to call this hook before connector->state has been
+        * initialized correctly.
+        *
+        * NOTE:
+        *
+        * If the duplicate state references refcounted resources this hook must
+        * acquire a reference for each of them. The driver must release these
+        * references again in @atomic_destroy_state.
+        *
+        * RETURNS:
+        *
+        * Duplicated atomic state or NULL when the allocation failed.
+        */
+       struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector);
+
+       /**
+        * @atomic_destroy_state:
+        *
+        * Destroy a state duplicated with @atomic_duplicate_state and release
+        * or unreference all resources it references
+        */
+       void (*atomic_destroy_state)(struct drm_connector *connector,
+                                    struct drm_connector_state *state);
+
+       /**
+        * @atomic_set_property:
+        *
+        * Decode a driver-private property value and store the decoded value
+        * into the passed-in state structure. Since the atomic core decodes all
+        * standardized properties (even for extensions beyond the core set of
+        * properties which might not be implemented by all drivers) this
+        * requires drivers to subclass the state structure.
+        *
+        * Such driver-private properties should really only be implemented for
+        * truly hardware/vendor specific state. Instead it is preferred to
+        * standardize atomic extension and decode the properties used to expose
+        * such an extension in the core.
+        *
+        * Do not call this function directly, use
+        * drm_atomic_connector_set_property() instead.
+        *
+        * This callback is optional if the driver does not support any
+        * driver-private atomic properties.
+        *
+        * NOTE:
+        *
+        * This function is called in the state assembly phase of atomic
+        * modesets, which can be aborted for any reason (including on
+        * userspace's request to just check whether a configuration would be
+        * possible). Drivers MUST NOT touch any persistent state (hardware or
+        * software) or data structures except the passed in @state parameter.
+        *
+        * Also since userspace controls in which order properties are set this
+        * function must not do any input validation (since the state update is
+        * incomplete and hence likely inconsistent). Instead any such input
+        * validation must be done in the various atomic_check callbacks.
+        *
+        * RETURNS:
+        *
+        * 0 if the property has been found, -EINVAL if the property isn't
+        * implemented by the driver (which shouldn't ever happen, the core only
+        * asks for properties attached to this connector). No other validation
+        * is allowed by the driver. The core already checks that the property
+        * value is within the range (integer, valid enum value, ...) the driver
+        * set when registering the property.
+        */
+       int (*atomic_set_property)(struct drm_connector *connector,
+                                  struct drm_connector_state *state,
+                                  struct drm_property *property,
+                                  uint64_t val);
+
+       /**
+        * @atomic_get_property:
+        *
+        * Reads out the decoded driver-private property. This is used to
+        * implement the GETCONNECTOR IOCTL.
+        *
+        * Do not call this function directly, use
+        * drm_atomic_connector_get_property() instead.
+        *
+        * This callback is optional if the driver does not support any
+        * driver-private atomic properties.
+        *
+        * RETURNS:
+        *
+        * 0 on success, -EINVAL if the property isn't implemented by the
+        * driver (which shouldn't ever happen, the core only asks for
+        * properties attached to this connector).
+        */
+       int (*atomic_get_property)(struct drm_connector *connector,
+                                  const struct drm_connector_state *state,
+                                  struct drm_property *property,
+                                  uint64_t *val);
+};
+
+/* mode specified on the command line */
+struct drm_cmdline_mode {
+       bool specified;
+       bool refresh_specified;
+       bool bpp_specified;
+       int xres, yres;
+       int bpp;
+       int refresh;
+       bool rb;
+       bool interlace;
+       bool cvt;
+       bool margins;
+       enum drm_connector_force force;
+};
+
+/**
+ * struct drm_connector - central DRM connector control structure
+ * @dev: parent DRM device
+ * @kdev: kernel device for sysfs attributes
+ * @attr: sysfs attributes
+ * @head: list management
+ * @base: base KMS object
+ * @name: human readable name, can be overwritten by the driver
+ * @connector_type: one of the DRM_MODE_CONNECTOR_<foo> types from drm_mode.h
+ * @connector_type_id: index into connector type enum
+ * @interlace_allowed: can this connector handle interlaced modes?
+ * @doublescan_allowed: can this connector handle doublescan?
+ * @stereo_allowed: can this connector handle stereo modes?
+ * @registered: is this connector exposed (registered) with userspace?
+ * @modes: modes available on this connector (from fill_modes() + user)
+ * @status: one of the drm_connector_status enums (connected, not, or unknown)
+ * @probed_modes: list of modes derived directly from the display
+ * @funcs: connector control functions
+ * @edid_blob_ptr: DRM property containing EDID if present
+ * @properties: property tracking for this connector
+ * @dpms: current dpms state
+ * @helper_private: mid-layer private data
+ * @cmdline_mode: mode line parsed from the kernel cmdline for this connector
+ * @force: a DRM_FORCE_<foo> state for forced mode sets
+ * @override_edid: has the EDID been overwritten through debugfs for testing?
+ * @encoder_ids: valid encoders for this connector
+ * @encoder: encoder driving this connector, if any
+ * @eld: EDID-like data, if present
+ * @latency_present: AV delay info from ELD, if found
+ * @video_latency: video latency info from ELD, if found
+ * @audio_latency: audio latency info from ELD, if found
+ * @null_edid_counter: track sinks that give us all zeros for the EDID
+ * @bad_edid_counter: track sinks that give us an EDID with invalid checksum
+ * @edid_corrupt: indicates whether the last read EDID was corrupt
+ * @debugfs_entry: debugfs directory for this connector
+ * @state: current atomic state for this connector
+ * @has_tile: is this connector connected to a tiled monitor
+ * @tile_group: tile group for the connected monitor
+ * @tile_is_single_monitor: whether the tile is one monitor housing
+ * @num_h_tile: number of horizontal tiles in the tile group
+ * @num_v_tile: number of vertical tiles in the tile group
+ * @tile_h_loc: horizontal location of this tile
+ * @tile_v_loc: vertical location of this tile
+ * @tile_h_size: horizontal size of this tile.
+ * @tile_v_size: vertical size of this tile.
+ *
+ * Each connector may be connected to one or more CRTCs, or may be clonable by
+ * another connector if they can share a CRTC.  Each connector also has a specific
+ * position in the broader display (referred to as a 'screen' though it could
+ * span multiple monitors).
+ */
+struct drm_connector {
+       struct drm_device *dev;
+       struct device *kdev;
+       struct device_attribute *attr;
+       struct list_head head;
+
+       struct drm_mode_object base;
+
+       char *name;
+
+       /**
+        * @index: Compacted connector index, which matches the position inside
+        * the mode_config.list for drivers not supporting hot-add/removing. Can
+        * be used as an array index. It is invariant over the lifetime of the
+        * connector.
+        */
+       unsigned index;
+
+       int connector_type;
+       int connector_type_id;
+       bool interlace_allowed;
+       bool doublescan_allowed;
+       bool stereo_allowed;
+       bool registered;
+       struct list_head modes; /* list of modes on this connector */
+
+       enum drm_connector_status status;
+
+       /* these are modes added by probing with DDC or the BIOS */
+       struct list_head probed_modes;
+
+       /**
+        * @display_info: Display information is filled from EDID information
+        * when a display is detected. For non hot-pluggable displays such as
+        * flat panels in embedded systems, the driver should initialize the
+        * display_info.width_mm and display_info.height_mm fields with the
+        * physical size of the display.
+        */
+       struct drm_display_info display_info;
+       const struct drm_connector_funcs *funcs;
+
+       struct drm_property_blob *edid_blob_ptr;
+       struct drm_object_properties properties;
+
+       /**
+        * @path_blob_ptr:
+        *
+        * DRM blob property data for the DP MST path property.
+        */
+       struct drm_property_blob *path_blob_ptr;
+
+       /**
+        * @tile_blob_ptr:
+        *
+        * DRM blob property data for the tile property (used mostly by DP MST).
+        * This is meant for screens which are driven through separate display
+        * pipelines represented by &drm_crtc, which might not be running with
+        * genlocked clocks. For tiled panels which are genlocked, like
+        * dual-link LVDS or dual-link DSI, the driver should try to not expose
+        * the tiling and virtualize both &drm_crtc and &drm_plane if needed.
+        */
+       struct drm_property_blob *tile_blob_ptr;
+
+/* should we poll this connector for connects and disconnects */
+/* hot plug detectable */
+#define DRM_CONNECTOR_POLL_HPD (1 << 0)
+/* poll for connections */
+#define DRM_CONNECTOR_POLL_CONNECT (1 << 1)
+/* can cleanly poll for disconnections without flickering the screen */
+/* DACs should rarely do this without a lot of testing */
+#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)
+
+       /**
+        * @polled:
+        *
+        * Connector polling mode, a combination of
+        *
+        * DRM_CONNECTOR_POLL_HPD
+        *     The connector generates hotplug events and doesn't need to be
+        *     periodically polled. The CONNECT and DISCONNECT flags must not
+        *     be set together with the HPD flag.
+        *
+        * DRM_CONNECTOR_POLL_CONNECT
+        *     Periodically poll the connector for connection.
+        *
+        * DRM_CONNECTOR_POLL_DISCONNECT
+        *     Periodically poll the connector for disconnection.
+        *
+        * Set to 0 for connectors that don't support connection status
+        * discovery.
+        */
+       uint8_t polled;
+
+       /* requested DPMS state */
+       int dpms;
+
+       const struct drm_connector_helper_funcs *helper_private;
+
+       /* forced on connector */
+       struct drm_cmdline_mode cmdline_mode;
+       enum drm_connector_force force;
+       bool override_edid;
+
+#define DRM_CONNECTOR_MAX_ENCODER 3
+       uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
+       struct drm_encoder *encoder; /* currently active encoder */
+
+#define MAX_ELD_BYTES  128
+       /* EDID bits */
+       uint8_t eld[MAX_ELD_BYTES];
+       bool latency_present[2];
+       int video_latency[2];   /* [0]: progressive, [1]: interlaced */
+       int audio_latency[2];
+       int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
+       unsigned bad_edid_counter;
+
+       /* Flag for raw EDID header corruption - used in Displayport
+        * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6
+        */
+       bool edid_corrupt;
+
+       struct dentry *debugfs_entry;
+
+       struct drm_connector_state *state;
+
+       /* DisplayID bits */
+       bool has_tile;
+       struct drm_tile_group *tile_group;
+       bool tile_is_single_monitor;
+
+       uint8_t num_h_tile, num_v_tile;
+       uint8_t tile_h_loc, tile_v_loc;
+       uint16_t tile_h_size, tile_v_size;
+};
+
+#define obj_to_connector(x) container_of(x, struct drm_connector, base)
+
+int drm_connector_init(struct drm_device *dev,
+                      struct drm_connector *connector,
+                      const struct drm_connector_funcs *funcs,
+                      int connector_type);
+int drm_connector_register(struct drm_connector *connector);
+void drm_connector_unregister(struct drm_connector *connector);
+int drm_mode_connector_attach_encoder(struct drm_connector *connector,
+                                     struct drm_encoder *encoder);
+
+void drm_connector_cleanup(struct drm_connector *connector);
+static inline unsigned drm_connector_index(struct drm_connector *connector)
+{
+       return connector->index;
+}
+
+/**
+ * drm_connector_lookup - lookup connector object
+ * @dev: DRM device
+ * @id: connector object id
+ *
+ * This function looks up the connector object specified by id
+ * add takes a reference to it.
+ */
+static inline struct drm_connector *drm_connector_lookup(struct drm_device *dev,
+               uint32_t id)
+{
+       struct drm_mode_object *mo;
+       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CONNECTOR);
+       return mo ? obj_to_connector(mo) : NULL;
+}
+
+/**
+ * drm_connector_reference - incr the connector refcnt
+ * @connector: connector
+ *
+ * This function increments the connector's refcount.
+ */
+static inline void drm_connector_reference(struct drm_connector *connector)
+{
+       drm_mode_object_reference(&connector->base);
+}
+
+/**
+ * drm_connector_unreference - unref a connector
+ * @connector: connector to unref
+ *
+ * This function decrements the connector's refcount and frees it if it drops to zero.
+ */
+static inline void drm_connector_unreference(struct drm_connector *connector)
+{
+       drm_mode_object_unreference(&connector->base);
+}
+
+const char *drm_get_connector_status_name(enum drm_connector_status status);
+const char *drm_get_subpixel_order_name(enum subpixel_order order);
+const char *drm_get_dpms_name(int val);
+const char *drm_get_dvi_i_subconnector_name(int val);
+const char *drm_get_dvi_i_select_name(int val);
+const char *drm_get_tv_subconnector_name(int val);
+const char *drm_get_tv_select_name(int val);
+
+int drm_mode_create_dvi_i_properties(struct drm_device *dev);
+int drm_mode_create_tv_properties(struct drm_device *dev,
+                                 unsigned int num_modes,
+                                 const char * const modes[]);
+int drm_mode_create_scaling_mode_property(struct drm_device *dev);
+int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
+int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
+
+int drm_mode_connector_set_path_property(struct drm_connector *connector,
+                                        const char *path);
+int drm_mode_connector_set_tile_property(struct drm_connector *connector);
+int drm_mode_connector_update_edid_property(struct drm_connector *connector,
+                                           const struct edid *edid);
+
+/**
+ * drm_for_each_connector - iterate over all connectors
+ * @connector: the loop cursor
+ * @dev: the DRM device
+ *
+ * Iterate over all connectors of @dev.
+ */
+#define drm_for_each_connector(connector, dev) \
+       for (assert_drm_connector_list_read_locked(&(dev)->mode_config),        \
+            connector = list_first_entry(&(dev)->mode_config.connector_list,   \
+                                         struct drm_connector, head);          \
+            &connector->head != (&(dev)->mode_config.connector_list);          \
+            connector = list_next_entry(connector, head))
+
+#endif
diff --git a/include/drm/drm_core.h b/include/drm/drm_core.h
deleted file mode 100644 (file)
index 4e75238..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2004 Jon Smirl <jonsmirl@gmail.com>
- *
- * 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, sub license,
- * 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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.
- */
-#define CORE_AUTHOR            "Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"
-
-#define CORE_NAME              "drm"
-#define CORE_DESC              "DRM shared core routines"
-#define CORE_DATE              "20060810"
-
-#define DRM_IF_MAJOR   1
-#define DRM_IF_MINOR   4
-
-#define CORE_MAJOR     1
-#define CORE_MINOR     1
-#define CORE_PATCHLEVEL 0
index 44e0708..0aa2925 100644 (file)
 #include <uapi/drm/drm_mode.h>
 #include <uapi/drm/drm_fourcc.h>
 #include <drm/drm_modeset_lock.h>
+#include <drm/drm_rect.h>
+#include <drm/drm_mode_object.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_property.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_color_mgmt.h>
 
 struct drm_device;
 struct drm_mode_set;
-struct drm_framebuffer;
-struct drm_object_properties;
 struct drm_file;
 struct drm_clip_rect;
 struct device_node;
 struct fence;
 struct edid;
 
-struct drm_mode_object {
-       uint32_t id;
-       uint32_t type;
-       struct drm_object_properties *properties;
-       struct kref refcount;
-       void (*free_cb)(struct kref *kref);
-};
-
-#define DRM_OBJECT_MAX_PROPERTY 24
-struct drm_object_properties {
-       int count, atomic_count;
-       /* NOTE: if we ever start dynamically destroying properties (ie.
-        * not at drm_mode_config_cleanup() time), then we'd have to do
-        * a better job of detaching property from mode objects to avoid
-        * dangling property pointers:
-        */
-       struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY];
-       /* do not read/write values directly, but use drm_object_property_get_value()
-        * and drm_object_property_set_value():
-        */
-       uint64_t values[DRM_OBJECT_MAX_PROPERTY];
-};
-
 static inline int64_t U642I64(uint64_t val)
 {
        return (int64_t)*((int64_t *)&val);
@@ -78,84 +65,6 @@ static inline uint64_t I642U64(int64_t val)
        return (uint64_t)*((uint64_t *)&val);
 }
 
-/*
- * Rotation property bits. DRM_ROTATE_<degrees> rotates the image by the
- * specified amount in degrees in counter clockwise direction. DRM_REFLECT_X and
- * DRM_REFLECT_Y reflects the image along the specified axis prior to rotation
- */
-#define DRM_ROTATE_MASK 0x0f
-#define DRM_ROTATE_0   0
-#define DRM_ROTATE_90  1
-#define DRM_ROTATE_180 2
-#define DRM_ROTATE_270 3
-#define DRM_REFLECT_MASK (~DRM_ROTATE_MASK)
-#define DRM_REFLECT_X  4
-#define DRM_REFLECT_Y  5
-
-enum drm_connector_force {
-       DRM_FORCE_UNSPECIFIED,
-       DRM_FORCE_OFF,
-       DRM_FORCE_ON,         /* force on analog part normally */
-       DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */
-};
-
-#include <drm/drm_modes.h>
-
-enum drm_connector_status {
-       connector_status_connected = 1,
-       connector_status_disconnected = 2,
-       connector_status_unknown = 3,
-};
-
-enum subpixel_order {
-       SubPixelUnknown = 0,
-       SubPixelHorizontalRGB,
-       SubPixelHorizontalBGR,
-       SubPixelVerticalRGB,
-       SubPixelVerticalBGR,
-       SubPixelNone,
-};
-
-#define DRM_COLOR_FORMAT_RGB444                (1<<0)
-#define DRM_COLOR_FORMAT_YCRCB444      (1<<1)
-#define DRM_COLOR_FORMAT_YCRCB422      (1<<2)
-
-#define DRM_BUS_FLAG_DE_LOW            (1<<0)
-#define DRM_BUS_FLAG_DE_HIGH           (1<<1)
-/* drive data on pos. edge */
-#define DRM_BUS_FLAG_PIXDATA_POSEDGE   (1<<2)
-/* drive data on neg. edge */
-#define DRM_BUS_FLAG_PIXDATA_NEGEDGE   (1<<3)
-
-/*
- * Describes a given display (e.g. CRT or flat panel) and its limitations.
- */
-struct drm_display_info {
-       char name[DRM_DISPLAY_INFO_LEN];
-
-       /* Physical size */
-        unsigned int width_mm;
-       unsigned int height_mm;
-
-       /* Clock limits FIXME: storage format */
-       unsigned int min_vfreq, max_vfreq;
-       unsigned int min_hfreq, max_hfreq;
-       unsigned int pixel_clock;
-       unsigned int bpc;
-
-       enum subpixel_order subpixel_order;
-       u32 color_formats;
-
-       const u32 *bus_formats;
-       unsigned int num_bus_formats;
-       u32 bus_flags;
-
-       /* Mask of supported hdmi deep color modes */
-       u8 edid_hdmi_dc_modes;
-
-       u8 cea_rev;
-};
-
 /* data corresponds to displayid vend/prod/serial */
 struct drm_tile_group {
        struct kref refcount;
@@ -164,130 +73,7 @@ struct drm_tile_group {
        u8 group_data[8];
 };
 
-/**
- * struct drm_framebuffer_funcs - framebuffer hooks
- */
-struct drm_framebuffer_funcs {
-       /**
-        * @destroy:
-        *
-        * Clean up framebuffer resources, specifically also unreference the
-        * backing storage. The core guarantees to call this function for every
-        * framebuffer successfully created by ->fb_create() in
-        * &drm_mode_config_funcs. Drivers must also call
-        * drm_framebuffer_cleanup() to release DRM core resources for this
-        * framebuffer.
-        */
-       void (*destroy)(struct drm_framebuffer *framebuffer);
-
-       /**
-        * @create_handle:
-        *
-        * Create a buffer handle in the driver-specific buffer manager (either
-        * GEM or TTM) valid for the passed-in struct &drm_file. This is used by
-        * the core to implement the GETFB IOCTL, which returns (for
-        * sufficiently priviledged user) also a native buffer handle. This can
-        * be used for seamless transitions between modesetting clients by
-        * copying the current screen contents to a private buffer and blending
-        * between that and the new contents.
-        *
-        * GEM based drivers should call drm_gem_handle_create() to create the
-        * handle.
-        *
-        * RETURNS:
-        *
-        * 0 on success or a negative error code on failure.
-        */
-       int (*create_handle)(struct drm_framebuffer *fb,
-                            struct drm_file *file_priv,
-                            unsigned int *handle);
-       /**
-        * @dirty:
-        *
-        * Optional callback for the dirty fb IOCTL.
-        *
-        * Userspace can notify the driver via this callback that an area of the
-        * framebuffer has changed and should be flushed to the display
-        * hardware. This can also be used internally, e.g. by the fbdev
-        * emulation, though that's not the case currently.
-        *
-        * See documentation in drm_mode.h for the struct drm_mode_fb_dirty_cmd
-        * for more information as all the semantics and arguments have a one to
-        * one mapping on this function.
-        *
-        * RETURNS:
-        *
-        * 0 on success or a negative error code on failure.
-        */
-       int (*dirty)(struct drm_framebuffer *framebuffer,
-                    struct drm_file *file_priv, unsigned flags,
-                    unsigned color, struct drm_clip_rect *clips,
-                    unsigned num_clips);
-};
-
-struct drm_framebuffer {
-       struct drm_device *dev;
-       /*
-        * Note that the fb is refcounted for the benefit of driver internals,
-        * for example some hw, disabling a CRTC/plane is asynchronous, and
-        * scanout does not actually complete until the next vblank.  So some
-        * cleanup (like releasing the reference(s) on the backing GEM bo(s))
-        * should be deferred.  In cases like this, the driver would like to
-        * hold a ref to the fb even though it has already been removed from
-        * userspace perspective.
-        * The refcount is stored inside the mode object.
-        */
-       /*
-        * Place on the dev->mode_config.fb_list, access protected by
-        * dev->mode_config.fb_lock.
-        */
-       struct list_head head;
-       struct drm_mode_object base;
-       const struct drm_framebuffer_funcs *funcs;
-       unsigned int pitches[4];
-       unsigned int offsets[4];
-       uint64_t modifier[4];
-       unsigned int width;
-       unsigned int height;
-       /* depth can be 15 or 16 */
-       unsigned int depth;
-       int bits_per_pixel;
-       int flags;
-       uint32_t pixel_format; /* fourcc format */
-       int hot_x;
-       int hot_y;
-       struct list_head filp_head;
-};
-
-struct drm_property_blob {
-       struct drm_mode_object base;
-       struct drm_device *dev;
-       struct list_head head_global;
-       struct list_head head_file;
-       size_t length;
-       unsigned char data[];
-};
-
-struct drm_property_enum {
-       uint64_t value;
-       struct list_head head;
-       char name[DRM_PROP_NAME_LEN];
-};
-
-struct drm_property {
-       struct list_head head;
-       struct drm_mode_object base;
-       uint32_t flags;
-       char name[DRM_PROP_NAME_LEN];
-       uint32_t num_values;
-       uint64_t *values;
-       struct drm_device *dev;
-
-       struct list_head enum_list;
-};
-
 struct drm_crtc;
-struct drm_connector;
 struct drm_encoder;
 struct drm_pending_vblank_event;
 struct drm_plane;
@@ -296,7 +82,6 @@ struct drm_atomic_state;
 
 struct drm_crtc_helper_funcs;
 struct drm_encoder_helper_funcs;
-struct drm_connector_helper_funcs;
 struct drm_plane_helper_funcs;
 
 /**
@@ -324,8 +109,6 @@ struct drm_plane_helper_funcs;
  * @ctm: Transformation matrix
  * @gamma_lut: Lookup table for converting pixel data after the
  *     conversion matrix
- * @event: optional pointer to a DRM event to signal upon completion of the
- *     state update
  * @state: backpointer to global drm_atomic_state
  *
  * Note that the distinction between @enable and @active is rather subtile:
@@ -374,6 +157,46 @@ struct drm_crtc_state {
        struct drm_property_blob *ctm;
        struct drm_property_blob *gamma_lut;
 
+       /**
+        * @event:
+        *
+        * Optional pointer to a DRM event to signal upon completion of the
+        * state update. The driver must send out the event when the atomic
+        * commit operation completes. There are two cases:
+        *
+        *  - The event is for a CRTC which is being disabled through this
+        *    atomic commit. In that case the event can be send out any time
+        *    after the hardware has stopped scanning out the current
+        *    framebuffers. It should contain the timestamp and counter for the
+        *    last vblank before the display pipeline was shut off.
+        *
+        *  - For a CRTC which is enabled at the end of the commit (even when it
+        *    undergoes an full modeset) the vblank timestamp and counter must
+        *    be for the vblank right before the first frame that scans out the
+        *    new set of buffers. Again the event can only be sent out after the
+        *    hardware has stopped scanning out the old buffers.
+        *
+        *  - Events for disabled CRTCs are not allowed, and drivers can ignore
+        *    that case.
+        *
+        * This can be handled by the drm_crtc_send_vblank_event() function,
+        * which the driver should call on the provided event upon completion of
+        * the atomic commit. Note that if the driver supports vblank signalling
+        * and timestamping the vblank counters and timestamps must agree with
+        * the ones returned from page flip events. With the current vblank
+        * helper infrastructure this can be achieved by holding a vblank
+        * reference while the page flip is pending, acquired through
+        * drm_crtc_vblank_get() and released with drm_crtc_vblank_put().
+        * Drivers are free to implement their own vblank counter and timestamp
+        * tracking though, e.g. if they have accurate timestamp registers in
+        * hardware.
+        *
+        * For hardware which supports some means to synchronize vblank
+        * interrupt delivery with committing display state there's also
+        * drm_crtc_arm_vblank_event(). See the documentation of that function
+        * for a detailed discussion of the constraints it needs to be used
+        * safely.
+        */
        struct drm_pending_vblank_event *event;
 
        struct drm_atomic_state *state;
@@ -545,16 +368,6 @@ struct drm_crtc_funcs {
         * counter and timestamp tracking though, e.g. if they have accurate
         * timestamp registers in hardware.
         *
-        * FIXME:
-        *
-        * Up to that point drivers need to manage events themselves and can use
-        * even->base.list freely for that. Specifically they need to ensure
-        * that they don't send out page flip (or vblank) events for which the
-        * corresponding drm file has been closed already. The drm core
-        * unfortunately does not (yet) take care of that. Therefore drivers
-        * currently must clean up and release pending events in their
-        * ->preclose driver function.
-        *
         * This callback is optional.
         *
         * NOTE:
@@ -580,6 +393,24 @@ struct drm_crtc_funcs {
                         struct drm_pending_vblank_event *event,
                         uint32_t flags);
 
+       /**
+        * @page_flip_target:
+        *
+        * Same as @page_flip but with an additional parameter specifying the
+        * absolute target vertical blank period (as reported by
+        * drm_crtc_vblank_count()) when the flip should take effect.
+        *
+        * Note that the core code calls drm_crtc_vblank_get before this entry
+        * point, and will call drm_crtc_vblank_put if this entry point returns
+        * any non-0 error code. It's the driver's responsibility to call
+        * drm_crtc_vblank_put after this entry point returns 0, typically when
+        * the flip completes.
+        */
+       int (*page_flip_target)(struct drm_crtc *crtc,
+                               struct drm_framebuffer *fb,
+                               struct drm_pending_vblank_event *event,
+                               uint32_t flags, uint32_t target);
+
        /**
         * @set_property:
         *
@@ -717,1335 +548,140 @@ struct drm_crtc_funcs {
         * Everything added from this callback should be unregistered in
         * the early_unregister callback.
         *
-        * Returns:
-        *
-        * 0 on success, or a negative error code on failure.
-        */
-       int (*late_register)(struct drm_crtc *crtc);
-
-       /**
-        * @early_unregister:
-        *
-        * This optional hook should be used to unregister the additional
-        * userspace interfaces attached to the crtc from
-        * late_unregister(). It is called from drm_dev_unregister(),
-        * early in the driver unload sequence to disable userspace access
-        * before data structures are torndown.
-        */
-       void (*early_unregister)(struct drm_crtc *crtc);
-};
-
-/**
- * struct drm_crtc - central CRTC control structure
- * @dev: parent DRM device
- * @port: OF node used by drm_of_find_possible_crtcs()
- * @head: list management
- * @name: human readable name, can be overwritten by the driver
- * @mutex: per-CRTC locking
- * @base: base KMS object for ID tracking etc.
- * @primary: primary plane for this CRTC
- * @cursor: cursor plane for this CRTC
- * @cursor_x: current x position of the cursor, used for universal cursor planes
- * @cursor_y: current y position of the cursor, used for universal cursor planes
- * @enabled: is this CRTC enabled?
- * @mode: current mode timings
- * @hwmode: mode timings as programmed to hw regs
- * @x: x position on screen
- * @y: y position on screen
- * @funcs: CRTC control functions
- * @gamma_size: size of gamma ramp
- * @gamma_store: gamma ramp values
- * @helper_private: mid-layer private data
- * @properties: property tracking for this CRTC
- *
- * Each CRTC may have one or more connectors associated with it.  This structure
- * allows the CRTC to be controlled.
- */
-struct drm_crtc {
-       struct drm_device *dev;
-       struct device_node *port;
-       struct list_head head;
-
-       char *name;
-
-       /**
-        * @mutex:
-        *
-        * This provides a read lock for the overall crtc state (mode, dpms
-        * state, ...) and a write lock for everything which can be update
-        * without a full modeset (fb, cursor data, crtc properties ...). Full
-        * modeset also need to grab dev->mode_config.connection_mutex.
-        */
-       struct drm_modeset_lock mutex;
-
-       struct drm_mode_object base;
-
-       /* primary and cursor planes for CRTC */
-       struct drm_plane *primary;
-       struct drm_plane *cursor;
-
-       /**
-        * @index: Position inside the mode_config.list, can be used as an array
-        * index. It is invariant over the lifetime of the CRTC.
-        */
-       unsigned index;
-
-       /* position of cursor plane on crtc */
-       int cursor_x;
-       int cursor_y;
-
-       bool enabled;
-
-       /* Requested mode from modesetting. */
-       struct drm_display_mode mode;
-
-       /* Programmed mode in hw, after adjustments for encoders,
-        * crtc, panel scaling etc. Needed for timestamping etc.
-        */
-       struct drm_display_mode hwmode;
-
-       int x, y;
-       const struct drm_crtc_funcs *funcs;
-
-       /* Legacy FB CRTC gamma size for reporting to userspace */
-       uint32_t gamma_size;
-       uint16_t *gamma_store;
-
-       /* if you are using the helper */
-       const struct drm_crtc_helper_funcs *helper_private;
-
-       struct drm_object_properties properties;
-
-       /**
-        * @state:
-        *
-        * Current atomic state for this CRTC.
-        */
-       struct drm_crtc_state *state;
-
-       /**
-        * @commit_list:
-        *
-        * List of &drm_crtc_commit structures tracking pending commits.
-        * Protected by @commit_lock. This list doesn't hold its own full
-        * reference, but burrows it from the ongoing commit. Commit entries
-        * must be removed from this list once the commit is fully completed,
-        * but before it's correspoding &drm_atomic_state gets destroyed.
-        */
-       struct list_head commit_list;
-
-       /**
-        * @commit_lock:
-        *
-        * Spinlock to protect @commit_list.
-        */
-       spinlock_t commit_lock;
-
-       /**
-        * @acquire_ctx:
-        *
-        * Per-CRTC implicit acquire context used by atomic drivers for legacy
-        * IOCTLs, so that atomic drivers can get at the locking acquire
-        * context.
-        */
-       struct drm_modeset_acquire_ctx *acquire_ctx;
-};
-
-/**
- * struct drm_connector_state - mutable connector state
- * @connector: backpointer to the connector
- * @crtc: CRTC to connect connector to, NULL if disabled
- * @best_encoder: can be used by helpers and drivers to select the encoder
- * @state: backpointer to global drm_atomic_state
- */
-struct drm_connector_state {
-       struct drm_connector *connector;
-
-       struct drm_crtc *crtc;  /* do not write directly, use drm_atomic_set_crtc_for_connector() */
-
-       struct drm_encoder *best_encoder;
-
-       struct drm_atomic_state *state;
-};
-
-/**
- * struct drm_connector_funcs - control connectors on a given device
- *
- * Each CRTC may have one or more connectors attached to it.  The functions
- * below allow the core DRM code to control connectors, enumerate available modes,
- * etc.
- */
-struct drm_connector_funcs {
-       /**
-        * @dpms:
-        *
-        * Legacy entry point to set the per-connector DPMS state. Legacy DPMS
-        * is exposed as a standard property on the connector, but diverted to
-        * this callback in the drm core. Note that atomic drivers don't
-        * implement the 4 level DPMS support on the connector any more, but
-        * instead only have an on/off "ACTIVE" property on the CRTC object.
-        *
-        * Drivers implementing atomic modeset should use
-        * drm_atomic_helper_connector_dpms() to implement this hook.
-        *
-        * RETURNS:
-        *
-        * 0 on success or a negative error code on failure.
-        */
-       int (*dpms)(struct drm_connector *connector, int mode);
-
-       /**
-        * @reset:
-        *
-        * Reset connector hardware and software state to off. This function isn't
-        * called by the core directly, only through drm_mode_config_reset().
-        * It's not a helper hook only for historical reasons.
-        *
-        * Atomic drivers can use drm_atomic_helper_connector_reset() to reset
-        * atomic state using this hook.
-        */
-       void (*reset)(struct drm_connector *connector);
-
-       /**
-        * @detect:
-        *
-        * Check to see if anything is attached to the connector. The parameter
-        * force is set to false whilst polling, true when checking the
-        * connector due to a user request. force can be used by the driver to
-        * avoid expensive, destructive operations during automated probing.
-        *
-        * FIXME:
-        *
-        * Note that this hook is only called by the probe helper. It's not in
-        * the helper library vtable purely for historical reasons. The only DRM
-        * core entry point to probe connector state is @fill_modes.
-        *
-        * RETURNS:
-        *
-        * drm_connector_status indicating the connector's status.
-        */
-       enum drm_connector_status (*detect)(struct drm_connector *connector,
-                                           bool force);
-
-       /**
-        * @force:
-        *
-        * This function is called to update internal encoder state when the
-        * connector is forced to a certain state by userspace, either through
-        * the sysfs interfaces or on the kernel cmdline. In that case the
-        * @detect callback isn't called.
-        *
-        * FIXME:
-        *
-        * Note that this hook is only called by the probe helper. It's not in
-        * the helper library vtable purely for historical reasons. The only DRM
-        * core entry point to probe connector state is @fill_modes.
-        */
-       void (*force)(struct drm_connector *connector);
-
-       /**
-        * @fill_modes:
-        *
-        * Entry point for output detection and basic mode validation. The
-        * driver should reprobe the output if needed (e.g. when hotplug
-        * handling is unreliable), add all detected modes to connector->modes
-        * and filter out any the device can't support in any configuration. It
-        * also needs to filter out any modes wider or higher than the
-        * parameters max_width and max_height indicate.
-        *
-        * The drivers must also prune any modes no longer valid from
-        * connector->modes. Furthermore it must update connector->status and
-        * connector->edid.  If no EDID has been received for this output
-        * connector->edid must be NULL.
-        *
-        * Drivers using the probe helpers should use
-        * drm_helper_probe_single_connector_modes() or
-        * drm_helper_probe_single_connector_modes_nomerge() to implement this
-        * function.
-        *
-        * RETURNS:
-        *
-        * The number of modes detected and filled into connector->modes.
-        */
-       int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
-
-       /**
-        * @set_property:
-        *
-        * This is the legacy entry point to update a property attached to the
-        * connector.
-        *
-        * Drivers implementing atomic modeset should use
-        * drm_atomic_helper_connector_set_property() to implement this hook.
-        *
-        * This callback is optional if the driver does not support any legacy
-        * driver-private properties.
-        *
-        * RETURNS:
-        *
-        * 0 on success or a negative error code on failure.
-        */
-       int (*set_property)(struct drm_connector *connector, struct drm_property *property,
-                            uint64_t val);
-
-       /**
-        * @late_register:
-        *
-        * This optional hook can be used to register additional userspace
-        * interfaces attached to the connector, light backlight control, i2c,
-        * DP aux or similar interfaces. It is called late in the driver load
-        * sequence from drm_connector_register() when registering all the
-        * core drm connector interfaces. Everything added from this callback
-        * should be unregistered in the early_unregister callback.
-        *
-        * Returns:
-        *
-        * 0 on success, or a negative error code on failure.
-        */
-       int (*late_register)(struct drm_connector *connector);
-
-       /**
-        * @early_unregister:
-        *
-        * This optional hook should be used to unregister the additional
-        * userspace interfaces attached to the connector from
-        * late_unregister(). It is called from drm_connector_unregister(),
-        * early in the driver unload sequence to disable userspace access
-        * before data structures are torndown.
-        */
-       void (*early_unregister)(struct drm_connector *connector);
-
-       /**
-        * @destroy:
-        *
-        * Clean up connector resources. This is called at driver unload time
-        * through drm_mode_config_cleanup(). It can also be called at runtime
-        * when a connector is being hot-unplugged for drivers that support
-        * connector hotplugging (e.g. DisplayPort MST).
-        */
-       void (*destroy)(struct drm_connector *connector);
-
-       /**
-        * @atomic_duplicate_state:
-        *
-        * Duplicate the current atomic state for this connector and return it.
-        * The core and helpers gurantee that any atomic state duplicated with
-        * this hook and still owned by the caller (i.e. not transferred to the
-        * driver by calling ->atomic_commit() from struct
-        * &drm_mode_config_funcs) will be cleaned up by calling the
-        * @atomic_destroy_state hook in this structure.
-        *
-        * Atomic drivers which don't subclass struct &drm_connector_state should use
-        * drm_atomic_helper_connector_duplicate_state(). Drivers that subclass the
-        * state structure to extend it with driver-private state should use
-        * __drm_atomic_helper_connector_duplicate_state() to make sure shared state is
-        * duplicated in a consistent fashion across drivers.
-        *
-        * It is an error to call this hook before connector->state has been
-        * initialized correctly.
-        *
-        * NOTE:
-        *
-        * If the duplicate state references refcounted resources this hook must
-        * acquire a reference for each of them. The driver must release these
-        * references again in @atomic_destroy_state.
-        *
-        * RETURNS:
-        *
-        * Duplicated atomic state or NULL when the allocation failed.
-        */
-       struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector);
-
-       /**
-        * @atomic_destroy_state:
-        *
-        * Destroy a state duplicated with @atomic_duplicate_state and release
-        * or unreference all resources it references
-        */
-       void (*atomic_destroy_state)(struct drm_connector *connector,
-                                    struct drm_connector_state *state);
-
-       /**
-        * @atomic_set_property:
-        *
-        * Decode a driver-private property value and store the decoded value
-        * into the passed-in state structure. Since the atomic core decodes all
-        * standardized properties (even for extensions beyond the core set of
-        * properties which might not be implemented by all drivers) this
-        * requires drivers to subclass the state structure.
-        *
-        * Such driver-private properties should really only be implemented for
-        * truly hardware/vendor specific state. Instead it is preferred to
-        * standardize atomic extension and decode the properties used to expose
-        * such an extension in the core.
-        *
-        * Do not call this function directly, use
-        * drm_atomic_connector_set_property() instead.
-        *
-        * This callback is optional if the driver does not support any
-        * driver-private atomic properties.
-        *
-        * NOTE:
-        *
-        * This function is called in the state assembly phase of atomic
-        * modesets, which can be aborted for any reason (including on
-        * userspace's request to just check whether a configuration would be
-        * possible). Drivers MUST NOT touch any persistent state (hardware or
-        * software) or data structures except the passed in @state parameter.
-        *
-        * Also since userspace controls in which order properties are set this
-        * function must not do any input validation (since the state update is
-        * incomplete and hence likely inconsistent). Instead any such input
-        * validation must be done in the various atomic_check callbacks.
-        *
-        * RETURNS:
-        *
-        * 0 if the property has been found, -EINVAL if the property isn't
-        * implemented by the driver (which shouldn't ever happen, the core only
-        * asks for properties attached to this connector). No other validation
-        * is allowed by the driver. The core already checks that the property
-        * value is within the range (integer, valid enum value, ...) the driver
-        * set when registering the property.
-        */
-       int (*atomic_set_property)(struct drm_connector *connector,
-                                  struct drm_connector_state *state,
-                                  struct drm_property *property,
-                                  uint64_t val);
-
-       /**
-        * @atomic_get_property:
-        *
-        * Reads out the decoded driver-private property. This is used to
-        * implement the GETCONNECTOR IOCTL.
-        *
-        * Do not call this function directly, use
-        * drm_atomic_connector_get_property() instead.
-        *
-        * This callback is optional if the driver does not support any
-        * driver-private atomic properties.
-        *
-        * RETURNS:
-        *
-        * 0 on success, -EINVAL if the property isn't implemented by the
-        * driver (which shouldn't ever happen, the core only asks for
-        * properties attached to this connector).
-        */
-       int (*atomic_get_property)(struct drm_connector *connector,
-                                  const struct drm_connector_state *state,
-                                  struct drm_property *property,
-                                  uint64_t *val);
-};
-
-/**
- * struct drm_encoder_funcs - encoder controls
- *
- * Encoders sit between CRTCs and connectors.
- */
-struct drm_encoder_funcs {
-       /**
-        * @reset:
-        *
-        * Reset encoder hardware and software state to off. This function isn't
-        * called by the core directly, only through drm_mode_config_reset().
-        * It's not a helper hook only for historical reasons.
-        */
-       void (*reset)(struct drm_encoder *encoder);
-
-       /**
-        * @destroy:
-        *
-        * Clean up encoder resources. This is only called at driver unload time
-        * through drm_mode_config_cleanup() since an encoder cannot be
-        * hotplugged in DRM.
-        */
-       void (*destroy)(struct drm_encoder *encoder);
-
-       /**
-        * @late_register:
-        *
-        * This optional hook can be used to register additional userspace
-        * interfaces attached to the encoder like debugfs interfaces.
-        * It is called late in the driver load sequence from drm_dev_register().
-        * Everything added from this callback should be unregistered in
-        * the early_unregister callback.
-        *
-        * Returns:
-        *
-        * 0 on success, or a negative error code on failure.
-        */
-       int (*late_register)(struct drm_encoder *encoder);
-
-       /**
-        * @early_unregister:
-        *
-        * This optional hook should be used to unregister the additional
-        * userspace interfaces attached to the encoder from
-        * late_unregister(). It is called from drm_dev_unregister(),
-        * early in the driver unload sequence to disable userspace access
-        * before data structures are torndown.
-        */
-       void (*early_unregister)(struct drm_encoder *encoder);
-};
-
-#define DRM_CONNECTOR_MAX_ENCODER 3
-
-/**
- * struct drm_encoder - central DRM encoder structure
- * @dev: parent DRM device
- * @head: list management
- * @base: base KMS object
- * @name: human readable name, can be overwritten by the driver
- * @encoder_type: one of the %DRM_MODE_ENCODER_<foo> types in drm_mode.h
- * @possible_crtcs: bitmask of potential CRTC bindings
- * @possible_clones: bitmask of potential sibling encoders for cloning
- * @crtc: currently bound CRTC
- * @bridge: bridge associated to the encoder
- * @funcs: control functions
- * @helper_private: mid-layer private data
- *
- * CRTCs drive pixels to encoders, which convert them into signals
- * appropriate for a given connector or set of connectors.
- */
-struct drm_encoder {
-       struct drm_device *dev;
-       struct list_head head;
-
-       struct drm_mode_object base;
-       char *name;
-       int encoder_type;
-
-       /**
-        * @index: Position inside the mode_config.list, can be used as an array
-        * index. It is invariant over the lifetime of the encoder.
-        */
-       unsigned index;
-
-       uint32_t possible_crtcs;
-       uint32_t possible_clones;
-
-       struct drm_crtc *crtc;
-       struct drm_bridge *bridge;
-       const struct drm_encoder_funcs *funcs;
-       const struct drm_encoder_helper_funcs *helper_private;
-};
-
-/* should we poll this connector for connects and disconnects */
-/* hot plug detectable */
-#define DRM_CONNECTOR_POLL_HPD (1 << 0)
-/* poll for connections */
-#define DRM_CONNECTOR_POLL_CONNECT (1 << 1)
-/* can cleanly poll for disconnections without flickering the screen */
-/* DACs should rarely do this without a lot of testing */
-#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)
-
-#define MAX_ELD_BYTES  128
-
-/**
- * struct drm_connector - central DRM connector control structure
- * @dev: parent DRM device
- * @kdev: kernel device for sysfs attributes
- * @attr: sysfs attributes
- * @head: list management
- * @base: base KMS object
- * @name: human readable name, can be overwritten by the driver
- * @connector_type: one of the %DRM_MODE_CONNECTOR_<foo> types from drm_mode.h
- * @connector_type_id: index into connector type enum
- * @interlace_allowed: can this connector handle interlaced modes?
- * @doublescan_allowed: can this connector handle doublescan?
- * @stereo_allowed: can this connector handle stereo modes?
- * @registered: is this connector exposed (registered) with userspace?
- * @modes: modes available on this connector (from fill_modes() + user)
- * @status: one of the drm_connector_status enums (connected, not, or unknown)
- * @probed_modes: list of modes derived directly from the display
- * @display_info: information about attached display (e.g. from EDID)
- * @funcs: connector control functions
- * @edid_blob_ptr: DRM property containing EDID if present
- * @properties: property tracking for this connector
- * @polled: a %DRM_CONNECTOR_POLL_<foo> value for core driven polling
- * @dpms: current dpms state
- * @helper_private: mid-layer private data
- * @cmdline_mode: mode line parsed from the kernel cmdline for this connector
- * @force: a %DRM_FORCE_<foo> state for forced mode sets
- * @override_edid: has the EDID been overwritten through debugfs for testing?
- * @encoder_ids: valid encoders for this connector
- * @encoder: encoder driving this connector, if any
- * @eld: EDID-like data, if present
- * @dvi_dual: dual link DVI, if found
- * @max_tmds_clock: max clock rate, if found
- * @latency_present: AV delay info from ELD, if found
- * @video_latency: video latency info from ELD, if found
- * @audio_latency: audio latency info from ELD, if found
- * @null_edid_counter: track sinks that give us all zeros for the EDID
- * @bad_edid_counter: track sinks that give us an EDID with invalid checksum
- * @edid_corrupt: indicates whether the last read EDID was corrupt
- * @debugfs_entry: debugfs directory for this connector
- * @state: current atomic state for this connector
- * @has_tile: is this connector connected to a tiled monitor
- * @tile_group: tile group for the connected monitor
- * @tile_is_single_monitor: whether the tile is one monitor housing
- * @num_h_tile: number of horizontal tiles in the tile group
- * @num_v_tile: number of vertical tiles in the tile group
- * @tile_h_loc: horizontal location of this tile
- * @tile_v_loc: vertical location of this tile
- * @tile_h_size: horizontal size of this tile.
- * @tile_v_size: vertical size of this tile.
- *
- * Each connector may be connected to one or more CRTCs, or may be clonable by
- * another connector if they can share a CRTC.  Each connector also has a specific
- * position in the broader display (referred to as a 'screen' though it could
- * span multiple monitors).
- */
-struct drm_connector {
-       struct drm_device *dev;
-       struct device *kdev;
-       struct device_attribute *attr;
-       struct list_head head;
-
-       struct drm_mode_object base;
-
-       char *name;
-
-       /**
-        * @index: Compacted connector index, which matches the position inside
-        * the mode_config.list for drivers not supporting hot-add/removing. Can
-        * be used as an array index. It is invariant over the lifetime of the
-        * connector.
-        */
-       unsigned index;
-
-       int connector_type;
-       int connector_type_id;
-       bool interlace_allowed;
-       bool doublescan_allowed;
-       bool stereo_allowed;
-       bool registered;
-       struct list_head modes; /* list of modes on this connector */
-
-       enum drm_connector_status status;
-
-       /* these are modes added by probing with DDC or the BIOS */
-       struct list_head probed_modes;
-
-       struct drm_display_info display_info;
-       const struct drm_connector_funcs *funcs;
-
-       struct drm_property_blob *edid_blob_ptr;
-       struct drm_object_properties properties;
-
-       /**
-        * @path_blob_ptr:
-        *
-        * DRM blob property data for the DP MST path property.
-        */
-       struct drm_property_blob *path_blob_ptr;
-
-       /**
-        * @tile_blob_ptr:
-        *
-        * DRM blob property data for the tile property (used mostly by DP MST).
-        * This is meant for screens which are driven through separate display
-        * pipelines represented by &drm_crtc, which might not be running with
-        * genlocked clocks. For tiled panels which are genlocked, like
-        * dual-link LVDS or dual-link DSI, the driver should try to not expose
-        * the tiling and virtualize both &drm_crtc and &drm_plane if needed.
-        */
-       struct drm_property_blob *tile_blob_ptr;
-
-       uint8_t polled; /* DRM_CONNECTOR_POLL_* */
-
-       /* requested DPMS state */
-       int dpms;
-
-       const struct drm_connector_helper_funcs *helper_private;
-
-       /* forced on connector */
-       struct drm_cmdline_mode cmdline_mode;
-       enum drm_connector_force force;
-       bool override_edid;
-       uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
-       struct drm_encoder *encoder; /* currently active encoder */
-
-       /* EDID bits */
-       uint8_t eld[MAX_ELD_BYTES];
-       bool dvi_dual;
-       int max_tmds_clock;     /* in MHz */
-       bool latency_present[2];
-       int video_latency[2];   /* [0]: progressive, [1]: interlaced */
-       int audio_latency[2];
-       int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
-       unsigned bad_edid_counter;
-
-       /* Flag for raw EDID header corruption - used in Displayport
-        * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6
-        */
-       bool edid_corrupt;
-
-       struct dentry *debugfs_entry;
-
-       struct drm_connector_state *state;
-
-       /* DisplayID bits */
-       bool has_tile;
-       struct drm_tile_group *tile_group;
-       bool tile_is_single_monitor;
-
-       uint8_t num_h_tile, num_v_tile;
-       uint8_t tile_h_loc, tile_v_loc;
-       uint16_t tile_h_size, tile_v_size;
-};
-
-/**
- * struct drm_plane_state - mutable plane state
- * @plane: backpointer to the plane
- * @crtc: currently bound CRTC, NULL if disabled
- * @fb: currently bound framebuffer
- * @fence: optional fence to wait for before scanning out @fb
- * @crtc_x: left position of visible portion of plane on crtc
- * @crtc_y: upper position of visible portion of plane on crtc
- * @crtc_w: width of visible portion of plane on crtc
- * @crtc_h: height of visible portion of plane on crtc
- * @src_x: left position of visible portion of plane within
- *     plane (in 16.16)
- * @src_y: upper position of visible portion of plane within
- *     plane (in 16.16)
- * @src_w: width of visible portion of plane (in 16.16)
- * @src_h: height of visible portion of plane (in 16.16)
- * @rotation: rotation of the plane
- * @zpos: priority of the given plane on crtc (optional)
- * @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1
- *     where N is the number of active planes for given crtc
- * @state: backpointer to global drm_atomic_state
- */
-struct drm_plane_state {
-       struct drm_plane *plane;
-
-       struct drm_crtc *crtc;   /* do not write directly, use drm_atomic_set_crtc_for_plane() */
-       struct drm_framebuffer *fb;  /* do not write directly, use drm_atomic_set_fb_for_plane() */
-       struct fence *fence;
-
-       /* Signed dest location allows it to be partially off screen */
-       int32_t crtc_x, crtc_y;
-       uint32_t crtc_w, crtc_h;
-
-       /* Source values are 16.16 fixed point */
-       uint32_t src_x, src_y;
-       uint32_t src_h, src_w;
-
-       /* Plane rotation */
-       unsigned int rotation;
-
-       /* Plane zpos */
-       unsigned int zpos;
-       unsigned int normalized_zpos;
-
-       struct drm_atomic_state *state;
-};
-
-
-/**
- * struct drm_plane_funcs - driver plane control functions
- */
-struct drm_plane_funcs {
-       /**
-        * @update_plane:
-        *
-        * This is the legacy entry point to enable and configure the plane for
-        * the given CRTC and framebuffer. It is never called to disable the
-        * plane, i.e. the passed-in crtc and fb paramters are never NULL.
-        *
-        * The source rectangle in frame buffer memory coordinates is given by
-        * the src_x, src_y, src_w and src_h parameters (as 16.16 fixed point
-        * values). Devices that don't support subpixel plane coordinates can
-        * ignore the fractional part.
-        *
-        * The destination rectangle in CRTC coordinates is given by the
-        * crtc_x, crtc_y, crtc_w and crtc_h parameters (as integer values).
-        * Devices scale the source rectangle to the destination rectangle. If
-        * scaling is not supported, and the source rectangle size doesn't match
-        * the destination rectangle size, the driver must return a
-        * -<errorname>EINVAL</errorname> error.
-        *
-        * Drivers implementing atomic modeset should use
-        * drm_atomic_helper_update_plane() to implement this hook.
-        *
-        * RETURNS:
-        *
-        * 0 on success or a negative error code on failure.
-        */
-       int (*update_plane)(struct drm_plane *plane,
-                           struct drm_crtc *crtc, struct drm_framebuffer *fb,
-                           int crtc_x, int crtc_y,
-                           unsigned int crtc_w, unsigned int crtc_h,
-                           uint32_t src_x, uint32_t src_y,
-                           uint32_t src_w, uint32_t src_h);
-
-       /**
-        * @disable_plane:
-        *
-        * This is the legacy entry point to disable the plane. The DRM core
-        * calls this method in response to a DRM_IOCTL_MODE_SETPLANE IOCTL call
-        * with the frame buffer ID set to 0.  Disabled planes must not be
-        * processed by the CRTC.
-        *
-        * Drivers implementing atomic modeset should use
-        * drm_atomic_helper_disable_plane() to implement this hook.
-        *
-        * RETURNS:
-        *
-        * 0 on success or a negative error code on failure.
-        */
-       int (*disable_plane)(struct drm_plane *plane);
-
-       /**
-        * @destroy:
-        *
-        * Clean up plane resources. This is only called at driver unload time
-        * through drm_mode_config_cleanup() since a plane cannot be hotplugged
-        * in DRM.
-        */
-       void (*destroy)(struct drm_plane *plane);
-
-       /**
-        * @reset:
-        *
-        * Reset plane hardware and software state to off. This function isn't
-        * called by the core directly, only through drm_mode_config_reset().
-        * It's not a helper hook only for historical reasons.
-        *
-        * Atomic drivers can use drm_atomic_helper_plane_reset() to reset
-        * atomic state using this hook.
-        */
-       void (*reset)(struct drm_plane *plane);
-
-       /**
-        * @set_property:
-        *
-        * This is the legacy entry point to update a property attached to the
-        * plane.
-        *
-        * Drivers implementing atomic modeset should use
-        * drm_atomic_helper_plane_set_property() to implement this hook.
-        *
-        * This callback is optional if the driver does not support any legacy
-        * driver-private properties.
-        *
-        * RETURNS:
-        *
-        * 0 on success or a negative error code on failure.
-        */
-       int (*set_property)(struct drm_plane *plane,
-                           struct drm_property *property, uint64_t val);
-
-       /**
-        * @atomic_duplicate_state:
-        *
-        * Duplicate the current atomic state for this plane and return it.
-        * The core and helpers gurantee that any atomic state duplicated with
-        * this hook and still owned by the caller (i.e. not transferred to the
-        * driver by calling ->atomic_commit() from struct
-        * &drm_mode_config_funcs) will be cleaned up by calling the
-        * @atomic_destroy_state hook in this structure.
-        *
-        * Atomic drivers which don't subclass struct &drm_plane_state should use
-        * drm_atomic_helper_plane_duplicate_state(). Drivers that subclass the
-        * state structure to extend it with driver-private state should use
-        * __drm_atomic_helper_plane_duplicate_state() to make sure shared state is
-        * duplicated in a consistent fashion across drivers.
-        *
-        * It is an error to call this hook before plane->state has been
-        * initialized correctly.
-        *
-        * NOTE:
-        *
-        * If the duplicate state references refcounted resources this hook must
-        * acquire a reference for each of them. The driver must release these
-        * references again in @atomic_destroy_state.
-        *
-        * RETURNS:
-        *
-        * Duplicated atomic state or NULL when the allocation failed.
-        */
-       struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
-
-       /**
-        * @atomic_destroy_state:
-        *
-        * Destroy a state duplicated with @atomic_duplicate_state and release
-        * or unreference all resources it references
-        */
-       void (*atomic_destroy_state)(struct drm_plane *plane,
-                                    struct drm_plane_state *state);
-
-       /**
-        * @atomic_set_property:
-        *
-        * Decode a driver-private property value and store the decoded value
-        * into the passed-in state structure. Since the atomic core decodes all
-        * standardized properties (even for extensions beyond the core set of
-        * properties which might not be implemented by all drivers) this
-        * requires drivers to subclass the state structure.
-        *
-        * Such driver-private properties should really only be implemented for
-        * truly hardware/vendor specific state. Instead it is preferred to
-        * standardize atomic extension and decode the properties used to expose
-        * such an extension in the core.
-        *
-        * Do not call this function directly, use
-        * drm_atomic_plane_set_property() instead.
-        *
-        * This callback is optional if the driver does not support any
-        * driver-private atomic properties.
-        *
-        * NOTE:
-        *
-        * This function is called in the state assembly phase of atomic
-        * modesets, which can be aborted for any reason (including on
-        * userspace's request to just check whether a configuration would be
-        * possible). Drivers MUST NOT touch any persistent state (hardware or
-        * software) or data structures except the passed in @state parameter.
-        *
-        * Also since userspace controls in which order properties are set this
-        * function must not do any input validation (since the state update is
-        * incomplete and hence likely inconsistent). Instead any such input
-        * validation must be done in the various atomic_check callbacks.
-        *
-        * RETURNS:
-        *
-        * 0 if the property has been found, -EINVAL if the property isn't
-        * implemented by the driver (which shouldn't ever happen, the core only
-        * asks for properties attached to this plane). No other validation is
-        * allowed by the driver. The core already checks that the property
-        * value is within the range (integer, valid enum value, ...) the driver
-        * set when registering the property.
-        */
-       int (*atomic_set_property)(struct drm_plane *plane,
-                                  struct drm_plane_state *state,
-                                  struct drm_property *property,
-                                  uint64_t val);
-
-       /**
-        * @atomic_get_property:
-        *
-        * Reads out the decoded driver-private property. This is used to
-        * implement the GETPLANE IOCTL.
-        *
-        * Do not call this function directly, use
-        * drm_atomic_plane_get_property() instead.
-        *
-        * This callback is optional if the driver does not support any
-        * driver-private atomic properties.
-        *
-        * RETURNS:
-        *
-        * 0 on success, -EINVAL if the property isn't implemented by the
-        * driver (which should never happen, the core only asks for
-        * properties attached to this plane).
-        */
-       int (*atomic_get_property)(struct drm_plane *plane,
-                                  const struct drm_plane_state *state,
-                                  struct drm_property *property,
-                                  uint64_t *val);
-       /**
-        * @late_register:
-        *
-        * This optional hook can be used to register additional userspace
-        * interfaces attached to the plane like debugfs interfaces.
-        * It is called late in the driver load sequence from drm_dev_register().
-        * Everything added from this callback should be unregistered in
-        * the early_unregister callback.
-        *
-        * Returns:
-        *
-        * 0 on success, or a negative error code on failure.
-        */
-       int (*late_register)(struct drm_plane *plane);
-
-       /**
-        * @early_unregister:
-        *
-        * This optional hook should be used to unregister the additional
-        * userspace interfaces attached to the plane from
-        * late_unregister(). It is called from drm_dev_unregister(),
-        * early in the driver unload sequence to disable userspace access
-        * before data structures are torndown.
-        */
-       void (*early_unregister)(struct drm_plane *plane);
-};
-
-enum drm_plane_type {
-       DRM_PLANE_TYPE_OVERLAY,
-       DRM_PLANE_TYPE_PRIMARY,
-       DRM_PLANE_TYPE_CURSOR,
-};
-
-
-/**
- * struct drm_plane - central DRM plane control structure
- * @dev: DRM device this plane belongs to
- * @head: for list management
- * @name: human readable name, can be overwritten by the driver
- * @base: base mode object
- * @possible_crtcs: pipes this plane can be bound to
- * @format_types: array of formats supported by this plane
- * @format_count: number of formats supported
- * @format_default: driver hasn't supplied supported formats for the plane
- * @crtc: currently bound CRTC
- * @fb: currently bound fb
- * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by
- *     drm_mode_set_config_internal() to implement correct refcounting.
- * @funcs: helper functions
- * @properties: property tracking for this plane
- * @type: type of plane (overlay, primary, cursor)
- * @state: current atomic state for this plane
- * @zpos_property: zpos property for this plane
- * @helper_private: mid-layer private data
- */
-struct drm_plane {
-       struct drm_device *dev;
-       struct list_head head;
-
-       char *name;
-
-       /**
-        * @mutex:
-        *
-        * Protects modeset plane state, together with the mutex of &drm_crtc
-        * this plane is linked to (when active, getting actived or getting
-        * disabled).
-        */
-       struct drm_modeset_lock mutex;
-
-       struct drm_mode_object base;
-
-       uint32_t possible_crtcs;
-       uint32_t *format_types;
-       unsigned int format_count;
-       bool format_default;
-
-       struct drm_crtc *crtc;
-       struct drm_framebuffer *fb;
-
-       struct drm_framebuffer *old_fb;
-
-       const struct drm_plane_funcs *funcs;
-
-       struct drm_object_properties properties;
-
-       enum drm_plane_type type;
-
-       /**
-        * @index: Position inside the mode_config.list, can be used as an array
-        * index. It is invariant over the lifetime of the plane.
-        */
-       unsigned index;
-
-       const struct drm_plane_helper_funcs *helper_private;
-
-       struct drm_plane_state *state;
-
-       struct drm_property *zpos_property;
-};
-
-/**
- * struct drm_bridge_funcs - drm_bridge control functions
- * @attach: Called during drm_bridge_attach
- */
-struct drm_bridge_funcs {
-       int (*attach)(struct drm_bridge *bridge);
-
-       /**
-        * @mode_fixup:
-        *
-        * This callback is used to validate and adjust a mode. The paramater
-        * mode is the display mode that should be fed to the next element in
-        * the display chain, either the final &drm_connector or the next
-        * &drm_bridge. The parameter adjusted_mode is the input mode the bridge
-        * requires. It can be modified by this callback and does not need to
-        * match mode.
-        *
-        * This is the only hook that allows a bridge to reject a modeset. If
-        * this function passes all other callbacks must succeed for this
-        * configuration.
-        *
-        * NOTE:
-        *
-        * This function is called in the check phase of atomic modesets, which
-        * can be aborted for any reason (including on userspace's request to
-        * just check whether a configuration would be possible). Drivers MUST
-        * NOT touch any persistent state (hardware or software) or data
-        * structures except the passed in @state parameter.
-        *
-        * RETURNS:
-        *
-        * True if an acceptable configuration is possible, false if the modeset
-        * operation should be rejected.
-        */
-       bool (*mode_fixup)(struct drm_bridge *bridge,
-                          const struct drm_display_mode *mode,
-                          struct drm_display_mode *adjusted_mode);
-       /**
-        * @disable:
-        *
-        * This callback should disable the bridge. It is called right before
-        * the preceding element in the display pipe is disabled. If the
-        * preceding element is a bridge this means it's called before that
-        * bridge's ->disable() function. If the preceding element is a
-        * &drm_encoder it's called right before the encoder's ->disable(),
-        * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_funcs.
-        *
-        * The bridge can assume that the display pipe (i.e. clocks and timing
-        * signals) feeding it is still running when this callback is called.
-        *
-        * The disable callback is optional.
-        */
-       void (*disable)(struct drm_bridge *bridge);
-
-       /**
-        * @post_disable:
-        *
-        * This callback should disable the bridge. It is called right after
-        * the preceding element in the display pipe is disabled. If the
-        * preceding element is a bridge this means it's called after that
-        * bridge's ->post_disable() function. If the preceding element is a
-        * &drm_encoder it's called right after the encoder's ->disable(),
-        * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_funcs.
-        *
-        * The bridge must assume that the display pipe (i.e. clocks and timing
-        * singals) feeding it is no longer running when this callback is
-        * called.
-        *
-        * The post_disable callback is optional.
-        */
-       void (*post_disable)(struct drm_bridge *bridge);
-
-       /**
-        * @mode_set:
-        *
-        * This callback should set the given mode on the bridge. It is called
-        * after the ->mode_set() callback for the preceding element in the
-        * display pipeline has been called already. The display pipe (i.e.
-        * clocks and timing signals) is off when this function is called.
-        */
-       void (*mode_set)(struct drm_bridge *bridge,
-                        struct drm_display_mode *mode,
-                        struct drm_display_mode *adjusted_mode);
-       /**
-        * @pre_enable:
-        *
-        * This callback should enable the bridge. It is called right before
-        * the preceding element in the display pipe is enabled. If the
-        * preceding element is a bridge this means it's called before that
-        * bridge's ->pre_enable() function. If the preceding element is a
-        * &drm_encoder it's called right before the encoder's ->enable(),
-        * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs.
-        *
-        * The display pipe (i.e. clocks and timing signals) feeding this bridge
-        * will not yet be running when this callback is called. The bridge must
-        * not enable the display link feeding the next bridge in the chain (if
-        * there is one) when this callback is called.
+        * Returns:
         *
-        * The pre_enable callback is optional.
+        * 0 on success, or a negative error code on failure.
         */
-       void (*pre_enable)(struct drm_bridge *bridge);
+       int (*late_register)(struct drm_crtc *crtc);
 
        /**
-        * @enable:
-        *
-        * This callback should enable the bridge. It is called right after
-        * the preceding element in the display pipe is enabled. If the
-        * preceding element is a bridge this means it's called after that
-        * bridge's ->enable() function. If the preceding element is a
-        * &drm_encoder it's called right after the encoder's ->enable(),
-        * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs.
-        *
-        * The bridge can assume that the display pipe (i.e. clocks and timing
-        * signals) feeding it is running when this callback is called. This
-        * callback must enable the display link feeding the next bridge in the
-        * chain if there is one.
+        * @early_unregister:
         *
-        * The enable callback is optional.
+        * This optional hook should be used to unregister the additional
+        * userspace interfaces attached to the crtc from
+        * late_unregister(). It is called from drm_dev_unregister(),
+        * early in the driver unload sequence to disable userspace access
+        * before data structures are torndown.
         */
-       void (*enable)(struct drm_bridge *bridge);
+       void (*early_unregister)(struct drm_crtc *crtc);
 };
 
 /**
- * struct drm_bridge - central DRM bridge control structure
- * @dev: DRM device this bridge belongs to
- * @encoder: encoder to which this bridge is connected
- * @next: the next bridge in the encoder chain
- * @of_node: device node pointer to the bridge
- * @list: to keep track of all added bridges
- * @funcs: control functions
- * @driver_private: pointer to the bridge driver's internal context
+ * struct drm_crtc - central CRTC control structure
+ * @dev: parent DRM device
+ * @port: OF node used by drm_of_find_possible_crtcs()
+ * @head: list management
+ * @name: human readable name, can be overwritten by the driver
+ * @mutex: per-CRTC locking
+ * @base: base KMS object for ID tracking etc.
+ * @primary: primary plane for this CRTC
+ * @cursor: cursor plane for this CRTC
+ * @cursor_x: current x position of the cursor, used for universal cursor planes
+ * @cursor_y: current y position of the cursor, used for universal cursor planes
+ * @enabled: is this CRTC enabled?
+ * @mode: current mode timings
+ * @hwmode: mode timings as programmed to hw regs
+ * @x: x position on screen
+ * @y: y position on screen
+ * @funcs: CRTC control functions
+ * @gamma_size: size of gamma ramp
+ * @gamma_store: gamma ramp values
+ * @helper_private: mid-layer private data
+ * @properties: property tracking for this CRTC
+ *
+ * Each CRTC may have one or more connectors associated with it.  This structure
+ * allows the CRTC to be controlled.
  */
-struct drm_bridge {
+struct drm_crtc {
        struct drm_device *dev;
-       struct drm_encoder *encoder;
-       struct drm_bridge *next;
-#ifdef CONFIG_OF
-       struct device_node *of_node;
-#endif
-       struct list_head list;
-
-       const struct drm_bridge_funcs *funcs;
-       void *driver_private;
-};
+       struct device_node *port;
+       struct list_head head;
 
-/**
- * struct drm_crtc_commit - track modeset commits on a CRTC
- *
- * This structure is used to track pending modeset changes and atomic commit on
- * a per-CRTC basis. Since updating the list should never block this structure
- * is reference counted to allow waiters to safely wait on an event to complete,
- * without holding any locks.
- *
- * It has 3 different events in total to allow a fine-grained synchronization
- * between outstanding updates::
- *
- *     atomic commit thread                    hardware
- *
- *     write new state into hardware   ---->   ...
- *     signal hw_done
- *                                             switch to new state on next
- *     ...                                     v/hblank
- *
- *     wait for buffers to show up             ...
- *
- *     ...                                     send completion irq
- *                                             irq handler signals flip_done
- *     cleanup old buffers
- *
- *     signal cleanup_done
- *
- *     wait for flip_done              <----
- *     clean up atomic state
- *
- * The important bit to know is that cleanup_done is the terminal event, but the
- * ordering between flip_done and hw_done is entirely up to the specific driver
- * and modeset state change.
- *
- * For an implementation of how to use this look at
- * drm_atomic_helper_setup_commit() from the atomic helper library.
- */
-struct drm_crtc_commit {
-       /**
-        * @crtc:
-        *
-        * DRM CRTC for this commit.
-        */
-       struct drm_crtc *crtc;
+       char *name;
 
        /**
-        * @ref:
+        * @mutex:
         *
-        * Reference count for this structure. Needed to allow blocking on
-        * completions without the risk of the completion disappearing
-        * meanwhile.
+        * This provides a read lock for the overall crtc state (mode, dpms
+        * state, ...) and a write lock for everything which can be update
+        * without a full modeset (fb, cursor data, crtc properties ...). Full
+        * modeset also need to grab dev->mode_config.connection_mutex.
         */
-       struct kref ref;
+       struct drm_modeset_lock mutex;
+
+       struct drm_mode_object base;
+
+       /* primary and cursor planes for CRTC */
+       struct drm_plane *primary;
+       struct drm_plane *cursor;
 
        /**
-        * @flip_done:
-        *
-        * Will be signaled when the hardware has flipped to the new set of
-        * buffers. Signals at the same time as when the drm event for this
-        * commit is sent to userspace, or when an out-fence is singalled. Note
-        * that for most hardware, in most cases this happens after @hw_done is
-        * signalled.
+        * @index: Position inside the mode_config.list, can be used as an array
+        * index. It is invariant over the lifetime of the CRTC.
         */
-       struct completion flip_done;
+       unsigned index;
 
-       /**
-        * @hw_done:
-        *
-        * Will be signalled when all hw register changes for this commit have
-        * been written out. Especially when disabling a pipe this can be much
-        * later than than @flip_done, since that can signal already when the
-        * screen goes black, whereas to fully shut down a pipe more register
-        * I/O is required.
-        *
-        * Note that this does not need to include separately reference-counted
-        * resources like backing storage buffer pinning, or runtime pm
-        * management.
+       /* position of cursor plane on crtc */
+       int cursor_x;
+       int cursor_y;
+
+       bool enabled;
+
+       /* Requested mode from modesetting. */
+       struct drm_display_mode mode;
+
+       /* Programmed mode in hw, after adjustments for encoders,
+        * crtc, panel scaling etc. Needed for timestamping etc.
         */
-       struct completion hw_done;
+       struct drm_display_mode hwmode;
+
+       int x, y;
+       const struct drm_crtc_funcs *funcs;
+
+       /* Legacy FB CRTC gamma size for reporting to userspace */
+       uint32_t gamma_size;
+       uint16_t *gamma_store;
+
+       /* if you are using the helper */
+       const struct drm_crtc_helper_funcs *helper_private;
+
+       struct drm_object_properties properties;
 
        /**
-        * @cleanup_done:
+        * @state:
         *
-        * Will be signalled after old buffers have been cleaned up by calling
-        * drm_atomic_helper_cleanup_planes(). Since this can only happen after
-        * a vblank wait completed it might be a bit later. This completion is
-        * useful to throttle updates and avoid hardware updates getting ahead
-        * of the buffer cleanup too much.
+        * Current atomic state for this CRTC.
         */
-       struct completion cleanup_done;
+       struct drm_crtc_state *state;
 
        /**
-        * @commit_entry:
+        * @commit_list:
         *
-        * Entry on the per-CRTC commit_list. Protected by crtc->commit_lock.
+        * List of &drm_crtc_commit structures tracking pending commits.
+        * Protected by @commit_lock. This list doesn't hold its own full
+        * reference, but burrows it from the ongoing commit. Commit entries
+        * must be removed from this list once the commit is fully completed,
+        * but before it's correspoding &drm_atomic_state gets destroyed.
         */
-       struct list_head commit_entry;
+       struct list_head commit_list;
 
        /**
-        * @event:
+        * @commit_lock:
         *
-        * &drm_pending_vblank_event pointer to clean up private events.
+        * Spinlock to protect @commit_list.
         */
-       struct drm_pending_vblank_event *event;
-};
-
-struct __drm_planes_state {
-       struct drm_plane *ptr;
-       struct drm_plane_state *state;
-};
-
-struct __drm_crtcs_state {
-       struct drm_crtc *ptr;
-       struct drm_crtc_state *state;
-       struct drm_crtc_commit *commit;
-};
-
-struct __drm_connnectors_state {
-       struct drm_connector *ptr;
-       struct drm_connector_state *state;
-};
-
-/**
- * struct drm_atomic_state - the global state object for atomic updates
- * @dev: parent DRM device
- * @allow_modeset: allow full modeset
- * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics
- * @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL.
- * @planes: pointer to array of structures with per-plane data
- * @crtcs: pointer to array of CRTC pointers
- * @num_connector: size of the @connectors and @connector_states arrays
- * @connectors: pointer to array of structures with per-connector data
- * @acquire_ctx: acquire context for this atomic modeset state update
- */
-struct drm_atomic_state {
-       struct drm_device *dev;
-       bool allow_modeset : 1;
-       bool legacy_cursor_update : 1;
-       bool legacy_set_config : 1;
-       struct __drm_planes_state *planes;
-       struct __drm_crtcs_state *crtcs;
-       int num_connector;
-       struct __drm_connnectors_state *connectors;
-
-       struct drm_modeset_acquire_ctx *acquire_ctx;
+       spinlock_t commit_lock;
 
        /**
-        * @commit_work:
+        * @acquire_ctx:
         *
-        * Work item which can be used by the driver or helpers to execute the
-        * commit without blocking.
+        * Per-CRTC implicit acquire context used by atomic drivers for legacy
+        * IOCTLs, so that atomic drivers can get at the locking acquire
+        * context.
         */
-       struct work_struct commit_work;
+       struct drm_modeset_acquire_ctx *acquire_ctx;
 };
 
-
 /**
  * struct drm_mode_set - new values for a CRTC config change
  * @fb: framebuffer to use for new config
@@ -2237,17 +873,9 @@ struct drm_mode_config_funcs {
         * CRTC index supplied in &drm_event to userspace.
         *
         * The drm core will supply a struct &drm_event in the event
-        * member of each CRTC's &drm_crtc_state structure. This can be handled by the
-        * drm_crtc_send_vblank_event() function, which the driver should call on
-        * the provided event upon completion of the atomic commit. Note that if
-        * the driver supports vblank signalling and timestamping the vblank
-        * counters and timestamps must agree with the ones returned from page
-        * flip events. With the current vblank helper infrastructure this can
-        * be achieved by holding a vblank reference while the page flip is
-        * pending, acquired through drm_crtc_vblank_get() and released with
-        * drm_crtc_vblank_put(). Drivers are free to implement their own vblank
-        * counter and timestamp tracking though, e.g. if they have accurate
-        * timestamp registers in hardware.
+        * member of each CRTC's &drm_crtc_state structure. See the
+        * documentation for &drm_crtc_state for more details about the precise
+        * semantics of this event.
         *
         * NOTE:
         *
@@ -2635,12 +1263,6 @@ struct drm_mode_config {
         * HDMI infoframe aspect ratio setting.
         */
        struct drm_property *aspect_ratio_property;
-       /**
-        * @dirty_info_property: Optional connector property to give userspace a
-        * hint that the DIRTY_FB ioctl should be used.
-        */
-       struct drm_property *dirty_info_property;
-
        /**
         * @degamma_lut_property: Optional CRTC property to set the LUT used to
         * convert the framebuffer's colors to linear gamma.
@@ -2702,43 +1324,7 @@ struct drm_mode_config {
        struct drm_mode_config_helper_funcs *helper_private;
 };
 
-/**
- * drm_for_each_plane_mask - iterate over planes specified by bitmask
- * @plane: the loop cursor
- * @dev: the DRM device
- * @plane_mask: bitmask of plane indices
- *
- * Iterate over all planes specified by bitmask.
- */
-#define drm_for_each_plane_mask(plane, dev, plane_mask) \
-       list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
-               for_each_if ((plane_mask) & (1 << drm_plane_index(plane)))
-
-/**
- * drm_for_each_encoder_mask - iterate over encoders specified by bitmask
- * @encoder: the loop cursor
- * @dev: the DRM device
- * @encoder_mask: bitmask of encoder indices
- *
- * Iterate over all encoders specified by bitmask.
- */
-#define drm_for_each_encoder_mask(encoder, dev, encoder_mask) \
-       list_for_each_entry((encoder), &(dev)->mode_config.encoder_list, head) \
-               for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder)))
-
 #define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
-#define obj_to_connector(x) container_of(x, struct drm_connector, base)
-#define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
-#define obj_to_mode(x) container_of(x, struct drm_display_mode, base)
-#define obj_to_fb(x) container_of(x, struct drm_framebuffer, base)
-#define obj_to_property(x) container_of(x, struct drm_property, base)
-#define obj_to_blob(x) container_of(x, struct drm_property_blob, base)
-#define obj_to_plane(x) container_of(x, struct drm_plane, base)
-
-struct drm_prop_enum_list {
-       int type;
-       char *name;
-};
 
 extern __printf(6, 7)
 int drm_crtc_init_with_planes(struct drm_device *dev,
@@ -2756,7 +1342,7 @@ extern void drm_crtc_cleanup(struct drm_crtc *crtc);
  * Given a registered CRTC, return the index of that CRTC within a DRM
  * device's list of CRTCs.
  */
-static inline unsigned int drm_crtc_index(struct drm_crtc *crtc)
+static inline unsigned int drm_crtc_index(const struct drm_crtc *crtc)
 {
        return crtc->index;
 }
@@ -2773,184 +1359,17 @@ static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc)
        return 1 << drm_crtc_index(crtc);
 }
 
-int drm_connector_init(struct drm_device *dev,
-                      struct drm_connector *connector,
-                      const struct drm_connector_funcs *funcs,
-                      int connector_type);
-int drm_connector_register(struct drm_connector *connector);
-void drm_connector_unregister(struct drm_connector *connector);
-
-extern void drm_connector_cleanup(struct drm_connector *connector);
-static inline unsigned drm_connector_index(struct drm_connector *connector)
-{
-       return connector->index;
-}
-
-extern __printf(5, 6)
-int drm_encoder_init(struct drm_device *dev,
-                    struct drm_encoder *encoder,
-                    const struct drm_encoder_funcs *funcs,
-                    int encoder_type, const char *name, ...);
-
-/**
- * drm_encoder_index - find the index of a registered encoder
- * @encoder: encoder to find index for
- *
- * Given a registered encoder, return the index of that encoder within a DRM
- * device's list of encoders.
- */
-static inline unsigned int drm_encoder_index(struct drm_encoder *encoder)
-{
-       return encoder->index;
-}
-
-/**
- * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
- * @encoder: encoder to test
- * @crtc: crtc to test
- *
- * Return false if @encoder can't be driven by @crtc, true otherwise.
- */
-static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
-                                      struct drm_crtc *crtc)
-{
-       return !!(encoder->possible_crtcs & drm_crtc_mask(crtc));
-}
-
-extern __printf(8, 9)
-int drm_universal_plane_init(struct drm_device *dev,
-                            struct drm_plane *plane,
-                            unsigned long possible_crtcs,
-                            const struct drm_plane_funcs *funcs,
-                            const uint32_t *formats,
-                            unsigned int format_count,
-                            enum drm_plane_type type,
-                            const char *name, ...);
-extern int drm_plane_init(struct drm_device *dev,
-                         struct drm_plane *plane,
-                         unsigned long possible_crtcs,
-                         const struct drm_plane_funcs *funcs,
-                         const uint32_t *formats, unsigned int format_count,
-                         bool is_primary);
-extern void drm_plane_cleanup(struct drm_plane *plane);
-
-/**
- * drm_plane_index - find the index of a registered plane
- * @plane: plane to find index for
- *
- * Given a registered plane, return the index of that plane within a DRM
- * device's list of planes.
- */
-static inline unsigned int drm_plane_index(struct drm_plane *plane)
-{
-       return plane->index;
-}
-extern struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx);
-extern void drm_plane_force_disable(struct drm_plane *plane);
 extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
                                   int *hdisplay, int *vdisplay);
 extern int drm_crtc_force_disable(struct drm_crtc *crtc);
 extern int drm_crtc_force_disable_all(struct drm_device *dev);
 
-extern void drm_encoder_cleanup(struct drm_encoder *encoder);
-
-extern const char *drm_get_connector_status_name(enum drm_connector_status status);
-extern const char *drm_get_subpixel_order_name(enum subpixel_order order);
-extern const char *drm_get_dpms_name(int val);
-extern const char *drm_get_dvi_i_subconnector_name(int val);
-extern const char *drm_get_dvi_i_select_name(int val);
-extern const char *drm_get_tv_subconnector_name(int val);
-extern const char *drm_get_tv_select_name(int val);
 extern void drm_mode_config_init(struct drm_device *dev);
 extern void drm_mode_config_reset(struct drm_device *dev);
 extern void drm_mode_config_cleanup(struct drm_device *dev);
 
-extern int drm_mode_connector_set_path_property(struct drm_connector *connector,
-                                               const char *path);
-int drm_mode_connector_set_tile_property(struct drm_connector *connector);
-extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
-                                                  const struct edid *edid);
-
-extern int drm_display_info_set_bus_formats(struct drm_display_info *info,
-                                           const u32 *formats,
-                                           unsigned int num_formats);
-
-static inline bool drm_property_type_is(struct drm_property *property,
-               uint32_t type)
-{
-       /* instanceof for props.. handles extended type vs original types: */
-       if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
-               return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type;
-       return property->flags & type;
-}
-
-extern int drm_object_property_set_value(struct drm_mode_object *obj,
-                                        struct drm_property *property,
-                                        uint64_t val);
-extern int drm_object_property_get_value(struct drm_mode_object *obj,
-                                        struct drm_property *property,
-                                        uint64_t *value);
-extern int drm_framebuffer_init(struct drm_device *dev,
-                               struct drm_framebuffer *fb,
-                               const struct drm_framebuffer_funcs *funcs);
-extern struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
-                                                     uint32_t id);
-extern void drm_framebuffer_remove(struct drm_framebuffer *fb);
-extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
-extern void drm_framebuffer_unregister_private(struct drm_framebuffer *fb);
-
-extern void drm_object_attach_property(struct drm_mode_object *obj,
-                                      struct drm_property *property,
-                                      uint64_t init_val);
-extern struct drm_property *drm_property_create(struct drm_device *dev, int flags,
-                                               const char *name, int num_values);
-extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
-                                        const char *name,
-                                        const struct drm_prop_enum_list *props,
-                                        int num_values);
-struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
-                                        int flags, const char *name,
-                                        const struct drm_prop_enum_list *props,
-                                        int num_props,
-                                        uint64_t supported_bits);
-struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
-                                        const char *name,
-                                        uint64_t min, uint64_t max);
-struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
-                                        int flags, const char *name,
-                                        int64_t min, int64_t max);
-struct drm_property *drm_property_create_object(struct drm_device *dev,
-                                        int flags, const char *name, uint32_t type);
-struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
-                                        const char *name);
-struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
-                                                   size_t length,
-                                                   const void *data);
-struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
-                                                   uint32_t id);
-struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob);
-void drm_property_unreference_blob(struct drm_property_blob *blob);
-extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
-extern int drm_property_add_enum(struct drm_property *property, int index,
-                                uint64_t value, const char *name);
-extern int drm_mode_create_dvi_i_properties(struct drm_device *dev);
-extern int drm_mode_create_tv_properties(struct drm_device *dev,
-                                        unsigned int num_modes,
-                                        const char * const modes[]);
-extern int drm_mode_create_scaling_mode_property(struct drm_device *dev);
-extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
-extern int drm_mode_create_dirty_info_property(struct drm_device *dev);
-extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
-
-extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
-                                            struct drm_encoder *encoder);
-extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
-                                        int gamma_size);
-
 extern int drm_mode_set_config_internal(struct drm_mode_set *set);
 
-extern uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth);
-
 extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
                                                         char topology[8]);
 extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
@@ -2958,40 +1377,7 @@ extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
 extern void drm_mode_put_tile_group(struct drm_device *dev,
                                   struct drm_tile_group *tg);
 
-extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
-                                      struct drm_property *property,
-                                      uint64_t value);
-
-extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
-                                                             unsigned int supported_rotations);
-extern unsigned int drm_rotation_simplify(unsigned int rotation,
-                                         unsigned int supported_rotations);
-extern void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
-                                      uint degamma_lut_size,
-                                      bool has_ctm,
-                                      uint gamma_lut_size);
-
-int drm_plane_create_zpos_property(struct drm_plane *plane,
-                                  unsigned int zpos,
-                                  unsigned int min, unsigned int max);
-
-int drm_plane_create_zpos_immutable_property(struct drm_plane *plane,
-                                            unsigned int zpos);
-
 /* Helpers */
-struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
-                                            uint32_t id, uint32_t type);
-void drm_mode_object_reference(struct drm_mode_object *obj);
-void drm_mode_object_unreference(struct drm_mode_object *obj);
-
-static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
-               uint32_t id)
-{
-       struct drm_mode_object *mo;
-       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PLANE);
-       return mo ? obj_to_plane(mo) : NULL;
-}
-
 static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev,
        uint32_t id)
 {
@@ -3000,120 +1386,6 @@ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev,
        return mo ? obj_to_crtc(mo) : NULL;
 }
 
-static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
-       uint32_t id)
-{
-       struct drm_mode_object *mo;
-       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
-       return mo ? obj_to_encoder(mo) : NULL;
-}
-
-/**
- * drm_connector_lookup - lookup connector object
- * @dev: DRM device
- * @id: connector object id
- *
- * This function looks up the connector object specified by id
- * add takes a reference to it.
- */
-static inline struct drm_connector *drm_connector_lookup(struct drm_device *dev,
-               uint32_t id)
-{
-       struct drm_mode_object *mo;
-       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CONNECTOR);
-       return mo ? obj_to_connector(mo) : NULL;
-}
-
-static inline struct drm_property *drm_property_find(struct drm_device *dev,
-               uint32_t id)
-{
-       struct drm_mode_object *mo;
-       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY);
-       return mo ? obj_to_property(mo) : NULL;
-}
-
-/*
- * Extract a degamma/gamma LUT value provided by user and round it to the
- * precision supported by the hardware.
- */
-static inline uint32_t drm_color_lut_extract(uint32_t user_input,
-                                            uint32_t bit_precision)
-{
-       uint32_t val = user_input;
-       uint32_t max = 0xffff >> (16 - bit_precision);
-
-       /* Round only if we're not using full precision. */
-       if (bit_precision < 16) {
-               val += 1UL << (16 - bit_precision - 1);
-               val >>= 16 - bit_precision;
-       }
-
-       return clamp_val(val, 0, max);
-}
-
-/**
- * drm_framebuffer_reference - incr the fb refcnt
- * @fb: framebuffer
- *
- * This functions increments the fb's refcount.
- */
-static inline void drm_framebuffer_reference(struct drm_framebuffer *fb)
-{
-       drm_mode_object_reference(&fb->base);
-}
-
-/**
- * drm_framebuffer_unreference - unref a framebuffer
- * @fb: framebuffer to unref
- *
- * This functions decrements the fb's refcount and frees it if it drops to zero.
- */
-static inline void drm_framebuffer_unreference(struct drm_framebuffer *fb)
-{
-       drm_mode_object_unreference(&fb->base);
-}
-
-/**
- * drm_framebuffer_read_refcount - read the framebuffer reference count.
- * @fb: framebuffer
- *
- * This functions returns the framebuffer's reference count.
- */
-static inline uint32_t drm_framebuffer_read_refcount(struct drm_framebuffer *fb)
-{
-       return atomic_read(&fb->base.refcount.refcount);
-}
-
-/**
- * drm_connector_reference - incr the connector refcnt
- * @connector: connector
- *
- * This function increments the connector's refcount.
- */
-static inline void drm_connector_reference(struct drm_connector *connector)
-{
-       drm_mode_object_reference(&connector->base);
-}
-
-/**
- * drm_connector_unreference - unref a connector
- * @connector: connector to unref
- *
- * This function decrements the connector's refcount and frees it if it drops to zero.
- */
-static inline void drm_connector_unreference(struct drm_connector *connector)
-{
-       drm_mode_object_unreference(&connector->base);
-}
-
-/* Plane list iterator for legacy (overlay only) planes. */
-#define drm_for_each_legacy_plane(plane, dev) \
-       list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
-               for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-
-#define drm_for_each_plane(plane, dev) \
-       list_for_each_entry(plane, &(dev)->mode_config.plane_list, head)
-
 #define drm_for_each_crtc(crtc, dev) \
        list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head)
 
@@ -3131,67 +1403,4 @@ assert_drm_connector_list_read_locked(struct drm_mode_config *mode_config)
                !drm_modeset_is_locked(&mode_config->connection_mutex));
 }
 
-#define drm_for_each_connector(connector, dev) \
-       for (assert_drm_connector_list_read_locked(&(dev)->mode_config),        \
-            connector = list_first_entry(&(dev)->mode_config.connector_list,   \
-                                         struct drm_connector, head);          \
-            &connector->head != (&(dev)->mode_config.connector_list);          \
-            connector = list_next_entry(connector, head))
-
-#define drm_for_each_encoder(encoder, dev) \
-       list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head)
-
-#define drm_for_each_fb(fb, dev) \
-       for (WARN_ON(!mutex_is_locked(&(dev)->mode_config.fb_lock)),            \
-            fb = list_first_entry(&(dev)->mode_config.fb_list, \
-                                         struct drm_framebuffer, head);        \
-            &fb->head != (&(dev)->mode_config.fb_list);                        \
-            fb = list_next_entry(fb, head))
-
-/* drm_edid.c */
-bool drm_probe_ddc(struct i2c_adapter *adapter);
-struct edid *drm_get_edid(struct drm_connector *connector,
-                         struct i2c_adapter *adapter);
-struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
-                                    struct i2c_adapter *adapter);
-struct edid *drm_edid_duplicate(const struct edid *edid);
-int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
-
-u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
-enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code);
-bool drm_detect_hdmi_monitor(struct edid *edid);
-bool drm_detect_monitor_audio(struct edid *edid);
-bool drm_rgb_quant_range_selectable(struct edid *edid);
-int drm_add_modes_noedid(struct drm_connector *connector,
-                        int hdisplay, int vdisplay);
-void drm_set_preferred_mode(struct drm_connector *connector,
-                           int hpref, int vpref);
-
-int drm_edid_header_is_valid(const u8 *raw_edid);
-bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid,
-                         bool *edid_corrupt);
-bool drm_edid_is_valid(struct edid *edid);
-void drm_edid_get_monitor_name(struct edid *edid, char *name,
-                              int buflen);
-struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
-                                          int hsize, int vsize, int fresh,
-                                          bool rb);
-
-/* drm_bridge.c */
-extern int drm_bridge_add(struct drm_bridge *bridge);
-extern void drm_bridge_remove(struct drm_bridge *bridge);
-extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
-extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
-
-bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
-                       const struct drm_display_mode *mode,
-                       struct drm_display_mode *adjusted_mode);
-void drm_bridge_disable(struct drm_bridge *bridge);
-void drm_bridge_post_disable(struct drm_bridge *bridge);
-void drm_bridge_mode_set(struct drm_bridge *bridge,
-                       struct drm_display_mode *mode,
-                       struct drm_display_mode *adjusted_mode);
-void drm_bridge_pre_enable(struct drm_bridge *bridge);
-void drm_bridge_enable(struct drm_bridge *bridge);
-
 #endif /* __DRM_CRTC_H__ */
index 4b37afa..982c299 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <drm/drm_crtc.h>
 #include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_modeset_helper.h>
 
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
 extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
@@ -53,11 +54,6 @@ extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
 
 extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode);
 
-extern void drm_helper_move_panel_connectors_to_head(struct drm_device *);
-
-extern void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
-                                          const struct drm_mode_fb_cmd2 *mode_cmd);
-
 extern void drm_helper_resume_force_mode(struct drm_device *dev);
 
 int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
diff --git a/include/drm/drm_dp_aux_dev.h b/include/drm/drm_dp_aux_dev.h
deleted file mode 100644 (file)
index 1b76d99..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright © 2015 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.
- *
- * Authors:
- *    Rafael Antognolli <rafael.antognolli@intel.com>
- *
- */
-
-#ifndef DRM_DP_AUX_DEV
-#define DRM_DP_AUX_DEV
-
-#include <drm/drm_dp_helper.h>
-
-#ifdef CONFIG_DRM_DP_AUX_CHARDEV
-
-int drm_dp_aux_dev_init(void);
-void drm_dp_aux_dev_exit(void);
-int drm_dp_aux_register_devnode(struct drm_dp_aux *aux);
-void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux);
-
-#else
-
-static inline int drm_dp_aux_dev_init(void)
-{
-       return 0;
-}
-
-static inline void drm_dp_aux_dev_exit(void)
-{
-}
-
-static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
-{
-       return 0;
-}
-
-static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
-{
-}
-
-#endif
-
-#endif
index 63b8bd5..2a79882 100644 (file)
 # define DP_DS_PORT_TYPE_DVI               2
 # define DP_DS_PORT_TYPE_HDMI              3
 # define DP_DS_PORT_TYPE_NON_EDID          4
+# define DP_DS_PORT_TYPE_DP_DUALMODE        5
+# define DP_DS_PORT_TYPE_WIRELESS           6
 # define DP_DS_PORT_HPD                            (1 << 3)
 /* offset 1 for VGA is maximum megapixels per second / 8 */
 /* offset 2 */
-# define DP_DS_VGA_MAX_BPC_MASK                    (3 << 0)
-# define DP_DS_VGA_8BPC                            0
-# define DP_DS_VGA_10BPC                   1
-# define DP_DS_VGA_12BPC                   2
-# define DP_DS_VGA_16BPC                   3
+# define DP_DS_MAX_BPC_MASK                (3 << 0)
+# define DP_DS_8BPC                        0
+# define DP_DS_10BPC                       1
+# define DP_DS_12BPC                       2
+# define DP_DS_16BPC                       3
 
 /* link configuration */
 #define        DP_LINK_BW_SET                      0x100
 #define DP_SOURCE_OUI                      0x300
 #define DP_SINK_OUI                        0x400
 #define DP_BRANCH_OUI                      0x500
+#define DP_BRANCH_ID                        0x503
+#define DP_BRANCH_HW_REV                    0x509
+#define DP_BRANCH_SW_REV                    0x50A
 
 #define DP_SET_POWER                        0x600
 # define DP_SET_POWER_D0                    0x1
@@ -813,6 +818,13 @@ int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link);
 int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link);
 int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link);
 int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link);
+int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                               const u8 port_cap[4]);
+int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                             const u8 port_cap[4]);
+int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]);
+void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                            const u8 port_cap[4], struct drm_dp_aux *aux);
 
 void drm_dp_aux_init(struct drm_dp_aux *aux);
 int drm_dp_aux_register(struct drm_dp_aux *aux);
index 919933d..c3a7d44 100644 (file)
@@ -25,6 +25,9 @@
 
 #include <linux/types.h>
 
+struct drm_device;
+struct i2c_adapter;
+
 #define EDID_LENGTH 128
 #define DDC_ADDR 0x50
 #define DDC_ADDR2 0x52 /* E-DDC 1.2 - where DisplayID can hide */
@@ -423,9 +426,36 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld)
        return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK;
 }
 
+bool drm_probe_ddc(struct i2c_adapter *adapter);
 struct edid *drm_do_get_edid(struct drm_connector *connector,
        int (*get_edid_block)(void *data, u8 *buf, unsigned int block,
                              size_t len),
        void *data);
+struct edid *drm_get_edid(struct drm_connector *connector,
+                         struct i2c_adapter *adapter);
+struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
+                                    struct i2c_adapter *adapter);
+struct edid *drm_edid_duplicate(const struct edid *edid);
+int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
+
+u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
+enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code);
+bool drm_detect_hdmi_monitor(struct edid *edid);
+bool drm_detect_monitor_audio(struct edid *edid);
+bool drm_rgb_quant_range_selectable(struct edid *edid);
+int drm_add_modes_noedid(struct drm_connector *connector,
+                        int hdisplay, int vdisplay);
+void drm_set_preferred_mode(struct drm_connector *connector,
+                           int hpref, int vpref);
+
+int drm_edid_header_is_valid(const u8 *raw_edid);
+bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid,
+                         bool *edid_corrupt);
+bool drm_edid_is_valid(struct edid *edid);
+void drm_edid_get_monitor_name(struct edid *edid, char *name,
+                              int buflen);
+struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
+                                          int hsize, int vsize, int fresh,
+                                          bool rb);
 
 #endif /* __DRM_EDID_H__ */
diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
new file mode 100644 (file)
index 0000000..387e33a
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_ENCODER_H__
+#define __DRM_ENCODER_H__
+
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <drm/drm_mode_object.h>
+
+/**
+ * struct drm_encoder_funcs - encoder controls
+ *
+ * Encoders sit between CRTCs and connectors.
+ */
+struct drm_encoder_funcs {
+       /**
+        * @reset:
+        *
+        * Reset encoder hardware and software state to off. This function isn't
+        * called by the core directly, only through drm_mode_config_reset().
+        * It's not a helper hook only for historical reasons.
+        */
+       void (*reset)(struct drm_encoder *encoder);
+
+       /**
+        * @destroy:
+        *
+        * Clean up encoder resources. This is only called at driver unload time
+        * through drm_mode_config_cleanup() since an encoder cannot be
+        * hotplugged in DRM.
+        */
+       void (*destroy)(struct drm_encoder *encoder);
+
+       /**
+        * @late_register:
+        *
+        * This optional hook can be used to register additional userspace
+        * interfaces attached to the encoder like debugfs interfaces.
+        * It is called late in the driver load sequence from drm_dev_register().
+        * Everything added from this callback should be unregistered in
+        * the early_unregister callback.
+        *
+        * Returns:
+        *
+        * 0 on success, or a negative error code on failure.
+        */
+       int (*late_register)(struct drm_encoder *encoder);
+
+       /**
+        * @early_unregister:
+        *
+        * This optional hook should be used to unregister the additional
+        * userspace interfaces attached to the encoder from
+        * late_unregister(). It is called from drm_dev_unregister(),
+        * early in the driver unload sequence to disable userspace access
+        * before data structures are torndown.
+        */
+       void (*early_unregister)(struct drm_encoder *encoder);
+};
+
+/**
+ * struct drm_encoder - central DRM encoder structure
+ * @dev: parent DRM device
+ * @head: list management
+ * @base: base KMS object
+ * @name: human readable name, can be overwritten by the driver
+ * @crtc: currently bound CRTC
+ * @bridge: bridge associated to the encoder
+ * @funcs: control functions
+ * @helper_private: mid-layer private data
+ *
+ * CRTCs drive pixels to encoders, which convert them into signals
+ * appropriate for a given connector or set of connectors.
+ */
+struct drm_encoder {
+       struct drm_device *dev;
+       struct list_head head;
+
+       struct drm_mode_object base;
+       char *name;
+       /**
+        * @encoder_type:
+        *
+        * One of the DRM_MODE_ENCODER_<foo> types in drm_mode.h. The following
+        * encoder types are defined thus far:
+        *
+        * - DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A.
+        *
+        * - DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort.
+        *
+        * - DRM_MODE_ENCODER_LVDS for display panels, or in general any panel
+        *   with a proprietary parallel connector.
+        *
+        * - DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video,
+        *   Component, SCART).
+        *
+        * - DRM_MODE_ENCODER_VIRTUAL for virtual machine displays
+        *
+        * - DRM_MODE_ENCODER_DSI for panels connected using the DSI serial bus.
+        *
+        * - DRM_MODE_ENCODER_DPI for panels connected using the DPI parallel
+        *   bus.
+        *
+        * - DRM_MODE_ENCODER_DPMST for special fake encoders used to allow
+        *   mutliple DP MST streams to share one physical encoder.
+        */
+       int encoder_type;
+
+       /**
+        * @index: Position inside the mode_config.list, can be used as an array
+        * index. It is invariant over the lifetime of the encoder.
+        */
+       unsigned index;
+
+       /**
+        * @possible_crtcs: Bitmask of potential CRTC bindings, using
+        * drm_crtc_index() as the index into the bitfield. The driver must set
+        * the bits for all &drm_crtc objects this encoder can be connected to
+        * before calling drm_encoder_init().
+        *
+        * In reality almost every driver gets this wrong.
+        *
+        * Note that since CRTC objects can't be hotplugged the assigned indices
+        * are stable and hence known before registering all objects.
+        */
+       uint32_t possible_crtcs;
+
+       /**
+        * @possible_clones: Bitmask of potential sibling encoders for cloning,
+        * using drm_encoder_index() as the index into the bitfield. The driver
+        * must set the bits for all &drm_encoder objects which can clone a
+        * &drm_crtc together with this encoder before calling
+        * drm_encoder_init(). Drivers should set the bit representing the
+        * encoder itself, too. Cloning bits should be set such that when two
+        * encoders can be used in a cloned configuration, they both should have
+        * each another bits set.
+        *
+        * In reality almost every driver gets this wrong.
+        *
+        * Note that since encoder objects can't be hotplugged the assigned indices
+        * are stable and hence known before registering all objects.
+        */
+       uint32_t possible_clones;
+
+       struct drm_crtc *crtc;
+       struct drm_bridge *bridge;
+       const struct drm_encoder_funcs *funcs;
+       const struct drm_encoder_helper_funcs *helper_private;
+};
+
+#define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
+
+__printf(5, 6)
+int drm_encoder_init(struct drm_device *dev,
+                    struct drm_encoder *encoder,
+                    const struct drm_encoder_funcs *funcs,
+                    int encoder_type, const char *name, ...);
+
+/**
+ * drm_encoder_index - find the index of a registered encoder
+ * @encoder: encoder to find index for
+ *
+ * Given a registered encoder, return the index of that encoder within a DRM
+ * device's list of encoders.
+ */
+static inline unsigned int drm_encoder_index(struct drm_encoder *encoder)
+{
+       return encoder->index;
+}
+
+/* FIXME: We have an include file mess still, drm_crtc.h needs untangling. */
+static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc);
+
+/**
+ * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
+ * @encoder: encoder to test
+ * @crtc: crtc to test
+ *
+ * Returns false if @encoder can't be driven by @crtc, true otherwise.
+ */
+static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
+                                      struct drm_crtc *crtc)
+{
+       return !!(encoder->possible_crtcs & drm_crtc_mask(crtc));
+}
+
+/**
+ * drm_encoder_find - find a &drm_encoder
+ * @dev: DRM device
+ * @id: encoder id
+ *
+ * Returns the encoder with @id, NULL if it doesn't exist. Simple wrapper around
+ * drm_mode_object_find().
+ */
+static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
+                                                  uint32_t id)
+{
+       struct drm_mode_object *mo;
+
+       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
+
+       return mo ? obj_to_encoder(mo) : NULL;
+}
+
+void drm_encoder_cleanup(struct drm_encoder *encoder);
+
+/**
+ * drm_for_each_encoder_mask - iterate over encoders specified by bitmask
+ * @encoder: the loop cursor
+ * @dev: the DRM device
+ * @encoder_mask: bitmask of encoder indices
+ *
+ * Iterate over all encoders specified by bitmask.
+ */
+#define drm_for_each_encoder_mask(encoder, dev, encoder_mask) \
+       list_for_each_entry((encoder), &(dev)->mode_config.encoder_list, head) \
+               for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder)))
+
+/**
+ * drm_for_each_encoder - iterate over all encoders
+ * @encoder: the loop cursor
+ * @dev: the DRM device
+ *
+ * Iterate over all encoders of @dev.
+ */
+#define drm_for_each_encoder(encoder, dev) \
+       list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head)
+
+#endif
index db8d478..ed8edfe 100644 (file)
@@ -32,6 +32,7 @@
 
 struct drm_fb_helper;
 
+#include <drm/drm_crtc.h>
 #include <linux/kgdb.h>
 
 enum mode_set_atomic {
@@ -176,6 +177,7 @@ struct drm_fb_helper_connector {
  *              the screen buffer
  * @dirty_lock: spinlock protecting @dirty_clip
  * @dirty_work: worker used to flush the framebuffer
+ * @resume_work: worker used during resume if the console lock is already taken
  *
  * This is the main structure used by the fbdev helpers. Drivers supporting
  * fbdev emulation should embedded this into their overall driver structure.
@@ -196,6 +198,7 @@ struct drm_fb_helper {
        struct drm_clip_rect dirty_clip;
        spinlock_t dirty_lock;
        struct work_struct dirty_work;
+       struct work_struct resume_work;
 
        /**
         * @kernel_fb_list:
@@ -214,8 +217,20 @@ struct drm_fb_helper {
        bool delayed_hotplug;
 };
 
+/**
+ * define DRM_FB_HELPER_DEFAULT_OPS - helper define for drm drivers
+ *
+ * Helper define to register default implementations of drm_fb_helper
+ * functions. To be used in struct fb_ops of drm drivers.
+ */
+#define DRM_FB_HELPER_DEFAULT_OPS \
+       .fb_check_var   = drm_fb_helper_check_var, \
+       .fb_set_par     = drm_fb_helper_set_par, \
+       .fb_setcmap     = drm_fb_helper_setcmap, \
+       .fb_blank       = drm_fb_helper_blank, \
+       .fb_pan_display = drm_fb_helper_pan_display
+
 #ifdef CONFIG_DRM_FBDEV_EMULATION
-int drm_fb_helper_modinit(void);
 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
                           const struct drm_fb_helper_funcs *funcs);
 int drm_fb_helper_init(struct drm_device *dev,
@@ -263,7 +278,9 @@ void drm_fb_helper_cfb_copyarea(struct fb_info *info,
 void drm_fb_helper_cfb_imageblit(struct fb_info *info,
                                 const struct fb_image *image);
 
-void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state);
+void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend);
+void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
+                                       bool suspend);
 
 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
 
@@ -283,11 +300,6 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
 int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
                                       struct drm_connector *connector);
 #else
-static inline int drm_fb_helper_modinit(void)
-{
-       return 0;
-}
-
 static inline void drm_fb_helper_prepare(struct drm_device *dev,
                                        struct drm_fb_helper *helper,
                                        const struct drm_fb_helper_funcs *funcs)
@@ -417,7 +429,12 @@ static inline void drm_fb_helper_cfb_imageblit(struct fb_info *info,
 }
 
 static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper,
-                                            int state)
+                                            bool suspend)
+{
+}
+
+static inline void
+drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, bool suspend)
 {
 }
 
@@ -475,5 +492,18 @@ drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
 {
        return 0;
 }
+
+#endif
+
+static inline int
+drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
+                                             const char *name, bool primary)
+{
+#if IS_REACHABLE(CONFIG_FB)
+       return remove_conflicting_framebuffers(a, name, primary);
+#else
+       return 0;
 #endif
+}
+
 #endif
index 7f90a39..30c30fa 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include <uapi/drm/drm_fourcc.h>
 
+uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth);
 void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp);
 int drm_format_num_planes(uint32_t format);
 int drm_format_plane_cpp(uint32_t format, int plane);
@@ -32,6 +33,6 @@ int drm_format_horz_chroma_subsampling(uint32_t format);
 int drm_format_vert_chroma_subsampling(uint32_t format);
 int drm_format_plane_width(int width, uint32_t format, int plane);
 int drm_format_plane_height(int height, uint32_t format, int plane);
-const char *drm_get_format_name(uint32_t format);
+char *drm_get_format_name(uint32_t format) __malloc;
 
 #endif /* __DRM_FOURCC_H__ */
diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h
new file mode 100644 (file)
index 0000000..f5ae1f4
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_FRAMEBUFFER_H__
+#define __DRM_FRAMEBUFFER_H__
+
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <drm/drm_mode_object.h>
+
+struct drm_framebuffer;
+struct drm_file;
+struct drm_device;
+
+/**
+ * struct drm_framebuffer_funcs - framebuffer hooks
+ */
+struct drm_framebuffer_funcs {
+       /**
+        * @destroy:
+        *
+        * Clean up framebuffer resources, specifically also unreference the
+        * backing storage. The core guarantees to call this function for every
+        * framebuffer successfully created by ->fb_create() in
+        * &drm_mode_config_funcs. Drivers must also call
+        * drm_framebuffer_cleanup() to release DRM core resources for this
+        * framebuffer.
+        */
+       void (*destroy)(struct drm_framebuffer *framebuffer);
+
+       /**
+        * @create_handle:
+        *
+        * Create a buffer handle in the driver-specific buffer manager (either
+        * GEM or TTM) valid for the passed-in struct &drm_file. This is used by
+        * the core to implement the GETFB IOCTL, which returns (for
+        * sufficiently priviledged user) also a native buffer handle. This can
+        * be used for seamless transitions between modesetting clients by
+        * copying the current screen contents to a private buffer and blending
+        * between that and the new contents.
+        *
+        * GEM based drivers should call drm_gem_handle_create() to create the
+        * handle.
+        *
+        * RETURNS:
+        *
+        * 0 on success or a negative error code on failure.
+        */
+       int (*create_handle)(struct drm_framebuffer *fb,
+                            struct drm_file *file_priv,
+                            unsigned int *handle);
+       /**
+        * @dirty:
+        *
+        * Optional callback for the dirty fb IOCTL.
+        *
+        * Userspace can notify the driver via this callback that an area of the
+        * framebuffer has changed and should be flushed to the display
+        * hardware. This can also be used internally, e.g. by the fbdev
+        * emulation, though that's not the case currently.
+        *
+        * See documentation in drm_mode.h for the struct drm_mode_fb_dirty_cmd
+        * for more information as all the semantics and arguments have a one to
+        * one mapping on this function.
+        *
+        * RETURNS:
+        *
+        * 0 on success or a negative error code on failure.
+        */
+       int (*dirty)(struct drm_framebuffer *framebuffer,
+                    struct drm_file *file_priv, unsigned flags,
+                    unsigned color, struct drm_clip_rect *clips,
+                    unsigned num_clips);
+};
+
+/**
+ * struct drm_framebuffer - frame buffer object
+ *
+ * Note that the fb is refcounted for the benefit of driver internals,
+ * for example some hw, disabling a CRTC/plane is asynchronous, and
+ * scanout does not actually complete until the next vblank.  So some
+ * cleanup (like releasing the reference(s) on the backing GEM bo(s))
+ * should be deferred.  In cases like this, the driver would like to
+ * hold a ref to the fb even though it has already been removed from
+ * userspace perspective. See drm_framebuffer_reference() and
+ * drm_framebuffer_unreference().
+ *
+ * The refcount is stored inside the mode object @base.
+ */
+struct drm_framebuffer {
+       /**
+        * @dev: DRM device this framebuffer belongs to
+        */
+       struct drm_device *dev;
+       /**
+        * @head: Place on the dev->mode_config.fb_list, access protected by
+        * dev->mode_config.fb_lock.
+        */
+       struct list_head head;
+
+       /**
+        * @base: base modeset object structure, contains the reference count.
+        */
+       struct drm_mode_object base;
+       /**
+        * @funcs: framebuffer vfunc table
+        */
+       const struct drm_framebuffer_funcs *funcs;
+       /**
+        * @pitches: Line stride per buffer. For userspace created object this
+        * is copied from drm_mode_fb_cmd2.
+        */
+       unsigned int pitches[4];
+       /**
+        * @offsets: Offset from buffer start to the actual pixel data in bytes,
+        * per buffer. For userspace created object this is copied from
+        * drm_mode_fb_cmd2.
+        *
+        * Note that this is a linear offset and does not take into account
+        * tiling or buffer laytou per @modifier. It meant to be used when the
+        * actual pixel data for this framebuffer plane starts at an offset,
+        * e.g.  when multiple planes are allocated within the same backing
+        * storage buffer object. For tiled layouts this generally means it
+        * @offsets must at least be tile-size aligned, but hardware often has
+        * stricter requirements.
+        *
+        * This should not be used to specifiy x/y pixel offsets into the buffer
+        * data (even for linear buffers). Specifying an x/y pixel offset is
+        * instead done through the source rectangle in struct &drm_plane_state.
+        */
+       unsigned int offsets[4];
+       /**
+        * @modifier: Data layout modifier, per buffer. This is used to describe
+        * tiling, or also special layouts (like compression) of auxiliary
+        * buffers. For userspace created object this is copied from
+        * drm_mode_fb_cmd2.
+        */
+       uint64_t modifier[4];
+       /**
+        * @width: Logical width of the visible area of the framebuffer, in
+        * pixels.
+        */
+       unsigned int width;
+       /**
+        * @height: Logical height of the visible area of the framebuffer, in
+        * pixels.
+        */
+       unsigned int height;
+       /**
+        * @depth: Depth in bits per pixel for RGB formats. 0 for everything
+        * else. Legacy information derived from @pixel_format, it's suggested to use
+        * the DRM FOURCC codes and helper functions directly instead.
+        */
+       unsigned int depth;
+       /**
+        * @bits_per_pixel: Storage used bits per pixel for RGB formats. 0 for
+        * everything else. Legacy information derived from @pixel_format, it's
+        * suggested to use the DRM FOURCC codes and helper functions directly
+        * instead.
+        */
+       int bits_per_pixel;
+       /**
+        * @flags: Framebuffer flags like DRM_MODE_FB_INTERLACED or
+        * DRM_MODE_FB_MODIFIERS.
+        */
+       int flags;
+       /**
+        * @pixel_format: DRM FOURCC code describing the pixel format.
+        */
+       uint32_t pixel_format; /* fourcc format */
+       /**
+        * @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor
+        * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR
+        * universal plane.
+        */
+       int hot_x;
+       /**
+        * @hot_y: Y coordinate of the cursor hotspot. Used by the legacy cursor
+        * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR
+        * universal plane.
+        */
+       int hot_y;
+       /**
+        * @filp_head: Placed on struct &drm_file fbs list_head, protected by
+        * fbs_lock in the same structure.
+        */
+       struct list_head filp_head;
+};
+
+#define obj_to_fb(x) container_of(x, struct drm_framebuffer, base)
+
+int drm_framebuffer_init(struct drm_device *dev,
+                        struct drm_framebuffer *fb,
+                        const struct drm_framebuffer_funcs *funcs);
+struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
+                                              uint32_t id);
+void drm_framebuffer_remove(struct drm_framebuffer *fb);
+void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
+void drm_framebuffer_unregister_private(struct drm_framebuffer *fb);
+
+/**
+ * drm_framebuffer_reference - incr the fb refcnt
+ * @fb: framebuffer
+ *
+ * This functions increments the fb's refcount.
+ */
+static inline void drm_framebuffer_reference(struct drm_framebuffer *fb)
+{
+       drm_mode_object_reference(&fb->base);
+}
+
+/**
+ * drm_framebuffer_unreference - unref a framebuffer
+ * @fb: framebuffer to unref
+ *
+ * This functions decrements the fb's refcount and frees it if it drops to zero.
+ */
+static inline void drm_framebuffer_unreference(struct drm_framebuffer *fb)
+{
+       drm_mode_object_unreference(&fb->base);
+}
+
+/**
+ * drm_framebuffer_read_refcount - read the framebuffer reference count.
+ * @fb: framebuffer
+ *
+ * This functions returns the framebuffer's reference count.
+ */
+static inline uint32_t drm_framebuffer_read_refcount(struct drm_framebuffer *fb)
+{
+       return atomic_read(&fb->base.refcount.refcount);
+}
+
+/**
+ * drm_for_each_fb - iterate over all framebuffers
+ * @fb: the loop cursor
+ * @dev: the DRM device
+ *
+ * Iterate over all framebuffers of @dev. User must hold the fb_lock from
+ * &drm_mode_config.
+ */
+#define drm_for_each_fb(fb, dev) \
+       for (WARN_ON(!mutex_is_locked(&(dev)->mode_config.fb_lock)),            \
+            fb = list_first_entry(&(dev)->mode_config.fb_list, \
+                                         struct drm_framebuffer, head);        \
+            &fb->head != (&(dev)->mode_config.fb_list);                        \
+            fb = list_next_entry(fb, head))
+#endif
index fca1cd1..9f63736 100644 (file)
@@ -210,8 +210,8 @@ drm_gem_object_reference(struct drm_gem_object *obj)
  * drm_gem_object_unreference_unlocked().
  *
  * Drivers should never call this directly in their code. Instead they should
- * wrap it up into a driver_gem_object_unreference(struct driver_gem_object
- * *obj) wrapper function, and use that. Shared code should never call this, to
+ * wrap it up into a ``driver_gem_object_unreference(struct driver_gem_object
+ * *obj)`` wrapper function, and use that. Shared code should never call this, to
  * avoid breaking drivers by accident which still depend upon dev->struct_mutex
  * locking.
  */
index 47ac925..4fef190 100644 (file)
@@ -265,11 +265,15 @@ int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
                                    u16 end);
 int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
                                  u16 end);
-int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline);
 int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi);
 int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
                             enum mipi_dsi_dcs_tear_mode mode);
 int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format);
+int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline);
+int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,
+                                       u16 brightness);
+int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
+                                       u16 *brightness);
 
 /**
  * struct mipi_dsi_driver - DSI driver
index fc65118..205ddcf 100644 (file)
@@ -37,6 +37,7 @@
  * Generic range manager structs
  */
 #include <linux/bug.h>
+#include <linux/rbtree.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
@@ -61,6 +62,7 @@ enum drm_mm_allocator_flags {
 struct drm_mm_node {
        struct list_head node_list;
        struct list_head hole_stack;
+       struct rb_node rb;
        unsigned hole_follows : 1;
        unsigned scanned_block : 1;
        unsigned scanned_prev_free : 1;
@@ -70,6 +72,7 @@ struct drm_mm_node {
        unsigned long color;
        u64 start;
        u64 size;
+       u64 __subtree_last;
        struct drm_mm *mm;
 };
 
@@ -79,6 +82,9 @@ struct drm_mm {
        /* head_node.node_list is the list of all memory nodes, ordered
         * according to the (increasing) start address of the memory node. */
        struct drm_mm_node head_node;
+       /* Keep an interval_tree for fast lookup of drm_mm_nodes by address. */
+       struct rb_root interval_tree;
+
        unsigned int scan_check_range : 1;
        unsigned scan_alignment;
        unsigned long scan_color;
@@ -295,6 +301,12 @@ void drm_mm_init(struct drm_mm *mm,
 void drm_mm_takedown(struct drm_mm *mm);
 bool drm_mm_clean(struct drm_mm *mm);
 
+struct drm_mm_node *
+drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last);
+
+struct drm_mm_node *
+drm_mm_interval_next(struct drm_mm_node *node, u64 start, u64 last);
+
 void drm_mm_init_scan(struct drm_mm *mm,
                      u64 size,
                      unsigned alignment,
diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h
new file mode 100644 (file)
index 0000000..43460b2
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_MODESET_H__
+#define __DRM_MODESET_H__
+
+#include <linux/kref.h>
+struct drm_object_properties;
+struct drm_property;
+struct drm_device;
+
+/**
+ * struct drm_mode_object - base structure for modeset objects
+ * @id: userspace visible identifier
+ * @type: type of the object, one of DRM_MODE_OBJECT\_\*
+ * @properties: properties attached to this object, including values
+ * @refcount: reference count for objects which with dynamic lifetime
+ * @free_cb: free function callback, only set for objects with dynamic lifetime
+ *
+ * Base structure for modeset objects visible to userspace. Objects can be
+ * looked up using drm_mode_object_find(). Besides basic uapi interface
+ * properties like @id and @type it provides two services:
+ *
+ * - It tracks attached properties and their values. This is used by &drm_crtc,
+ *   &drm_plane and &drm_connector. Properties are attached by calling
+ *   drm_object_attach_property() before the object is visible to userspace.
+ *
+ * - For objects with dynamic lifetimes (as indicated by a non-NULL @free_cb) it
+ *   provides reference counting through drm_mode_object_reference() and
+ *   drm_mode_object_unreference(). This is used by &drm_framebuffer,
+ *   &drm_connector and &drm_property_blob. These objects provide specialized
+ *   reference counting wrappers.
+ */
+struct drm_mode_object {
+       uint32_t id;
+       uint32_t type;
+       struct drm_object_properties *properties;
+       struct kref refcount;
+       void (*free_cb)(struct kref *kref);
+};
+
+#define DRM_OBJECT_MAX_PROPERTY 24
+/**
+ * struct drm_object_properties - property tracking for &drm_mode_object
+ */
+struct drm_object_properties {
+       /**
+        * @count: number of valid properties, must be less than or equal to
+        * DRM_OBJECT_MAX_PROPERTY.
+        */
+
+       int count;
+       /**
+        * @properties: Array of pointers to &drm_property.
+        *
+        * NOTE: if we ever start dynamically destroying properties (ie.
+        * not at drm_mode_config_cleanup() time), then we'd have to do
+        * a better job of detaching property from mode objects to avoid
+        * dangling property pointers:
+        */
+       struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY];
+
+       /**
+        * @values: Array to store the property values, matching @properties. Do
+        * not read/write values directly, but use
+        * drm_object_property_get_value() and drm_object_property_set_value().
+        *
+        * Note that atomic drivers do not store mutable properties in this
+        * array, but only the decoded values in the corresponding state
+        * structure. The decoding is done using the ->atomic_get_property and
+        * ->atomic_set_property hooks of the corresponding object. Hence atomic
+        * drivers should not use drm_object_property_set_value() and
+        * drm_object_property_get_value() on mutable objects, i.e. those
+        * without the DRM_MODE_PROP_IMMUTABLE flag set.
+        */
+       uint64_t values[DRM_OBJECT_MAX_PROPERTY];
+};
+
+/* Avoid boilerplate.  I'm tired of typing. */
+#define DRM_ENUM_NAME_FN(fnname, list)                         \
+       const char *fnname(int val)                             \
+       {                                                       \
+               int i;                                          \
+               for (i = 0; i < ARRAY_SIZE(list); i++) {        \
+                       if (list[i].type == val)                \
+                               return list[i].name;            \
+               }                                               \
+               return "(unknown)";                             \
+       }
+
+struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
+                                            uint32_t id, uint32_t type);
+void drm_mode_object_reference(struct drm_mode_object *obj);
+void drm_mode_object_unreference(struct drm_mode_object *obj);
+
+int drm_object_property_set_value(struct drm_mode_object *obj,
+                                 struct drm_property *property,
+                                 uint64_t val);
+int drm_object_property_get_value(struct drm_mode_object *obj,
+                                 struct drm_property *property,
+                                 uint64_t *value);
+
+void drm_object_attach_property(struct drm_mode_object *obj,
+                               struct drm_property *property,
+                               uint64_t init_val);
+#endif
index ff48177..9934d91 100644 (file)
 #ifndef __DRM_MODES_H__
 #define __DRM_MODES_H__
 
+#include <linux/hdmi.h>
+
+#include <drm/drm_mode_object.h>
+#include <drm/drm_connector.h>
+
+struct videomode;
+
 /*
  * Note on terminology:  here, for brevity and convenience, we refer to connector
  * control chips as 'CRTCs'.  They can control any type of connector, VGA, LVDS,
@@ -400,20 +407,7 @@ struct drm_display_mode {
        enum hdmi_picture_aspect picture_aspect_ratio;
 };
 
-/* mode specified on the command line */
-struct drm_cmdline_mode {
-       bool specified;
-       bool refresh_specified;
-       bool bpp_specified;
-       int xres, yres;
-       int bpp;
-       int refresh;
-       bool rb;
-       bool interlace;
-       bool cvt;
-       bool margins;
-       enum drm_connector_force force;
-};
+#define obj_to_mode(x) container_of(x, struct drm_display_mode, base)
 
 /**
  * drm_mode_is_stereo - check for stereo mode flags
@@ -434,7 +428,7 @@ struct drm_cmdline_mode;
 struct drm_display_mode *drm_mode_create(struct drm_device *dev);
 void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
 void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
-                               const struct drm_display_mode *in);
+                              const struct drm_display_mode *in);
 int drm_mode_convert_umode(struct drm_display_mode *out,
                           const struct drm_mode_modeinfo *in);
 void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
@@ -457,8 +451,9 @@ void drm_display_mode_from_videomode(const struct videomode *vm,
                                     struct drm_display_mode *dmode);
 void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
                                   struct videomode *vm);
+void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags);
 int of_get_drm_display_mode(struct device_node *np,
-                           struct drm_display_mode *dmode,
+                           struct drm_display_mode *dmode, u32 *bus_flags,
                            int index);
 
 void drm_mode_set_name(struct drm_display_mode *mode);
diff --git a/include/drm/drm_modeset_helper.h b/include/drm/drm_modeset_helper.h
new file mode 100644 (file)
index 0000000..b8051d5
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_KMS_HELPER_H__
+#define __DRM_KMS_HELPER_H__
+
+#include <drm/drmP.h>
+
+void drm_helper_move_panel_connectors_to_head(struct drm_device *);
+
+void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
+                                   const struct drm_mode_fb_cmd2 *mode_cmd);
+
+int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+                 const struct drm_crtc_funcs *funcs);
+
+#endif
index b55f218..10e449c 100644 (file)
@@ -266,6 +266,8 @@ struct drm_crtc_helper_funcs {
         * disable anything at the CRTC level. To ensure that runtime PM
         * handling (using either DPMS or the new "ACTIVE" property) works
         * @disable must be the inverse of @enable for atomic drivers.
+        * Atomic drivers should consider to use @atomic_disable instead of
+        * this one.
         *
         * NOTE:
         *
@@ -391,6 +393,28 @@ struct drm_crtc_helper_funcs {
         */
        void (*atomic_flush)(struct drm_crtc *crtc,
                             struct drm_crtc_state *old_crtc_state);
+
+       /**
+        * @atomic_disable:
+        *
+        * This callback should be used to disable the CRTC. With the atomic
+        * drivers it is called after all encoders connected to this CRTC have
+        * been shut off already using their own ->disable hook. If that
+        * sequence is too simple drivers can just add their own hooks and call
+        * it from this CRTC callback here by looping over all encoders
+        * connected to it using for_each_encoder_on_crtc().
+        *
+        * This hook is used only by atomic helpers. Atomic drivers don't
+        * need to implement it if there's no need to disable anything at the
+        * CRTC level.
+        *
+        * Comparing to @disable, this one provides the additional input
+        * parameter @old_crtc_state which could be used to access the old
+        * state. Atomic drivers should consider to use this one instead
+        * of @disable.
+        */
+       void (*atomic_disable)(struct drm_crtc *crtc,
+                              struct drm_crtc_state *old_crtc_state);
 };
 
 /**
@@ -523,11 +547,40 @@ struct drm_encoder_helper_funcs {
         *
         * This callback is used both by the legacy CRTC helpers and the atomic
         * modeset helpers. It is optional in the atomic helpers.
+        *
+        * NOTE:
+        *
+        * If the driver uses the atomic modeset helpers and needs to inspect
+        * the connector state or connector display info during mode setting,
+        * @atomic_mode_set can be used instead.
         */
        void (*mode_set)(struct drm_encoder *encoder,
                         struct drm_display_mode *mode,
                         struct drm_display_mode *adjusted_mode);
 
+       /**
+        * @atomic_mode_set:
+        *
+        * This callback is used to update the display mode of an encoder.
+        *
+        * Note that the display pipe is completely off when this function is
+        * called. Drivers which need hardware to be running before they program
+        * the new display mode (because they implement runtime PM) should not
+        * use this hook, because the helper library calls it only once and not
+        * every time the display pipeline is suspended using either DPMS or the
+        * new "ACTIVE" property. Such drivers should instead move all their
+        * encoder setup into the ->enable() callback.
+        *
+        * This callback is used by the atomic modeset helpers in place of the
+        * @mode_set callback, if set by the driver. It is optional and should
+        * be used instead of @mode_set if the driver needs to inspect the
+        * connector state or display info, since there is no direct way to
+        * go from the encoder to the current connector.
+        */
+       void (*atomic_mode_set)(struct drm_encoder *encoder,
+                               struct drm_crtc_state *crtc_state,
+                               struct drm_connector_state *conn_state);
+
        /**
         * @get_crtc:
         *
@@ -826,7 +879,7 @@ struct drm_plane_helper_funcs {
         * everything else must complete successfully.
         */
        int (*prepare_fb)(struct drm_plane *plane,
-                         const struct drm_plane_state *new_state);
+                         struct drm_plane_state *new_state);
        /**
         * @cleanup_fb:
         *
@@ -837,7 +890,7 @@ struct drm_plane_helper_funcs {
         * transitional plane helpers, but it is optional.
         */
        void (*cleanup_fb)(struct drm_plane *plane,
-                          const struct drm_plane_state *old_state);
+                          struct drm_plane_state *old_state);
 
        /**
         * @atomic_check:
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
new file mode 100644 (file)
index 0000000..43cf193
--- /dev/null
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_PLANE_H__
+#define __DRM_PLANE_H__
+
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <drm/drm_mode_object.h>
+
+struct drm_crtc;
+
+/**
+ * struct drm_plane_state - mutable plane state
+ * @plane: backpointer to the plane
+ * @crtc: currently bound CRTC, NULL if disabled
+ * @fb: currently bound framebuffer
+ * @fence: optional fence to wait for before scanning out @fb
+ * @crtc_x: left position of visible portion of plane on crtc
+ * @crtc_y: upper position of visible portion of plane on crtc
+ * @crtc_w: width of visible portion of plane on crtc
+ * @crtc_h: height of visible portion of plane on crtc
+ * @src_x: left position of visible portion of plane within
+ *     plane (in 16.16)
+ * @src_y: upper position of visible portion of plane within
+ *     plane (in 16.16)
+ * @src_w: width of visible portion of plane (in 16.16)
+ * @src_h: height of visible portion of plane (in 16.16)
+ * @rotation: rotation of the plane
+ * @zpos: priority of the given plane on crtc (optional)
+ * @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1
+ *     where N is the number of active planes for given crtc
+ * @src: clipped source coordinates of the plane (in 16.16)
+ * @dst: clipped destination coordinates of the plane
+ * @visible: visibility of the plane
+ * @state: backpointer to global drm_atomic_state
+ */
+struct drm_plane_state {
+       struct drm_plane *plane;
+
+       struct drm_crtc *crtc;   /* do not write directly, use drm_atomic_set_crtc_for_plane() */
+       struct drm_framebuffer *fb;  /* do not write directly, use drm_atomic_set_fb_for_plane() */
+       struct fence *fence;
+
+       /* Signed dest location allows it to be partially off screen */
+       int32_t crtc_x, crtc_y;
+       uint32_t crtc_w, crtc_h;
+
+       /* Source values are 16.16 fixed point */
+       uint32_t src_x, src_y;
+       uint32_t src_h, src_w;
+
+       /* Plane rotation */
+       unsigned int rotation;
+
+       /* Plane zpos */
+       unsigned int zpos;
+       unsigned int normalized_zpos;
+
+       /* Clipped coordinates */
+       struct drm_rect src, dst;
+
+       /*
+        * Is the plane actually visible? Can be false even
+        * if fb!=NULL and crtc!=NULL, due to clipping.
+        */
+       bool visible;
+
+       struct drm_atomic_state *state;
+};
+
+
+/**
+ * struct drm_plane_funcs - driver plane control functions
+ */
+struct drm_plane_funcs {
+       /**
+        * @update_plane:
+        *
+        * This is the legacy entry point to enable and configure the plane for
+        * the given CRTC and framebuffer. It is never called to disable the
+        * plane, i.e. the passed-in crtc and fb paramters are never NULL.
+        *
+        * The source rectangle in frame buffer memory coordinates is given by
+        * the src_x, src_y, src_w and src_h parameters (as 16.16 fixed point
+        * values). Devices that don't support subpixel plane coordinates can
+        * ignore the fractional part.
+        *
+        * The destination rectangle in CRTC coordinates is given by the
+        * crtc_x, crtc_y, crtc_w and crtc_h parameters (as integer values).
+        * Devices scale the source rectangle to the destination rectangle. If
+        * scaling is not supported, and the source rectangle size doesn't match
+        * the destination rectangle size, the driver must return a
+        * -<errorname>EINVAL</errorname> error.
+        *
+        * Drivers implementing atomic modeset should use
+        * drm_atomic_helper_update_plane() to implement this hook.
+        *
+        * RETURNS:
+        *
+        * 0 on success or a negative error code on failure.
+        */
+       int (*update_plane)(struct drm_plane *plane,
+                           struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                           int crtc_x, int crtc_y,
+                           unsigned int crtc_w, unsigned int crtc_h,
+                           uint32_t src_x, uint32_t src_y,
+                           uint32_t src_w, uint32_t src_h);
+
+       /**
+        * @disable_plane:
+        *
+        * This is the legacy entry point to disable the plane. The DRM core
+        * calls this method in response to a DRM_IOCTL_MODE_SETPLANE IOCTL call
+        * with the frame buffer ID set to 0.  Disabled planes must not be
+        * processed by the CRTC.
+        *
+        * Drivers implementing atomic modeset should use
+        * drm_atomic_helper_disable_plane() to implement this hook.
+        *
+        * RETURNS:
+        *
+        * 0 on success or a negative error code on failure.
+        */
+       int (*disable_plane)(struct drm_plane *plane);
+
+       /**
+        * @destroy:
+        *
+        * Clean up plane resources. This is only called at driver unload time
+        * through drm_mode_config_cleanup() since a plane cannot be hotplugged
+        * in DRM.
+        */
+       void (*destroy)(struct drm_plane *plane);
+
+       /**
+        * @reset:
+        *
+        * Reset plane hardware and software state to off. This function isn't
+        * called by the core directly, only through drm_mode_config_reset().
+        * It's not a helper hook only for historical reasons.
+        *
+        * Atomic drivers can use drm_atomic_helper_plane_reset() to reset
+        * atomic state using this hook.
+        */
+       void (*reset)(struct drm_plane *plane);
+
+       /**
+        * @set_property:
+        *
+        * This is the legacy entry point to update a property attached to the
+        * plane.
+        *
+        * Drivers implementing atomic modeset should use
+        * drm_atomic_helper_plane_set_property() to implement this hook.
+        *
+        * This callback is optional if the driver does not support any legacy
+        * driver-private properties.
+        *
+        * RETURNS:
+        *
+        * 0 on success or a negative error code on failure.
+        */
+       int (*set_property)(struct drm_plane *plane,
+                           struct drm_property *property, uint64_t val);
+
+       /**
+        * @atomic_duplicate_state:
+        *
+        * Duplicate the current atomic state for this plane and return it.
+        * The core and helpers gurantee that any atomic state duplicated with
+        * this hook and still owned by the caller (i.e. not transferred to the
+        * driver by calling ->atomic_commit() from struct
+        * &drm_mode_config_funcs) will be cleaned up by calling the
+        * @atomic_destroy_state hook in this structure.
+        *
+        * Atomic drivers which don't subclass struct &drm_plane_state should use
+        * drm_atomic_helper_plane_duplicate_state(). Drivers that subclass the
+        * state structure to extend it with driver-private state should use
+        * __drm_atomic_helper_plane_duplicate_state() to make sure shared state is
+        * duplicated in a consistent fashion across drivers.
+        *
+        * It is an error to call this hook before plane->state has been
+        * initialized correctly.
+        *
+        * NOTE:
+        *
+        * If the duplicate state references refcounted resources this hook must
+        * acquire a reference for each of them. The driver must release these
+        * references again in @atomic_destroy_state.
+        *
+        * RETURNS:
+        *
+        * Duplicated atomic state or NULL when the allocation failed.
+        */
+       struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
+
+       /**
+        * @atomic_destroy_state:
+        *
+        * Destroy a state duplicated with @atomic_duplicate_state and release
+        * or unreference all resources it references
+        */
+       void (*atomic_destroy_state)(struct drm_plane *plane,
+                                    struct drm_plane_state *state);
+
+       /**
+        * @atomic_set_property:
+        *
+        * Decode a driver-private property value and store the decoded value
+        * into the passed-in state structure. Since the atomic core decodes all
+        * standardized properties (even for extensions beyond the core set of
+        * properties which might not be implemented by all drivers) this
+        * requires drivers to subclass the state structure.
+        *
+        * Such driver-private properties should really only be implemented for
+        * truly hardware/vendor specific state. Instead it is preferred to
+        * standardize atomic extension and decode the properties used to expose
+        * such an extension in the core.
+        *
+        * Do not call this function directly, use
+        * drm_atomic_plane_set_property() instead.
+        *
+        * This callback is optional if the driver does not support any
+        * driver-private atomic properties.
+        *
+        * NOTE:
+        *
+        * This function is called in the state assembly phase of atomic
+        * modesets, which can be aborted for any reason (including on
+        * userspace's request to just check whether a configuration would be
+        * possible). Drivers MUST NOT touch any persistent state (hardware or
+        * software) or data structures except the passed in @state parameter.
+        *
+        * Also since userspace controls in which order properties are set this
+        * function must not do any input validation (since the state update is
+        * incomplete and hence likely inconsistent). Instead any such input
+        * validation must be done in the various atomic_check callbacks.
+        *
+        * RETURNS:
+        *
+        * 0 if the property has been found, -EINVAL if the property isn't
+        * implemented by the driver (which shouldn't ever happen, the core only
+        * asks for properties attached to this plane). No other validation is
+        * allowed by the driver. The core already checks that the property
+        * value is within the range (integer, valid enum value, ...) the driver
+        * set when registering the property.
+        */
+       int (*atomic_set_property)(struct drm_plane *plane,
+                                  struct drm_plane_state *state,
+                                  struct drm_property *property,
+                                  uint64_t val);
+
+       /**
+        * @atomic_get_property:
+        *
+        * Reads out the decoded driver-private property. This is used to
+        * implement the GETPLANE IOCTL.
+        *
+        * Do not call this function directly, use
+        * drm_atomic_plane_get_property() instead.
+        *
+        * This callback is optional if the driver does not support any
+        * driver-private atomic properties.
+        *
+        * RETURNS:
+        *
+        * 0 on success, -EINVAL if the property isn't implemented by the
+        * driver (which should never happen, the core only asks for
+        * properties attached to this plane).
+        */
+       int (*atomic_get_property)(struct drm_plane *plane,
+                                  const struct drm_plane_state *state,
+                                  struct drm_property *property,
+                                  uint64_t *val);
+       /**
+        * @late_register:
+        *
+        * This optional hook can be used to register additional userspace
+        * interfaces attached to the plane like debugfs interfaces.
+        * It is called late in the driver load sequence from drm_dev_register().
+        * Everything added from this callback should be unregistered in
+        * the early_unregister callback.
+        *
+        * Returns:
+        *
+        * 0 on success, or a negative error code on failure.
+        */
+       int (*late_register)(struct drm_plane *plane);
+
+       /**
+        * @early_unregister:
+        *
+        * This optional hook should be used to unregister the additional
+        * userspace interfaces attached to the plane from
+        * late_unregister(). It is called from drm_dev_unregister(),
+        * early in the driver unload sequence to disable userspace access
+        * before data structures are torndown.
+        */
+       void (*early_unregister)(struct drm_plane *plane);
+};
+
+/**
+ * enum drm_plane_type - uapi plane type enumeration
+ *
+ * For historical reasons not all planes are made the same. This enumeration is
+ * used to tell the different types of planes apart to implement the different
+ * uapi semantics for them. For userspace which is universal plane aware and
+ * which is using that atomic IOCTL there's no difference between these planes
+ * (beyong what the driver and hardware can support of course).
+ *
+ * For compatibility with legacy userspace, only overlay planes are made
+ * available to userspace by default. Userspace clients may set the
+ * DRM_CLIENT_CAP_UNIVERSAL_PLANES client capability bit to indicate that they
+ * wish to receive a universal plane list containing all plane types. See also
+ * drm_for_each_legacy_plane().
+ *
+ * WARNING: The values of this enum is UABI since they're exposed in the "type"
+ * property.
+ */
+enum drm_plane_type {
+       /**
+        * @DRM_PLANE_TYPE_OVERLAY:
+        *
+        * Overlay planes represent all non-primary, non-cursor planes. Some
+        * drivers refer to these types of planes as "sprites" internally.
+        */
+       DRM_PLANE_TYPE_OVERLAY,
+
+       /**
+        * @DRM_PLANE_TYPE_PRIMARY:
+        *
+        * Primary planes represent a "main" plane for a CRTC.  Primary planes
+        * are the planes operated upon by CRTC modesetting and flipping
+        * operations described in the page_flip and set_config hooks in struct
+        * &drm_crtc_funcs.
+        */
+       DRM_PLANE_TYPE_PRIMARY,
+
+       /**
+        * @DRM_PLANE_TYPE_CURSOR:
+        *
+        * Cursor planes represent a "cursor" plane for a CRTC.  Cursor planes
+        * are the planes operated upon by the DRM_IOCTL_MODE_CURSOR and
+        * DRM_IOCTL_MODE_CURSOR2 IOCTLs.
+        */
+       DRM_PLANE_TYPE_CURSOR,
+};
+
+
+/**
+ * struct drm_plane - central DRM plane control structure
+ * @dev: DRM device this plane belongs to
+ * @head: for list management
+ * @name: human readable name, can be overwritten by the driver
+ * @base: base mode object
+ * @possible_crtcs: pipes this plane can be bound to
+ * @format_types: array of formats supported by this plane
+ * @format_count: number of formats supported
+ * @format_default: driver hasn't supplied supported formats for the plane
+ * @crtc: currently bound CRTC
+ * @fb: currently bound fb
+ * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by
+ *     drm_mode_set_config_internal() to implement correct refcounting.
+ * @funcs: helper functions
+ * @properties: property tracking for this plane
+ * @type: type of plane (overlay, primary, cursor)
+ * @state: current atomic state for this plane
+ * @zpos_property: zpos property for this plane
+ * @helper_private: mid-layer private data
+ */
+struct drm_plane {
+       struct drm_device *dev;
+       struct list_head head;
+
+       char *name;
+
+       /**
+        * @mutex:
+        *
+        * Protects modeset plane state, together with the mutex of &drm_crtc
+        * this plane is linked to (when active, getting actived or getting
+        * disabled).
+        */
+       struct drm_modeset_lock mutex;
+
+       struct drm_mode_object base;
+
+       uint32_t possible_crtcs;
+       uint32_t *format_types;
+       unsigned int format_count;
+       bool format_default;
+
+       struct drm_crtc *crtc;
+       struct drm_framebuffer *fb;
+
+       struct drm_framebuffer *old_fb;
+
+       const struct drm_plane_funcs *funcs;
+
+       struct drm_object_properties properties;
+
+       enum drm_plane_type type;
+
+       /**
+        * @index: Position inside the mode_config.list, can be used as an array
+        * index. It is invariant over the lifetime of the plane.
+        */
+       unsigned index;
+
+       const struct drm_plane_helper_funcs *helper_private;
+
+       struct drm_plane_state *state;
+
+       struct drm_property *zpos_property;
+};
+
+#define obj_to_plane(x) container_of(x, struct drm_plane, base)
+
+extern __printf(8, 9)
+int drm_universal_plane_init(struct drm_device *dev,
+                            struct drm_plane *plane,
+                            unsigned long possible_crtcs,
+                            const struct drm_plane_funcs *funcs,
+                            const uint32_t *formats,
+                            unsigned int format_count,
+                            enum drm_plane_type type,
+                            const char *name, ...);
+extern int drm_plane_init(struct drm_device *dev,
+                         struct drm_plane *plane,
+                         unsigned long possible_crtcs,
+                         const struct drm_plane_funcs *funcs,
+                         const uint32_t *formats, unsigned int format_count,
+                         bool is_primary);
+extern void drm_plane_cleanup(struct drm_plane *plane);
+
+/**
+ * drm_plane_index - find the index of a registered plane
+ * @plane: plane to find index for
+ *
+ * Given a registered plane, return the index of that plane within a DRM
+ * device's list of planes.
+ */
+static inline unsigned int drm_plane_index(struct drm_plane *plane)
+{
+       return plane->index;
+}
+extern struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx);
+extern void drm_plane_force_disable(struct drm_plane *plane);
+
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+                                      struct drm_property *property,
+                                      uint64_t value);
+
+/**
+ * drm_plane_find - find a &drm_plane
+ * @dev: DRM device
+ * @id: plane id
+ *
+ * Returns the plane with @id, NULL if it doesn't exist. Simple wrapper around
+ * drm_mode_object_find().
+ */
+static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
+               uint32_t id)
+{
+       struct drm_mode_object *mo;
+       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PLANE);
+       return mo ? obj_to_plane(mo) : NULL;
+}
+
+/**
+ * drm_for_each_plane_mask - iterate over planes specified by bitmask
+ * @plane: the loop cursor
+ * @dev: the DRM device
+ * @plane_mask: bitmask of plane indices
+ *
+ * Iterate over all planes specified by bitmask.
+ */
+#define drm_for_each_plane_mask(plane, dev, plane_mask) \
+       list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
+               for_each_if ((plane_mask) & (1 << drm_plane_index(plane)))
+
+/**
+ * drm_for_each_legacy_plane - iterate over all planes for legacy userspace
+ * @plane: the loop cursor
+ * @dev: the DRM device
+ *
+ * Iterate over all legacy planes of @dev, excluding primary and cursor planes.
+ * This is useful for implementing userspace apis when userspace is not
+ * universal plane aware. See also enum &drm_plane_type.
+ */
+#define drm_for_each_legacy_plane(plane, dev) \
+       list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
+               for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+
+/**
+ * drm_for_each_plane - iterate over all planes
+ * @plane: the loop cursor
+ * @dev: the DRM device
+ *
+ * Iterate over all planes of @dev, include primary and cursor planes.
+ */
+#define drm_for_each_plane(plane, dev) \
+       list_for_each_entry(plane, &(dev)->mode_config.plane_list, head)
+
+
+#endif
index 0e0c357..c189596 100644 (file)
@@ -27,6 +27,7 @@
 #include <drm/drm_rect.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_modeset_helper.h>
 
 /*
  * Drivers that don't allow primary plane scaling may pass this macro in place
  */
 #define DRM_PLANE_HELPER_NO_SCALING (1<<16)
 
-int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
-                 const struct drm_crtc_funcs *funcs);
-
+int drm_plane_helper_check_state(struct drm_plane_state *state,
+                                const struct drm_rect *clip,
+                                int min_scale, int max_scale,
+                                bool can_position,
+                                bool can_update_disabled);
 int drm_plane_helper_check_update(struct drm_plane *plane,
                                  struct drm_crtc *crtc,
                                  struct drm_framebuffer *fb,
diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h
new file mode 100644 (file)
index 0000000..43c4b6a
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __DRM_PROPERTY_H__
+#define __DRM_PROPERTY_H__
+
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <drm/drm_mode_object.h>
+
+/**
+ * struct drm_property_enum - symbolic values for enumerations
+ * @value: numeric property value for this enum entry
+ * @head: list of enum values, linked to enum_list in &drm_property
+ * @name: symbolic name for the enum
+ *
+ * For enumeration and bitmask properties this structure stores the symbolic
+ * decoding for each value. This is used for example for the rotation property.
+ */
+struct drm_property_enum {
+       uint64_t value;
+       struct list_head head;
+       char name[DRM_PROP_NAME_LEN];
+};
+
+/**
+ * struct drm_property - modeset object property
+ *
+ * This structure represent a modeset object property. It combines both the name
+ * of the property with the set of permissible values. This means that when a
+ * driver wants to use a property with the same name on different objects, but
+ * with different value ranges, then it must create property for each one. An
+ * example would be rotation of &drm_plane, when e.g. the primary plane cannot
+ * be rotated. But if both the name and the value range match, then the same
+ * property structure can be instantiated multiple times for the same object.
+ * Userspace must be able to cope with this and cannot assume that the same
+ * symbolic property will have the same modeset object ID on all modeset
+ * objects.
+ *
+ * Properties are created by one of the special functions, as explained in
+ * detail in the @flags structure member.
+ *
+ * To actually expose a property it must be attached to each object using
+ * drm_object_attach_property(). Currently properties can only be attached to
+ * &drm_connector, &drm_crtc and &drm_plane.
+ *
+ * Properties are also used as the generic metadatatransport for the atomic
+ * IOCTL. Everything that was set directly in structures in the legacy modeset
+ * IOCTLs (like the plane source or destination windows, or e.g. the links to
+ * the CRTC) is exposed as a property with the DRM_MODE_PROP_ATOMIC flag set.
+ */
+struct drm_property {
+       /**
+        * @head: per-device list of properties, for cleanup.
+        */
+       struct list_head head;
+
+       /**
+        * @base: base KMS object
+        */
+       struct drm_mode_object base;
+
+       /**
+        * @flags:
+        *
+        * Property flags and type. A property needs to be one of the following
+        * types:
+        *
+        * DRM_MODE_PROP_RANGE
+        *     Range properties report their minimum and maximum admissible unsigned values.
+        *     The KMS core verifies that values set by application fit in that
+        *     range. The range is unsigned. Range properties are created using
+        *     drm_property_create_range().
+        *
+        * DRM_MODE_PROP_SIGNED_RANGE
+        *     Range properties report their minimum and maximum admissible unsigned values.
+        *     The KMS core verifies that values set by application fit in that
+        *     range. The range is signed. Range properties are created using
+        *     drm_property_create_signed_range().
+        *
+        * DRM_MODE_PROP_ENUM
+        *     Enumerated properties take a numerical value that ranges from 0 to
+        *     the number of enumerated values defined by the property minus one,
+        *     and associate a free-formed string name to each value. Applications
+        *     can retrieve the list of defined value-name pairs and use the
+        *     numerical value to get and set property instance values. Enum
+        *     properties are created using drm_property_create_enum().
+        *
+        * DRM_MODE_PROP_BITMASK
+        *     Bitmask properties are enumeration properties that additionally
+        *     restrict all enumerated values to the 0..63 range. Bitmask property
+        *     instance values combine one or more of the enumerated bits defined
+        *     by the property. Bitmask properties are created using
+        *     drm_property_create_bitmask().
+        *
+        * DRM_MODE_PROB_OBJECT
+        *     Object properties are used to link modeset objects. This is used
+        *     extensively in the atomic support to create the display pipeline,
+        *     by linking &drm_framebuffer to &drm_plane, &drm_plane to
+        *     &drm_crtc and &drm_connector to &drm_crtc. An object property can
+        *     only link to a specific type of &drm_mode_object, this limit is
+        *     enforced by the core. Object properties are created using
+        *     drm_property_create_object().
+        *
+        *     Object properties work like blob properties, but in a more
+        *     general fashion. They are limited to atomic drivers and must have
+        *     the DRM_MODE_PROP_ATOMIC flag set.
+        *
+        * DRM_MODE_PROP_BLOB
+        *     Blob properties store a binary blob without any format restriction.
+        *     The binary blobs are created as KMS standalone objects, and blob
+        *     property instance values store the ID of their associated blob
+        *     object. Blob properties are created by calling
+        *     drm_property_create() with DRM_MODE_PROP_BLOB as the type.
+        *
+        *     Actual blob objects to contain blob data are created using
+        *     drm_property_create_blob(), or through the corresponding IOCTL.
+        *
+        *     Besides the built-in limit to only accept blob objects blob
+        *     properties work exactly like object properties. The only reasons
+        *     blob properties exist is backwards compatibility with existing
+        *     userspace.
+        *
+        * In addition a property can have any combination of the below flags:
+        *
+        * DRM_MODE_PROP_ATOMIC
+        *     Set for properties which encode atomic modeset state. Such
+        *     properties are not exposed to legacy userspace.
+        *
+        * DRM_MODE_PROP_IMMUTABLE
+        *     Set for properties where userspace cannot be changed by
+        *     userspace. The kernel is allowed to update the value of these
+        *     properties. This is generally used to expose probe state to
+        *     usersapce, e.g. the EDID, or the connector path property on DP
+        *     MST sinks.
+        */
+       uint32_t flags;
+
+       /**
+        * @name: symbolic name of the properties
+        */
+       char name[DRM_PROP_NAME_LEN];
+
+       /**
+        * @num_values: size of the @values array.
+        */
+       uint32_t num_values;
+
+       /**
+        * @values:
+        *
+        * Array with limits and values for the property. The
+        * interpretation of these limits is dependent upon the type per @flags.
+        */
+       uint64_t *values;
+
+       /**
+        * @dev: DRM device
+        */
+       struct drm_device *dev;
+
+       /**
+        * @enum_list:
+        *
+        * List of &drm_prop_enum_list structures with the symbolic names for
+        * enum and bitmask values.
+        */
+       struct list_head enum_list;
+};
+
+/**
+ * struct drm_property_blob - Blob data for &drm_property
+ * @base: base KMS object
+ * @dev: DRM device
+ * @head_global: entry on the global blob list in &drm_mode_config
+ *     property_blob_list.
+ * @head_file: entry on the per-file blob list in &drm_file blobs list.
+ * @length: size of the blob in bytes, invariant over the lifetime of the object
+ * @data: actual data, embedded at the end of this structure
+ *
+ * Blobs are used to store bigger values than what fits directly into the 64
+ * bits available for a &drm_property.
+ *
+ * Blobs are reference counted using drm_property_reference_blob() and
+ * drm_property_unreference_blob(). They are created using
+ * drm_property_create_blob().
+ */
+struct drm_property_blob {
+       struct drm_mode_object base;
+       struct drm_device *dev;
+       struct list_head head_global;
+       struct list_head head_file;
+       size_t length;
+       unsigned char data[];
+};
+
+struct drm_prop_enum_list {
+       int type;
+       char *name;
+};
+
+#define obj_to_property(x) container_of(x, struct drm_property, base)
+#define obj_to_blob(x) container_of(x, struct drm_property_blob, base)
+
+/**
+ * drm_property_type_is - check the type of a property
+ * @property: property to check
+ * @type: property type to compare with
+ *
+ * This is a helper function becauase the uapi encoding of property types is
+ * a bit special for historical reasons.
+ */
+static inline bool drm_property_type_is(struct drm_property *property,
+                                       uint32_t type)
+{
+       /* instanceof for props.. handles extended type vs original types: */
+       if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+               return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type;
+       return property->flags & type;
+}
+
+struct drm_property *drm_property_create(struct drm_device *dev, int flags,
+                                        const char *name, int num_values);
+struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
+                                             const char *name,
+                                             const struct drm_prop_enum_list *props,
+                                             int num_values);
+struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
+                                                int flags, const char *name,
+                                                const struct drm_prop_enum_list *props,
+                                                int num_props,
+                                                uint64_t supported_bits);
+struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
+                                              const char *name,
+                                              uint64_t min, uint64_t max);
+struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
+                                                     int flags, const char *name,
+                                                     int64_t min, int64_t max);
+struct drm_property *drm_property_create_object(struct drm_device *dev,
+                                               int flags, const char *name, uint32_t type);
+struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
+                                             const char *name);
+int drm_property_add_enum(struct drm_property *property, int index,
+                         uint64_t value, const char *name);
+void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
+
+struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
+                                                  size_t length,
+                                                  const void *data);
+struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
+                                                  uint32_t id);
+int drm_property_replace_global_blob(struct drm_device *dev,
+                                    struct drm_property_blob **replace,
+                                    size_t length,
+                                    const void *data,
+                                    struct drm_mode_object *obj_holds_id,
+                                    struct drm_property *prop_holds_id);
+struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob);
+void drm_property_unreference_blob(struct drm_property_blob *blob);
+
+/**
+ * drm_connector_find - find property object
+ * @dev: DRM device
+ * @id: property object id
+ *
+ * This function looks up the property object specified by id and returns it.
+ */
+static inline struct drm_property *drm_property_find(struct drm_device *dev,
+                                                    uint32_t id)
+{
+       struct drm_mode_object *mo;
+       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY);
+       return mo ? obj_to_property(mo) : NULL;
+}
+
+#endif
index 2690397..01a8436 100644 (file)
@@ -60,9 +60,35 @@ struct drm_simple_display_pipe_funcs {
         *
         * This function is called when the underlying plane state is updated.
         * This hook is optional.
+        *
+        * This is the function drivers should submit the
+        * &drm_pending_vblank_event from. Using either
+        * drm_crtc_arm_vblank_event(), when the driver supports vblank
+        * interrupt handling, or drm_crtc_send_vblank_event() directly in case
+        * the hardware lacks vblank support entirely.
         */
        void (*update)(struct drm_simple_display_pipe *pipe,
                       struct drm_plane_state *plane_state);
+
+       /**
+        * @prepare_fb:
+        *
+        * Optional, called by struct &drm_plane_helper_funcs ->prepare_fb .
+        * Please read the documentation for the ->prepare_fb hook in
+        * struct &drm_plane_helper_funcs for more details.
+        */
+       int (*prepare_fb)(struct drm_simple_display_pipe *pipe,
+                         struct drm_plane_state *plane_state);
+
+       /**
+        * @cleanup_fb:
+        *
+        * Optional, called by struct &drm_plane_helper_funcs ->cleanup_fb .
+        * Please read the documentation for the ->cleanup_fb hook in
+        * struct &drm_plane_helper_funcs for more details.
+        */
+       void (*cleanup_fb)(struct drm_simple_display_pipe *pipe,
+                          struct drm_plane_state *plane_state);
 };
 
 /**
@@ -85,6 +111,11 @@ struct drm_simple_display_pipe {
        const struct drm_simple_display_pipe_funcs *funcs;
 };
 
+int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
+                                         struct drm_bridge *bridge);
+
+void drm_simple_display_pipe_detach_bridge(struct drm_simple_display_pipe *pipe);
+
 int drm_simple_display_pipe_init(struct drm_device *dev,
                        struct drm_simple_display_pipe *pipe,
                        const struct drm_simple_display_pipe_funcs *funcs,
index 06ea8e0..9c03895 100644 (file)
  */
 
 #include <drm/drm_mm.h>
-#include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/rbtree.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
+struct drm_file;
+
 struct drm_vma_offset_file {
        struct rb_node vm_rb;
-       struct file *vm_filp;
+       struct drm_file *vm_tag;
        unsigned long vm_count;
 };
 
 struct drm_vma_offset_node {
        rwlock_t vm_lock;
        struct drm_mm_node vm_node;
-       struct rb_node vm_rb;
        struct rb_root vm_files;
 };
 
 struct drm_vma_offset_manager {
        rwlock_t vm_lock;
-       struct rb_root vm_addr_space_rb;
        struct drm_mm vm_addr_space_mm;
 };
 
@@ -62,10 +61,11 @@ int drm_vma_offset_add(struct drm_vma_offset_manager *mgr,
 void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr,
                           struct drm_vma_offset_node *node);
 
-int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp);
-void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp);
+int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag);
+void drm_vma_node_revoke(struct drm_vma_offset_node *node,
+                        struct drm_file *tag);
 bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node,
-                            struct file *filp);
+                            struct drm_file *tag);
 
 /**
  * drm_vma_offset_exact_lookup_locked() - Look up node by exact address
@@ -216,9 +216,9 @@ static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node,
 /**
  * drm_vma_node_verify_access() - Access verification helper for TTM
  * @node: Offset node
- * @filp: Open-file
+ * @tag: Tag of file to check
  *
- * This checks whether @filp is granted access to @node. It is the same as
+ * This checks whether @tag is granted access to @node. It is the same as
  * drm_vma_node_is_allowed() but suitable as drop-in helper for TTM
  * verify_access() callbacks.
  *
@@ -226,9 +226,9 @@ static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node,
  * 0 if access is granted, -EACCES otherwise.
  */
 static inline int drm_vma_node_verify_access(struct drm_vma_offset_node *node,
-                                            struct file *filp)
+                                            struct drm_file *tag)
 {
-       return drm_vma_node_is_allowed(node, filp) ? 0 : -EACCES;
+       return drm_vma_node_is_allowed(node, tag) ? 0 : -EACCES;
 }
 
 #endif /* __DRM_VMA_MANAGER_H__ */
index 3e419d9..a254830 100644 (file)
@@ -1,6 +1,24 @@
 #ifndef __DRM_I2C_TDA998X_H__
 #define __DRM_I2C_TDA998X_H__
 
+#include <linux/hdmi.h>
+#include <dt-bindings/display/tda998x.h>
+
+enum {
+       AFMT_UNUSED =   0,
+       AFMT_SPDIF =    TDA998x_SPDIF,
+       AFMT_I2S =      TDA998x_I2S,
+};
+
+struct tda998x_audio_params {
+       u8 config;
+       u8 format;
+       unsigned sample_width;
+       unsigned sample_rate;
+       struct hdmi_audio_infoframe cea;
+       u8 status[5];
+};
+
 struct tda998x_encoder_params {
        u8 swap_b:3;
        u8 mirr_b:1;
@@ -15,16 +33,7 @@ struct tda998x_encoder_params {
        u8 swap_e:3;
        u8 mirr_e:1;
 
-       u8 audio_cfg;
-       u8 audio_clk_cfg;
-       u8 audio_frame[6];
-
-       enum {
-               AFMT_SPDIF,
-               AFMT_I2S
-       } audio_format;
-
-       unsigned audio_sample_rate;
+       struct tda998x_audio_params audio_params;
 };
 
 #endif
index b1755f8..4e1b274 100644 (file)
@@ -93,6 +93,6 @@ extern bool i915_gpu_turbo_disable(void);
 #define    I845_TSEG_SIZE_1M   (3 << 1)
 
 #define INTEL_BSM 0x5c
-#define   INTEL_BSM_MASK (0xFFFF << 20)
+#define   INTEL_BSM_MASK       (-(1u << 20))
 
 #endif                         /* _I915_DRM_H_ */
index 33466bf..0d5f426 100644 (file)
 #define INTEL_IVB_Q_IDS(info) \
        INTEL_QUANTA_VGA_DEVICE(info) /* Quanta transcode */
 
-#define INTEL_HSW_D_IDS(info) \
+#define INTEL_HSW_IDS(info) \
        INTEL_VGA_DEVICE(0x0402, info), /* GT1 desktop */ \
        INTEL_VGA_DEVICE(0x0412, info), /* GT2 desktop */ \
        INTEL_VGA_DEVICE(0x0422, info), /* GT3 desktop */ \
        INTEL_VGA_DEVICE(0x0D2B, info), /* CRW GT3 reserved */ \
        INTEL_VGA_DEVICE(0x0D0E, info), /* CRW GT1 reserved */ \
        INTEL_VGA_DEVICE(0x0D1E, info), /* CRW GT2 reserved */ \
-       INTEL_VGA_DEVICE(0x0D2E, info)  /* CRW GT3 reserved */ \
-
-#define INTEL_HSW_M_IDS(info) \
+       INTEL_VGA_DEVICE(0x0D2E, info),  /* CRW GT3 reserved */ \
        INTEL_VGA_DEVICE(0x0406, info), /* GT1 mobile */ \
        INTEL_VGA_DEVICE(0x0416, info), /* GT2 mobile */ \
        INTEL_VGA_DEVICE(0x0426, info), /* GT2 mobile */ \
        INTEL_VGA_DEVICE(0x0D16, info), /* CRW GT2 mobile */ \
        INTEL_VGA_DEVICE(0x0D26, info)  /* CRW GT3 mobile */
 
-#define INTEL_VLV_M_IDS(info) \
+#define INTEL_VLV_IDS(info) \
        INTEL_VGA_DEVICE(0x0f30, info), \
        INTEL_VGA_DEVICE(0x0f31, info), \
        INTEL_VGA_DEVICE(0x0f32, info), \
        INTEL_VGA_DEVICE(0x0f33, info), \
-       INTEL_VGA_DEVICE(0x0157, info)
-
-#define INTEL_VLV_D_IDS(info) \
+       INTEL_VGA_DEVICE(0x0157, info), \
        INTEL_VGA_DEVICE(0x0155, info)
 
-#define INTEL_BDW_GT12M_IDS(info)  \
+#define INTEL_BDW_GT12_IDS(info)  \
        INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \
        INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \
        INTEL_VGA_DEVICE(0x160B, info), /* GT1 Iris */ \
        INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \
        INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \
        INTEL_VGA_DEVICE(0x161B, info), /* GT2 ULT */ \
-       INTEL_VGA_DEVICE(0x161E, info)  /* GT2 ULX */
-
-#define INTEL_BDW_GT12D_IDS(info) \
+       INTEL_VGA_DEVICE(0x161E, info),  /* GT2 ULX */ \
        INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \
        INTEL_VGA_DEVICE(0x160D, info), /* GT1 Workstation */ \
        INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \
        INTEL_VGA_DEVICE(0x161D, info)  /* GT2 Workstation */
 
-#define INTEL_BDW_GT3M_IDS(info) \
+#define INTEL_BDW_GT3_IDS(info) \
        INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \
        INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \
        INTEL_VGA_DEVICE(0x162B, info), /* Iris */ \
-       INTEL_VGA_DEVICE(0x162E, info)  /* ULX */
-
-#define INTEL_BDW_GT3D_IDS(info) \
+       INTEL_VGA_DEVICE(0x162E, info),  /* ULX */\
        INTEL_VGA_DEVICE(0x162A, info), /* Server */ \
        INTEL_VGA_DEVICE(0x162D, info)  /* Workstation */
 
        INTEL_VGA_DEVICE(0x163A, info), /* Server */ \
        INTEL_VGA_DEVICE(0x163D, info)  /* Workstation */
 
-#define INTEL_BDW_M_IDS(info) \
-       INTEL_BDW_GT12M_IDS(info), \
-       INTEL_BDW_GT3M_IDS(info), \
-       INTEL_BDW_RSVDM_IDS(info)
-
-#define INTEL_BDW_D_IDS(info) \
-       INTEL_BDW_GT12D_IDS(info), \
-       INTEL_BDW_GT3D_IDS(info), \
+#define INTEL_BDW_IDS(info) \
+       INTEL_BDW_GT12_IDS(info), \
+       INTEL_BDW_GT3_IDS(info), \
+       INTEL_BDW_RSVDM_IDS(info), \
+       INTEL_BDW_GT12_IDS(info), \
+       INTEL_BDW_GT3_IDS(info), \
        INTEL_BDW_RSVDD_IDS(info)
 
 #define INTEL_CHV_IDS(info) \
index 6f2c598..9eb940d 100644 (file)
@@ -45,37 +45,7 @@ struct ttm_bo_device;
 
 struct drm_mm_node;
 
-/**
- * struct ttm_place
- *
- * @fpfn:      first valid page frame number to put the object
- * @lpfn:      last valid page frame number to put the object
- * @flags:     memory domain and caching flags for the object
- *
- * Structure indicating a possible place to put an object.
- */
-struct ttm_place {
-       unsigned        fpfn;
-       unsigned        lpfn;
-       uint32_t        flags;
-};
-
-/**
- * struct ttm_placement
- *
- * @num_placement:     number of preferred placements
- * @placement:         preferred placements
- * @num_busy_placement:        number of preferred placements when need to evict buffer
- * @busy_placement:    preferred placements when need to evict buffer
- *
- * Structure indicating the placement you request for an object.
- */
-struct ttm_placement {
-       unsigned                num_placement;
-       const struct ttm_place  *placement;
-       unsigned                num_busy_placement;
-       const struct ttm_place  *busy_placement;
-};
+struct ttm_placement;
 
 /**
  * struct ttm_bus_placement
index 99c6d01..4f0a921 100644 (file)
@@ -133,7 +133,6 @@ struct ttm_tt {
  * struct ttm_dma_tt
  *
  * @ttm: Base ttm_tt struct.
- * @cpu_address: The CPU address of the pages
  * @dma_address: The DMA (bus) addresses of the pages
  * @pages_list: used by some page allocation backend
  *
@@ -143,7 +142,6 @@ struct ttm_tt {
  */
 struct ttm_dma_tt {
        struct ttm_tt ttm;
-       void **cpu_address;
        dma_addr_t *dma_address;
        struct list_head pages_list;
 };
@@ -961,7 +959,6 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev,
  * ttm_bo_move_ttm
  *
  * @bo: A pointer to a struct ttm_buffer_object.
- * @evict: 1: This is an eviction. Don't try to pipeline.
  * @interruptible: Sleep interruptible if waiting.
  * @no_wait_gpu: Return immediately if the GPU is busy.
  * @new_mem: struct ttm_mem_reg indicating where to move.
@@ -977,14 +974,13 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev,
  */
 
 extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
-                          bool evict, bool interruptible, bool no_wait_gpu,
+                          bool interruptible, bool no_wait_gpu,
                           struct ttm_mem_reg *new_mem);
 
 /**
  * ttm_bo_move_memcpy
  *
  * @bo: A pointer to a struct ttm_buffer_object.
- * @evict: 1: This is an eviction. Don't try to pipeline.
  * @interruptible: Sleep interruptible if waiting.
  * @no_wait_gpu: Return immediately if the GPU is busy.
  * @new_mem: struct ttm_mem_reg indicating where to move.
@@ -1000,8 +996,7 @@ extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
  */
 
 extern int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
-                             bool evict, bool interruptible,
-                             bool no_wait_gpu,
+                             bool interruptible, bool no_wait_gpu,
                              struct ttm_mem_reg *new_mem);
 
 /**
index 72dcbe8..c452089 100644 (file)
@@ -155,4 +155,5 @@ extern int ttm_mem_global_alloc_page(struct ttm_mem_global *glob,
 extern void ttm_mem_global_free_page(struct ttm_mem_global *glob,
                                     struct page *page);
 extern size_t ttm_round_pot(size_t size);
+extern uint64_t ttm_get_kernel_zone_memory_size(struct ttm_mem_global *glob);
 #endif
index 8ed44f9..932be0c 100644 (file)
@@ -30,6 +30,9 @@
 
 #ifndef _TTM_PLACEMENT_H_
 #define _TTM_PLACEMENT_H_
+
+#include <linux/types.h>
+
 /*
  * Memory regions for data placement.
  */
 #define TTM_PL_SYSTEM           0
 #define TTM_PL_TT               1
 #define TTM_PL_VRAM             2
-#define TTM_PL_PRIV0            3
-#define TTM_PL_PRIV1            4
-#define TTM_PL_PRIV2            5
-#define TTM_PL_PRIV3            6
-#define TTM_PL_PRIV4            7
-#define TTM_PL_PRIV5            8
-#define TTM_PL_SWAPPED          15
+#define TTM_PL_PRIV             3
 
 #define TTM_PL_FLAG_SYSTEM      (1 << TTM_PL_SYSTEM)
 #define TTM_PL_FLAG_TT          (1 << TTM_PL_TT)
 #define TTM_PL_FLAG_VRAM        (1 << TTM_PL_VRAM)
-#define TTM_PL_FLAG_PRIV0       (1 << TTM_PL_PRIV0)
-#define TTM_PL_FLAG_PRIV1       (1 << TTM_PL_PRIV1)
-#define TTM_PL_FLAG_PRIV2       (1 << TTM_PL_PRIV2)
-#define TTM_PL_FLAG_PRIV3       (1 << TTM_PL_PRIV3)
-#define TTM_PL_FLAG_PRIV4       (1 << TTM_PL_PRIV4)
-#define TTM_PL_FLAG_PRIV5       (1 << TTM_PL_PRIV5)
-#define TTM_PL_FLAG_SWAPPED     (1 << TTM_PL_SWAPPED)
+#define TTM_PL_FLAG_PRIV        (1 << TTM_PL_PRIV)
 #define TTM_PL_MASK_MEM         0x0000FFFF
 
 /*
@@ -72,7 +63,6 @@
 #define TTM_PL_FLAG_CACHED      (1 << 16)
 #define TTM_PL_FLAG_UNCACHED    (1 << 17)
 #define TTM_PL_FLAG_WC          (1 << 18)
-#define TTM_PL_FLAG_SHARED      (1 << 20)
 #define TTM_PL_FLAG_NO_EVICT    (1 << 21)
 #define TTM_PL_FLAG_TOPDOWN     (1 << 22)
 
 
 #define TTM_PL_MASK_MEMTYPE     (TTM_PL_MASK_MEM | TTM_PL_MASK_CACHING)
 
-/*
- * Access flags to be used for CPU- and GPU- mappings.
- * The idea is that the TTM synchronization mechanism will
- * allow concurrent READ access and exclusive write access.
- * Currently GPU- and CPU accesses are exclusive.
+/**
+ * struct ttm_place
+ *
+ * @fpfn:      first valid page frame number to put the object
+ * @lpfn:      last valid page frame number to put the object
+ * @flags:     memory domain and caching flags for the object
+ *
+ * Structure indicating a possible place to put an object.
  */
+struct ttm_place {
+       unsigned        fpfn;
+       unsigned        lpfn;
+       uint32_t        flags;
+};
 
-#define TTM_ACCESS_READ         (1 << 0)
-#define TTM_ACCESS_WRITE        (1 << 1)
+/**
+ * struct ttm_placement
+ *
+ * @num_placement:     number of preferred placements
+ * @placement:         preferred placements
+ * @num_busy_placement:        number of preferred placements when need to evict buffer
+ * @busy_placement:    preferred placements when need to evict buffer
+ *
+ * Structure indicating the placement you request for an object.
+ */
+struct ttm_placement {
+       unsigned                num_placement;
+       const struct ttm_place  *placement;
+       unsigned                num_busy_placement;
+       const struct ttm_place  *busy_placement;
+};
 
 #endif
diff --git a/include/dt-bindings/display/tda998x.h b/include/dt-bindings/display/tda998x.h
new file mode 100644 (file)
index 0000000..34757a3
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _DT_BINDINGS_TDA998X_H
+#define _DT_BINDINGS_TDA998X_H
+
+#define TDA998x_SPDIF  1
+#define TDA998x_I2S    2
+
+#endif /*_DT_BINDINGS_TDA998X_H */
index 86baaa4..a44794e 100644 (file)
@@ -51,6 +51,16 @@ struct fence_array {
 
 extern const struct fence_ops fence_array_ops;
 
+/**
+ * fence_is_array - check if a fence is from the array subsclass
+ *
+ * Return true if it is a fence_array and false otherwise.
+ */
+static inline bool fence_is_array(struct fence *fence)
+{
+       return fence->ops == &fence_array_ops;
+}
+
 /**
  * to_fence_array - cast a fence to a fence_array
  * @fence: fence to cast to a fence_array
index 2ac6fa5..0d76305 100644 (file)
@@ -60,7 +60,7 @@ struct fence_cb;
  * implementer of the fence for its own purposes. Can be used in different
  * ways by different fence implementers, so do not rely on this.
  *
- * *) Since atomic bitops are used, this is not guaranteed to be the case.
+ * Since atomic bitops are used, this is not guaranteed to be the case.
  * Particularly, if the bit was set, but fence_signal was called right
  * before this bit was set, it would have been able to set the
  * FENCE_FLAG_SIGNALED_BIT, before enable_signaling was called.
index 645ad06..58df02b 100644 (file)
  * See Documentation/io-mapping.txt
  */
 
-#ifdef CONFIG_HAVE_ATOMIC_IOMAP
-
-#include <asm/iomap.h>
-
 struct io_mapping {
        resource_size_t base;
        unsigned long size;
        pgprot_t prot;
+       void __iomem *iomem;
 };
 
+#ifdef CONFIG_HAVE_ATOMIC_IOMAP
+
+#include <asm/iomap.h>
 /*
  * For small address space machines, mapping large objects
  * into the kernel virtual space isn't practical. Where
@@ -49,34 +49,25 @@ struct io_mapping {
  */
 
 static inline struct io_mapping *
-io_mapping_create_wc(resource_size_t base, unsigned long size)
+io_mapping_init_wc(struct io_mapping *iomap,
+                  resource_size_t base,
+                  unsigned long size)
 {
-       struct io_mapping *iomap;
        pgprot_t prot;
 
-       iomap = kmalloc(sizeof(*iomap), GFP_KERNEL);
-       if (!iomap)
-               goto out_err;
-
        if (iomap_create_wc(base, size, &prot))
-               goto out_free;
+               return NULL;
 
        iomap->base = base;
        iomap->size = size;
        iomap->prot = prot;
        return iomap;
-
-out_free:
-       kfree(iomap);
-out_err:
-       return NULL;
 }
 
 static inline void
-io_mapping_free(struct io_mapping *mapping)
+io_mapping_fini(struct io_mapping *mapping)
 {
        iomap_free(mapping->base, mapping->size);
-       kfree(mapping);
 }
 
 /* Atomic map/unmap */
@@ -121,21 +112,46 @@ io_mapping_unmap(void __iomem *vaddr)
 #else
 
 #include <linux/uaccess.h>
-
-/* this struct isn't actually defined anywhere */
-struct io_mapping;
+#include <asm/pgtable.h>
 
 /* Create the io_mapping object*/
 static inline struct io_mapping *
-io_mapping_create_wc(resource_size_t base, unsigned long size)
+io_mapping_init_wc(struct io_mapping *iomap,
+                  resource_size_t base,
+                  unsigned long size)
 {
-       return (struct io_mapping __force *) ioremap_wc(base, size);
+       iomap->base = base;
+       iomap->size = size;
+       iomap->iomem = ioremap_wc(base, size);
+#if defined(pgprot_noncached_wc) /* archs can't agree on a name ... */
+       iomap->prot = pgprot_noncached_wc(PAGE_KERNEL);
+#elif defined(pgprot_writecombine)
+       iomap->prot = pgprot_writecombine(PAGE_KERNEL);
+#else
+       iomap->prot = pgprot_noncached(PAGE_KERNEL);
+#endif
+
+       return iomap;
 }
 
 static inline void
-io_mapping_free(struct io_mapping *mapping)
+io_mapping_fini(struct io_mapping *mapping)
+{
+       iounmap(mapping->iomem);
+}
+
+/* Non-atomic map/unmap */
+static inline void __iomem *
+io_mapping_map_wc(struct io_mapping *mapping,
+                 unsigned long offset,
+                 unsigned long size)
+{
+       return mapping->iomem + offset;
+}
+
+static inline void
+io_mapping_unmap(void __iomem *vaddr)
 {
-       iounmap((void __force __iomem *) mapping);
 }
 
 /* Atomic map/unmap */
@@ -145,30 +161,42 @@ io_mapping_map_atomic_wc(struct io_mapping *mapping,
 {
        preempt_disable();
        pagefault_disable();
-       return ((char __force __iomem *) mapping) + offset;
+       return io_mapping_map_wc(mapping, offset, PAGE_SIZE);
 }
 
 static inline void
 io_mapping_unmap_atomic(void __iomem *vaddr)
 {
+       io_mapping_unmap(vaddr);
        pagefault_enable();
        preempt_enable();
 }
 
-/* Non-atomic map/unmap */
-static inline void __iomem *
-io_mapping_map_wc(struct io_mapping *mapping,
-                 unsigned long offset,
-                 unsigned long size)
+#endif /* HAVE_ATOMIC_IOMAP */
+
+static inline struct io_mapping *
+io_mapping_create_wc(resource_size_t base,
+                    unsigned long size)
 {
-       return ((char __force __iomem *) mapping) + offset;
+       struct io_mapping *iomap;
+
+       iomap = kmalloc(sizeof(*iomap), GFP_KERNEL);
+       if (!iomap)
+               return NULL;
+
+       if (!io_mapping_init_wc(iomap, base, size)) {
+               kfree(iomap);
+               return NULL;
+       }
+
+       return iomap;
 }
 
 static inline void
-io_mapping_unmap(void __iomem *vaddr)
+io_mapping_free(struct io_mapping *iomap)
 {
+       io_mapping_fini(iomap);
+       kfree(iomap);
 }
 
-#endif /* HAVE_ATOMIC_IOMAP */
-
 #endif /* _LINUX_IO_MAPPING_H */
index c6ffe8b..aa17ccf 100644 (file)
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/fence.h>
-
-struct sync_file_cb {
-       struct fence_cb cb;
-       struct fence *fence;
-       struct sync_file *sync_file;
-};
+#include <linux/fence-array.h>
 
 /**
  * struct sync_file - sync file to export to the userspace
@@ -32,10 +27,9 @@ struct sync_file_cb {
  * @kref:              reference count on fence.
  * @name:              name of sync_file.  Useful for debugging
  * @sync_file_list:    membership in global file list
- * @num_fences:                number of sync_pts in the fence
  * @wq:                        wait queue for fence signaling
- * @status:            0: signaled, >0:active, <0: error
- * @cbs:               sync_pts callback information
+ * @fence:             fence with the fences in the sync_file
+ * @cb:                        fence callback information
  */
 struct sync_file {
        struct file             *file;
@@ -44,14 +38,16 @@ struct sync_file {
 #ifdef CONFIG_DEBUG_FS
        struct list_head        sync_file_list;
 #endif
-       int num_fences;
 
        wait_queue_head_t       wq;
-       atomic_t                status;
 
-       struct sync_file_cb     cbs[];
+       struct fence            *fence;
+       struct fence_cb cb;
 };
 
+#define POLL_ENABLED FENCE_FLAG_USER_BITS
+
 struct sync_file *sync_file_create(struct fence *fence);
+struct fence *sync_file_get_fence(int fd);
 
 #endif /* _LINUX_SYNC_H */
index 8c3b412..ee162e3 100644 (file)
@@ -73,34 +73,6 @@ static inline void vga_set_legacy_decoding(struct pci_dev *pdev,
                                           unsigned int decodes) { };
 #endif
 
-/**
- *     vga_get         - acquire & locks VGA resources
- *
- *     @pdev: pci device of the VGA card or NULL for the system default
- *     @rsrc: bit mask of resources to acquire and lock
- *     @interruptible: blocking should be interruptible by signals ?
- *
- *     This function acquires VGA resources for the given
- *     card and mark those resources locked. If the resource requested
- *     are "normal" (and not legacy) resources, the arbiter will first check
- *     whether the card is doing legacy decoding for that type of resource. If
- *     yes, the lock is "converted" into a legacy resource lock.
- *     The arbiter will first look for all VGA cards that might conflict
- *     and disable their IOs and/or Memory access, including VGA forwarding
- *     on P2P bridges if necessary, so that the requested resources can
- *     be used. Then, the card is marked as locking these resources and
- *     the IO and/or Memory accesse are enabled on the card (including
- *     VGA forwarding on parent P2P bridges if any).
- *     This function will block if some conflicting card is already locking
- *     one of the required resources (or any resource on a different bus
- *     segment, since P2P bridges don't differenciate VGA memory and IO
- *     afaik). You can indicate whether this blocking should be interruptible
- *     by a signal (for userland interface) or not.
- *     Must not be called at interrupt time or in atomic context.
- *     If the card already owns the resources, the function succeeds.
- *     Nested calls are supported (a per-resource counter is maintained)
- */
-
 #if defined(CONFIG_VGA_ARB)
 extern int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible);
 #else
@@ -108,11 +80,14 @@ static inline int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interrupt
 #endif
 
 /**
- *     vga_get_interruptible
+ * vga_get_interruptible
+ * @pdev: pci device of the VGA card or NULL for the system default
+ * @rsrc: bit mask of resources to acquire and lock
  *
- *     Shortcut to vga_get
+ * Shortcut to vga_get with interruptible set to true.
+ *
+ * On success, release the VGA resource again with vga_put().
  */
-
 static inline int vga_get_interruptible(struct pci_dev *pdev,
                                        unsigned int rsrc)
 {
@@ -120,47 +95,26 @@ static inline int vga_get_interruptible(struct pci_dev *pdev,
 }
 
 /**
- *     vga_get_uninterruptible
+ * vga_get_uninterruptible - shortcut to vga_get()
+ * @pdev: pci device of the VGA card or NULL for the system default
+ * @rsrc: bit mask of resources to acquire and lock
  *
- *     Shortcut to vga_get
+ * Shortcut to vga_get with interruptible set to false.
+ *
+ * On success, release the VGA resource again with vga_put().
  */
-
 static inline int vga_get_uninterruptible(struct pci_dev *pdev,
                                          unsigned int rsrc)
 {
        return vga_get(pdev, rsrc, 0);
 }
 
-/**
- *     vga_tryget      - try to acquire & lock legacy VGA resources
- *
- *     @pdev: pci devivce of VGA card or NULL for system default
- *     @rsrc: bit mask of resources to acquire and lock
- *
- *     This function performs the same operation as vga_get(), but
- *     will return an error (-EBUSY) instead of blocking if the resources
- *     are already locked by another card. It can be called in any context
- */
-
 #if defined(CONFIG_VGA_ARB)
 extern int vga_tryget(struct pci_dev *pdev, unsigned int rsrc);
 #else
 static inline int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) { return 0; }
 #endif
 
-/**
- *     vga_put         - release lock on legacy VGA resources
- *
- *     @pdev: pci device of VGA card or NULL for system default
- *     @rsrc: but mask of resource to release
- *
- *     This function releases resources previously locked by vga_get()
- *     or vga_tryget(). The resources aren't disabled right away, so
- *     that a subsequence vga_get() on the same card will succeed
- *     immediately. Resources have a counter, so locks are only
- *     released if the counter reaches 0.
- */
-
 #if defined(CONFIG_VGA_ARB)
 extern void vga_put(struct pci_dev *pdev, unsigned int rsrc);
 #else
@@ -168,25 +122,6 @@ extern void vga_put(struct pci_dev *pdev, unsigned int rsrc);
 #endif
 
 
-/**
- *     vga_default_device
- *
- *     This can be defined by the platform. The default implementation
- *     is rather dumb and will probably only work properly on single
- *     vga card setups and/or x86 platforms.
- *
- *     If your VGA default device is not PCI, you'll have to return
- *     NULL here. In this case, I assume it will not conflict with
- *     any PCI card. If this is not true, I'll have to define two archs
- *     hooks for enabling/disabling the VGA default device if that is
- *     possible. This may be a problem with real _ISA_ VGA cards, in
- *     addition to a PCI one. I don't know at this point how to deal
- *     with that card. Can theirs IOs be disabled at all ? If not, then
- *     I suppose it's a matter of having the proper arch hook telling
- *     us about it, so we basically never allow anybody to succeed a
- *     vga_get()...
- */
-
 #ifdef CONFIG_VGA_ARB
 extern struct pci_dev *vga_default_device(void);
 extern void vga_set_default_device(struct pci_dev *pdev);
@@ -195,14 +130,11 @@ static inline struct pci_dev *vga_default_device(void) { return NULL; };
 static inline void vga_set_default_device(struct pci_dev *pdev) { };
 #endif
 
-/**
- *     vga_conflicts
- *
- *     Architectures should define this if they have several
- *     independent PCI domains that can afford concurrent VGA
- *     decoding
+/*
+ * Architectures should define this if they have several
+ * independent PCI domains that can afford concurrent VGA
+ * decoding
  */
-
 #ifndef __ARCH_HAS_VGA_CONFLICT
 static inline int vga_conflicts(struct pci_dev *p1, struct pci_dev *p2)
 {
@@ -210,34 +142,6 @@ static inline int vga_conflicts(struct pci_dev *p1, struct pci_dev *p2)
 }
 #endif
 
-/**
- *     vga_client_register
- *
- *     @pdev: pci device of the VGA client
- *     @cookie: client cookie to be used in callbacks
- *     @irq_set_state: irq state change callback
- *     @set_vga_decode: vga decode change callback
- *
- *     return value: 0 on success, -1 on failure
- *     Register a client with the VGA arbitration logic
- *
- *     Clients have two callback mechanisms they can use.
- *     irq enable/disable callback -
- *             If a client can't disable its GPUs VGA resources, then we
- *             need to be able to ask it to turn off its irqs when we
- *             turn off its mem and io decoding.
- *     set_vga_decode
- *             If a client can disable its GPU VGA resource, it will
- *             get a callback from this to set the encode/decode state
- *
- * Rationale: we cannot disable VGA decode resources unconditionally
- * some single GPU laptops seem to require ACPI or BIOS access to the
- * VGA registers to control things like backlights etc.
- * Hopefully newer multi-GPU laptops do something saner, and desktops
- * won't have any special ACPI for this.
- * They driver will get a callback when VGA arbitration is first used
- * by userspace since we some older X servers have issues.
- */
 #if defined(CONFIG_VGA_ARB)
 int vga_client_register(struct pci_dev *pdev, void *cookie,
                        void (*irq_set_state)(void *cookie, bool state),
index 462246a..d6b5a21 100644 (file)
@@ -77,6 +77,10 @@ extern "C" {
 #define AMDGPU_GEM_CREATE_NO_CPU_ACCESS                (1 << 1)
 /* Flag that USWC attributes should be used for GTT */
 #define AMDGPU_GEM_CREATE_CPU_GTT_USWC         (1 << 2)
+/* Flag that the memory should be in VRAM and cleared */
+#define AMDGPU_GEM_CREATE_VRAM_CLEARED         (1 << 3)
+/* Flag that create shadow bo(GTT) while allocating vram bo */
+#define AMDGPU_GEM_CREATE_SHADOW               (1 << 4)
 
 struct drm_amdgpu_gem_create_in  {
        /** the requested memory size */
@@ -481,6 +485,8 @@ struct drm_amdgpu_cs_chunk_data {
 #define AMDGPU_INFO_DEV_INFO                   0x16
 /* visible vram usage */
 #define AMDGPU_INFO_VIS_VRAM_USAGE             0x17
+/* number of TTM buffer evictions */
+#define AMDGPU_INFO_NUM_EVICTIONS              0x18
 
 #define AMDGPU_INFO_MMR_SE_INDEX_SHIFT 0
 #define AMDGPU_INFO_MMR_SE_INDEX_MASK  0xff
@@ -643,6 +649,7 @@ struct drm_amdgpu_info_hw_ip {
  * Supported GPU families
  */
 #define AMDGPU_FAMILY_UNKNOWN                  0
+#define AMDGPU_FAMILY_SI                       110 /* Hainan, Oland, Verde, Pitcairn, Tahiti */
 #define AMDGPU_FAMILY_CI                       120 /* Bonaire, Hawaii */
 #define AMDGPU_FAMILY_KV                       125 /* Kaveri, Kabini, Mullins */
 #define AMDGPU_FAMILY_VI                       130 /* Iceland, Tonga */
index 452675f..b2c5284 100644 (file)
@@ -646,6 +646,7 @@ struct drm_gem_open {
 #define DRM_CAP_CURSOR_WIDTH           0x8
 #define DRM_CAP_CURSOR_HEIGHT          0x9
 #define DRM_CAP_ADDFB2_MODIFIERS       0x10
+#define DRM_CAP_PAGE_FLIP_TARGET       0x11
 
 /** DRM_IOCTL_GET_CAP ioctl argument type */
 struct drm_get_cap {
index 49a7265..df0e350 100644 (file)
@@ -520,7 +520,13 @@ struct drm_color_lut {
 
 #define DRM_MODE_PAGE_FLIP_EVENT 0x01
 #define DRM_MODE_PAGE_FLIP_ASYNC 0x02
-#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT|DRM_MODE_PAGE_FLIP_ASYNC)
+#define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4
+#define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8
+#define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \
+                                  DRM_MODE_PAGE_FLIP_TARGET_RELATIVE)
+#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \
+                                 DRM_MODE_PAGE_FLIP_ASYNC | \
+                                 DRM_MODE_PAGE_FLIP_TARGET)
 
 /*
  * Request a page flip on the specified crtc.
@@ -543,8 +549,7 @@ struct drm_color_lut {
  * 'as soon as possible', meaning that it not delay waiting for vblank.
  * This may cause tearing on the screen.
  *
- * The reserved field must be zero until we figure out something
- * clever to use it for.
+ * The reserved field must be zero.
  */
 
 struct drm_mode_crtc_page_flip {
@@ -555,6 +560,34 @@ struct drm_mode_crtc_page_flip {
        __u64 user_data;
 };
 
+/*
+ * Request a page flip on the specified crtc.
+ *
+ * Same as struct drm_mode_crtc_page_flip, but supports new flags and
+ * re-purposes the reserved field:
+ *
+ * The sequence field must be zero unless either of the
+ * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is specified. When
+ * the ABSOLUTE flag is specified, the sequence field denotes the absolute
+ * vblank sequence when the flip should take effect. When the RELATIVE
+ * flag is specified, the sequence field denotes the relative (to the
+ * current one when the ioctl is called) vblank sequence when the flip
+ * should take effect. NOTE: DRM_IOCTL_WAIT_VBLANK must still be used to
+ * make sure the vblank sequence before the target one has passed before
+ * calling this ioctl. The purpose of the
+ * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is merely to clarify
+ * the target for when code dealing with a page flip runs during a
+ * vertical blank period.
+ */
+
+struct drm_mode_crtc_page_flip_target {
+       __u32 crtc_id;
+       __u32 fb_id;
+       __u32 flags;
+       __u32 sequence;
+       __u64 user_data;
+};
+
 /* create a dumb scanout buffer */
 struct drm_mode_create_dumb {
        __u32 height;
index d7e81a3..03725fe 100644 (file)
@@ -62,6 +62,30 @@ extern "C" {
 #define I915_ERROR_UEVENT              "ERROR"
 #define I915_RESET_UEVENT              "RESET"
 
+/*
+ * MOCS indexes used for GPU surfaces, defining the cacheability of the
+ * surface data and the coherency for this data wrt. CPU vs. GPU accesses.
+ */
+enum i915_mocs_table_index {
+       /*
+        * Not cached anywhere, coherency between CPU and GPU accesses is
+        * guaranteed.
+        */
+       I915_MOCS_UNCACHED,
+       /*
+        * Cacheability and coherency controlled by the kernel automatically
+        * based on the DRM_I915_GEM_SET_CACHING IOCTL setting and the current
+        * usage of the surface (used for display scanout or not).
+        */
+       I915_MOCS_PTE,
+       /*
+        * Cached in all GPU caches available on the platform.
+        * Coherency between CPU and GPU accesses to the surface is not
+        * guaranteed without extra synchronization.
+        */
+       I915_MOCS_CACHED,
+};
+
 /* Each region is a minimum of 16k, and there are at most 255 of them.
  */
 #define I915_NR_TEX_REGIONS 255        /* table size 2k - maximum due to use
@@ -363,6 +387,7 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_EXEC_SOFTPIN     37
 #define I915_PARAM_HAS_POOLED_EU        38
 #define I915_PARAM_MIN_EU_IN_POOL       39
+#define I915_PARAM_MMAP_GTT_VERSION     40
 
 typedef struct drm_i915_getparam {
        __s32 param;
@@ -698,15 +723,20 @@ struct drm_i915_gem_exec_object2 {
         */
        __u64 offset;
 
-#define EXEC_OBJECT_NEEDS_FENCE (1<<0)
-#define EXEC_OBJECT_NEEDS_GTT  (1<<1)
-#define EXEC_OBJECT_WRITE      (1<<2)
+#define EXEC_OBJECT_NEEDS_FENCE                 (1<<0)
+#define EXEC_OBJECT_NEEDS_GTT           (1<<1)
+#define EXEC_OBJECT_WRITE               (1<<2)
 #define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3)
-#define EXEC_OBJECT_PINNED     (1<<4)
-#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_PINNED<<1)
+#define EXEC_OBJECT_PINNED              (1<<4)
+#define EXEC_OBJECT_PAD_TO_SIZE                 (1<<5)
+/* All remaining bits are MBZ and RESERVED FOR FUTURE USE */
+#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_PAD_TO_SIZE<<1)
        __u64 flags;
 
-       __u64 rsvd1;
+       union {
+               __u64 rsvd1;
+               __u64 pad_to_size;
+       };
        __u64 rsvd2;
 };
 
@@ -826,7 +856,16 @@ struct drm_i915_gem_busy {
         * having flushed any pending activity), and a non-zero return that
         * the object is still in-flight on the GPU. (The GPU has not yet
         * signaled completion for all pending requests that reference the
-        * object.)
+        * object.) An object is guaranteed to become idle eventually (so
+        * long as no new GPU commands are executed upon it). Due to the
+        * asynchronous nature of the hardware, an object reported
+        * as busy may become idle before the ioctl is completed.
+        *
+        * Furthermore, if the object is busy, which engine is busy is only
+        * provided as a guide. There are race conditions which prevent the
+        * report of which engines are busy from being always accurate.
+        * However, the converse is not true. If the object is idle, the
+        * result of the ioctl, that all engines are idle, is accurate.
         *
         * The returned dword is split into two fields to indicate both
         * the engines on which the object is being read, and the
@@ -849,6 +888,11 @@ struct drm_i915_gem_busy {
         * execution engines, e.g. multiple media engines, which are
         * mapped to the same identifier in the EXECBUFFER2 ioctl and
         * so are not separately reported for busyness.
+        *
+        * Caveat emptor:
+        * Only the boolean result of this query is reliable; that is whether
+        * the object is idle or busy. The report of which engines are busy
+        * should be only used as a heuristic.
         */
        __u32 busy;
 };
@@ -897,6 +941,7 @@ struct drm_i915_gem_caching {
 #define I915_TILING_NONE       0
 #define I915_TILING_X          1
 #define I915_TILING_Y          2
+#define I915_TILING_LAST       I915_TILING_Y
 
 #define I915_BIT_6_SWIZZLE_NONE                0
 #define I915_BIT_6_SWIZZLE_9           1
index 49f778d..8c51e8a 100644 (file)
@@ -42,6 +42,15 @@ extern "C" {
 #define MSM_PIPE_2D1         0x02
 #define MSM_PIPE_3D0         0x10
 
+/* The pipe-id just uses the lower bits, so can be OR'd with flags in
+ * the upper 16 bits (which could be extended further, if needed, maybe
+ * we extend/overload the pipe-id some day to deal with multiple rings,
+ * but even then I don't think we need the full lower 16 bits).
+ */
+#define MSM_PIPE_ID_MASK     0xffff
+#define MSM_PIPE_ID(x)       ((x) & MSM_PIPE_ID_MASK)
+#define MSM_PIPE_FLAGS(x)    ((x) & ~MSM_PIPE_ID_MASK)
+
 /* timeouts are specified in clock-monotonic absolute times (to simplify
  * restarting interrupted ioctls).  The following struct is logically the
  * same as 'struct timespec' but 32/64b ABI safe.
@@ -175,17 +184,28 @@ struct drm_msm_gem_submit_bo {
        __u64 presumed;       /* in/out, presumed buffer address */
 };
 
+/* Valid submit ioctl flags: */
+#define MSM_SUBMIT_NO_IMPLICIT   0x80000000 /* disable implicit sync */
+#define MSM_SUBMIT_FENCE_FD_IN   0x40000000 /* enable input fence_fd */
+#define MSM_SUBMIT_FENCE_FD_OUT  0x20000000 /* enable output fence_fd */
+#define MSM_SUBMIT_FLAGS                ( \
+               MSM_SUBMIT_NO_IMPLICIT   | \
+               MSM_SUBMIT_FENCE_FD_IN   | \
+               MSM_SUBMIT_FENCE_FD_OUT  | \
+               0)
+
 /* Each cmdstream submit consists of a table of buffers involved, and
  * one or more cmdstream buffers.  This allows for conditional execution
  * (context-restore), and IB buffers needed for per tile/bin draw cmds.
  */
 struct drm_msm_gem_submit {
-       __u32 pipe;           /* in, MSM_PIPE_x */
+       __u32 flags;          /* MSM_PIPE_x | MSM_SUBMIT_x */
        __u32 fence;          /* out */
        __u32 nr_bos;         /* in, number of submit_bo's */
        __u32 nr_cmds;        /* in, number of submit_cmd's */
        __u64 __user bos;     /* in, ptr to array of submit_bo's */
        __u64 __user cmds;    /* in, ptr to array of submit_cmd's */
+       __s32 fence_fd;       /* in/out fence fd (see MSM_SUBMIT_FENCE_FD_IN/OUT) */
 };
 
 /* The normal way to synchronize with the GPU is just to CPU_PREP on
index 929aba2..6965d09 100644 (file)
@@ -399,6 +399,7 @@ header-y += string.h
 header-y += suspend_ioctls.h
 header-y += swab.h
 header-y += synclink.h
+header-y += sync_file.h
 header-y += sysctl.h
 header-y += sysinfo.h
 header-y += target_core_user.h
index 413303d..5b287d6 100644 (file)
@@ -85,15 +85,12 @@ struct sync_file_info {
 #define SYNC_IOC_MERGE         _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
 
 /**
- * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence
+ * DOC: SYNC_IOC_FILE_INFO - get detailed information on a sync_file
  *
- * Takes a struct sync_file_info_data with extra space allocated for pt_info.
- * Caller should write the size of the buffer into len.  On return, len is
- * updated to reflect the total size of the sync_file_info_data including
- * pt_info.
- *
- * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
- * To iterate over the sync_pt_infos, use the sync_pt_info.len field.
+ * Takes a struct sync_file_info. If num_fences is 0, the field is updated
+ * with the actual number of fences. If num_fences is > 0, the system will
+ * use the pointer provided on sync_fence_info to return up to num_fences of
+ * struct sync_fence_info, with detailed fence information.
  */
 #define SYNC_IOC_FILE_INFO     _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info)
 
diff --git a/include/video/imx-ipu-image-convert.h b/include/video/imx-ipu-image-convert.h
new file mode 100644 (file)
index 0000000..7b87efc
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2012-2016 Mentor Graphics Inc.
+ *
+ * i.MX Queued image conversion support, with tiling and rotation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#ifndef __IMX_IPU_IMAGE_CONVERT_H__
+#define __IMX_IPU_IMAGE_CONVERT_H__
+
+#include <video/imx-ipu-v3.h>
+
+struct ipu_image_convert_ctx;
+
+/**
+ * struct ipu_image_convert_run - image conversion run request struct
+ *
+ * @ctx:       the conversion context
+ * @in_phys:   dma addr of input image buffer for this run
+ * @out_phys:  dma addr of output image buffer for this run
+ * @status:    completion status of this run
+ */
+struct ipu_image_convert_run {
+       struct ipu_image_convert_ctx *ctx;
+
+       dma_addr_t in_phys;
+       dma_addr_t out_phys;
+
+       int status;
+
+       /* internal to image converter, callers don't touch */
+       struct list_head list;
+};
+
+/**
+ * ipu_image_convert_cb_t - conversion callback function prototype
+ *
+ * @run:       the completed conversion run pointer
+ * @ctx:       a private context pointer for the callback
+ */
+typedef void (*ipu_image_convert_cb_t)(struct ipu_image_convert_run *run,
+                                      void *ctx);
+
+/**
+ * ipu_image_convert_enum_format() - enumerate the image converter's
+ *     supported input and output pixel formats.
+ *
+ * @index:     pixel format index
+ * @fourcc:    v4l2 fourcc for this index
+ *
+ * Returns 0 with a valid index and fills in v4l2 fourcc, -EINVAL otherwise.
+ *
+ * In V4L2, drivers can call ipu_image_enum_format() in .enum_fmt.
+ */
+int ipu_image_convert_enum_format(int index, u32 *fourcc);
+
+/**
+ * ipu_image_convert_adjust() - adjust input/output images to IPU restrictions.
+ *
+ * @in:                input image format, adjusted on return
+ * @out:       output image format, adjusted on return
+ * @rot_mode:  rotation mode
+ *
+ * In V4L2, drivers can call ipu_image_convert_adjust() in .try_fmt.
+ */
+void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
+                             enum ipu_rotate_mode rot_mode);
+
+/**
+ * ipu_image_convert_verify() - verify that input/output image formats
+ *         and rotation mode meet IPU restrictions.
+ *
+ * @in:                input image format
+ * @out:       output image format
+ * @rot_mode:  rotation mode
+ *
+ * Returns 0 if the formats and rotation mode meet IPU restrictions,
+ * -EINVAL otherwise.
+ */
+int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
+                            enum ipu_rotate_mode rot_mode);
+
+/**
+ * ipu_image_convert_prepare() - prepare a conversion context.
+ *
+ * @ipu:       the IPU handle to use for the conversions
+ * @ic_task:   the IC task to use for the conversions
+ * @in:                input image format
+ * @out:       output image format
+ * @rot_mode:  rotation mode
+ * @complete:  run completion callback
+ * @complete_context:  a context pointer for the completion callback
+ *
+ * Returns an opaque conversion context pointer on success, error pointer
+ * on failure. The input/output formats and rotation mode must already meet
+ * IPU retrictions.
+ *
+ * In V4L2, drivers should call ipu_image_convert_prepare() at streamon.
+ */
+struct ipu_image_convert_ctx *
+ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+                         struct ipu_image *in, struct ipu_image *out,
+                         enum ipu_rotate_mode rot_mode,
+                         ipu_image_convert_cb_t complete,
+                         void *complete_context);
+
+/**
+ * ipu_image_convert_unprepare() - unprepare a conversion context.
+ *
+ * @ctx: the conversion context pointer to unprepare
+ *
+ * Aborts any active or pending conversions for this context and
+ * frees the context. Any currently active or pending runs belonging
+ * to this context are returned via the completion callback with an
+ * error run status.
+ *
+ * In V4L2, drivers should call ipu_image_convert_unprepare() at
+ * streamoff.
+ */
+void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx);
+
+/**
+ * ipu_image_convert_queue() - queue a conversion run
+ *
+ * @run: the run request pointer
+ *
+ * ipu_image_convert_run must be dynamically allocated (_not_ as a local
+ * var) by callers and filled in with a previously prepared conversion
+ * context handle and the dma addr's of the input and output image buffers
+ * for this conversion run.
+ *
+ * When this conversion completes, the run pointer is returned via the
+ * completion callback. The caller is responsible for freeing the run
+ * object after it completes.
+ *
+ * In V4L2, drivers should call ipu_image_convert_queue() while
+ * streaming to queue the conversion of a received input buffer.
+ * For example mem2mem devices this would be called in .device_run.
+ */
+int ipu_image_convert_queue(struct ipu_image_convert_run *run);
+
+/**
+ * ipu_image_convert_abort() - abort conversions
+ *
+ * @ctx: the conversion context pointer
+ *
+ * This will abort any active or pending conversions for this context.
+ * Any currently active or pending runs belonging to this context are
+ * returned via the completion callback with an error run status.
+ */
+void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx);
+
+/**
+ * ipu_image_convert() - asynchronous image conversion request
+ *
+ * @ipu:       the IPU handle to use for the conversion
+ * @ic_task:   the IC task to use for the conversion
+ * @in:                input image format
+ * @out:       output image format
+ * @rot_mode:  rotation mode
+ * @complete:  run completion callback
+ * @complete_context:  a context pointer for the completion callback
+ *
+ * Request a single image conversion. Returns the run that has been queued.
+ * A conversion context is automatically created and is available in run->ctx.
+ * As with ipu_image_convert_prepare(), the input/output formats and rotation
+ * mode must already meet IPU retrictions.
+ *
+ * On successful return the caller can queue more run requests if needed, using
+ * the prepared context in run->ctx. The caller is responsible for unpreparing
+ * the context when no more conversion requests are needed.
+ */
+struct ipu_image_convert_run *
+ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+                 struct ipu_image *in, struct ipu_image *out,
+                 enum ipu_rotate_mode rot_mode,
+                 ipu_image_convert_cb_t complete,
+                 void *complete_context);
+
+/**
+ * ipu_image_convert_sync() - synchronous single image conversion request
+ *
+ * @ipu:       the IPU handle to use for the conversion
+ * @ic_task:   the IC task to use for the conversion
+ * @in:                input image format
+ * @out:       output image format
+ * @rot_mode:  rotation mode
+ *
+ * Carry out a single image conversion. Returns when the conversion
+ * completes. The input/output formats and rotation mode must already
+ * meet IPU retrictions. The created context is automatically unprepared
+ * and the run freed on return.
+ */
+int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+                          struct ipu_image *in, struct ipu_image *out,
+                          enum ipu_rotate_mode rot_mode);
+
+
+#endif /* __IMX_IPU_IMAGE_CONVERT_H__ */
index 7adeaae..173073e 100644 (file)
@@ -63,23 +63,41 @@ enum ipu_csi_dest {
 /*
  * Enumeration of IPU rotation modes
  */
+#define IPU_ROT_BIT_VFLIP (1 << 0)
+#define IPU_ROT_BIT_HFLIP (1 << 1)
+#define IPU_ROT_BIT_90    (1 << 2)
+
 enum ipu_rotate_mode {
        IPU_ROTATE_NONE = 0,
-       IPU_ROTATE_VERT_FLIP,
-       IPU_ROTATE_HORIZ_FLIP,
-       IPU_ROTATE_180,
-       IPU_ROTATE_90_RIGHT,
-       IPU_ROTATE_90_RIGHT_VFLIP,
-       IPU_ROTATE_90_RIGHT_HFLIP,
-       IPU_ROTATE_90_LEFT,
+       IPU_ROTATE_VERT_FLIP = IPU_ROT_BIT_VFLIP,
+       IPU_ROTATE_HORIZ_FLIP = IPU_ROT_BIT_HFLIP,
+       IPU_ROTATE_180 = (IPU_ROT_BIT_VFLIP | IPU_ROT_BIT_HFLIP),
+       IPU_ROTATE_90_RIGHT = IPU_ROT_BIT_90,
+       IPU_ROTATE_90_RIGHT_VFLIP = (IPU_ROT_BIT_90 | IPU_ROT_BIT_VFLIP),
+       IPU_ROTATE_90_RIGHT_HFLIP = (IPU_ROT_BIT_90 | IPU_ROT_BIT_HFLIP),
+       IPU_ROTATE_90_LEFT = (IPU_ROT_BIT_90 |
+                             IPU_ROT_BIT_VFLIP | IPU_ROT_BIT_HFLIP),
 };
 
+/* 90-degree rotations require the IRT unit */
+#define ipu_rot_mode_is_irt(m) (((m) & IPU_ROT_BIT_90) != 0)
+
 enum ipu_color_space {
        IPUV3_COLORSPACE_RGB,
        IPUV3_COLORSPACE_YUV,
        IPUV3_COLORSPACE_UNKNOWN,
 };
 
+/*
+ * Enumeration of VDI MOTION select
+ */
+enum ipu_motion_sel {
+       MOTION_NONE = 0,
+       LOW_MOTION,
+       MED_MOTION,
+       HIGH_MOTION,
+};
+
 struct ipuv3_channel;
 
 enum ipu_channel_irq {
@@ -97,20 +115,42 @@ enum ipu_channel_irq {
 #define IPUV3_CHANNEL_CSI2                      2
 #define IPUV3_CHANNEL_CSI3                      3
 #define IPUV3_CHANNEL_VDI_MEM_IC_VF             5
+/*
+ * NOTE: channels 6,7 are unused in the IPU and are not IDMAC channels,
+ * but the direct CSI->VDI linking is handled the same way as IDMAC
+ * channel linking in the FSU via the IPU_FS_PROC_FLOW registers, so
+ * these channel names are used to support the direct CSI->VDI link.
+ */
+#define IPUV3_CHANNEL_CSI_DIRECT                6
+#define IPUV3_CHANNEL_CSI_VDI_PREV              7
+#define IPUV3_CHANNEL_MEM_VDI_PREV              8
+#define IPUV3_CHANNEL_MEM_VDI_CUR               9
+#define IPUV3_CHANNEL_MEM_VDI_NEXT             10
 #define IPUV3_CHANNEL_MEM_IC_PP                        11
 #define IPUV3_CHANNEL_MEM_IC_PRP_VF            12
+#define IPUV3_CHANNEL_VDI_MEM_RECENT           13
 #define IPUV3_CHANNEL_G_MEM_IC_PRP_VF          14
 #define IPUV3_CHANNEL_G_MEM_IC_PP              15
+#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF_ALPHA    17
+#define IPUV3_CHANNEL_G_MEM_IC_PP_ALPHA                18
+#define IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB_ALPHA        19
 #define IPUV3_CHANNEL_IC_PRP_ENC_MEM           20
 #define IPUV3_CHANNEL_IC_PRP_VF_MEM            21
 #define IPUV3_CHANNEL_IC_PP_MEM                        22
 #define IPUV3_CHANNEL_MEM_BG_SYNC              23
 #define IPUV3_CHANNEL_MEM_BG_ASYNC             24
+#define IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB      25
+#define IPUV3_CHANNEL_MEM_VDI_PLANE3_COMB      26
 #define IPUV3_CHANNEL_MEM_FG_SYNC              27
 #define IPUV3_CHANNEL_MEM_DC_SYNC              28
 #define IPUV3_CHANNEL_MEM_FG_ASYNC             29
 #define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA                31
+#define IPUV3_CHANNEL_MEM_FG_ASYNC_ALPHA       33
+#define IPUV3_CHANNEL_DC_MEM_READ              40
 #define IPUV3_CHANNEL_MEM_DC_ASYNC             41
+#define IPUV3_CHANNEL_MEM_DC_COMMAND           42
+#define IPUV3_CHANNEL_MEM_DC_COMMAND2          43
+#define IPUV3_CHANNEL_MEM_DC_OUTPUT_MASK       44
 #define IPUV3_CHANNEL_MEM_ROT_ENC              45
 #define IPUV3_CHANNEL_MEM_ROT_VF               46
 #define IPUV3_CHANNEL_MEM_ROT_PP               47
@@ -118,6 +158,8 @@ enum ipu_channel_irq {
 #define IPUV3_CHANNEL_ROT_VF_MEM               49
 #define IPUV3_CHANNEL_ROT_PP_MEM               50
 #define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA                51
+#define IPUV3_CHANNEL_MEM_BG_ASYNC_ALPHA       52
+#define IPUV3_NUM_CHANNELS                     64
 
 int ipu_map_irq(struct ipu_soc *ipu, int irq);
 int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
@@ -138,6 +180,7 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
 /*
  * IPU Common functions
  */
+int ipu_get_num(struct ipu_soc *ipu);
 void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
 void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
 void ipu_dump(struct ipu_soc *ipu);
@@ -160,6 +203,10 @@ int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel);
 bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
 void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
 void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
+int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch);
+int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch);
+int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink);
+int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink);
 
 /*
  * IPU Channel Parameter Memory (cpmem) functions
@@ -184,8 +231,10 @@ void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres);
 void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
+void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
+int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
 void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
 void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
@@ -316,6 +365,19 @@ struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task);
 void ipu_ic_put(struct ipu_ic *ic);
 void ipu_ic_dump(struct ipu_ic *ic);
 
+/*
+ * IPU Video De-Interlacer (vdi) functions
+ */
+struct ipu_vdi;
+void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field);
+void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel);
+void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres);
+void ipu_vdi_unsetup(struct ipu_vdi *vdi);
+int ipu_vdi_enable(struct ipu_vdi *vdi);
+int ipu_vdi_disable(struct ipu_vdi *vdi);
+struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu);
+void ipu_vdi_put(struct ipu_vdi *vdi);
+
 /*
  * IPU Sensor Multiple FIFO Controller (SMFC) functions
  */