diff options
author | Dave Airlie <airlied@redhat.com> | 2016-08-24 22:59:50 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-08-24 22:59:50 -0400 |
commit | e9c3ddee6a08c5b25cdb06b524320a5a98250513 (patch) | |
tree | 41cc2cc030ef965c1d34b336c994a3ac9c00c13e | |
parent | 51d6120792ab5f46d6f5f7f37b65d05cc1afc019 (diff) | |
parent | 7b4d3e297e8a7d3b82e68231ff077e891c370349 (diff) |
Merge branch 'drm-next-4.9' of git://people.freedesktop.org/~agd5f/linux into drm-next
First drm-next pull for radeon and amdgpu for 4.9. Highlights:
- powerplay support for iceland asics
- improved GPU reset (both full asic and per block)
- UVD and VCE powergating for CZ and ST
- VCE clockgating for CZ and ST
- Support for pre-initialized (e.g., zeroed) vram buffers
- ttm cleanups
- virtual display support
- core and radeon/amdgpu support for page_flip_target
- lots of bug fixes and clean ups
* 'drm-next-4.9' of git://people.freedesktop.org/~agd5f/linux: (171 commits)
drm/amdgpu: use memcpy_toio for VCE firmware upload
drm/amdgpu: use memcpy_to/fromio for UVD fw upload
drm/amd/powerplay: delete useless code in iceland_hwmgr.c.
drm/radeon: switch UVD code to use UVD_NO_OP for padding
drm/amdgpu: switch UVD code to use UVD_NO_OP for padding
drm/radeon: add support for UVD_NO_OP register
drm/amdgpu: add support for UVD_NO_OP register
drm/amdgpu: fix VCE ib alignment value
drm/amdgpu: fix IB alignment for UVD
drm/amd/amdgpu: Print ring name in amdgpu_ib_schedule()
drm/radeon: remove dead code, si_mc_load_microcode (v2)
drm/radeon/cik: remove dead code (v2)
drm/amd/powerplay: avoid NULL dereference, cz_hwmgr.c
drm/amd/powerplay: avoid NULL pointer dereference
drm/amdgpu/gmc8: remove dead code (v2)
drm/amdgpu/gmc7: remove dead code (v2)
drm/amdgpu: Fix indentation in dce_v8_0_audio_write_sad_regs()
drm/amdgpu: Use correct mask in dce_v8_0_afmt_setmode() and fix comment typos.
drm/amdgpu: cleanup amdgpu_vm_bo_update params
drm/amdgpu: stop adding dummy entry in amdgpu_ttm_placement_init
...
127 files changed, 14468 insertions, 2022 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index fe1e86ea6d27..cbb64d9a82f8 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -163,9 +163,6 @@ config DRM_AMDGPU | |||
163 | If M is selected, the module will be called amdgpu. | 163 | If M is selected, the module will be called amdgpu. |
164 | 164 | ||
165 | source "drivers/gpu/drm/amd/amdgpu/Kconfig" | 165 | source "drivers/gpu/drm/amd/amdgpu/Kconfig" |
166 | source "drivers/gpu/drm/amd/powerplay/Kconfig" | ||
167 | |||
168 | source "drivers/gpu/drm/amd/acp/Kconfig" | ||
169 | 166 | ||
170 | source "drivers/gpu/drm/nouveau/Kconfig" | 167 | source "drivers/gpu/drm/nouveau/Kconfig" |
171 | 168 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig index 7335c0420c70..f3cb69de0c44 100644 --- a/drivers/gpu/drm/amd/amdgpu/Kconfig +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig | |||
@@ -25,3 +25,5 @@ config DRM_AMDGPU_GART_DEBUGFS | |||
25 | Selecting this option creates a debugfs file to inspect the mapped | 25 | Selecting this option creates a debugfs file to inspect the mapped |
26 | pages. Uses more memory for housekeeping, enable only for debugging. | 26 | pages. Uses more memory for housekeeping, enable only for debugging. |
27 | 27 | ||
28 | source "drivers/gpu/drm/amd/powerplay/Kconfig" | ||
29 | source "drivers/gpu/drm/amd/acp/Kconfig" | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index c7fcdcedaadb..21dd7c00da15 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile | |||
@@ -58,7 +58,8 @@ amdgpu-y += \ | |||
58 | # add DCE block | 58 | # add DCE block |
59 | amdgpu-y += \ | 59 | amdgpu-y += \ |
60 | dce_v10_0.o \ | 60 | dce_v10_0.o \ |
61 | dce_v11_0.o | 61 | dce_v11_0.o \ |
62 | dce_virtual.o | ||
62 | 63 | ||
63 | # add GFX block | 64 | # add GFX block |
64 | amdgpu-y += \ | 65 | amdgpu-y += \ |
diff --git a/drivers/gpu/drm/amd/amdgpu/ObjectID.h b/drivers/gpu/drm/amd/amdgpu/ObjectID.h index 06192698bd96..b8d66670bb17 100644 --- a/drivers/gpu/drm/amd/amdgpu/ObjectID.h +++ b/drivers/gpu/drm/amd/amdgpu/ObjectID.h | |||
@@ -90,6 +90,7 @@ | |||
90 | #define ENCODER_OBJECT_ID_INTERNAL_VCE 0x24 | 90 | #define ENCODER_OBJECT_ID_INTERNAL_VCE 0x24 |
91 | #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 0x25 | 91 | #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 0x25 |
92 | #define ENCODER_OBJECT_ID_INTERNAL_AMCLK 0x27 | 92 | #define ENCODER_OBJECT_ID_INTERNAL_AMCLK 0x27 |
93 | #define ENCODER_OBJECT_ID_VIRTUAL 0x28 | ||
93 | 94 | ||
94 | #define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO 0xFF | 95 | #define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO 0xFF |
95 | 96 | ||
@@ -119,6 +120,7 @@ | |||
119 | #define CONNECTOR_OBJECT_ID_eDP 0x14 | 120 | #define CONNECTOR_OBJECT_ID_eDP 0x14 |
120 | #define CONNECTOR_OBJECT_ID_MXM 0x15 | 121 | #define CONNECTOR_OBJECT_ID_MXM 0x15 |
121 | #define CONNECTOR_OBJECT_ID_LVDS_eDP 0x16 | 122 | #define CONNECTOR_OBJECT_ID_LVDS_eDP 0x16 |
123 | #define CONNECTOR_OBJECT_ID_VIRTUAL 0x17 | ||
122 | 124 | ||
123 | /* deleted */ | 125 | /* deleted */ |
124 | 126 | ||
@@ -147,6 +149,7 @@ | |||
147 | #define GRAPH_OBJECT_ENUM_ID5 0x05 | 149 | #define GRAPH_OBJECT_ENUM_ID5 0x05 |
148 | #define GRAPH_OBJECT_ENUM_ID6 0x06 | 150 | #define GRAPH_OBJECT_ENUM_ID6 0x06 |
149 | #define GRAPH_OBJECT_ENUM_ID7 0x07 | 151 | #define GRAPH_OBJECT_ENUM_ID7 0x07 |
152 | #define GRAPH_OBJECT_ENUM_VIRTUAL 0x08 | ||
150 | 153 | ||
151 | /****************************************************/ | 154 | /****************************************************/ |
152 | /* Graphics Object ID Bit definition */ | 155 | /* Graphics Object ID Bit definition */ |
@@ -408,6 +411,10 @@ | |||
408 | GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ | 411 | GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ |
409 | ENCODER_OBJECT_ID_HDMI_ANX9805 << OBJECT_ID_SHIFT) | 412 | ENCODER_OBJECT_ID_HDMI_ANX9805 << OBJECT_ID_SHIFT) |
410 | 413 | ||
414 | #define ENCODER_VIRTUAL_ENUM_VIRTUAL ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ | ||
415 | GRAPH_OBJECT_ENUM_VIRTUAL << ENUM_ID_SHIFT |\ | ||
416 | ENCODER_OBJECT_ID_VIRTUAL << OBJECT_ID_SHIFT) | ||
417 | |||
411 | /****************************************************/ | 418 | /****************************************************/ |
412 | /* Connector Object ID definition - Shared with BIOS */ | 419 | /* Connector Object ID definition - Shared with BIOS */ |
413 | /****************************************************/ | 420 | /****************************************************/ |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 8ebc5f1eb4c0..3cc2629eb158 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h | |||
@@ -51,6 +51,7 @@ | |||
51 | #include "amdgpu_ih.h" | 51 | #include "amdgpu_ih.h" |
52 | #include "amdgpu_irq.h" | 52 | #include "amdgpu_irq.h" |
53 | #include "amdgpu_ucode.h" | 53 | #include "amdgpu_ucode.h" |
54 | #include "amdgpu_ttm.h" | ||
54 | #include "amdgpu_gds.h" | 55 | #include "amdgpu_gds.h" |
55 | #include "amd_powerplay.h" | 56 | #include "amd_powerplay.h" |
56 | #include "amdgpu_acp.h" | 57 | #include "amdgpu_acp.h" |
@@ -91,6 +92,8 @@ extern unsigned amdgpu_pcie_lane_cap; | |||
91 | extern unsigned amdgpu_cg_mask; | 92 | extern unsigned amdgpu_cg_mask; |
92 | extern unsigned amdgpu_pg_mask; | 93 | extern unsigned amdgpu_pg_mask; |
93 | extern char *amdgpu_disable_cu; | 94 | extern char *amdgpu_disable_cu; |
95 | extern int amdgpu_sclk_deep_sleep_en; | ||
96 | extern char *amdgpu_virtual_display; | ||
94 | 97 | ||
95 | #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 | 98 | #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 |
96 | #define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */ | 99 | #define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */ |
@@ -248,10 +251,9 @@ struct amdgpu_vm_pte_funcs { | |||
248 | uint64_t pe, uint64_t src, | 251 | uint64_t pe, uint64_t src, |
249 | unsigned count); | 252 | unsigned count); |
250 | /* write pte one entry at a time with addr mapping */ | 253 | /* write pte one entry at a time with addr mapping */ |
251 | void (*write_pte)(struct amdgpu_ib *ib, | 254 | void (*write_pte)(struct amdgpu_ib *ib, uint64_t pe, |
252 | const dma_addr_t *pages_addr, uint64_t pe, | 255 | uint64_t value, unsigned count, |
253 | uint64_t addr, unsigned count, | 256 | uint32_t incr); |
254 | uint32_t incr, uint32_t flags); | ||
255 | /* for linear pte/pde updates without addr mapping */ | 257 | /* for linear pte/pde updates without addr mapping */ |
256 | void (*set_pte_pde)(struct amdgpu_ib *ib, | 258 | void (*set_pte_pde)(struct amdgpu_ib *ib, |
257 | uint64_t pe, | 259 | uint64_t pe, |
@@ -396,46 +398,9 @@ int amdgpu_fence_wait_empty(struct amdgpu_ring *ring); | |||
396 | unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring); | 398 | unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring); |
397 | 399 | ||
398 | /* | 400 | /* |
399 | * TTM. | 401 | * BO. |
400 | */ | 402 | */ |
401 | 403 | ||
402 | #define AMDGPU_TTM_LRU_SIZE 20 | ||
403 | |||
404 | struct amdgpu_mman_lru { | ||
405 | struct list_head *lru[TTM_NUM_MEM_TYPES]; | ||
406 | struct list_head *swap_lru; | ||
407 | }; | ||
408 | |||
409 | struct amdgpu_mman { | ||
410 | struct ttm_bo_global_ref bo_global_ref; | ||
411 | struct drm_global_reference mem_global_ref; | ||
412 | struct ttm_bo_device bdev; | ||
413 | bool mem_global_referenced; | ||
414 | bool initialized; | ||
415 | |||
416 | #if defined(CONFIG_DEBUG_FS) | ||
417 | struct dentry *vram; | ||
418 | struct dentry *gtt; | ||
419 | #endif | ||
420 | |||
421 | /* buffer handling */ | ||
422 | const struct amdgpu_buffer_funcs *buffer_funcs; | ||
423 | struct amdgpu_ring *buffer_funcs_ring; | ||
424 | /* Scheduler entity for buffer moves */ | ||
425 | struct amd_sched_entity entity; | ||
426 | |||
427 | /* custom LRU management */ | ||
428 | struct amdgpu_mman_lru log2_size[AMDGPU_TTM_LRU_SIZE]; | ||
429 | }; | ||
430 | |||
431 | int amdgpu_copy_buffer(struct amdgpu_ring *ring, | ||
432 | uint64_t src_offset, | ||
433 | uint64_t dst_offset, | ||
434 | uint32_t byte_count, | ||
435 | struct reservation_object *resv, | ||
436 | struct fence **fence); | ||
437 | int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma); | ||
438 | |||
439 | struct amdgpu_bo_list_entry { | 404 | struct amdgpu_bo_list_entry { |
440 | struct amdgpu_bo *robj; | 405 | struct amdgpu_bo *robj; |
441 | struct ttm_validate_buffer tv; | 406 | struct ttm_validate_buffer tv; |
@@ -498,10 +463,12 @@ struct amdgpu_bo { | |||
498 | struct amdgpu_device *adev; | 463 | struct amdgpu_device *adev; |
499 | struct drm_gem_object gem_base; | 464 | struct drm_gem_object gem_base; |
500 | struct amdgpu_bo *parent; | 465 | struct amdgpu_bo *parent; |
466 | struct amdgpu_bo *shadow; | ||
501 | 467 | ||
502 | struct ttm_bo_kmap_obj dma_buf_vmap; | 468 | struct ttm_bo_kmap_obj dma_buf_vmap; |
503 | struct amdgpu_mn *mn; | 469 | struct amdgpu_mn *mn; |
504 | struct list_head mn_list; | 470 | struct list_head mn_list; |
471 | struct list_head shadow_list; | ||
505 | }; | 472 | }; |
506 | #define gem_to_amdgpu_bo(gobj) container_of((gobj), struct amdgpu_bo, gem_base) | 473 | #define gem_to_amdgpu_bo(gobj) container_of((gobj), struct amdgpu_bo, gem_base) |
507 | 474 | ||
@@ -677,6 +644,8 @@ struct amdgpu_mc { | |||
677 | uint32_t fw_version; | 644 | uint32_t fw_version; |
678 | struct amdgpu_irq_src vm_fault; | 645 | struct amdgpu_irq_src vm_fault; |
679 | uint32_t vram_type; | 646 | uint32_t vram_type; |
647 | uint32_t srbm_soft_reset; | ||
648 | struct amdgpu_mode_mc_save save; | ||
680 | }; | 649 | }; |
681 | 650 | ||
682 | /* | 651 | /* |
@@ -721,10 +690,11 @@ void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev, | |||
721 | */ | 690 | */ |
722 | 691 | ||
723 | struct amdgpu_flip_work { | 692 | struct amdgpu_flip_work { |
724 | struct work_struct flip_work; | 693 | struct delayed_work flip_work; |
725 | struct work_struct unpin_work; | 694 | struct work_struct unpin_work; |
726 | struct amdgpu_device *adev; | 695 | struct amdgpu_device *adev; |
727 | int crtc_id; | 696 | int crtc_id; |
697 | u32 target_vblank; | ||
728 | uint64_t base; | 698 | uint64_t base; |
729 | struct drm_pending_vblank_event *event; | 699 | struct drm_pending_vblank_event *event; |
730 | struct amdgpu_bo *old_rbo; | 700 | struct amdgpu_bo *old_rbo; |
@@ -815,13 +785,17 @@ struct amdgpu_ring { | |||
815 | /* maximum number of VMIDs */ | 785 | /* maximum number of VMIDs */ |
816 | #define AMDGPU_NUM_VM 16 | 786 | #define AMDGPU_NUM_VM 16 |
817 | 787 | ||
788 | /* Maximum number of PTEs the hardware can write with one command */ | ||
789 | #define AMDGPU_VM_MAX_UPDATE_SIZE 0x3FFFF | ||
790 | |||
818 | /* number of entries in page table */ | 791 | /* number of entries in page table */ |
819 | #define AMDGPU_VM_PTE_COUNT (1 << amdgpu_vm_block_size) | 792 | #define AMDGPU_VM_PTE_COUNT (1 << amdgpu_vm_block_size) |
820 | 793 | ||
821 | /* PTBs (Page Table Blocks) need to be aligned to 32K */ | 794 | /* PTBs (Page Table Blocks) need to be aligned to 32K */ |
822 | #define AMDGPU_VM_PTB_ALIGN_SIZE 32768 | 795 | #define AMDGPU_VM_PTB_ALIGN_SIZE 32768 |
823 | #define AMDGPU_VM_PTB_ALIGN_MASK (AMDGPU_VM_PTB_ALIGN_SIZE - 1) | 796 | |
824 | #define AMDGPU_VM_PTB_ALIGN(a) (((a) + AMDGPU_VM_PTB_ALIGN_MASK) & ~AMDGPU_VM_PTB_ALIGN_MASK) | 797 | /* LOG2 number of continuous pages for the fragment field */ |
798 | #define AMDGPU_LOG2_PAGES_PER_FRAG 4 | ||
825 | 799 | ||
826 | #define AMDGPU_PTE_VALID (1 << 0) | 800 | #define AMDGPU_PTE_VALID (1 << 0) |
827 | #define AMDGPU_PTE_SYSTEM (1 << 1) | 801 | #define AMDGPU_PTE_SYSTEM (1 << 1) |
@@ -833,10 +807,7 @@ struct amdgpu_ring { | |||
833 | #define AMDGPU_PTE_READABLE (1 << 5) | 807 | #define AMDGPU_PTE_READABLE (1 << 5) |
834 | #define AMDGPU_PTE_WRITEABLE (1 << 6) | 808 | #define AMDGPU_PTE_WRITEABLE (1 << 6) |
835 | 809 | ||
836 | /* PTE (Page Table Entry) fragment field for different page sizes */ | 810 | #define AMDGPU_PTE_FRAG(x) ((x & 0x1f) << 7) |
837 | #define AMDGPU_PTE_FRAG_4KB (0 << 7) | ||
838 | #define AMDGPU_PTE_FRAG_64KB (4 << 7) | ||
839 | #define AMDGPU_LOG2_PAGES_PER_FRAG 4 | ||
840 | 811 | ||
841 | /* How to programm VM fault handling */ | 812 | /* How to programm VM fault handling */ |
842 | #define AMDGPU_VM_FAULT_STOP_NEVER 0 | 813 | #define AMDGPU_VM_FAULT_STOP_NEVER 0 |
@@ -846,6 +817,7 @@ struct amdgpu_ring { | |||
846 | struct amdgpu_vm_pt { | 817 | struct amdgpu_vm_pt { |
847 | struct amdgpu_bo_list_entry entry; | 818 | struct amdgpu_bo_list_entry entry; |
848 | uint64_t addr; | 819 | uint64_t addr; |
820 | uint64_t shadow_addr; | ||
849 | }; | 821 | }; |
850 | 822 | ||
851 | struct amdgpu_vm { | 823 | struct amdgpu_vm { |
@@ -948,7 +920,6 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, | |||
948 | struct amdgpu_job *job); | 920 | struct amdgpu_job *job); |
949 | int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job); | 921 | int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job); |
950 | void amdgpu_vm_reset_id(struct amdgpu_device *adev, unsigned vm_id); | 922 | void amdgpu_vm_reset_id(struct amdgpu_device *adev, unsigned vm_id); |
951 | uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr); | ||
952 | int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, | 923 | int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, |
953 | struct amdgpu_vm *vm); | 924 | struct amdgpu_vm *vm); |
954 | int amdgpu_vm_clear_freed(struct amdgpu_device *adev, | 925 | int amdgpu_vm_clear_freed(struct amdgpu_device *adev, |
@@ -957,7 +928,7 @@ int amdgpu_vm_clear_invalids(struct amdgpu_device *adev, struct amdgpu_vm *vm, | |||
957 | struct amdgpu_sync *sync); | 928 | struct amdgpu_sync *sync); |
958 | int amdgpu_vm_bo_update(struct amdgpu_device *adev, | 929 | int amdgpu_vm_bo_update(struct amdgpu_device *adev, |
959 | struct amdgpu_bo_va *bo_va, | 930 | struct amdgpu_bo_va *bo_va, |
960 | struct ttm_mem_reg *mem); | 931 | bool clear); |
961 | void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev, | 932 | void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev, |
962 | struct amdgpu_bo *bo); | 933 | struct amdgpu_bo *bo); |
963 | struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm, | 934 | struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm, |
@@ -1195,6 +1166,10 @@ struct amdgpu_gfx { | |||
1195 | unsigned ce_ram_size; | 1166 | unsigned ce_ram_size; |
1196 | struct amdgpu_cu_info cu_info; | 1167 | struct amdgpu_cu_info cu_info; |
1197 | const struct amdgpu_gfx_funcs *funcs; | 1168 | const struct amdgpu_gfx_funcs *funcs; |
1169 | |||
1170 | /* reset mask */ | ||
1171 | uint32_t grbm_soft_reset; | ||
1172 | uint32_t srbm_soft_reset; | ||
1198 | }; | 1173 | }; |
1199 | 1174 | ||
1200 | int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm, | 1175 | int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm, |
@@ -1683,6 +1658,7 @@ struct amdgpu_uvd { | |||
1683 | bool address_64_bit; | 1658 | bool address_64_bit; |
1684 | bool use_ctx_buf; | 1659 | bool use_ctx_buf; |
1685 | struct amd_sched_entity entity; | 1660 | struct amd_sched_entity entity; |
1661 | uint32_t srbm_soft_reset; | ||
1686 | }; | 1662 | }; |
1687 | 1663 | ||
1688 | /* | 1664 | /* |
@@ -1709,6 +1685,7 @@ struct amdgpu_vce { | |||
1709 | struct amdgpu_irq_src irq; | 1685 | struct amdgpu_irq_src irq; |
1710 | unsigned harvest_config; | 1686 | unsigned harvest_config; |
1711 | struct amd_sched_entity entity; | 1687 | struct amd_sched_entity entity; |
1688 | uint32_t srbm_soft_reset; | ||
1712 | }; | 1689 | }; |
1713 | 1690 | ||
1714 | /* | 1691 | /* |
@@ -1729,6 +1706,7 @@ struct amdgpu_sdma { | |||
1729 | struct amdgpu_irq_src trap_irq; | 1706 | struct amdgpu_irq_src trap_irq; |
1730 | struct amdgpu_irq_src illegal_inst_irq; | 1707 | struct amdgpu_irq_src illegal_inst_irq; |
1731 | int num_instances; | 1708 | int num_instances; |
1709 | uint32_t srbm_soft_reset; | ||
1732 | }; | 1710 | }; |
1733 | 1711 | ||
1734 | /* | 1712 | /* |
@@ -1956,6 +1934,7 @@ struct amdgpu_ip_block_status { | |||
1956 | bool valid; | 1934 | bool valid; |
1957 | bool sw; | 1935 | bool sw; |
1958 | bool hw; | 1936 | bool hw; |
1937 | bool hang; | ||
1959 | }; | 1938 | }; |
1960 | 1939 | ||
1961 | struct amdgpu_device { | 1940 | struct amdgpu_device { |
@@ -2055,6 +2034,7 @@ struct amdgpu_device { | |||
2055 | atomic_t gpu_reset_counter; | 2034 | atomic_t gpu_reset_counter; |
2056 | 2035 | ||
2057 | /* display */ | 2036 | /* display */ |
2037 | bool enable_virtual_display; | ||
2058 | struct amdgpu_mode_info mode_info; | 2038 | struct amdgpu_mode_info mode_info; |
2059 | struct work_struct hotplug_work; | 2039 | struct work_struct hotplug_work; |
2060 | struct amdgpu_irq_src crtc_irq; | 2040 | struct amdgpu_irq_src crtc_irq; |
@@ -2117,6 +2097,10 @@ struct amdgpu_device { | |||
2117 | struct kfd_dev *kfd; | 2097 | struct kfd_dev *kfd; |
2118 | 2098 | ||
2119 | struct amdgpu_virtualization virtualization; | 2099 | struct amdgpu_virtualization virtualization; |
2100 | |||
2101 | /* link all shadow bo */ | ||
2102 | struct list_head shadow_list; | ||
2103 | struct mutex shadow_list_lock; | ||
2120 | }; | 2104 | }; |
2121 | 2105 | ||
2122 | bool amdgpu_device_is_px(struct drm_device *dev); | 2106 | bool amdgpu_device_is_px(struct drm_device *dev); |
@@ -2192,6 +2176,9 @@ void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v); | |||
2192 | #define REG_GET_FIELD(value, reg, field) \ | 2176 | #define REG_GET_FIELD(value, reg, field) \ |
2193 | (((value) & REG_FIELD_MASK(reg, field)) >> REG_FIELD_SHIFT(reg, field)) | 2177 | (((value) & REG_FIELD_MASK(reg, field)) >> REG_FIELD_SHIFT(reg, field)) |
2194 | 2178 | ||
2179 | #define WREG32_FIELD(reg, field, val) \ | ||
2180 | WREG32(mm##reg, (RREG32(mm##reg) & ~REG_FIELD_MASK(reg, field)) | (val) << REG_FIELD_SHIFT(reg, field)) | ||
2181 | |||
2195 | /* | 2182 | /* |
2196 | * BIOS helpers. | 2183 | * BIOS helpers. |
2197 | */ | 2184 | */ |
@@ -2242,7 +2229,7 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring) | |||
2242 | #define amdgpu_gart_flush_gpu_tlb(adev, vmid) (adev)->gart.gart_funcs->flush_gpu_tlb((adev), (vmid)) | 2229 | #define amdgpu_gart_flush_gpu_tlb(adev, vmid) (adev)->gart.gart_funcs->flush_gpu_tlb((adev), (vmid)) |
2243 | #define amdgpu_gart_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gart.gart_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags)) | 2230 | #define amdgpu_gart_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gart.gart_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags)) |
2244 | #define amdgpu_vm_copy_pte(adev, ib, pe, src, count) ((adev)->vm_manager.vm_pte_funcs->copy_pte((ib), (pe), (src), (count))) | 2231 | #define amdgpu_vm_copy_pte(adev, ib, pe, src, count) ((adev)->vm_manager.vm_pte_funcs->copy_pte((ib), (pe), (src), (count))) |
2245 | #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))) | 2232 | #define amdgpu_vm_write_pte(adev, ib, pe, value, count, incr) ((adev)->vm_manager.vm_pte_funcs->write_pte((ib), (pe), (value), (count), (incr))) |
2246 | #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))) | 2233 | #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))) |
2247 | #define amdgpu_ring_parse_cs(r, p, ib) ((r)->funcs->parse_cs((p), (ib))) | 2234 | #define amdgpu_ring_parse_cs(r, p, ib) ((r)->funcs->parse_cs((p), (ib))) |
2248 | #define amdgpu_ring_test_ring(r) (r)->funcs->test_ring((r)) | 2235 | #define amdgpu_ring_test_ring(r) (r)->funcs->test_ring((r)) |
@@ -2387,6 +2374,7 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring) | |||
2387 | 2374 | ||
2388 | /* Common functions */ | 2375 | /* Common functions */ |
2389 | int amdgpu_gpu_reset(struct amdgpu_device *adev); | 2376 | int amdgpu_gpu_reset(struct amdgpu_device *adev); |
2377 | bool amdgpu_need_backup(struct amdgpu_device *adev); | ||
2390 | void amdgpu_pci_config_reset(struct amdgpu_device *adev); | 2378 | void amdgpu_pci_config_reset(struct amdgpu_device *adev); |
2391 | bool amdgpu_card_posted(struct amdgpu_device *adev); | 2379 | bool amdgpu_card_posted(struct amdgpu_device *adev); |
2392 | void amdgpu_update_display_priority(struct amdgpu_device *adev); | 2380 | void amdgpu_update_display_priority(struct amdgpu_device *adev); |
@@ -2412,6 +2400,8 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, | |||
2412 | void amdgpu_vram_location(struct amdgpu_device *adev, struct amdgpu_mc *mc, u64 base); | 2400 | void amdgpu_vram_location(struct amdgpu_device *adev, struct amdgpu_mc *mc, u64 base); |
2413 | void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc); | 2401 | void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc); |
2414 | void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size); | 2402 | void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size); |
2403 | u64 amdgpu_ttm_get_gtt_mem_size(struct amdgpu_device *adev); | ||
2404 | int amdgpu_ttm_global_init(struct amdgpu_device *adev); | ||
2415 | void amdgpu_program_register_sequence(struct amdgpu_device *adev, | 2405 | void amdgpu_program_register_sequence(struct amdgpu_device *adev, |
2416 | const u32 *registers, | 2406 | const u32 *registers, |
2417 | const u32 array_size); | 2407 | const u32 array_size); |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index 983175363b06..1b621160b52e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | |||
@@ -259,6 +259,33 @@ static const int object_connector_convert[] = { | |||
259 | DRM_MODE_CONNECTOR_Unknown | 259 | DRM_MODE_CONNECTOR_Unknown |
260 | }; | 260 | }; |
261 | 261 | ||
262 | bool amdgpu_atombios_has_dce_engine_info(struct amdgpu_device *adev) | ||
263 | { | ||
264 | struct amdgpu_mode_info *mode_info = &adev->mode_info; | ||
265 | struct atom_context *ctx = mode_info->atom_context; | ||
266 | int index = GetIndexIntoMasterTable(DATA, Object_Header); | ||
267 | u16 size, data_offset; | ||
268 | u8 frev, crev; | ||
269 | ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj; | ||
270 | ATOM_OBJECT_HEADER *obj_header; | ||
271 | |||
272 | if (!amdgpu_atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) | ||
273 | return false; | ||
274 | |||
275 | if (crev < 2) | ||
276 | return false; | ||
277 | |||
278 | obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset); | ||
279 | path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *) | ||
280 | (ctx->bios + data_offset + | ||
281 | le16_to_cpu(obj_header->usDisplayPathTableOffset)); | ||
282 | |||
283 | if (path_obj->ucNumOfDispPath) | ||
284 | return true; | ||
285 | else | ||
286 | return false; | ||
287 | } | ||
288 | |||
262 | bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev) | 289 | bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev) |
263 | { | 290 | { |
264 | struct amdgpu_mode_info *mode_info = &adev->mode_info; | 291 | struct amdgpu_mode_info *mode_info = &adev->mode_info; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h index 8c2e69661799..15dd43ec38bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h | |||
@@ -140,6 +140,8 @@ struct amdgpu_i2c_bus_rec amdgpu_atombios_lookup_i2c_gpio(struct amdgpu_device * | |||
140 | uint8_t id); | 140 | uint8_t id); |
141 | void amdgpu_atombios_i2c_init(struct amdgpu_device *adev); | 141 | void amdgpu_atombios_i2c_init(struct amdgpu_device *adev); |
142 | 142 | ||
143 | bool amdgpu_atombios_has_dce_engine_info(struct amdgpu_device *adev); | ||
144 | |||
143 | bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev); | 145 | bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev); |
144 | 146 | ||
145 | int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev); | 147 | int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev); |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c index 33e47a43ae32..345305235349 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c | |||
@@ -39,7 +39,8 @@ static int amdgpu_benchmark_do_move(struct amdgpu_device *adev, unsigned size, | |||
39 | start_jiffies = jiffies; | 39 | start_jiffies = jiffies; |
40 | for (i = 0; i < n; i++) { | 40 | for (i = 0; i < n; i++) { |
41 | struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; | 41 | struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; |
42 | r = amdgpu_copy_buffer(ring, saddr, daddr, size, NULL, &fence); | 42 | r = amdgpu_copy_buffer(ring, saddr, daddr, size, NULL, &fence, |
43 | false); | ||
43 | if (r) | 44 | if (r) |
44 | goto exit_do_move; | 45 | goto exit_do_move; |
45 | r = fence_wait(fence, false); | 46 | r = fence_wait(fence, false); |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index ff0b55a65ca3..319a5e1d9389 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | |||
@@ -1504,6 +1504,86 @@ static const struct drm_connector_funcs amdgpu_connector_edp_funcs = { | |||
1504 | .force = amdgpu_connector_dvi_force, | 1504 | .force = amdgpu_connector_dvi_force, |
1505 | }; | 1505 | }; |
1506 | 1506 | ||
1507 | static struct drm_encoder * | ||
1508 | amdgpu_connector_virtual_encoder(struct drm_connector *connector) | ||
1509 | { | ||
1510 | int enc_id = connector->encoder_ids[0]; | ||
1511 | struct drm_encoder *encoder; | ||
1512 | int i; | ||
1513 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
1514 | if (connector->encoder_ids[i] == 0) | ||
1515 | break; | ||
1516 | |||
1517 | encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); | ||
1518 | if (!encoder) | ||
1519 | continue; | ||
1520 | |||
1521 | if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) | ||
1522 | return encoder; | ||
1523 | } | ||
1524 | |||
1525 | /* pick the first one */ | ||
1526 | if (enc_id) | ||
1527 | return drm_encoder_find(connector->dev, enc_id); | ||
1528 | return NULL; | ||
1529 | } | ||
1530 | |||
1531 | static int amdgpu_connector_virtual_get_modes(struct drm_connector *connector) | ||
1532 | { | ||
1533 | struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); | ||
1534 | |||
1535 | if (encoder) { | ||
1536 | amdgpu_connector_add_common_modes(encoder, connector); | ||
1537 | } | ||
1538 | |||
1539 | return 0; | ||
1540 | } | ||
1541 | |||
1542 | static int amdgpu_connector_virtual_mode_valid(struct drm_connector *connector, | ||
1543 | struct drm_display_mode *mode) | ||
1544 | { | ||
1545 | return MODE_OK; | ||
1546 | } | ||
1547 | |||
1548 | int amdgpu_connector_virtual_dpms(struct drm_connector *connector, int mode) | ||
1549 | { | ||
1550 | return 0; | ||
1551 | } | ||
1552 | |||
1553 | static enum drm_connector_status | ||
1554 | |||
1555 | amdgpu_connector_virtual_detect(struct drm_connector *connector, bool force) | ||
1556 | { | ||
1557 | return connector_status_connected; | ||
1558 | } | ||
1559 | |||
1560 | int amdgpu_connector_virtual_set_property(struct drm_connector *connector, | ||
1561 | struct drm_property *property, | ||
1562 | uint64_t val) | ||
1563 | { | ||
1564 | return 0; | ||
1565 | } | ||
1566 | |||
1567 | static void amdgpu_connector_virtual_force(struct drm_connector *connector) | ||
1568 | { | ||
1569 | return; | ||
1570 | } | ||
1571 | |||
1572 | static const struct drm_connector_helper_funcs amdgpu_connector_virtual_helper_funcs = { | ||
1573 | .get_modes = amdgpu_connector_virtual_get_modes, | ||
1574 | .mode_valid = amdgpu_connector_virtual_mode_valid, | ||
1575 | .best_encoder = amdgpu_connector_virtual_encoder, | ||
1576 | }; | ||
1577 | |||
1578 | static const struct drm_connector_funcs amdgpu_connector_virtual_funcs = { | ||
1579 | .dpms = amdgpu_connector_virtual_dpms, | ||
1580 | .detect = amdgpu_connector_virtual_detect, | ||
1581 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
1582 | .set_property = amdgpu_connector_virtual_set_property, | ||
1583 | .destroy = amdgpu_connector_destroy, | ||
1584 | .force = amdgpu_connector_virtual_force, | ||
1585 | }; | ||
1586 | |||
1507 | void | 1587 | void |
1508 | amdgpu_connector_add(struct amdgpu_device *adev, | 1588 | amdgpu_connector_add(struct amdgpu_device *adev, |
1509 | uint32_t connector_id, | 1589 | uint32_t connector_id, |
@@ -1888,6 +1968,17 @@ amdgpu_connector_add(struct amdgpu_device *adev, | |||
1888 | connector->interlace_allowed = false; | 1968 | connector->interlace_allowed = false; |
1889 | connector->doublescan_allowed = false; | 1969 | connector->doublescan_allowed = false; |
1890 | break; | 1970 | break; |
1971 | case DRM_MODE_CONNECTOR_VIRTUAL: | ||
1972 | amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL); | ||
1973 | if (!amdgpu_dig_connector) | ||
1974 | goto failed; | ||
1975 | amdgpu_connector->con_priv = amdgpu_dig_connector; | ||
1976 | drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_virtual_funcs, connector_type); | ||
1977 | drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_virtual_helper_funcs); | ||
1978 | subpixel_order = SubPixelHorizontalRGB; | ||
1979 | connector->interlace_allowed = false; | ||
1980 | connector->doublescan_allowed = false; | ||
1981 | break; | ||
1891 | } | 1982 | } |
1892 | } | 1983 | } |
1893 | 1984 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 0307ff5887c5..d80e5d3a4add 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | |||
@@ -287,18 +287,56 @@ static u64 amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev) | |||
287 | return max(bytes_moved_threshold, 1024*1024ull); | 287 | return max(bytes_moved_threshold, 1024*1024ull); |
288 | } | 288 | } |
289 | 289 | ||
290 | static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, | ||
291 | struct amdgpu_bo *bo) | ||
292 | { | ||
293 | u64 initial_bytes_moved; | ||
294 | uint32_t domain; | ||
295 | int r; | ||
296 | |||
297 | if (bo->pin_count) | ||
298 | return 0; | ||
299 | |||
300 | /* Avoid moving this one if we have moved too many buffers | ||
301 | * for this IB already. | ||
302 | * | ||
303 | * Note that this allows moving at least one buffer of | ||
304 | * any size, because it doesn't take the current "bo" | ||
305 | * into account. We don't want to disallow buffer moves | ||
306 | * completely. | ||
307 | */ | ||
308 | if (p->bytes_moved <= p->bytes_moved_threshold) | ||
309 | domain = bo->prefered_domains; | ||
310 | else | ||
311 | domain = bo->allowed_domains; | ||
312 | |||
313 | retry: | ||
314 | amdgpu_ttm_placement_from_domain(bo, domain); | ||
315 | initial_bytes_moved = atomic64_read(&bo->adev->num_bytes_moved); | ||
316 | r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); | ||
317 | p->bytes_moved += atomic64_read(&bo->adev->num_bytes_moved) - | ||
318 | initial_bytes_moved; | ||
319 | |||
320 | if (unlikely(r)) { | ||
321 | if (r != -ERESTARTSYS && domain != bo->allowed_domains) { | ||
322 | domain = bo->allowed_domains; | ||
323 | goto retry; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return r; | ||
328 | } | ||
329 | |||
290 | int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p, | 330 | int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p, |
291 | struct list_head *validated) | 331 | struct list_head *validated) |
292 | { | 332 | { |
293 | struct amdgpu_bo_list_entry *lobj; | 333 | struct amdgpu_bo_list_entry *lobj; |
294 | u64 initial_bytes_moved; | ||
295 | int r; | 334 | int r; |
296 | 335 | ||
297 | list_for_each_entry(lobj, validated, tv.head) { | 336 | list_for_each_entry(lobj, validated, tv.head) { |
298 | struct amdgpu_bo *bo = lobj->robj; | 337 | struct amdgpu_bo *bo = lobj->robj; |
299 | bool binding_userptr = false; | 338 | bool binding_userptr = false; |
300 | struct mm_struct *usermm; | 339 | struct mm_struct *usermm; |
301 | uint32_t domain; | ||
302 | 340 | ||
303 | usermm = amdgpu_ttm_tt_get_usermm(bo->tbo.ttm); | 341 | usermm = amdgpu_ttm_tt_get_usermm(bo->tbo.ttm); |
304 | if (usermm && usermm != current->mm) | 342 | if (usermm && usermm != current->mm) |
@@ -313,35 +351,13 @@ int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p, | |||
313 | binding_userptr = true; | 351 | binding_userptr = true; |
314 | } | 352 | } |
315 | 353 | ||
316 | if (bo->pin_count) | 354 | r = amdgpu_cs_bo_validate(p, bo); |
317 | continue; | 355 | if (r) |
318 | |||
319 | /* Avoid moving this one if we have moved too many buffers | ||
320 | * for this IB already. | ||
321 | * | ||
322 | * Note that this allows moving at least one buffer of | ||
323 | * any size, because it doesn't take the current "bo" | ||
324 | * into account. We don't want to disallow buffer moves | ||
325 | * completely. | ||
326 | */ | ||
327 | if (p->bytes_moved <= p->bytes_moved_threshold) | ||
328 | domain = bo->prefered_domains; | ||
329 | else | ||
330 | domain = bo->allowed_domains; | ||
331 | |||
332 | retry: | ||
333 | amdgpu_ttm_placement_from_domain(bo, domain); | ||
334 | initial_bytes_moved = atomic64_read(&bo->adev->num_bytes_moved); | ||
335 | r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); | ||
336 | p->bytes_moved += atomic64_read(&bo->adev->num_bytes_moved) - | ||
337 | initial_bytes_moved; | ||
338 | |||
339 | if (unlikely(r)) { | ||
340 | if (r != -ERESTARTSYS && domain != bo->allowed_domains) { | ||
341 | domain = bo->allowed_domains; | ||
342 | goto retry; | ||
343 | } | ||
344 | return r; | 356 | return r; |
357 | if (bo->shadow) { | ||
358 | r = amdgpu_cs_bo_validate(p, bo); | ||
359 | if (r) | ||
360 | return r; | ||
345 | } | 361 | } |
346 | 362 | ||
347 | if (binding_userptr) { | 363 | if (binding_userptr) { |
@@ -386,8 +402,10 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, | |||
386 | 402 | ||
387 | r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, | 403 | r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, |
388 | &duplicates); | 404 | &duplicates); |
389 | if (unlikely(r != 0)) | 405 | if (unlikely(r != 0)) { |
406 | DRM_ERROR("ttm_eu_reserve_buffers failed.\n"); | ||
390 | goto error_free_pages; | 407 | goto error_free_pages; |
408 | } | ||
391 | 409 | ||
392 | /* Without a BO list we don't have userptr BOs */ | 410 | /* Without a BO list we don't have userptr BOs */ |
393 | if (!p->bo_list) | 411 | if (!p->bo_list) |
@@ -427,9 +445,10 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, | |||
427 | /* Unreserve everything again. */ | 445 | /* Unreserve everything again. */ |
428 | ttm_eu_backoff_reservation(&p->ticket, &p->validated); | 446 | ttm_eu_backoff_reservation(&p->ticket, &p->validated); |
429 | 447 | ||
430 | /* We tried to often, just abort */ | 448 | /* We tried too many times, just abort */ |
431 | if (!--tries) { | 449 | if (!--tries) { |
432 | r = -EDEADLK; | 450 | r = -EDEADLK; |
451 | DRM_ERROR("deadlock in %s\n", __func__); | ||
433 | goto error_free_pages; | 452 | goto error_free_pages; |
434 | } | 453 | } |
435 | 454 | ||
@@ -441,11 +460,13 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, | |||
441 | sizeof(struct page*)); | 460 | sizeof(struct page*)); |
442 | if (!e->user_pages) { | 461 | if (!e->user_pages) { |
443 | r = -ENOMEM; | 462 | r = -ENOMEM; |
463 | DRM_ERROR("calloc failure in %s\n", __func__); | ||
444 | goto error_free_pages; | 464 | goto error_free_pages; |
445 | } | 465 | } |
446 | 466 | ||
447 | r = amdgpu_ttm_tt_get_user_pages(ttm, e->user_pages); | 467 | r = amdgpu_ttm_tt_get_user_pages(ttm, e->user_pages); |
448 | if (r) { | 468 | if (r) { |
469 | DRM_ERROR("amdgpu_ttm_tt_get_user_pages failed.\n"); | ||
449 | drm_free_large(e->user_pages); | 470 | drm_free_large(e->user_pages); |
450 | e->user_pages = NULL; | 471 | e->user_pages = NULL; |
451 | goto error_free_pages; | 472 | goto error_free_pages; |
@@ -462,12 +483,16 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, | |||
462 | p->bytes_moved = 0; | 483 | p->bytes_moved = 0; |
463 | 484 | ||
464 | r = amdgpu_cs_list_validate(p, &duplicates); | 485 | r = amdgpu_cs_list_validate(p, &duplicates); |
465 | if (r) | 486 | if (r) { |
487 | DRM_ERROR("amdgpu_cs_list_validate(duplicates) failed.\n"); | ||
466 | goto error_validate; | 488 | goto error_validate; |
489 | } | ||
467 | 490 | ||
468 | r = amdgpu_cs_list_validate(p, &p->validated); | 491 | r = amdgpu_cs_list_validate(p, &p->validated); |
469 | if (r) | 492 | if (r) { |
493 | DRM_ERROR("amdgpu_cs_list_validate(validated) failed.\n"); | ||
470 | goto error_validate; | 494 | goto error_validate; |
495 | } | ||
471 | 496 | ||
472 | fpriv->vm.last_eviction_counter = | 497 | fpriv->vm.last_eviction_counter = |
473 | atomic64_read(&p->adev->num_evictions); | 498 | atomic64_read(&p->adev->num_evictions); |
@@ -617,7 +642,7 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p, | |||
617 | if (bo_va == NULL) | 642 | if (bo_va == NULL) |
618 | continue; | 643 | continue; |
619 | 644 | ||
620 | r = amdgpu_vm_bo_update(adev, bo_va, &bo->tbo.mem); | 645 | r = amdgpu_vm_bo_update(adev, bo_va, false); |
621 | if (r) | 646 | if (r) |
622 | return r; | 647 | return r; |
623 | 648 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index df7ab2458e50..c38dc47cd767 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #endif | 46 | #endif |
47 | #include "vi.h" | 47 | #include "vi.h" |
48 | #include "bif/bif_4_1_d.h" | 48 | #include "bif/bif_4_1_d.h" |
49 | #include <linux/pci.h> | ||
49 | 50 | ||
50 | static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev); | 51 | static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev); |
51 | static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev); | 52 | static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev); |
@@ -1181,10 +1182,38 @@ int amdgpu_ip_block_version_cmp(struct amdgpu_device *adev, | |||
1181 | return 1; | 1182 | return 1; |
1182 | } | 1183 | } |
1183 | 1184 | ||
1185 | static void amdgpu_whether_enable_virtual_display(struct amdgpu_device *adev) | ||
1186 | { | ||
1187 | adev->enable_virtual_display = false; | ||
1188 | |||
1189 | if (amdgpu_virtual_display) { | ||
1190 | struct drm_device *ddev = adev->ddev; | ||
1191 | const char *pci_address_name = pci_name(ddev->pdev); | ||
1192 | char *pciaddstr, *pciaddstr_tmp, *pciaddname; | ||
1193 | |||
1194 | pciaddstr = kstrdup(amdgpu_virtual_display, GFP_KERNEL); | ||
1195 | pciaddstr_tmp = pciaddstr; | ||
1196 | while ((pciaddname = strsep(&pciaddstr_tmp, ";"))) { | ||
1197 | if (!strcmp(pci_address_name, pciaddname)) { | ||
1198 | adev->enable_virtual_display = true; | ||
1199 | break; | ||
1200 | } | ||
1201 | } | ||
1202 | |||
1203 | DRM_INFO("virtual display string:%s, %s:virtual_display:%d\n", | ||
1204 | amdgpu_virtual_display, pci_address_name, | ||
1205 | adev->enable_virtual_display); | ||
1206 | |||
1207 | kfree(pciaddstr); | ||
1208 | } | ||
1209 | } | ||
1210 | |||
1184 | static int amdgpu_early_init(struct amdgpu_device *adev) | 1211 | static int amdgpu_early_init(struct amdgpu_device *adev) |
1185 | { | 1212 | { |
1186 | int i, r; | 1213 | int i, r; |
1187 | 1214 | ||
1215 | amdgpu_whether_enable_virtual_display(adev); | ||
1216 | |||
1188 | switch (adev->asic_type) { | 1217 | switch (adev->asic_type) { |
1189 | case CHIP_TOPAZ: | 1218 | case CHIP_TOPAZ: |
1190 | case CHIP_TONGA: | 1219 | case CHIP_TONGA: |
@@ -1521,6 +1550,9 @@ int amdgpu_device_init(struct amdgpu_device *adev, | |||
1521 | spin_lock_init(&adev->gc_cac_idx_lock); | 1550 | spin_lock_init(&adev->gc_cac_idx_lock); |
1522 | spin_lock_init(&adev->audio_endpt_idx_lock); | 1551 | spin_lock_init(&adev->audio_endpt_idx_lock); |
1523 | 1552 | ||
1553 | INIT_LIST_HEAD(&adev->shadow_list); | ||
1554 | mutex_init(&adev->shadow_list_lock); | ||
1555 | |||
1524 | adev->rmmio_base = pci_resource_start(adev->pdev, 5); | 1556 | adev->rmmio_base = pci_resource_start(adev->pdev, 5); |
1525 | adev->rmmio_size = pci_resource_len(adev->pdev, 5); | 1557 | adev->rmmio_size = pci_resource_len(adev->pdev, 5); |
1526 | adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size); | 1558 | adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size); |
@@ -1937,6 +1969,126 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon) | |||
1937 | return 0; | 1969 | return 0; |
1938 | } | 1970 | } |
1939 | 1971 | ||
1972 | static bool amdgpu_check_soft_reset(struct amdgpu_device *adev) | ||
1973 | { | ||
1974 | int i; | ||
1975 | bool asic_hang = false; | ||
1976 | |||
1977 | for (i = 0; i < adev->num_ip_blocks; i++) { | ||
1978 | if (!adev->ip_block_status[i].valid) | ||
1979 | continue; | ||
1980 | if (adev->ip_blocks[i].funcs->check_soft_reset) | ||
1981 | adev->ip_blocks[i].funcs->check_soft_reset(adev); | ||
1982 | if (adev->ip_block_status[i].hang) { | ||
1983 | DRM_INFO("IP block:%d is hang!\n", i); | ||
1984 | asic_hang = true; | ||
1985 | } | ||
1986 | } | ||
1987 | return asic_hang; | ||
1988 | } | ||
1989 | |||
1990 | int amdgpu_pre_soft_reset(struct amdgpu_device *adev) | ||
1991 | { | ||
1992 | int i, r = 0; | ||
1993 | |||
1994 | for (i = 0; i < adev->num_ip_blocks; i++) { | ||
1995 | if (!adev->ip_block_status[i].valid) | ||
1996 | continue; | ||
1997 | if (adev->ip_block_status[i].hang && | ||
1998 | adev->ip_blocks[i].funcs->pre_soft_reset) { | ||
1999 | r = adev->ip_blocks[i].funcs->pre_soft_reset(adev); | ||
2000 | if (r) | ||
2001 | return r; | ||
2002 | } | ||
2003 | } | ||
2004 | |||
2005 | return 0; | ||
2006 | } | ||
2007 | |||
2008 | static bool amdgpu_need_full_reset(struct amdgpu_device *adev) | ||
2009 | { | ||
2010 | if (adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang || | ||
2011 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_SMC].hang || | ||
2012 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_ACP].hang || | ||
2013 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang) { | ||
2014 | DRM_INFO("Some block need full reset!\n"); | ||
2015 | return true; | ||
2016 | } | ||
2017 | return false; | ||
2018 | } | ||
2019 | |||
2020 | static int amdgpu_soft_reset(struct amdgpu_device *adev) | ||
2021 | { | ||
2022 | int i, r = 0; | ||
2023 | |||
2024 | for (i = 0; i < adev->num_ip_blocks; i++) { | ||
2025 | if (!adev->ip_block_status[i].valid) | ||
2026 | continue; | ||
2027 | if (adev->ip_block_status[i].hang && | ||
2028 | adev->ip_blocks[i].funcs->soft_reset) { | ||
2029 | r = adev->ip_blocks[i].funcs->soft_reset(adev); | ||
2030 | if (r) | ||
2031 | return r; | ||
2032 | } | ||
2033 | } | ||
2034 | |||
2035 | return 0; | ||
2036 | } | ||
2037 | |||
2038 | static int amdgpu_post_soft_reset(struct amdgpu_device *adev) | ||
2039 | { | ||
2040 | int i, r = 0; | ||
2041 | |||
2042 | for (i = 0; i < adev->num_ip_blocks; i++) { | ||
2043 | if (!adev->ip_block_status[i].valid) | ||
2044 | continue; | ||
2045 | if (adev->ip_block_status[i].hang && | ||
2046 | adev->ip_blocks[i].funcs->post_soft_reset) | ||
2047 | r = adev->ip_blocks[i].funcs->post_soft_reset(adev); | ||
2048 | if (r) | ||
2049 | return r; | ||
2050 | } | ||
2051 | |||
2052 | return 0; | ||
2053 | } | ||
2054 | |||
2055 | bool amdgpu_need_backup(struct amdgpu_device *adev) | ||
2056 | { | ||
2057 | if (adev->flags & AMD_IS_APU) | ||
2058 | return false; | ||
2059 | |||
2060 | return amdgpu_lockup_timeout > 0 ? true : false; | ||
2061 | } | ||
2062 | |||
2063 | static int amdgpu_recover_vram_from_shadow(struct amdgpu_device *adev, | ||
2064 | struct amdgpu_ring *ring, | ||
2065 | struct amdgpu_bo *bo, | ||
2066 | struct fence **fence) | ||
2067 | { | ||
2068 | uint32_t domain; | ||
2069 | int r; | ||
2070 | |||
2071 | if (!bo->shadow) | ||
2072 | return 0; | ||
2073 | |||
2074 | r = amdgpu_bo_reserve(bo, false); | ||
2075 | if (r) | ||
2076 | return r; | ||
2077 | domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type); | ||
2078 | /* if bo has been evicted, then no need to recover */ | ||
2079 | if (domain == AMDGPU_GEM_DOMAIN_VRAM) { | ||
2080 | r = amdgpu_bo_restore_from_shadow(adev, ring, bo, | ||
2081 | NULL, fence, true); | ||
2082 | if (r) { | ||
2083 | DRM_ERROR("recover page table failed!\n"); | ||
2084 | goto err; | ||
2085 | } | ||
2086 | } | ||
2087 | err: | ||
2088 | amdgpu_bo_unreserve(bo); | ||
2089 | return r; | ||
2090 | } | ||
2091 | |||
1940 | /** | 2092 | /** |
1941 | * amdgpu_gpu_reset - reset the asic | 2093 | * amdgpu_gpu_reset - reset the asic |
1942 | * | 2094 | * |
@@ -1949,6 +2101,12 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev) | |||
1949 | { | 2101 | { |
1950 | int i, r; | 2102 | int i, r; |
1951 | int resched; | 2103 | int resched; |
2104 | bool need_full_reset; | ||
2105 | |||
2106 | if (!amdgpu_check_soft_reset(adev)) { | ||
2107 | DRM_INFO("No hardware hang detected. Did some blocks stall?\n"); | ||
2108 | return 0; | ||
2109 | } | ||
1952 | 2110 | ||
1953 | atomic_inc(&adev->gpu_reset_counter); | 2111 | atomic_inc(&adev->gpu_reset_counter); |
1954 | 2112 | ||
@@ -1967,40 +2125,88 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev) | |||
1967 | /* after all hw jobs are reset, hw fence is meaningless, so force_completion */ | 2125 | /* after all hw jobs are reset, hw fence is meaningless, so force_completion */ |
1968 | amdgpu_fence_driver_force_completion(adev); | 2126 | amdgpu_fence_driver_force_completion(adev); |
1969 | 2127 | ||
1970 | /* save scratch */ | 2128 | need_full_reset = amdgpu_need_full_reset(adev); |
1971 | amdgpu_atombios_scratch_regs_save(adev); | ||
1972 | r = amdgpu_suspend(adev); | ||
1973 | 2129 | ||
1974 | retry: | 2130 | if (!need_full_reset) { |
1975 | /* Disable fb access */ | 2131 | amdgpu_pre_soft_reset(adev); |
1976 | if (adev->mode_info.num_crtc) { | 2132 | r = amdgpu_soft_reset(adev); |
1977 | struct amdgpu_mode_mc_save save; | 2133 | amdgpu_post_soft_reset(adev); |
1978 | amdgpu_display_stop_mc_access(adev, &save); | 2134 | if (r || amdgpu_check_soft_reset(adev)) { |
1979 | amdgpu_wait_for_idle(adev, AMD_IP_BLOCK_TYPE_GMC); | 2135 | DRM_INFO("soft reset failed, will fallback to full reset!\n"); |
2136 | need_full_reset = true; | ||
2137 | } | ||
1980 | } | 2138 | } |
1981 | 2139 | ||
1982 | r = amdgpu_asic_reset(adev); | 2140 | if (need_full_reset) { |
1983 | /* post card */ | 2141 | /* save scratch */ |
1984 | amdgpu_atom_asic_init(adev->mode_info.atom_context); | 2142 | amdgpu_atombios_scratch_regs_save(adev); |
2143 | r = amdgpu_suspend(adev); | ||
1985 | 2144 | ||
1986 | if (!r) { | 2145 | retry: |
1987 | dev_info(adev->dev, "GPU reset succeeded, trying to resume\n"); | 2146 | /* Disable fb access */ |
1988 | r = amdgpu_resume(adev); | 2147 | if (adev->mode_info.num_crtc) { |
2148 | struct amdgpu_mode_mc_save save; | ||
2149 | amdgpu_display_stop_mc_access(adev, &save); | ||
2150 | amdgpu_wait_for_idle(adev, AMD_IP_BLOCK_TYPE_GMC); | ||
2151 | } | ||
2152 | |||
2153 | r = amdgpu_asic_reset(adev); | ||
2154 | /* post card */ | ||
2155 | amdgpu_atom_asic_init(adev->mode_info.atom_context); | ||
2156 | |||
2157 | if (!r) { | ||
2158 | dev_info(adev->dev, "GPU reset succeeded, trying to resume\n"); | ||
2159 | r = amdgpu_resume(adev); | ||
2160 | } | ||
2161 | /* restore scratch */ | ||
2162 | amdgpu_atombios_scratch_regs_restore(adev); | ||
1989 | } | 2163 | } |
1990 | /* restore scratch */ | ||
1991 | amdgpu_atombios_scratch_regs_restore(adev); | ||
1992 | if (!r) { | 2164 | if (!r) { |
2165 | amdgpu_irq_gpu_reset_resume_helper(adev); | ||
1993 | r = amdgpu_ib_ring_tests(adev); | 2166 | r = amdgpu_ib_ring_tests(adev); |
1994 | if (r) { | 2167 | if (r) { |
1995 | dev_err(adev->dev, "ib ring test failed (%d).\n", r); | 2168 | dev_err(adev->dev, "ib ring test failed (%d).\n", r); |
1996 | r = amdgpu_suspend(adev); | 2169 | r = amdgpu_suspend(adev); |
2170 | need_full_reset = true; | ||
1997 | goto retry; | 2171 | goto retry; |
1998 | } | 2172 | } |
2173 | /** | ||
2174 | * recovery vm page tables, since we cannot depend on VRAM is | ||
2175 | * consistent after gpu full reset. | ||
2176 | */ | ||
2177 | if (need_full_reset && amdgpu_need_backup(adev)) { | ||
2178 | struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; | ||
2179 | struct amdgpu_bo *bo, *tmp; | ||
2180 | struct fence *fence = NULL, *next = NULL; | ||
2181 | |||
2182 | DRM_INFO("recover vram bo from shadow\n"); | ||
2183 | mutex_lock(&adev->shadow_list_lock); | ||
2184 | list_for_each_entry_safe(bo, tmp, &adev->shadow_list, shadow_list) { | ||
2185 | amdgpu_recover_vram_from_shadow(adev, ring, bo, &next); | ||
2186 | if (fence) { | ||
2187 | r = fence_wait(fence, false); | ||
2188 | if (r) { | ||
2189 | WARN(r, "recovery from shadow isn't comleted\n"); | ||
2190 | break; | ||
2191 | } | ||
2192 | } | ||
1999 | 2193 | ||
2194 | fence_put(fence); | ||
2195 | fence = next; | ||
2196 | } | ||
2197 | mutex_unlock(&adev->shadow_list_lock); | ||
2198 | if (fence) { | ||
2199 | r = fence_wait(fence, false); | ||
2200 | if (r) | ||
2201 | WARN(r, "recovery from shadow isn't comleted\n"); | ||
2202 | } | ||
2203 | fence_put(fence); | ||
2204 | } | ||
2000 | for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { | 2205 | for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { |
2001 | struct amdgpu_ring *ring = adev->rings[i]; | 2206 | struct amdgpu_ring *ring = adev->rings[i]; |
2002 | if (!ring) | 2207 | if (!ring) |
2003 | continue; | 2208 | continue; |
2209 | |||
2004 | amd_sched_job_recovery(&ring->sched); | 2210 | amd_sched_job_recovery(&ring->sched); |
2005 | kthread_unpark(ring->sched.thread); | 2211 | kthread_unpark(ring->sched.thread); |
2006 | } | 2212 | } |
@@ -2020,7 +2226,6 @@ retry: | |||
2020 | /* bad news, how to tell it to userspace ? */ | 2226 | /* bad news, how to tell it to userspace ? */ |
2021 | dev_info(adev->dev, "GPU reset failed\n"); | 2227 | dev_info(adev->dev, "GPU reset failed\n"); |
2022 | } | 2228 | } |
2023 | amdgpu_irq_gpu_reset_resume_helper(adev); | ||
2024 | 2229 | ||
2025 | return r; | 2230 | return r; |
2026 | } | 2231 | } |
@@ -2178,22 +2383,26 @@ static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf, | |||
2178 | struct amdgpu_device *adev = f->f_inode->i_private; | 2383 | struct amdgpu_device *adev = f->f_inode->i_private; |
2179 | ssize_t result = 0; | 2384 | ssize_t result = 0; |
2180 | int r; | 2385 | int r; |
2181 | bool use_bank; | 2386 | bool pm_pg_lock, use_bank; |
2182 | unsigned instance_bank, sh_bank, se_bank; | 2387 | unsigned instance_bank, sh_bank, se_bank; |
2183 | 2388 | ||
2184 | if (size & 0x3 || *pos & 0x3) | 2389 | if (size & 0x3 || *pos & 0x3) |
2185 | return -EINVAL; | 2390 | return -EINVAL; |
2186 | 2391 | ||
2392 | /* are we reading registers for which a PG lock is necessary? */ | ||
2393 | pm_pg_lock = (*pos >> 23) & 1; | ||
2394 | |||
2187 | if (*pos & (1ULL << 62)) { | 2395 | if (*pos & (1ULL << 62)) { |
2188 | se_bank = (*pos >> 24) & 0x3FF; | 2396 | se_bank = (*pos >> 24) & 0x3FF; |
2189 | sh_bank = (*pos >> 34) & 0x3FF; | 2397 | sh_bank = (*pos >> 34) & 0x3FF; |
2190 | instance_bank = (*pos >> 44) & 0x3FF; | 2398 | instance_bank = (*pos >> 44) & 0x3FF; |
2191 | use_bank = 1; | 2399 | use_bank = 1; |
2192 | *pos &= 0xFFFFFF; | ||
2193 | } else { | 2400 | } else { |
2194 | use_bank = 0; | 2401 | use_bank = 0; |
2195 | } | 2402 | } |
2196 | 2403 | ||
2404 | *pos &= 0x3FFFF; | ||
2405 | |||
2197 | if (use_bank) { | 2406 | if (use_bank) { |
2198 | if (sh_bank >= adev->gfx.config.max_sh_per_se || | 2407 | if (sh_bank >= adev->gfx.config.max_sh_per_se || |
2199 | se_bank >= adev->gfx.config.max_shader_engines) | 2408 | se_bank >= adev->gfx.config.max_shader_engines) |
@@ -2203,6 +2412,9 @@ static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf, | |||
2203 | sh_bank, instance_bank); | 2412 | sh_bank, instance_bank); |
2204 | } | 2413 | } |
2205 | 2414 | ||
2415 | if (pm_pg_lock) | ||
2416 | mutex_lock(&adev->pm.mutex); | ||
2417 | |||
2206 | while (size) { | 2418 | while (size) { |
2207 | uint32_t value; | 2419 | uint32_t value; |
2208 | 2420 | ||
@@ -2228,6 +2440,9 @@ end: | |||
2228 | mutex_unlock(&adev->grbm_idx_mutex); | 2440 | mutex_unlock(&adev->grbm_idx_mutex); |
2229 | } | 2441 | } |
2230 | 2442 | ||
2443 | if (pm_pg_lock) | ||
2444 | mutex_unlock(&adev->pm.mutex); | ||
2445 | |||
2231 | return result; | 2446 | return result; |
2232 | } | 2447 | } |
2233 | 2448 | ||
@@ -2443,7 +2658,7 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf, | |||
2443 | return -ENOMEM; | 2658 | return -ENOMEM; |
2444 | 2659 | ||
2445 | /* version, increment each time something is added */ | 2660 | /* version, increment each time something is added */ |
2446 | config[no_regs++] = 0; | 2661 | config[no_regs++] = 2; |
2447 | config[no_regs++] = adev->gfx.config.max_shader_engines; | 2662 | config[no_regs++] = adev->gfx.config.max_shader_engines; |
2448 | config[no_regs++] = adev->gfx.config.max_tile_pipes; | 2663 | config[no_regs++] = adev->gfx.config.max_tile_pipes; |
2449 | config[no_regs++] = adev->gfx.config.max_cu_per_sh; | 2664 | config[no_regs++] = adev->gfx.config.max_cu_per_sh; |
@@ -2468,6 +2683,15 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf, | |||
2468 | config[no_regs++] = adev->gfx.config.gb_addr_config; | 2683 | config[no_regs++] = adev->gfx.config.gb_addr_config; |
2469 | config[no_regs++] = adev->gfx.config.num_rbs; | 2684 | config[no_regs++] = adev->gfx.config.num_rbs; |
2470 | 2685 | ||
2686 | /* rev==1 */ | ||
2687 | config[no_regs++] = adev->rev_id; | ||
2688 | config[no_regs++] = adev->pg_flags; | ||
2689 | config[no_regs++] = adev->cg_flags; | ||
2690 | |||
2691 | /* rev==2 */ | ||
2692 | config[no_regs++] = adev->family; | ||
2693 | config[no_regs++] = adev->external_rev_id; | ||
2694 | |||
2471 | while (size && (*pos < no_regs * 4)) { | 2695 | while (size && (*pos < no_regs * 4)) { |
2472 | uint32_t value; | 2696 | uint32_t value; |
2473 | 2697 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 76f96028313d..9af8d3c7ae8b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | |||
@@ -41,7 +41,7 @@ static void amdgpu_flip_callback(struct fence *f, struct fence_cb *cb) | |||
41 | container_of(cb, struct amdgpu_flip_work, cb); | 41 | container_of(cb, struct amdgpu_flip_work, cb); |
42 | 42 | ||
43 | fence_put(f); | 43 | fence_put(f); |
44 | schedule_work(&work->flip_work); | 44 | schedule_work(&work->flip_work.work); |
45 | } | 45 | } |
46 | 46 | ||
47 | static bool amdgpu_flip_handle_fence(struct amdgpu_flip_work *work, | 47 | 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, | |||
63 | 63 | ||
64 | static void amdgpu_flip_work_func(struct work_struct *__work) | 64 | static void amdgpu_flip_work_func(struct work_struct *__work) |
65 | { | 65 | { |
66 | struct delayed_work *delayed_work = | ||
67 | container_of(__work, struct delayed_work, work); | ||
66 | struct amdgpu_flip_work *work = | 68 | struct amdgpu_flip_work *work = |
67 | container_of(__work, struct amdgpu_flip_work, flip_work); | 69 | container_of(delayed_work, struct amdgpu_flip_work, flip_work); |
68 | struct amdgpu_device *adev = work->adev; | 70 | struct amdgpu_device *adev = work->adev; |
69 | struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id]; | 71 | struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id]; |
70 | 72 | ||
71 | struct drm_crtc *crtc = &amdgpuCrtc->base; | 73 | struct drm_crtc *crtc = &amdgpuCrtc->base; |
72 | unsigned long flags; | 74 | unsigned long flags; |
73 | unsigned i, repcnt = 4; | 75 | unsigned i; |
74 | int vpos, hpos, stat, min_udelay = 0; | 76 | int vpos, hpos; |
75 | struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; | ||
76 | 77 | ||
77 | if (amdgpu_flip_handle_fence(work, &work->excl)) | 78 | if (amdgpu_flip_handle_fence(work, &work->excl)) |
78 | return; | 79 | return; |
@@ -81,55 +82,23 @@ static void amdgpu_flip_work_func(struct work_struct *__work) | |||
81 | if (amdgpu_flip_handle_fence(work, &work->shared[i])) | 82 | if (amdgpu_flip_handle_fence(work, &work->shared[i])) |
82 | return; | 83 | return; |
83 | 84 | ||
84 | /* We borrow the event spin lock for protecting flip_status */ | 85 | /* Wait until we're out of the vertical blank period before the one |
85 | spin_lock_irqsave(&crtc->dev->event_lock, flags); | 86 | * targeted by the flip |
86 | |||
87 | /* If this happens to execute within the "virtually extended" vblank | ||
88 | * interval before the start of the real vblank interval then it needs | ||
89 | * to delay programming the mmio flip until the real vblank is entered. | ||
90 | * This prevents completing a flip too early due to the way we fudge | ||
91 | * our vblank counter and vblank timestamps in order to work around the | ||
92 | * problem that the hw fires vblank interrupts before actual start of | ||
93 | * vblank (when line buffer refilling is done for a frame). It | ||
94 | * complements the fudging logic in amdgpu_get_crtc_scanoutpos() for | ||
95 | * timestamping and amdgpu_get_vblank_counter_kms() for vblank counts. | ||
96 | * | ||
97 | * In practice this won't execute very often unless on very fast | ||
98 | * machines because the time window for this to happen is very small. | ||
99 | */ | 87 | */ |
100 | while (amdgpuCrtc->enabled && --repcnt) { | 88 | if (amdgpuCrtc->enabled && |
101 | /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank | 89 | (amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id, 0, |
102 | * start in hpos, and to the "fudged earlier" vblank start in | 90 | &vpos, &hpos, NULL, NULL, |
103 | * vpos. | 91 | &crtc->hwmode) |
104 | */ | 92 | & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == |
105 | stat = amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id, | 93 | (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) && |
106 | GET_DISTANCE_TO_VBLANKSTART, | 94 | (int)(work->target_vblank - |
107 | &vpos, &hpos, NULL, NULL, | 95 | amdgpu_get_vblank_counter_kms(adev->ddev, amdgpuCrtc->crtc_id)) > 0) { |
108 | &crtc->hwmode); | 96 | schedule_delayed_work(&work->flip_work, usecs_to_jiffies(1000)); |
109 | 97 | return; | |
110 | if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != | ||
111 | (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) || | ||
112 | !(vpos >= 0 && hpos <= 0)) | ||
113 | break; | ||
114 | |||
115 | /* Sleep at least until estimated real start of hw vblank */ | ||
116 | min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); | ||
117 | if (min_udelay > vblank->framedur_ns / 2000) { | ||
118 | /* Don't wait ridiculously long - something is wrong */ | ||
119 | repcnt = 0; | ||
120 | break; | ||
121 | } | ||
122 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | ||
123 | usleep_range(min_udelay, 2 * min_udelay); | ||
124 | spin_lock_irqsave(&crtc->dev->event_lock, flags); | ||
125 | } | 98 | } |
126 | 99 | ||
127 | if (!repcnt) | 100 | /* We borrow the event spin lock for protecting flip_status */ |
128 | DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, " | 101 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
129 | "framedur %d, linedur %d, stat %d, vpos %d, " | ||
130 | "hpos %d\n", work->crtc_id, min_udelay, | ||
131 | vblank->framedur_ns / 1000, | ||
132 | vblank->linedur_ns / 1000, stat, vpos, hpos); | ||
133 | 102 | ||
134 | /* Do the flip (mmio) */ | 103 | /* Do the flip (mmio) */ |
135 | adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base, work->async); | 104 | adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base, work->async); |
@@ -169,10 +138,10 @@ static void amdgpu_unpin_work_func(struct work_struct *__work) | |||
169 | kfree(work); | 138 | kfree(work); |
170 | } | 139 | } |
171 | 140 | ||
172 | int amdgpu_crtc_page_flip(struct drm_crtc *crtc, | 141 | int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, |
173 | struct drm_framebuffer *fb, | 142 | struct drm_framebuffer *fb, |
174 | struct drm_pending_vblank_event *event, | 143 | struct drm_pending_vblank_event *event, |
175 | uint32_t page_flip_flags) | 144 | uint32_t page_flip_flags, uint32_t target) |
176 | { | 145 | { |
177 | struct drm_device *dev = crtc->dev; | 146 | struct drm_device *dev = crtc->dev; |
178 | struct amdgpu_device *adev = dev->dev_private; | 147 | struct amdgpu_device *adev = dev->dev_private; |
@@ -191,7 +160,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc, | |||
191 | if (work == NULL) | 160 | if (work == NULL) |
192 | return -ENOMEM; | 161 | return -ENOMEM; |
193 | 162 | ||
194 | INIT_WORK(&work->flip_work, amdgpu_flip_work_func); | 163 | INIT_DELAYED_WORK(&work->flip_work, amdgpu_flip_work_func); |
195 | INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func); | 164 | INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func); |
196 | 165 | ||
197 | work->event = event; | 166 | work->event = event; |
@@ -237,12 +206,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc, | |||
237 | amdgpu_bo_unreserve(new_rbo); | 206 | amdgpu_bo_unreserve(new_rbo); |
238 | 207 | ||
239 | work->base = base; | 208 | work->base = base; |
240 | 209 | work->target_vblank = target - drm_crtc_vblank_count(crtc) + | |
241 | r = drm_crtc_vblank_get(crtc); | 210 | amdgpu_get_vblank_counter_kms(dev, work->crtc_id); |
242 | if (r) { | ||
243 | DRM_ERROR("failed to get vblank before flip\n"); | ||
244 | goto pflip_cleanup; | ||
245 | } | ||
246 | 211 | ||
247 | /* we borrow the event spin lock for protecting flip_wrok */ | 212 | /* we borrow the event spin lock for protecting flip_wrok */ |
248 | spin_lock_irqsave(&crtc->dev->event_lock, flags); | 213 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
@@ -250,7 +215,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc, | |||
250 | DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); | 215 | DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); |
251 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | 216 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); |
252 | r = -EBUSY; | 217 | r = -EBUSY; |
253 | goto vblank_cleanup; | 218 | goto pflip_cleanup; |
254 | } | 219 | } |
255 | 220 | ||
256 | amdgpu_crtc->pflip_status = AMDGPU_FLIP_PENDING; | 221 | amdgpu_crtc->pflip_status = AMDGPU_FLIP_PENDING; |
@@ -262,12 +227,9 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc, | |||
262 | /* update crtc fb */ | 227 | /* update crtc fb */ |
263 | crtc->primary->fb = fb; | 228 | crtc->primary->fb = fb; |
264 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | 229 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); |
265 | amdgpu_flip_work_func(&work->flip_work); | 230 | amdgpu_flip_work_func(&work->flip_work.work); |
266 | return 0; | 231 | return 0; |
267 | 232 | ||
268 | vblank_cleanup: | ||
269 | drm_crtc_vblank_put(crtc); | ||
270 | |||
271 | pflip_cleanup: | 233 | pflip_cleanup: |
272 | if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) { | 234 | if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) { |
273 | DRM_ERROR("failed to reserve new rbo in error path\n"); | 235 | DRM_ERROR("failed to reserve new rbo in error path\n"); |
@@ -335,7 +297,7 @@ int amdgpu_crtc_set_config(struct drm_mode_set *set) | |||
335 | return ret; | 297 | return ret; |
336 | } | 298 | } |
337 | 299 | ||
338 | static const char *encoder_names[38] = { | 300 | static const char *encoder_names[41] = { |
339 | "NONE", | 301 | "NONE", |
340 | "INTERNAL_LVDS", | 302 | "INTERNAL_LVDS", |
341 | "INTERNAL_TMDS1", | 303 | "INTERNAL_TMDS1", |
@@ -374,6 +336,9 @@ static const char *encoder_names[38] = { | |||
374 | "TRAVIS", | 336 | "TRAVIS", |
375 | "INTERNAL_VCE", | 337 | "INTERNAL_VCE", |
376 | "INTERNAL_UNIPHY3", | 338 | "INTERNAL_UNIPHY3", |
339 | "HDMI_ANX9805", | ||
340 | "INTERNAL_AMCLK", | ||
341 | "VIRTUAL", | ||
377 | }; | 342 | }; |
378 | 343 | ||
379 | static const char *hpd_names[6] = { | 344 | static const char *hpd_names[6] = { |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 11263c5b9967..7c911d0be2b3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | |||
@@ -53,9 +53,11 @@ | |||
53 | * - 3.2.0 - GFX8: Uses EOP_TC_WB_ACTION_EN, so UMDs don't have to do the same | 53 | * - 3.2.0 - GFX8: Uses EOP_TC_WB_ACTION_EN, so UMDs don't have to do the same |
54 | * at the end of IBs. | 54 | * at the end of IBs. |
55 | * - 3.3.0 - Add VM support for UVD on supported hardware. | 55 | * - 3.3.0 - Add VM support for UVD on supported hardware. |
56 | * - 3.4.0 - Add AMDGPU_INFO_NUM_EVICTIONS. | ||
57 | * - 3.5.0 - Add support for new UVD_NO_OP register. | ||
56 | */ | 58 | */ |
57 | #define KMS_DRIVER_MAJOR 3 | 59 | #define KMS_DRIVER_MAJOR 3 |
58 | #define KMS_DRIVER_MINOR 3 | 60 | #define KMS_DRIVER_MINOR 5 |
59 | #define KMS_DRIVER_PATCHLEVEL 0 | 61 | #define KMS_DRIVER_PATCHLEVEL 0 |
60 | 62 | ||
61 | int amdgpu_vram_limit = 0; | 63 | int amdgpu_vram_limit = 0; |
@@ -84,11 +86,13 @@ int amdgpu_sched_jobs = 32; | |||
84 | int amdgpu_sched_hw_submission = 2; | 86 | int amdgpu_sched_hw_submission = 2; |
85 | int amdgpu_powerplay = -1; | 87 | int amdgpu_powerplay = -1; |
86 | int amdgpu_powercontainment = 1; | 88 | int amdgpu_powercontainment = 1; |
89 | int amdgpu_sclk_deep_sleep_en = 1; | ||
87 | unsigned amdgpu_pcie_gen_cap = 0; | 90 | unsigned amdgpu_pcie_gen_cap = 0; |
88 | unsigned amdgpu_pcie_lane_cap = 0; | 91 | unsigned amdgpu_pcie_lane_cap = 0; |
89 | unsigned amdgpu_cg_mask = 0xffffffff; | 92 | unsigned amdgpu_cg_mask = 0xffffffff; |
90 | unsigned amdgpu_pg_mask = 0xffffffff; | 93 | unsigned amdgpu_pg_mask = 0xffffffff; |
91 | char *amdgpu_disable_cu = NULL; | 94 | char *amdgpu_disable_cu = NULL; |
95 | char *amdgpu_virtual_display = NULL; | ||
92 | 96 | ||
93 | MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes"); | 97 | MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes"); |
94 | module_param_named(vramlimit, amdgpu_vram_limit, int, 0600); | 98 | module_param_named(vramlimit, amdgpu_vram_limit, int, 0600); |
@@ -170,6 +174,9 @@ MODULE_PARM_DESC(powercontainment, "Power Containment (1 = enable (default), 0 = | |||
170 | module_param_named(powercontainment, amdgpu_powercontainment, int, 0444); | 174 | module_param_named(powercontainment, amdgpu_powercontainment, int, 0444); |
171 | #endif | 175 | #endif |
172 | 176 | ||
177 | MODULE_PARM_DESC(sclkdeepsleep, "SCLK Deep Sleep (1 = enable (default), 0 = disable)"); | ||
178 | module_param_named(sclkdeepsleep, amdgpu_sclk_deep_sleep_en, int, 0444); | ||
179 | |||
173 | MODULE_PARM_DESC(pcie_gen_cap, "PCIE Gen Caps (0: autodetect (default))"); | 180 | MODULE_PARM_DESC(pcie_gen_cap, "PCIE Gen Caps (0: autodetect (default))"); |
174 | module_param_named(pcie_gen_cap, amdgpu_pcie_gen_cap, uint, 0444); | 181 | module_param_named(pcie_gen_cap, amdgpu_pcie_gen_cap, uint, 0444); |
175 | 182 | ||
@@ -185,6 +192,9 @@ module_param_named(pg_mask, amdgpu_pg_mask, uint, 0444); | |||
185 | MODULE_PARM_DESC(disable_cu, "Disable CUs (se.sh.cu,...)"); | 192 | MODULE_PARM_DESC(disable_cu, "Disable CUs (se.sh.cu,...)"); |
186 | module_param_named(disable_cu, amdgpu_disable_cu, charp, 0444); | 193 | module_param_named(disable_cu, amdgpu_disable_cu, charp, 0444); |
187 | 194 | ||
195 | MODULE_PARM_DESC(virtual_display, "Enable virtual display feature (the virtual_display will be set like xxxx:xx:xx.x;xxxx:xx:xx.x)"); | ||
196 | module_param_named(virtual_display, amdgpu_virtual_display, charp, 0444); | ||
197 | |||
188 | static const struct pci_device_id pciidlist[] = { | 198 | static const struct pci_device_id pciidlist[] = { |
189 | #ifdef CONFIG_DRM_AMDGPU_CIK | 199 | #ifdef CONFIG_DRM_AMDGPU_CIK |
190 | /* Kaveri */ | 200 | /* Kaveri */ |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h index 503d54098128..e73728d90388 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h | |||
@@ -31,14 +31,6 @@ | |||
31 | #define AMDGPU_GWS_SHIFT PAGE_SHIFT | 31 | #define AMDGPU_GWS_SHIFT PAGE_SHIFT |
32 | #define AMDGPU_OA_SHIFT PAGE_SHIFT | 32 | #define AMDGPU_OA_SHIFT PAGE_SHIFT |
33 | 33 | ||
34 | #define AMDGPU_PL_GDS TTM_PL_PRIV0 | ||
35 | #define AMDGPU_PL_GWS TTM_PL_PRIV1 | ||
36 | #define AMDGPU_PL_OA TTM_PL_PRIV2 | ||
37 | |||
38 | #define AMDGPU_PL_FLAG_GDS TTM_PL_FLAG_PRIV0 | ||
39 | #define AMDGPU_PL_FLAG_GWS TTM_PL_FLAG_PRIV1 | ||
40 | #define AMDGPU_PL_FLAG_OA TTM_PL_FLAG_PRIV2 | ||
41 | |||
42 | struct amdgpu_ring; | 34 | struct amdgpu_ring; |
43 | struct amdgpu_bo; | 35 | struct amdgpu_bo; |
44 | 36 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c index 31a676376d73..c93a92a840ea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c | |||
@@ -186,10 +186,8 @@ struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev, | |||
186 | "AMDGPU i2c hw bus %s", name); | 186 | "AMDGPU i2c hw bus %s", name); |
187 | i2c->adapter.algo = &amdgpu_atombios_i2c_algo; | 187 | i2c->adapter.algo = &amdgpu_atombios_i2c_algo; |
188 | ret = i2c_add_adapter(&i2c->adapter); | 188 | ret = i2c_add_adapter(&i2c->adapter); |
189 | if (ret) { | 189 | if (ret) |
190 | DRM_ERROR("Failed to register hw i2c %s\n", name); | ||
191 | goto out_free; | 190 | goto out_free; |
192 | } | ||
193 | } else { | 191 | } else { |
194 | /* set the amdgpu bit adapter */ | 192 | /* set the amdgpu bit adapter */ |
195 | snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), | 193 | snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index a31d7ef3032c..f5810f700668 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | |||
@@ -142,7 +142,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, | |||
142 | } | 142 | } |
143 | 143 | ||
144 | if (!ring->ready) { | 144 | if (!ring->ready) { |
145 | dev_err(adev->dev, "couldn't schedule ib\n"); | 145 | dev_err(adev->dev, "couldn't schedule ib on ring <%s>\n", ring->name); |
146 | return -EINVAL; | 146 | return -EINVAL; |
147 | } | 147 | } |
148 | 148 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c index 534fc04e80fd..5ebb3f43feb6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c | |||
@@ -40,32 +40,15 @@ static int amdgpu_ih_ring_alloc(struct amdgpu_device *adev) | |||
40 | 40 | ||
41 | /* Allocate ring buffer */ | 41 | /* Allocate ring buffer */ |
42 | if (adev->irq.ih.ring_obj == NULL) { | 42 | if (adev->irq.ih.ring_obj == NULL) { |
43 | r = amdgpu_bo_create(adev, adev->irq.ih.ring_size, | 43 | r = amdgpu_bo_create_kernel(adev, adev->irq.ih.ring_size, |
44 | PAGE_SIZE, true, | 44 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, |
45 | AMDGPU_GEM_DOMAIN_GTT, 0, | 45 | &adev->irq.ih.ring_obj, |
46 | NULL, NULL, &adev->irq.ih.ring_obj); | 46 | &adev->irq.ih.gpu_addr, |
47 | (void **)&adev->irq.ih.ring); | ||
47 | if (r) { | 48 | if (r) { |
48 | DRM_ERROR("amdgpu: failed to create ih ring buffer (%d).\n", r); | 49 | DRM_ERROR("amdgpu: failed to create ih ring buffer (%d).\n", r); |
49 | return r; | 50 | return r; |
50 | } | 51 | } |
51 | r = amdgpu_bo_reserve(adev->irq.ih.ring_obj, false); | ||
52 | if (unlikely(r != 0)) | ||
53 | return r; | ||
54 | r = amdgpu_bo_pin(adev->irq.ih.ring_obj, | ||
55 | AMDGPU_GEM_DOMAIN_GTT, | ||
56 | &adev->irq.ih.gpu_addr); | ||
57 | if (r) { | ||
58 | amdgpu_bo_unreserve(adev->irq.ih.ring_obj); | ||
59 | DRM_ERROR("amdgpu: failed to pin ih ring buffer (%d).\n", r); | ||
60 | return r; | ||
61 | } | ||
62 | r = amdgpu_bo_kmap(adev->irq.ih.ring_obj, | ||
63 | (void **)&adev->irq.ih.ring); | ||
64 | amdgpu_bo_unreserve(adev->irq.ih.ring_obj); | ||
65 | if (r) { | ||
66 | DRM_ERROR("amdgpu: failed to map ih ring buffer (%d).\n", r); | ||
67 | return r; | ||
68 | } | ||
69 | } | 52 | } |
70 | return 0; | 53 | return 0; |
71 | } | 54 | } |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h index 7ef09352e534..f016464035b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h | |||
@@ -70,6 +70,7 @@ struct amdgpu_irq { | |||
70 | /* gen irq stuff */ | 70 | /* gen irq stuff */ |
71 | struct irq_domain *domain; /* GPU irq controller domain */ | 71 | struct irq_domain *domain; /* GPU irq controller domain */ |
72 | unsigned virq[AMDGPU_MAX_IRQ_SRC_ID]; | 72 | unsigned virq[AMDGPU_MAX_IRQ_SRC_ID]; |
73 | uint32_t srbm_soft_reset; | ||
73 | }; | 74 | }; |
74 | 75 | ||
75 | void amdgpu_irq_preinstall(struct drm_device *dev); | 76 | void amdgpu_irq_preinstall(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index d942654a1de0..b78e74048f3d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | |||
@@ -292,14 +292,14 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file | |||
292 | type = AMD_IP_BLOCK_TYPE_UVD; | 292 | type = AMD_IP_BLOCK_TYPE_UVD; |
293 | ring_mask = adev->uvd.ring.ready ? 1 : 0; | 293 | ring_mask = adev->uvd.ring.ready ? 1 : 0; |
294 | ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; | 294 | ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; |
295 | ib_size_alignment = 8; | 295 | ib_size_alignment = 16; |
296 | break; | 296 | break; |
297 | case AMDGPU_HW_IP_VCE: | 297 | case AMDGPU_HW_IP_VCE: |
298 | type = AMD_IP_BLOCK_TYPE_VCE; | 298 | type = AMD_IP_BLOCK_TYPE_VCE; |
299 | for (i = 0; i < AMDGPU_MAX_VCE_RINGS; i++) | 299 | for (i = 0; i < AMDGPU_MAX_VCE_RINGS; i++) |
300 | ring_mask |= ((adev->vce.ring[i].ready ? 1 : 0) << i); | 300 | ring_mask |= ((adev->vce.ring[i].ready ? 1 : 0) << i); |
301 | ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; | 301 | ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; |
302 | ib_size_alignment = 8; | 302 | ib_size_alignment = 1; |
303 | break; | 303 | break; |
304 | default: | 304 | default: |
305 | return -EINVAL; | 305 | return -EINVAL; |
@@ -373,6 +373,9 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file | |||
373 | case AMDGPU_INFO_NUM_BYTES_MOVED: | 373 | case AMDGPU_INFO_NUM_BYTES_MOVED: |
374 | ui64 = atomic64_read(&adev->num_bytes_moved); | 374 | ui64 = atomic64_read(&adev->num_bytes_moved); |
375 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; | 375 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
376 | case AMDGPU_INFO_NUM_EVICTIONS: | ||
377 | ui64 = atomic64_read(&adev->num_evictions); | ||
378 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; | ||
376 | case AMDGPU_INFO_VRAM_USAGE: | 379 | case AMDGPU_INFO_VRAM_USAGE: |
377 | ui64 = atomic64_read(&adev->vram_usage); | 380 | ui64 = atomic64_read(&adev->vram_usage); |
378 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; | 381 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 6b1d7d306564..7b0eff7d060b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <drm/drm_plane_helper.h> | 39 | #include <drm/drm_plane_helper.h> |
40 | #include <linux/i2c.h> | 40 | #include <linux/i2c.h> |
41 | #include <linux/i2c-algo-bit.h> | 41 | #include <linux/i2c-algo-bit.h> |
42 | #include <linux/hrtimer.h> | ||
43 | #include "amdgpu_irq.h" | ||
42 | 44 | ||
43 | struct amdgpu_bo; | 45 | struct amdgpu_bo; |
44 | struct amdgpu_device; | 46 | struct amdgpu_device; |
@@ -339,6 +341,8 @@ struct amdgpu_mode_info { | |||
339 | int num_dig; /* number of dig blocks */ | 341 | int num_dig; /* number of dig blocks */ |
340 | int disp_priority; | 342 | int disp_priority; |
341 | const struct amdgpu_display_funcs *funcs; | 343 | const struct amdgpu_display_funcs *funcs; |
344 | struct hrtimer vblank_timer; | ||
345 | enum amdgpu_interrupt_state vsync_timer_enabled; | ||
342 | }; | 346 | }; |
343 | 347 | ||
344 | #define AMDGPU_MAX_BL_LEVEL 0xFF | 348 | #define AMDGPU_MAX_BL_LEVEL 0xFF |
@@ -587,10 +591,10 @@ int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tile | |||
587 | void amdgpu_print_display_setup(struct drm_device *dev); | 591 | void amdgpu_print_display_setup(struct drm_device *dev); |
588 | int amdgpu_modeset_create_props(struct amdgpu_device *adev); | 592 | int amdgpu_modeset_create_props(struct amdgpu_device *adev); |
589 | int amdgpu_crtc_set_config(struct drm_mode_set *set); | 593 | int amdgpu_crtc_set_config(struct drm_mode_set *set); |
590 | int amdgpu_crtc_page_flip(struct drm_crtc *crtc, | 594 | int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, |
591 | struct drm_framebuffer *fb, | 595 | struct drm_framebuffer *fb, |
592 | struct drm_pending_vblank_event *event, | 596 | struct drm_pending_vblank_event *event, |
593 | uint32_t page_flip_flags); | 597 | uint32_t page_flip_flags, uint32_t target); |
594 | extern const struct drm_mode_config_funcs amdgpu_mode_funcs; | 598 | extern const struct drm_mode_config_funcs amdgpu_mode_funcs; |
595 | 599 | ||
596 | #endif | 600 | #endif |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 6f0873c75a25..b17734e0ecc8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | |||
@@ -44,14 +44,13 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev); | |||
44 | static u64 amdgpu_get_vis_part_size(struct amdgpu_device *adev, | 44 | static u64 amdgpu_get_vis_part_size(struct amdgpu_device *adev, |
45 | struct ttm_mem_reg *mem) | 45 | struct ttm_mem_reg *mem) |
46 | { | 46 | { |
47 | u64 ret = 0; | 47 | if (mem->start << PAGE_SHIFT >= adev->mc.visible_vram_size) |
48 | if (mem->start << PAGE_SHIFT < adev->mc.visible_vram_size) { | 48 | return 0; |
49 | ret = (u64)((mem->start << PAGE_SHIFT) + mem->size) > | 49 | |
50 | adev->mc.visible_vram_size ? | 50 | return ((mem->start << PAGE_SHIFT) + mem->size) > |
51 | adev->mc.visible_vram_size - (mem->start << PAGE_SHIFT) : | 51 | adev->mc.visible_vram_size ? |
52 | mem->size; | 52 | adev->mc.visible_vram_size - (mem->start << PAGE_SHIFT) : |
53 | } | 53 | mem->size; |
54 | return ret; | ||
55 | } | 54 | } |
56 | 55 | ||
57 | static void amdgpu_update_memory_usage(struct amdgpu_device *adev, | 56 | static void amdgpu_update_memory_usage(struct amdgpu_device *adev, |
@@ -99,6 +98,11 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) | |||
99 | 98 | ||
100 | drm_gem_object_release(&bo->gem_base); | 99 | drm_gem_object_release(&bo->gem_base); |
101 | amdgpu_bo_unref(&bo->parent); | 100 | amdgpu_bo_unref(&bo->parent); |
101 | if (!list_empty(&bo->shadow_list)) { | ||
102 | mutex_lock(&bo->adev->shadow_list_lock); | ||
103 | list_del_init(&bo->shadow_list); | ||
104 | mutex_unlock(&bo->adev->shadow_list_lock); | ||
105 | } | ||
102 | kfree(bo->metadata); | 106 | kfree(bo->metadata); |
103 | kfree(bo); | 107 | kfree(bo); |
104 | } | 108 | } |
@@ -112,84 +116,93 @@ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) | |||
112 | 116 | ||
113 | static void amdgpu_ttm_placement_init(struct amdgpu_device *adev, | 117 | static void amdgpu_ttm_placement_init(struct amdgpu_device *adev, |
114 | struct ttm_placement *placement, | 118 | struct ttm_placement *placement, |
115 | struct ttm_place *placements, | 119 | struct ttm_place *places, |
116 | u32 domain, u64 flags) | 120 | u32 domain, u64 flags) |
117 | { | 121 | { |
118 | u32 c = 0, i; | 122 | u32 c = 0; |
119 | |||
120 | placement->placement = placements; | ||
121 | placement->busy_placement = placements; | ||
122 | 123 | ||
123 | if (domain & AMDGPU_GEM_DOMAIN_VRAM) { | 124 | if (domain & AMDGPU_GEM_DOMAIN_VRAM) { |
125 | unsigned visible_pfn = adev->mc.visible_vram_size >> PAGE_SHIFT; | ||
126 | |||
124 | if (flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS && | 127 | if (flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS && |
125 | adev->mc.visible_vram_size < adev->mc.real_vram_size) { | 128 | !(flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) && |
126 | placements[c].fpfn = | 129 | adev->mc.visible_vram_size < adev->mc.real_vram_size) { |
127 | adev->mc.visible_vram_size >> PAGE_SHIFT; | 130 | places[c].fpfn = visible_pfn; |
128 | placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | | 131 | places[c].lpfn = 0; |
129 | TTM_PL_FLAG_VRAM | TTM_PL_FLAG_TOPDOWN; | 132 | places[c].flags = TTM_PL_FLAG_WC | |
133 | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM | | ||
134 | TTM_PL_FLAG_TOPDOWN; | ||
135 | c++; | ||
130 | } | 136 | } |
131 | placements[c].fpfn = 0; | 137 | |
132 | placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | | 138 | places[c].fpfn = 0; |
139 | places[c].lpfn = 0; | ||
140 | places[c].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | | ||
133 | TTM_PL_FLAG_VRAM; | 141 | TTM_PL_FLAG_VRAM; |
134 | if (!(flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) | 142 | if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) |
135 | placements[c - 1].flags |= TTM_PL_FLAG_TOPDOWN; | 143 | places[c].lpfn = visible_pfn; |
144 | else | ||
145 | places[c].flags |= TTM_PL_FLAG_TOPDOWN; | ||
146 | c++; | ||
136 | } | 147 | } |
137 | 148 | ||
138 | if (domain & AMDGPU_GEM_DOMAIN_GTT) { | 149 | if (domain & AMDGPU_GEM_DOMAIN_GTT) { |
139 | if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) { | 150 | places[c].fpfn = 0; |
140 | placements[c].fpfn = 0; | 151 | places[c].lpfn = 0; |
141 | placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT | | 152 | places[c].flags = TTM_PL_FLAG_TT; |
153 | if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) | ||
154 | places[c].flags |= TTM_PL_FLAG_WC | | ||
142 | TTM_PL_FLAG_UNCACHED; | 155 | TTM_PL_FLAG_UNCACHED; |
143 | } else { | 156 | else |
144 | placements[c].fpfn = 0; | 157 | places[c].flags |= TTM_PL_FLAG_CACHED; |
145 | placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT; | 158 | c++; |
146 | } | ||
147 | } | 159 | } |
148 | 160 | ||
149 | if (domain & AMDGPU_GEM_DOMAIN_CPU) { | 161 | if (domain & AMDGPU_GEM_DOMAIN_CPU) { |
150 | if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) { | 162 | places[c].fpfn = 0; |
151 | placements[c].fpfn = 0; | 163 | places[c].lpfn = 0; |
152 | placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_SYSTEM | | 164 | places[c].flags = TTM_PL_FLAG_SYSTEM; |
165 | if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) | ||
166 | places[c].flags |= TTM_PL_FLAG_WC | | ||
153 | TTM_PL_FLAG_UNCACHED; | 167 | TTM_PL_FLAG_UNCACHED; |
154 | } else { | 168 | else |
155 | placements[c].fpfn = 0; | 169 | places[c].flags |= TTM_PL_FLAG_CACHED; |
156 | placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM; | 170 | c++; |
157 | } | ||
158 | } | 171 | } |
159 | 172 | ||
160 | if (domain & AMDGPU_GEM_DOMAIN_GDS) { | 173 | if (domain & AMDGPU_GEM_DOMAIN_GDS) { |
161 | placements[c].fpfn = 0; | 174 | places[c].fpfn = 0; |
162 | placements[c++].flags = TTM_PL_FLAG_UNCACHED | | 175 | places[c].lpfn = 0; |
163 | AMDGPU_PL_FLAG_GDS; | 176 | places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GDS; |
177 | c++; | ||
164 | } | 178 | } |
179 | |||
165 | if (domain & AMDGPU_GEM_DOMAIN_GWS) { | 180 | if (domain & AMDGPU_GEM_DOMAIN_GWS) { |
166 | placements[c].fpfn = 0; | 181 | places[c].fpfn = 0; |
167 | placements[c++].flags = TTM_PL_FLAG_UNCACHED | | 182 | places[c].lpfn = 0; |
168 | AMDGPU_PL_FLAG_GWS; | 183 | places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GWS; |
184 | c++; | ||
169 | } | 185 | } |
186 | |||
170 | if (domain & AMDGPU_GEM_DOMAIN_OA) { | 187 | if (domain & AMDGPU_GEM_DOMAIN_OA) { |
171 | placements[c].fpfn = 0; | 188 | places[c].fpfn = 0; |
172 | placements[c++].flags = TTM_PL_FLAG_UNCACHED | | 189 | places[c].lpfn = 0; |
173 | AMDGPU_PL_FLAG_OA; | 190 | places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_OA; |
191 | c++; | ||
174 | } | 192 | } |
175 | 193 | ||
176 | if (!c) { | 194 | if (!c) { |
177 | placements[c].fpfn = 0; | 195 | places[c].fpfn = 0; |
178 | placements[c++].flags = TTM_PL_MASK_CACHING | | 196 | places[c].lpfn = 0; |
179 | TTM_PL_FLAG_SYSTEM; | 197 | places[c].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; |
198 | c++; | ||
180 | } | 199 | } |
200 | |||
181 | placement->num_placement = c; | 201 | placement->num_placement = c; |
182 | placement->num_busy_placement = c; | 202 | placement->placement = places; |
183 | 203 | ||
184 | for (i = 0; i < c; i++) { | 204 | placement->num_busy_placement = c; |
185 | if ((flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) && | 205 | placement->busy_placement = places; |
186 | (placements[i].flags & TTM_PL_FLAG_VRAM) && | ||
187 | !placements[i].fpfn) | ||
188 | placements[i].lpfn = | ||
189 | adev->mc.visible_vram_size >> PAGE_SHIFT; | ||
190 | else | ||
191 | placements[i].lpfn = 0; | ||
192 | } | ||
193 | } | 206 | } |
194 | 207 | ||
195 | void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *rbo, u32 domain) | 208 | void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *rbo, u32 domain) |
@@ -211,6 +224,69 @@ static void amdgpu_fill_placement_to_bo(struct amdgpu_bo *bo, | |||
211 | bo->placement.busy_placement = bo->placements; | 224 | bo->placement.busy_placement = bo->placements; |
212 | } | 225 | } |
213 | 226 | ||
227 | /** | ||
228 | * amdgpu_bo_create_kernel - create BO for kernel use | ||
229 | * | ||
230 | * @adev: amdgpu device object | ||
231 | * @size: size for the new BO | ||
232 | * @align: alignment for the new BO | ||
233 | * @domain: where to place it | ||
234 | * @bo_ptr: resulting BO | ||
235 | * @gpu_addr: GPU addr of the pinned BO | ||
236 | * @cpu_addr: optional CPU address mapping | ||
237 | * | ||
238 | * Allocates and pins a BO for kernel internal use. | ||
239 | * | ||
240 | * Returns 0 on success, negative error code otherwise. | ||
241 | */ | ||
242 | int amdgpu_bo_create_kernel(struct amdgpu_device *adev, | ||
243 | unsigned long size, int align, | ||
244 | u32 domain, struct amdgpu_bo **bo_ptr, | ||
245 | u64 *gpu_addr, void **cpu_addr) | ||
246 | { | ||
247 | int r; | ||
248 | |||
249 | r = amdgpu_bo_create(adev, size, align, true, domain, | ||
250 | AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, | ||
251 | NULL, NULL, bo_ptr); | ||
252 | if (r) { | ||
253 | dev_err(adev->dev, "(%d) failed to allocate kernel bo\n", r); | ||
254 | return r; | ||
255 | } | ||
256 | |||
257 | r = amdgpu_bo_reserve(*bo_ptr, false); | ||
258 | if (r) { | ||
259 | dev_err(adev->dev, "(%d) failed to reserve kernel bo\n", r); | ||
260 | goto error_free; | ||
261 | } | ||
262 | |||
263 | r = amdgpu_bo_pin(*bo_ptr, domain, gpu_addr); | ||
264 | if (r) { | ||
265 | dev_err(adev->dev, "(%d) kernel bo pin failed\n", r); | ||
266 | goto error_unreserve; | ||
267 | } | ||
268 | |||
269 | if (cpu_addr) { | ||
270 | r = amdgpu_bo_kmap(*bo_ptr, cpu_addr); | ||
271 | if (r) { | ||
272 | dev_err(adev->dev, "(%d) kernel bo map failed\n", r); | ||
273 | goto error_unreserve; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | amdgpu_bo_unreserve(*bo_ptr); | ||
278 | |||
279 | return 0; | ||
280 | |||
281 | error_unreserve: | ||
282 | amdgpu_bo_unreserve(*bo_ptr); | ||
283 | |||
284 | error_free: | ||
285 | amdgpu_bo_unref(bo_ptr); | ||
286 | |||
287 | return r; | ||
288 | } | ||
289 | |||
214 | int amdgpu_bo_create_restricted(struct amdgpu_device *adev, | 290 | int amdgpu_bo_create_restricted(struct amdgpu_device *adev, |
215 | unsigned long size, int byte_align, | 291 | unsigned long size, int byte_align, |
216 | bool kernel, u32 domain, u64 flags, | 292 | bool kernel, u32 domain, u64 flags, |
@@ -250,6 +326,7 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev, | |||
250 | } | 326 | } |
251 | bo->adev = adev; | 327 | bo->adev = adev; |
252 | INIT_LIST_HEAD(&bo->list); | 328 | INIT_LIST_HEAD(&bo->list); |
329 | INIT_LIST_HEAD(&bo->shadow_list); | ||
253 | INIT_LIST_HEAD(&bo->va); | 330 | INIT_LIST_HEAD(&bo->va); |
254 | bo->prefered_domains = domain & (AMDGPU_GEM_DOMAIN_VRAM | | 331 | bo->prefered_domains = domain & (AMDGPU_GEM_DOMAIN_VRAM | |
255 | AMDGPU_GEM_DOMAIN_GTT | | 332 | AMDGPU_GEM_DOMAIN_GTT | |
@@ -277,11 +354,79 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev, | |||
277 | if (unlikely(r != 0)) { | 354 | if (unlikely(r != 0)) { |
278 | return r; | 355 | return r; |
279 | } | 356 | } |
357 | |||
358 | if (flags & AMDGPU_GEM_CREATE_VRAM_CLEARED && | ||
359 | bo->tbo.mem.placement & TTM_PL_FLAG_VRAM) { | ||
360 | struct fence *fence; | ||
361 | |||
362 | if (adev->mman.buffer_funcs_ring == NULL || | ||
363 | !adev->mman.buffer_funcs_ring->ready) { | ||
364 | r = -EBUSY; | ||
365 | goto fail_free; | ||
366 | } | ||
367 | |||
368 | r = amdgpu_bo_reserve(bo, false); | ||
369 | if (unlikely(r != 0)) | ||
370 | goto fail_free; | ||
371 | |||
372 | amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM); | ||
373 | r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); | ||
374 | if (unlikely(r != 0)) | ||
375 | goto fail_unreserve; | ||
376 | |||
377 | amdgpu_fill_buffer(bo, 0, bo->tbo.resv, &fence); | ||
378 | amdgpu_bo_fence(bo, fence, false); | ||
379 | amdgpu_bo_unreserve(bo); | ||
380 | fence_put(bo->tbo.moving); | ||
381 | bo->tbo.moving = fence_get(fence); | ||
382 | fence_put(fence); | ||
383 | } | ||
280 | *bo_ptr = bo; | 384 | *bo_ptr = bo; |
281 | 385 | ||
282 | trace_amdgpu_bo_create(bo); | 386 | trace_amdgpu_bo_create(bo); |
283 | 387 | ||
284 | return 0; | 388 | return 0; |
389 | |||
390 | fail_unreserve: | ||
391 | amdgpu_bo_unreserve(bo); | ||
392 | fail_free: | ||
393 | amdgpu_bo_unref(&bo); | ||
394 | return r; | ||
395 | } | ||
396 | |||
397 | static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, | ||
398 | unsigned long size, int byte_align, | ||
399 | struct amdgpu_bo *bo) | ||
400 | { | ||
401 | struct ttm_placement placement = {0}; | ||
402 | struct ttm_place placements[AMDGPU_GEM_DOMAIN_MAX + 1]; | ||
403 | int r; | ||
404 | |||
405 | if (bo->shadow) | ||
406 | return 0; | ||
407 | |||
408 | bo->flags |= AMDGPU_GEM_CREATE_SHADOW; | ||
409 | memset(&placements, 0, | ||
410 | (AMDGPU_GEM_DOMAIN_MAX + 1) * sizeof(struct ttm_place)); | ||
411 | |||
412 | amdgpu_ttm_placement_init(adev, &placement, | ||
413 | placements, AMDGPU_GEM_DOMAIN_GTT, | ||
414 | AMDGPU_GEM_CREATE_CPU_GTT_USWC); | ||
415 | |||
416 | r = amdgpu_bo_create_restricted(adev, size, byte_align, true, | ||
417 | AMDGPU_GEM_DOMAIN_GTT, | ||
418 | AMDGPU_GEM_CREATE_CPU_GTT_USWC, | ||
419 | NULL, &placement, | ||
420 | bo->tbo.resv, | ||
421 | &bo->shadow); | ||
422 | if (!r) { | ||
423 | bo->shadow->parent = amdgpu_bo_ref(bo); | ||
424 | mutex_lock(&adev->shadow_list_lock); | ||
425 | list_add_tail(&bo->shadow_list, &adev->shadow_list); | ||
426 | mutex_unlock(&adev->shadow_list_lock); | ||
427 | } | ||
428 | |||
429 | return r; | ||
285 | } | 430 | } |
286 | 431 | ||
287 | int amdgpu_bo_create(struct amdgpu_device *adev, | 432 | int amdgpu_bo_create(struct amdgpu_device *adev, |
@@ -293,6 +438,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, | |||
293 | { | 438 | { |
294 | struct ttm_placement placement = {0}; | 439 | struct ttm_placement placement = {0}; |
295 | struct ttm_place placements[AMDGPU_GEM_DOMAIN_MAX + 1]; | 440 | struct ttm_place placements[AMDGPU_GEM_DOMAIN_MAX + 1]; |
441 | int r; | ||
296 | 442 | ||
297 | memset(&placements, 0, | 443 | memset(&placements, 0, |
298 | (AMDGPU_GEM_DOMAIN_MAX + 1) * sizeof(struct ttm_place)); | 444 | (AMDGPU_GEM_DOMAIN_MAX + 1) * sizeof(struct ttm_place)); |
@@ -300,9 +446,83 @@ int amdgpu_bo_create(struct amdgpu_device *adev, | |||
300 | amdgpu_ttm_placement_init(adev, &placement, | 446 | amdgpu_ttm_placement_init(adev, &placement, |
301 | placements, domain, flags); | 447 | placements, domain, flags); |
302 | 448 | ||
303 | return amdgpu_bo_create_restricted(adev, size, byte_align, kernel, | 449 | r = amdgpu_bo_create_restricted(adev, size, byte_align, kernel, |
304 | domain, flags, sg, &placement, | 450 | domain, flags, sg, &placement, |
305 | resv, bo_ptr); | 451 | resv, bo_ptr); |
452 | if (r) | ||
453 | return r; | ||
454 | |||
455 | if (amdgpu_need_backup(adev) && (flags & AMDGPU_GEM_CREATE_SHADOW)) { | ||
456 | r = amdgpu_bo_create_shadow(adev, size, byte_align, (*bo_ptr)); | ||
457 | if (r) | ||
458 | amdgpu_bo_unref(bo_ptr); | ||
459 | } | ||
460 | |||
461 | return r; | ||
462 | } | ||
463 | |||
464 | int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev, | ||
465 | struct amdgpu_ring *ring, | ||
466 | struct amdgpu_bo *bo, | ||
467 | struct reservation_object *resv, | ||
468 | struct fence **fence, | ||
469 | bool direct) | ||
470 | |||
471 | { | ||
472 | struct amdgpu_bo *shadow = bo->shadow; | ||
473 | uint64_t bo_addr, shadow_addr; | ||
474 | int r; | ||
475 | |||
476 | if (!shadow) | ||
477 | return -EINVAL; | ||
478 | |||
479 | bo_addr = amdgpu_bo_gpu_offset(bo); | ||
480 | shadow_addr = amdgpu_bo_gpu_offset(bo->shadow); | ||
481 | |||
482 | r = reservation_object_reserve_shared(bo->tbo.resv); | ||
483 | if (r) | ||
484 | goto err; | ||
485 | |||
486 | r = amdgpu_copy_buffer(ring, bo_addr, shadow_addr, | ||
487 | amdgpu_bo_size(bo), resv, fence, | ||
488 | direct); | ||
489 | if (!r) | ||
490 | amdgpu_bo_fence(bo, *fence, true); | ||
491 | |||
492 | err: | ||
493 | return r; | ||
494 | } | ||
495 | |||
496 | int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev, | ||
497 | struct amdgpu_ring *ring, | ||
498 | struct amdgpu_bo *bo, | ||
499 | struct reservation_object *resv, | ||
500 | struct fence **fence, | ||
501 | bool direct) | ||
502 | |||
503 | { | ||
504 | struct amdgpu_bo *shadow = bo->shadow; | ||
505 | uint64_t bo_addr, shadow_addr; | ||
506 | int r; | ||
507 | |||
508 | if (!shadow) | ||
509 | return -EINVAL; | ||
510 | |||
511 | bo_addr = amdgpu_bo_gpu_offset(bo); | ||
512 | shadow_addr = amdgpu_bo_gpu_offset(bo->shadow); | ||
513 | |||
514 | r = reservation_object_reserve_shared(bo->tbo.resv); | ||
515 | if (r) | ||
516 | goto err; | ||
517 | |||
518 | r = amdgpu_copy_buffer(ring, shadow_addr, bo_addr, | ||
519 | amdgpu_bo_size(bo), resv, fence, | ||
520 | direct); | ||
521 | if (!r) | ||
522 | amdgpu_bo_fence(bo, *fence, true); | ||
523 | |||
524 | err: | ||
525 | return r; | ||
306 | } | 526 | } |
307 | 527 | ||
308 | int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) | 528 | int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) |
@@ -380,16 +600,17 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, | |||
380 | return -EINVAL; | 600 | return -EINVAL; |
381 | 601 | ||
382 | if (bo->pin_count) { | 602 | if (bo->pin_count) { |
603 | uint32_t mem_type = bo->tbo.mem.mem_type; | ||
604 | |||
605 | if (domain != amdgpu_mem_type_to_domain(mem_type)) | ||
606 | return -EINVAL; | ||
607 | |||
383 | bo->pin_count++; | 608 | bo->pin_count++; |
384 | if (gpu_addr) | 609 | if (gpu_addr) |
385 | *gpu_addr = amdgpu_bo_gpu_offset(bo); | 610 | *gpu_addr = amdgpu_bo_gpu_offset(bo); |
386 | 611 | ||
387 | if (max_offset != 0) { | 612 | if (max_offset != 0) { |
388 | u64 domain_start; | 613 | u64 domain_start = bo->tbo.bdev->man[mem_type].gpu_offset; |
389 | if (domain == AMDGPU_GEM_DOMAIN_VRAM) | ||
390 | domain_start = bo->adev->mc.vram_start; | ||
391 | else | ||
392 | domain_start = bo->adev->mc.gtt_start; | ||
393 | WARN_ON_ONCE(max_offset < | 614 | WARN_ON_ONCE(max_offset < |
394 | (amdgpu_bo_gpu_offset(bo) - domain_start)); | 615 | (amdgpu_bo_gpu_offset(bo) - domain_start)); |
395 | } | 616 | } |
@@ -401,7 +622,8 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, | |||
401 | /* force to pin into visible video ram */ | 622 | /* force to pin into visible video ram */ |
402 | if ((bo->placements[i].flags & TTM_PL_FLAG_VRAM) && | 623 | if ((bo->placements[i].flags & TTM_PL_FLAG_VRAM) && |
403 | !(bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) && | 624 | !(bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) && |
404 | (!max_offset || max_offset > bo->adev->mc.visible_vram_size)) { | 625 | (!max_offset || max_offset > |
626 | bo->adev->mc.visible_vram_size)) { | ||
405 | if (WARN_ON_ONCE(min_offset > | 627 | if (WARN_ON_ONCE(min_offset > |
406 | bo->adev->mc.visible_vram_size)) | 628 | bo->adev->mc.visible_vram_size)) |
407 | return -EINVAL; | 629 | return -EINVAL; |
@@ -420,19 +642,23 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, | |||
420 | } | 642 | } |
421 | 643 | ||
422 | r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); | 644 | r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); |
423 | if (likely(r == 0)) { | 645 | if (unlikely(r)) { |
424 | bo->pin_count = 1; | ||
425 | if (gpu_addr != NULL) | ||
426 | *gpu_addr = amdgpu_bo_gpu_offset(bo); | ||
427 | if (domain == AMDGPU_GEM_DOMAIN_VRAM) { | ||
428 | bo->adev->vram_pin_size += amdgpu_bo_size(bo); | ||
429 | if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) | ||
430 | bo->adev->invisible_pin_size += amdgpu_bo_size(bo); | ||
431 | } else | ||
432 | bo->adev->gart_pin_size += amdgpu_bo_size(bo); | ||
433 | } else { | ||
434 | dev_err(bo->adev->dev, "%p pin failed\n", bo); | 646 | dev_err(bo->adev->dev, "%p pin failed\n", bo); |
647 | goto error; | ||
648 | } | ||
649 | |||
650 | bo->pin_count = 1; | ||
651 | if (gpu_addr != NULL) | ||
652 | *gpu_addr = amdgpu_bo_gpu_offset(bo); | ||
653 | if (domain == AMDGPU_GEM_DOMAIN_VRAM) { | ||
654 | bo->adev->vram_pin_size += amdgpu_bo_size(bo); | ||
655 | if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) | ||
656 | bo->adev->invisible_pin_size += amdgpu_bo_size(bo); | ||
657 | } else if (domain == AMDGPU_GEM_DOMAIN_GTT) { | ||
658 | bo->adev->gart_pin_size += amdgpu_bo_size(bo); | ||
435 | } | 659 | } |
660 | |||
661 | error: | ||
436 | return r; | 662 | return r; |
437 | } | 663 | } |
438 | 664 | ||
@@ -457,16 +683,20 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo) | |||
457 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | 683 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; |
458 | } | 684 | } |
459 | r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); | 685 | r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); |
460 | if (likely(r == 0)) { | 686 | if (unlikely(r)) { |
461 | if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { | ||
462 | bo->adev->vram_pin_size -= amdgpu_bo_size(bo); | ||
463 | if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) | ||
464 | bo->adev->invisible_pin_size -= amdgpu_bo_size(bo); | ||
465 | } else | ||
466 | bo->adev->gart_pin_size -= amdgpu_bo_size(bo); | ||
467 | } else { | ||
468 | dev_err(bo->adev->dev, "%p validate failed for unpin\n", bo); | 687 | dev_err(bo->adev->dev, "%p validate failed for unpin\n", bo); |
688 | goto error; | ||
689 | } | ||
690 | |||
691 | if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { | ||
692 | bo->adev->vram_pin_size -= amdgpu_bo_size(bo); | ||
693 | if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) | ||
694 | bo->adev->invisible_pin_size -= amdgpu_bo_size(bo); | ||
695 | } else { | ||
696 | bo->adev->gart_pin_size -= amdgpu_bo_size(bo); | ||
469 | } | 697 | } |
698 | |||
699 | error: | ||
470 | return r; | 700 | return r; |
471 | } | 701 | } |
472 | 702 | ||
@@ -637,7 +867,8 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) | |||
637 | for (i = 0; i < abo->placement.num_placement; i++) { | 867 | for (i = 0; i < abo->placement.num_placement; i++) { |
638 | /* Force into visible VRAM */ | 868 | /* Force into visible VRAM */ |
639 | if ((abo->placements[i].flags & TTM_PL_FLAG_VRAM) && | 869 | if ((abo->placements[i].flags & TTM_PL_FLAG_VRAM) && |
640 | (!abo->placements[i].lpfn || abo->placements[i].lpfn > lpfn)) | 870 | (!abo->placements[i].lpfn || |
871 | abo->placements[i].lpfn > lpfn)) | ||
641 | abo->placements[i].lpfn = lpfn; | 872 | abo->placements[i].lpfn = lpfn; |
642 | } | 873 | } |
643 | r = ttm_bo_validate(bo, &abo->placement, false, false); | 874 | r = ttm_bo_validate(bo, &abo->placement, false, false); |
@@ -674,3 +905,21 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct fence *fence, | |||
674 | else | 905 | else |
675 | reservation_object_add_excl_fence(resv, fence); | 906 | reservation_object_add_excl_fence(resv, fence); |
676 | } | 907 | } |
908 | |||
909 | /** | ||
910 | * amdgpu_bo_gpu_offset - return GPU offset of bo | ||
911 | * @bo: amdgpu object for which we query the offset | ||
912 | * | ||
913 | * Returns current GPU offset of the object. | ||
914 | * | ||
915 | * Note: object should either be pinned or reserved when calling this | ||
916 | * function, it might be useful to add check for this for debugging. | ||
917 | */ | ||
918 | u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) | ||
919 | { | ||
920 | WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM); | ||
921 | WARN_ON_ONCE(!ww_mutex_is_locked(&bo->tbo.resv->lock) && | ||
922 | !bo->pin_count); | ||
923 | |||
924 | return bo->tbo.offset; | ||
925 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index bdb01d932548..b6a27390ef88 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | |||
@@ -85,21 +85,6 @@ static inline void amdgpu_bo_unreserve(struct amdgpu_bo *bo) | |||
85 | ttm_bo_unreserve(&bo->tbo); | 85 | ttm_bo_unreserve(&bo->tbo); |
86 | } | 86 | } |
87 | 87 | ||
88 | /** | ||
89 | * amdgpu_bo_gpu_offset - return GPU offset of bo | ||
90 | * @bo: amdgpu object for which we query the offset | ||
91 | * | ||
92 | * Returns current GPU offset of the object. | ||
93 | * | ||
94 | * Note: object should either be pinned or reserved when calling this | ||
95 | * function, it might be useful to add check for this for debugging. | ||
96 | */ | ||
97 | static inline u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) | ||
98 | { | ||
99 | WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM); | ||
100 | return bo->tbo.offset; | ||
101 | } | ||
102 | |||
103 | static inline unsigned long amdgpu_bo_size(struct amdgpu_bo *bo) | 88 | static inline unsigned long amdgpu_bo_size(struct amdgpu_bo *bo) |
104 | { | 89 | { |
105 | return bo->tbo.num_pages << PAGE_SHIFT; | 90 | return bo->tbo.num_pages << PAGE_SHIFT; |
@@ -139,6 +124,10 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev, | |||
139 | struct ttm_placement *placement, | 124 | struct ttm_placement *placement, |
140 | struct reservation_object *resv, | 125 | struct reservation_object *resv, |
141 | struct amdgpu_bo **bo_ptr); | 126 | struct amdgpu_bo **bo_ptr); |
127 | int amdgpu_bo_create_kernel(struct amdgpu_device *adev, | ||
128 | unsigned long size, int align, | ||
129 | u32 domain, struct amdgpu_bo **bo_ptr, | ||
130 | u64 *gpu_addr, void **cpu_addr); | ||
142 | int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr); | 131 | int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr); |
143 | void amdgpu_bo_kunmap(struct amdgpu_bo *bo); | 132 | void amdgpu_bo_kunmap(struct amdgpu_bo *bo); |
144 | struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo); | 133 | struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo); |
@@ -165,6 +154,19 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, | |||
165 | int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo); | 154 | int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo); |
166 | void amdgpu_bo_fence(struct amdgpu_bo *bo, struct fence *fence, | 155 | void amdgpu_bo_fence(struct amdgpu_bo *bo, struct fence *fence, |
167 | bool shared); | 156 | bool shared); |
157 | u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo); | ||
158 | int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev, | ||
159 | struct amdgpu_ring *ring, | ||
160 | struct amdgpu_bo *bo, | ||
161 | struct reservation_object *resv, | ||
162 | struct fence **fence, bool direct); | ||
163 | int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev, | ||
164 | struct amdgpu_ring *ring, | ||
165 | struct amdgpu_bo *bo, | ||
166 | struct reservation_object *resv, | ||
167 | struct fence **fence, | ||
168 | bool direct); | ||
169 | |||
168 | 170 | ||
169 | /* | 171 | /* |
170 | * sub allocation | 172 | * sub allocation |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 5cc7052e391d..d4ec3cb187a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | |||
@@ -1103,54 +1103,46 @@ force: | |||
1103 | 1103 | ||
1104 | void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) | 1104 | void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) |
1105 | { | 1105 | { |
1106 | if (adev->pp_enabled) | 1106 | if (adev->pp_enabled || adev->pm.funcs->powergate_uvd) { |
1107 | /* enable/disable UVD */ | ||
1108 | mutex_lock(&adev->pm.mutex); | ||
1107 | amdgpu_dpm_powergate_uvd(adev, !enable); | 1109 | amdgpu_dpm_powergate_uvd(adev, !enable); |
1108 | else { | 1110 | mutex_unlock(&adev->pm.mutex); |
1109 | if (adev->pm.funcs->powergate_uvd) { | 1111 | } else { |
1112 | if (enable) { | ||
1110 | mutex_lock(&adev->pm.mutex); | 1113 | mutex_lock(&adev->pm.mutex); |
1111 | /* enable/disable UVD */ | 1114 | adev->pm.dpm.uvd_active = true; |
1112 | amdgpu_dpm_powergate_uvd(adev, !enable); | 1115 | adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD; |
1113 | mutex_unlock(&adev->pm.mutex); | 1116 | mutex_unlock(&adev->pm.mutex); |
1114 | } else { | 1117 | } else { |
1115 | if (enable) { | 1118 | mutex_lock(&adev->pm.mutex); |
1116 | mutex_lock(&adev->pm.mutex); | 1119 | adev->pm.dpm.uvd_active = false; |
1117 | adev->pm.dpm.uvd_active = true; | 1120 | mutex_unlock(&adev->pm.mutex); |
1118 | adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD; | ||
1119 | mutex_unlock(&adev->pm.mutex); | ||
1120 | } else { | ||
1121 | mutex_lock(&adev->pm.mutex); | ||
1122 | adev->pm.dpm.uvd_active = false; | ||
1123 | mutex_unlock(&adev->pm.mutex); | ||
1124 | } | ||
1125 | amdgpu_pm_compute_clocks(adev); | ||
1126 | } | 1121 | } |
1127 | 1122 | amdgpu_pm_compute_clocks(adev); | |
1128 | } | 1123 | } |
1129 | } | 1124 | } |
1130 | 1125 | ||
1131 | void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) | 1126 | void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) |
1132 | { | 1127 | { |
1133 | if (adev->pp_enabled) | 1128 | if (adev->pp_enabled || adev->pm.funcs->powergate_vce) { |
1129 | /* enable/disable VCE */ | ||
1130 | mutex_lock(&adev->pm.mutex); | ||
1134 | amdgpu_dpm_powergate_vce(adev, !enable); | 1131 | amdgpu_dpm_powergate_vce(adev, !enable); |
1135 | else { | 1132 | mutex_unlock(&adev->pm.mutex); |
1136 | if (adev->pm.funcs->powergate_vce) { | 1133 | } else { |
1134 | if (enable) { | ||
1137 | mutex_lock(&adev->pm.mutex); | 1135 | mutex_lock(&adev->pm.mutex); |
1138 | amdgpu_dpm_powergate_vce(adev, !enable); | 1136 | adev->pm.dpm.vce_active = true; |
1137 | /* XXX select vce level based on ring/task */ | ||
1138 | adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL; | ||
1139 | mutex_unlock(&adev->pm.mutex); | 1139 | mutex_unlock(&adev->pm.mutex); |
1140 | } else { | 1140 | } else { |
1141 | if (enable) { | 1141 | mutex_lock(&adev->pm.mutex); |
1142 | mutex_lock(&adev->pm.mutex); | 1142 | adev->pm.dpm.vce_active = false; |
1143 | adev->pm.dpm.vce_active = true; | 1143 | mutex_unlock(&adev->pm.mutex); |
1144 | /* XXX select vce level based on ring/task */ | ||
1145 | adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL; | ||
1146 | mutex_unlock(&adev->pm.mutex); | ||
1147 | } else { | ||
1148 | mutex_lock(&adev->pm.mutex); | ||
1149 | adev->pm.dpm.vce_active = false; | ||
1150 | mutex_unlock(&adev->pm.mutex); | ||
1151 | } | ||
1152 | amdgpu_pm_compute_clocks(adev); | ||
1153 | } | 1144 | } |
1145 | amdgpu_pm_compute_clocks(adev); | ||
1154 | } | 1146 | } |
1155 | } | 1147 | } |
1156 | 1148 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c index c5738a22b690..545074479e1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c | |||
@@ -52,7 +52,9 @@ static int amdgpu_powerplay_init(struct amdgpu_device *adev) | |||
52 | pp_init->chip_family = adev->family; | 52 | pp_init->chip_family = adev->family; |
53 | pp_init->chip_id = adev->asic_type; | 53 | pp_init->chip_id = adev->asic_type; |
54 | pp_init->device = amdgpu_cgs_create_device(adev); | 54 | pp_init->device = amdgpu_cgs_create_device(adev); |
55 | pp_init->powercontainment_enabled = amdgpu_powercontainment; | 55 | pp_init->rev_id = adev->pdev->revision; |
56 | pp_init->sub_sys_id = adev->pdev->subsystem_device; | ||
57 | pp_init->sub_vendor_id = adev->pdev->subsystem_vendor; | ||
56 | 58 | ||
57 | ret = amd_powerplay_init(pp_init, amd_pp); | 59 | ret = amd_powerplay_init(pp_init, amd_pp); |
58 | kfree(pp_init); | 60 | kfree(pp_init); |
@@ -106,11 +108,10 @@ static int amdgpu_pp_early_init(void *handle) | |||
106 | break; | 108 | break; |
107 | case CHIP_TONGA: | 109 | case CHIP_TONGA: |
108 | case CHIP_FIJI: | 110 | case CHIP_FIJI: |
109 | adev->pp_enabled = (amdgpu_powerplay == 0) ? false : true; | 111 | case CHIP_TOPAZ: |
110 | break; | ||
111 | case CHIP_CARRIZO: | 112 | case CHIP_CARRIZO: |
112 | case CHIP_STONEY: | 113 | case CHIP_STONEY: |
113 | adev->pp_enabled = (amdgpu_powerplay > 0) ? true : false; | 114 | adev->pp_enabled = (amdgpu_powerplay == 0) ? false : true; |
114 | break; | 115 | break; |
115 | /* These chips don't have powerplay implemenations */ | 116 | /* These chips don't have powerplay implemenations */ |
116 | case CHIP_BONAIRE: | 117 | case CHIP_BONAIRE: |
@@ -118,7 +119,6 @@ static int amdgpu_pp_early_init(void *handle) | |||
118 | case CHIP_KABINI: | 119 | case CHIP_KABINI: |
119 | case CHIP_MULLINS: | 120 | case CHIP_MULLINS: |
120 | case CHIP_KAVERI: | 121 | case CHIP_KAVERI: |
121 | case CHIP_TOPAZ: | ||
122 | default: | 122 | default: |
123 | adev->pp_enabled = false; | 123 | adev->pp_enabled = false; |
124 | break; | 124 | break; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 85aeb0a804bb..242ba04bfde6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | |||
@@ -222,33 +222,16 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, | |||
222 | 222 | ||
223 | /* Allocate ring buffer */ | 223 | /* Allocate ring buffer */ |
224 | if (ring->ring_obj == NULL) { | 224 | if (ring->ring_obj == NULL) { |
225 | r = amdgpu_bo_create(adev, ring->ring_size, PAGE_SIZE, true, | 225 | r = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE, |
226 | AMDGPU_GEM_DOMAIN_GTT, 0, | 226 | AMDGPU_GEM_DOMAIN_GTT, |
227 | NULL, NULL, &ring->ring_obj); | 227 | &ring->ring_obj, |
228 | &ring->gpu_addr, | ||
229 | (void **)&ring->ring); | ||
228 | if (r) { | 230 | if (r) { |
229 | dev_err(adev->dev, "(%d) ring create failed\n", r); | 231 | dev_err(adev->dev, "(%d) ring create failed\n", r); |
230 | return r; | 232 | return r; |
231 | } | 233 | } |
232 | r = amdgpu_bo_reserve(ring->ring_obj, false); | ||
233 | if (unlikely(r != 0)) | ||
234 | return r; | ||
235 | r = amdgpu_bo_pin(ring->ring_obj, AMDGPU_GEM_DOMAIN_GTT, | ||
236 | &ring->gpu_addr); | ||
237 | if (r) { | ||
238 | amdgpu_bo_unreserve(ring->ring_obj); | ||
239 | dev_err(adev->dev, "(%d) ring pin failed\n", r); | ||
240 | return r; | ||
241 | } | ||
242 | r = amdgpu_bo_kmap(ring->ring_obj, | ||
243 | (void **)&ring->ring); | ||
244 | |||
245 | memset((void *)ring->ring, 0, ring->ring_size); | 234 | memset((void *)ring->ring, 0, ring->ring_size); |
246 | |||
247 | amdgpu_bo_unreserve(ring->ring_obj); | ||
248 | if (r) { | ||
249 | dev_err(adev->dev, "(%d) ring map failed\n", r); | ||
250 | return r; | ||
251 | } | ||
252 | } | 235 | } |
253 | ring->ptr_mask = (ring->ring_size / 4) - 1; | 236 | ring->ptr_mask = (ring->ring_size / 4) - 1; |
254 | ring->max_dw = max_dw; | 237 | ring->max_dw = max_dw; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c index 05a53f4fc334..b827c75e95de 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c | |||
@@ -111,7 +111,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) | |||
111 | amdgpu_bo_kunmap(gtt_obj[i]); | 111 | amdgpu_bo_kunmap(gtt_obj[i]); |
112 | 112 | ||
113 | r = amdgpu_copy_buffer(ring, gtt_addr, vram_addr, | 113 | r = amdgpu_copy_buffer(ring, gtt_addr, vram_addr, |
114 | size, NULL, &fence); | 114 | size, NULL, &fence, false); |
115 | 115 | ||
116 | if (r) { | 116 | if (r) { |
117 | DRM_ERROR("Failed GTT->VRAM copy %d\n", i); | 117 | DRM_ERROR("Failed GTT->VRAM copy %d\n", i); |
@@ -156,7 +156,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) | |||
156 | amdgpu_bo_kunmap(vram_obj); | 156 | amdgpu_bo_kunmap(vram_obj); |
157 | 157 | ||
158 | r = amdgpu_copy_buffer(ring, vram_addr, gtt_addr, | 158 | r = amdgpu_copy_buffer(ring, vram_addr, gtt_addr, |
159 | size, NULL, &fence); | 159 | size, NULL, &fence, false); |
160 | 160 | ||
161 | if (r) { | 161 | if (r) { |
162 | DRM_ERROR("Failed VRAM->GTT copy %d\n", i); | 162 | DRM_ERROR("Failed VRAM->GTT copy %d\n", i); |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 9b61c8ba7aaf..5447973483ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <ttm/ttm_placement.h> | 34 | #include <ttm/ttm_placement.h> |
35 | #include <ttm/ttm_module.h> | 35 | #include <ttm/ttm_module.h> |
36 | #include <ttm/ttm_page_alloc.h> | 36 | #include <ttm/ttm_page_alloc.h> |
37 | #include <ttm/ttm_memory.h> | ||
37 | #include <drm/drmP.h> | 38 | #include <drm/drmP.h> |
38 | #include <drm/amdgpu_drm.h> | 39 | #include <drm/amdgpu_drm.h> |
39 | #include <linux/seq_file.h> | 40 | #include <linux/seq_file.h> |
@@ -74,7 +75,7 @@ static void amdgpu_ttm_mem_global_release(struct drm_global_reference *ref) | |||
74 | ttm_mem_global_release(ref->object); | 75 | ttm_mem_global_release(ref->object); |
75 | } | 76 | } |
76 | 77 | ||
77 | static int amdgpu_ttm_global_init(struct amdgpu_device *adev) | 78 | int amdgpu_ttm_global_init(struct amdgpu_device *adev) |
78 | { | 79 | { |
79 | struct drm_global_reference *global_ref; | 80 | struct drm_global_reference *global_ref; |
80 | struct amdgpu_ring *ring; | 81 | struct amdgpu_ring *ring; |
@@ -256,10 +257,8 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo, | |||
256 | 257 | ||
257 | switch (old_mem->mem_type) { | 258 | switch (old_mem->mem_type) { |
258 | case TTM_PL_VRAM: | 259 | case TTM_PL_VRAM: |
259 | old_start += adev->mc.vram_start; | ||
260 | break; | ||
261 | case TTM_PL_TT: | 260 | case TTM_PL_TT: |
262 | old_start += adev->mc.gtt_start; | 261 | old_start += bo->bdev->man[old_mem->mem_type].gpu_offset; |
263 | break; | 262 | break; |
264 | default: | 263 | default: |
265 | DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); | 264 | DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); |
@@ -267,10 +266,8 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo, | |||
267 | } | 266 | } |
268 | switch (new_mem->mem_type) { | 267 | switch (new_mem->mem_type) { |
269 | case TTM_PL_VRAM: | 268 | case TTM_PL_VRAM: |
270 | new_start += adev->mc.vram_start; | ||
271 | break; | ||
272 | case TTM_PL_TT: | 269 | case TTM_PL_TT: |
273 | new_start += adev->mc.gtt_start; | 270 | new_start += bo->bdev->man[new_mem->mem_type].gpu_offset; |
274 | break; | 271 | break; |
275 | default: | 272 | default: |
276 | DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); | 273 | DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); |
@@ -285,7 +282,7 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo, | |||
285 | 282 | ||
286 | r = amdgpu_copy_buffer(ring, old_start, new_start, | 283 | r = amdgpu_copy_buffer(ring, old_start, new_start, |
287 | new_mem->num_pages * PAGE_SIZE, /* bytes */ | 284 | new_mem->num_pages * PAGE_SIZE, /* bytes */ |
288 | bo->resv, &fence); | 285 | bo->resv, &fence, false); |
289 | if (r) | 286 | if (r) |
290 | return r; | 287 | return r; |
291 | 288 | ||
@@ -335,7 +332,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, | |||
335 | if (unlikely(r)) { | 332 | if (unlikely(r)) { |
336 | goto out_cleanup; | 333 | goto out_cleanup; |
337 | } | 334 | } |
338 | r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, new_mem); | 335 | r = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, new_mem); |
339 | out_cleanup: | 336 | out_cleanup: |
340 | ttm_bo_mem_put(bo, &tmp_mem); | 337 | ttm_bo_mem_put(bo, &tmp_mem); |
341 | return r; | 338 | return r; |
@@ -368,7 +365,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, | |||
368 | if (unlikely(r)) { | 365 | if (unlikely(r)) { |
369 | return r; | 366 | return r; |
370 | } | 367 | } |
371 | r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, &tmp_mem); | 368 | r = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, &tmp_mem); |
372 | if (unlikely(r)) { | 369 | if (unlikely(r)) { |
373 | goto out_cleanup; | 370 | goto out_cleanup; |
374 | } | 371 | } |
@@ -435,8 +432,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, | |||
435 | 432 | ||
436 | if (r) { | 433 | if (r) { |
437 | memcpy: | 434 | memcpy: |
438 | r = ttm_bo_move_memcpy(bo, evict, interruptible, | 435 | r = ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, new_mem); |
439 | no_wait_gpu, new_mem); | ||
440 | if (r) { | 436 | if (r) { |
441 | return r; | 437 | return r; |
442 | } | 438 | } |
@@ -950,6 +946,8 @@ static struct list_head *amdgpu_ttm_lru_tail(struct ttm_buffer_object *tbo) | |||
950 | struct list_head *res = lru->lru[tbo->mem.mem_type]; | 946 | struct list_head *res = lru->lru[tbo->mem.mem_type]; |
951 | 947 | ||
952 | lru->lru[tbo->mem.mem_type] = &tbo->lru; | 948 | lru->lru[tbo->mem.mem_type] = &tbo->lru; |
949 | while ((++lru)->lru[tbo->mem.mem_type] == res) | ||
950 | lru->lru[tbo->mem.mem_type] = &tbo->lru; | ||
953 | 951 | ||
954 | return res; | 952 | return res; |
955 | } | 953 | } |
@@ -960,6 +958,8 @@ static struct list_head *amdgpu_ttm_swap_lru_tail(struct ttm_buffer_object *tbo) | |||
960 | struct list_head *res = lru->swap_lru; | 958 | struct list_head *res = lru->swap_lru; |
961 | 959 | ||
962 | lru->swap_lru = &tbo->swap; | 960 | lru->swap_lru = &tbo->swap; |
961 | while ((++lru)->swap_lru == res) | ||
962 | lru->swap_lru = &tbo->swap; | ||
963 | 963 | ||
964 | return res; | 964 | return res; |
965 | } | 965 | } |
@@ -987,10 +987,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) | |||
987 | unsigned i, j; | 987 | unsigned i, j; |
988 | int r; | 988 | int r; |
989 | 989 | ||
990 | r = amdgpu_ttm_global_init(adev); | ||
991 | if (r) { | ||
992 | return r; | ||
993 | } | ||
994 | /* No others user of address space so set it to 0 */ | 990 | /* No others user of address space so set it to 0 */ |
995 | r = ttm_bo_device_init(&adev->mman.bdev, | 991 | r = ttm_bo_device_init(&adev->mman.bdev, |
996 | adev->mman.bo_global_ref.ref.object, | 992 | adev->mman.bo_global_ref.ref.object, |
@@ -1011,6 +1007,10 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) | |||
1011 | lru->swap_lru = &adev->mman.bdev.glob->swap_lru; | 1007 | lru->swap_lru = &adev->mman.bdev.glob->swap_lru; |
1012 | } | 1008 | } |
1013 | 1009 | ||
1010 | for (j = 0; j < TTM_NUM_MEM_TYPES; ++j) | ||
1011 | adev->mman.guard.lru[j] = NULL; | ||
1012 | adev->mman.guard.swap_lru = NULL; | ||
1013 | |||
1014 | adev->mman.initialized = true; | 1014 | adev->mman.initialized = true; |
1015 | r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM, | 1015 | r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM, |
1016 | adev->mc.real_vram_size >> PAGE_SHIFT); | 1016 | adev->mc.real_vram_size >> PAGE_SHIFT); |
@@ -1151,7 +1151,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, | |||
1151 | uint64_t dst_offset, | 1151 | uint64_t dst_offset, |
1152 | uint32_t byte_count, | 1152 | uint32_t byte_count, |
1153 | struct reservation_object *resv, | 1153 | struct reservation_object *resv, |
1154 | struct fence **fence) | 1154 | struct fence **fence, bool direct_submit) |
1155 | { | 1155 | { |
1156 | struct amdgpu_device *adev = ring->adev; | 1156 | struct amdgpu_device *adev = ring->adev; |
1157 | struct amdgpu_job *job; | 1157 | struct amdgpu_job *job; |
@@ -1195,8 +1195,79 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, | |||
1195 | 1195 | ||
1196 | amdgpu_ring_pad_ib(ring, &job->ibs[0]); | 1196 | amdgpu_ring_pad_ib(ring, &job->ibs[0]); |
1197 | WARN_ON(job->ibs[0].length_dw > num_dw); | 1197 | WARN_ON(job->ibs[0].length_dw > num_dw); |
1198 | if (direct_submit) { | ||
1199 | r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs, | ||
1200 | NULL, NULL, fence); | ||
1201 | job->fence = fence_get(*fence); | ||
1202 | if (r) | ||
1203 | DRM_ERROR("Error scheduling IBs (%d)\n", r); | ||
1204 | amdgpu_job_free(job); | ||
1205 | } else { | ||
1206 | r = amdgpu_job_submit(job, ring, &adev->mman.entity, | ||
1207 | AMDGPU_FENCE_OWNER_UNDEFINED, fence); | ||
1208 | if (r) | ||
1209 | goto error_free; | ||
1210 | } | ||
1211 | |||
1212 | return r; | ||
1213 | |||
1214 | error_free: | ||
1215 | amdgpu_job_free(job); | ||
1216 | return r; | ||
1217 | } | ||
1218 | |||
1219 | int amdgpu_fill_buffer(struct amdgpu_bo *bo, | ||
1220 | uint32_t src_data, | ||
1221 | struct reservation_object *resv, | ||
1222 | struct fence **fence) | ||
1223 | { | ||
1224 | struct amdgpu_device *adev = bo->adev; | ||
1225 | struct amdgpu_job *job; | ||
1226 | struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; | ||
1227 | |||
1228 | uint32_t max_bytes, byte_count; | ||
1229 | uint64_t dst_offset; | ||
1230 | unsigned int num_loops, num_dw; | ||
1231 | unsigned int i; | ||
1232 | int r; | ||
1233 | |||
1234 | byte_count = bo->tbo.num_pages << PAGE_SHIFT; | ||
1235 | max_bytes = adev->mman.buffer_funcs->fill_max_bytes; | ||
1236 | num_loops = DIV_ROUND_UP(byte_count, max_bytes); | ||
1237 | num_dw = num_loops * adev->mman.buffer_funcs->fill_num_dw; | ||
1238 | |||
1239 | /* for IB padding */ | ||
1240 | while (num_dw & 0x7) | ||
1241 | num_dw++; | ||
1242 | |||
1243 | r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, &job); | ||
1244 | if (r) | ||
1245 | return r; | ||
1246 | |||
1247 | if (resv) { | ||
1248 | r = amdgpu_sync_resv(adev, &job->sync, resv, | ||
1249 | AMDGPU_FENCE_OWNER_UNDEFINED); | ||
1250 | if (r) { | ||
1251 | DRM_ERROR("sync failed (%d).\n", r); | ||
1252 | goto error_free; | ||
1253 | } | ||
1254 | } | ||
1255 | |||
1256 | dst_offset = bo->tbo.mem.start << PAGE_SHIFT; | ||
1257 | for (i = 0; i < num_loops; i++) { | ||
1258 | uint32_t cur_size_in_bytes = min(byte_count, max_bytes); | ||
1259 | |||
1260 | amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data, | ||
1261 | dst_offset, cur_size_in_bytes); | ||
1262 | |||
1263 | dst_offset += cur_size_in_bytes; | ||
1264 | byte_count -= cur_size_in_bytes; | ||
1265 | } | ||
1266 | |||
1267 | amdgpu_ring_pad_ib(ring, &job->ibs[0]); | ||
1268 | WARN_ON(job->ibs[0].length_dw > num_dw); | ||
1198 | r = amdgpu_job_submit(job, ring, &adev->mman.entity, | 1269 | r = amdgpu_job_submit(job, ring, &adev->mman.entity, |
1199 | AMDGPU_FENCE_OWNER_UNDEFINED, fence); | 1270 | AMDGPU_FENCE_OWNER_UNDEFINED, fence); |
1200 | if (r) | 1271 | if (r) |
1201 | goto error_free; | 1272 | goto error_free; |
1202 | 1273 | ||
@@ -1387,3 +1458,8 @@ static void amdgpu_ttm_debugfs_fini(struct amdgpu_device *adev) | |||
1387 | 1458 | ||
1388 | #endif | 1459 | #endif |
1389 | } | 1460 | } |
1461 | |||
1462 | u64 amdgpu_ttm_get_gtt_mem_size(struct amdgpu_device *adev) | ||
1463 | { | ||
1464 | return ttm_get_kernel_zone_memory_size(adev->mman.mem_global_ref.object); | ||
1465 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h new file mode 100644 index 000000000000..72f6bfc15d8f --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __AMDGPU_TTM_H__ | ||
25 | #define __AMDGPU_TTM_H__ | ||
26 | |||
27 | #include "gpu_scheduler.h" | ||
28 | |||
29 | #define AMDGPU_PL_GDS TTM_PL_PRIV0 | ||
30 | #define AMDGPU_PL_GWS TTM_PL_PRIV1 | ||
31 | #define AMDGPU_PL_OA TTM_PL_PRIV2 | ||
32 | |||
33 | #define AMDGPU_PL_FLAG_GDS TTM_PL_FLAG_PRIV0 | ||
34 | #define AMDGPU_PL_FLAG_GWS TTM_PL_FLAG_PRIV1 | ||
35 | #define AMDGPU_PL_FLAG_OA TTM_PL_FLAG_PRIV2 | ||
36 | |||
37 | #define AMDGPU_TTM_LRU_SIZE 20 | ||
38 | |||
39 | struct amdgpu_mman_lru { | ||
40 | struct list_head *lru[TTM_NUM_MEM_TYPES]; | ||
41 | struct list_head *swap_lru; | ||
42 | }; | ||
43 | |||
44 | struct amdgpu_mman { | ||
45 | struct ttm_bo_global_ref bo_global_ref; | ||
46 | struct drm_global_reference mem_global_ref; | ||
47 | struct ttm_bo_device bdev; | ||
48 | bool mem_global_referenced; | ||
49 | bool initialized; | ||
50 | |||
51 | #if defined(CONFIG_DEBUG_FS) | ||
52 | struct dentry *vram; | ||
53 | struct dentry *gtt; | ||
54 | #endif | ||
55 | |||
56 | /* buffer handling */ | ||
57 | const struct amdgpu_buffer_funcs *buffer_funcs; | ||
58 | struct amdgpu_ring *buffer_funcs_ring; | ||
59 | /* Scheduler entity for buffer moves */ | ||
60 | struct amd_sched_entity entity; | ||
61 | |||
62 | /* custom LRU management */ | ||
63 | struct amdgpu_mman_lru log2_size[AMDGPU_TTM_LRU_SIZE]; | ||
64 | /* guard for log2_size array, don't add anything in between */ | ||
65 | struct amdgpu_mman_lru guard; | ||
66 | }; | ||
67 | |||
68 | int amdgpu_copy_buffer(struct amdgpu_ring *ring, | ||
69 | uint64_t src_offset, | ||
70 | uint64_t dst_offset, | ||
71 | uint32_t byte_count, | ||
72 | struct reservation_object *resv, | ||
73 | struct fence **fence, bool direct_submit); | ||
74 | int amdgpu_fill_buffer(struct amdgpu_bo *bo, | ||
75 | uint32_t src_data, | ||
76 | struct reservation_object *resv, | ||
77 | struct fence **fence); | ||
78 | |||
79 | int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma); | ||
80 | #endif | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index b11f4e8868d7..cc766cc53a87 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | |||
@@ -201,39 +201,14 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) | |||
201 | bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8) | 201 | bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8) |
202 | + AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE | 202 | + AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE |
203 | + AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles; | 203 | + AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles; |
204 | r = amdgpu_bo_create(adev, bo_size, PAGE_SIZE, true, | 204 | r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE, |
205 | AMDGPU_GEM_DOMAIN_VRAM, | 205 | AMDGPU_GEM_DOMAIN_VRAM, &adev->uvd.vcpu_bo, |
206 | AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, | 206 | &adev->uvd.gpu_addr, &adev->uvd.cpu_addr); |
207 | NULL, NULL, &adev->uvd.vcpu_bo); | ||
208 | if (r) { | 207 | if (r) { |
209 | dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r); | 208 | dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r); |
210 | return r; | 209 | return r; |
211 | } | 210 | } |
212 | 211 | ||
213 | r = amdgpu_bo_reserve(adev->uvd.vcpu_bo, false); | ||
214 | if (r) { | ||
215 | amdgpu_bo_unref(&adev->uvd.vcpu_bo); | ||
216 | dev_err(adev->dev, "(%d) failed to reserve UVD bo\n", r); | ||
217 | return r; | ||
218 | } | ||
219 | |||
220 | r = amdgpu_bo_pin(adev->uvd.vcpu_bo, AMDGPU_GEM_DOMAIN_VRAM, | ||
221 | &adev->uvd.gpu_addr); | ||
222 | if (r) { | ||
223 | amdgpu_bo_unreserve(adev->uvd.vcpu_bo); | ||
224 | amdgpu_bo_unref(&adev->uvd.vcpu_bo); | ||
225 | dev_err(adev->dev, "(%d) UVD bo pin failed\n", r); | ||
226 | return r; | ||
227 | } | ||
228 | |||
229 | r = amdgpu_bo_kmap(adev->uvd.vcpu_bo, &adev->uvd.cpu_addr); | ||
230 | if (r) { | ||
231 | dev_err(adev->dev, "(%d) UVD map failed\n", r); | ||
232 | return r; | ||
233 | } | ||
234 | |||
235 | amdgpu_bo_unreserve(adev->uvd.vcpu_bo); | ||
236 | |||
237 | ring = &adev->uvd.ring; | 212 | ring = &adev->uvd.ring; |
238 | rq = &ring->sched.sched_rq[AMD_SCHED_PRIORITY_NORMAL]; | 213 | rq = &ring->sched.sched_rq[AMD_SCHED_PRIORITY_NORMAL]; |
239 | r = amd_sched_entity_init(&ring->sched, &adev->uvd.entity, | 214 | r = amd_sched_entity_init(&ring->sched, &adev->uvd.entity, |
@@ -323,7 +298,7 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) | |||
323 | if (!adev->uvd.saved_bo) | 298 | if (!adev->uvd.saved_bo) |
324 | return -ENOMEM; | 299 | return -ENOMEM; |
325 | 300 | ||
326 | memcpy(adev->uvd.saved_bo, ptr, size); | 301 | memcpy_fromio(adev->uvd.saved_bo, ptr, size); |
327 | 302 | ||
328 | return 0; | 303 | return 0; |
329 | } | 304 | } |
@@ -340,7 +315,7 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev) | |||
340 | ptr = adev->uvd.cpu_addr; | 315 | ptr = adev->uvd.cpu_addr; |
341 | 316 | ||
342 | if (adev->uvd.saved_bo != NULL) { | 317 | if (adev->uvd.saved_bo != NULL) { |
343 | memcpy(ptr, adev->uvd.saved_bo, size); | 318 | memcpy_toio(ptr, adev->uvd.saved_bo, size); |
344 | kfree(adev->uvd.saved_bo); | 319 | kfree(adev->uvd.saved_bo); |
345 | adev->uvd.saved_bo = NULL; | 320 | adev->uvd.saved_bo = NULL; |
346 | } else { | 321 | } else { |
@@ -349,11 +324,11 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev) | |||
349 | 324 | ||
350 | hdr = (const struct common_firmware_header *)adev->uvd.fw->data; | 325 | hdr = (const struct common_firmware_header *)adev->uvd.fw->data; |
351 | offset = le32_to_cpu(hdr->ucode_array_offset_bytes); | 326 | offset = le32_to_cpu(hdr->ucode_array_offset_bytes); |
352 | memcpy(adev->uvd.cpu_addr, (adev->uvd.fw->data) + offset, | 327 | memcpy_toio(adev->uvd.cpu_addr, adev->uvd.fw->data + offset, |
353 | (adev->uvd.fw->size) - offset); | 328 | le32_to_cpu(hdr->ucode_size_bytes)); |
354 | size -= le32_to_cpu(hdr->ucode_size_bytes); | 329 | size -= le32_to_cpu(hdr->ucode_size_bytes); |
355 | ptr += le32_to_cpu(hdr->ucode_size_bytes); | 330 | ptr += le32_to_cpu(hdr->ucode_size_bytes); |
356 | memset(ptr, 0, size); | 331 | memset_io(ptr, 0, size); |
357 | } | 332 | } |
358 | 333 | ||
359 | return 0; | 334 | return 0; |
@@ -843,6 +818,7 @@ static int amdgpu_uvd_cs_reg(struct amdgpu_uvd_cs_ctx *ctx, | |||
843 | return r; | 818 | return r; |
844 | break; | 819 | break; |
845 | case mmUVD_ENGINE_CNTL: | 820 | case mmUVD_ENGINE_CNTL: |
821 | case mmUVD_NO_OP: | ||
846 | break; | 822 | break; |
847 | default: | 823 | default: |
848 | DRM_ERROR("Invalid reg 0x%X!\n", reg); | 824 | DRM_ERROR("Invalid reg 0x%X!\n", reg); |
@@ -981,8 +957,10 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, | |||
981 | ib->ptr[3] = addr >> 32; | 957 | ib->ptr[3] = addr >> 32; |
982 | ib->ptr[4] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0); | 958 | ib->ptr[4] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0); |
983 | ib->ptr[5] = 0; | 959 | ib->ptr[5] = 0; |
984 | for (i = 6; i < 16; ++i) | 960 | for (i = 6; i < 16; i += 2) { |
985 | ib->ptr[i] = PACKET2(0); | 961 | ib->ptr[i] = PACKET0(mmUVD_NO_OP, 0); |
962 | ib->ptr[i+1] = 0; | ||
963 | } | ||
986 | ib->length_dw = 16; | 964 | ib->length_dw = 16; |
987 | 965 | ||
988 | if (direct) { | 966 | if (direct) { |
@@ -1114,15 +1092,9 @@ static void amdgpu_uvd_idle_work_handler(struct work_struct *work) | |||
1114 | { | 1092 | { |
1115 | struct amdgpu_device *adev = | 1093 | struct amdgpu_device *adev = |
1116 | container_of(work, struct amdgpu_device, uvd.idle_work.work); | 1094 | container_of(work, struct amdgpu_device, uvd.idle_work.work); |
1117 | unsigned i, fences, handles = 0; | 1095 | unsigned fences = amdgpu_fence_count_emitted(&adev->uvd.ring); |
1118 | |||
1119 | fences = amdgpu_fence_count_emitted(&adev->uvd.ring); | ||
1120 | |||
1121 | for (i = 0; i < adev->uvd.max_handles; ++i) | ||
1122 | if (atomic_read(&adev->uvd.handles[i])) | ||
1123 | ++handles; | ||
1124 | 1096 | ||
1125 | if (fences == 0 && handles == 0) { | 1097 | if (fences == 0) { |
1126 | if (adev->pm.dpm_enabled) { | 1098 | if (adev->pm.dpm_enabled) { |
1127 | amdgpu_dpm_enable_uvd(adev, false); | 1099 | amdgpu_dpm_enable_uvd(adev, false); |
1128 | } else { | 1100 | } else { |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 05865ce35351..da52af2a935a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | |||
@@ -282,8 +282,8 @@ int amdgpu_vce_resume(struct amdgpu_device *adev) | |||
282 | 282 | ||
283 | hdr = (const struct common_firmware_header *)adev->vce.fw->data; | 283 | hdr = (const struct common_firmware_header *)adev->vce.fw->data; |
284 | offset = le32_to_cpu(hdr->ucode_array_offset_bytes); | 284 | offset = le32_to_cpu(hdr->ucode_array_offset_bytes); |
285 | memcpy(cpu_addr, (adev->vce.fw->data) + offset, | 285 | memcpy_toio(cpu_addr, adev->vce.fw->data + offset, |
286 | (adev->vce.fw->size) - offset); | 286 | adev->vce.fw->size - offset); |
287 | 287 | ||
288 | amdgpu_bo_kunmap(adev->vce.vcpu_bo); | 288 | amdgpu_bo_kunmap(adev->vce.vcpu_bo); |
289 | 289 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 8e642fc48df4..bf56f1814437 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | |||
@@ -51,19 +51,22 @@ | |||
51 | * SI supports 16. | 51 | * SI supports 16. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | /* Special value that no flush is necessary */ | ||
55 | #define AMDGPU_VM_NO_FLUSH (~0ll) | ||
56 | |||
57 | /* Local structure. Encapsulate some VM table update parameters to reduce | 54 | /* Local structure. Encapsulate some VM table update parameters to reduce |
58 | * the number of function parameters | 55 | * the number of function parameters |
59 | */ | 56 | */ |
60 | struct amdgpu_vm_update_params { | 57 | struct amdgpu_pte_update_params { |
58 | /* amdgpu device we do this update for */ | ||
59 | struct amdgpu_device *adev; | ||
61 | /* address where to copy page table entries from */ | 60 | /* address where to copy page table entries from */ |
62 | uint64_t src; | 61 | uint64_t src; |
63 | /* DMA addresses to use for mapping */ | ||
64 | dma_addr_t *pages_addr; | ||
65 | /* indirect buffer to fill with commands */ | 62 | /* indirect buffer to fill with commands */ |
66 | struct amdgpu_ib *ib; | 63 | struct amdgpu_ib *ib; |
64 | /* Function which actually does the update */ | ||
65 | void (*func)(struct amdgpu_pte_update_params *params, uint64_t pe, | ||
66 | uint64_t addr, unsigned count, uint32_t incr, | ||
67 | uint32_t flags); | ||
68 | /* indicate update pt or its shadow */ | ||
69 | bool shadow; | ||
67 | }; | 70 | }; |
68 | 71 | ||
69 | /** | 72 | /** |
@@ -467,10 +470,9 @@ struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm, | |||
467 | } | 470 | } |
468 | 471 | ||
469 | /** | 472 | /** |
470 | * amdgpu_vm_update_pages - helper to call the right asic function | 473 | * amdgpu_vm_do_set_ptes - helper to call the right asic function |
471 | * | 474 | * |
472 | * @adev: amdgpu_device pointer | 475 | * @params: see amdgpu_pte_update_params definition |
473 | * @vm_update_params: see amdgpu_vm_update_params definition | ||
474 | * @pe: addr of the page entry | 476 | * @pe: addr of the page entry |
475 | * @addr: dst addr to write into pe | 477 | * @addr: dst addr to write into pe |
476 | * @count: number of page entries to update | 478 | * @count: number of page entries to update |
@@ -480,35 +482,47 @@ struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm, | |||
480 | * Traces the parameters and calls the right asic functions | 482 | * Traces the parameters and calls the right asic functions |
481 | * to setup the page table using the DMA. | 483 | * to setup the page table using the DMA. |
482 | */ | 484 | */ |
483 | static void amdgpu_vm_update_pages(struct amdgpu_device *adev, | 485 | static void amdgpu_vm_do_set_ptes(struct amdgpu_pte_update_params *params, |
484 | struct amdgpu_vm_update_params | 486 | uint64_t pe, uint64_t addr, |
485 | *vm_update_params, | 487 | unsigned count, uint32_t incr, |
486 | uint64_t pe, uint64_t addr, | 488 | uint32_t flags) |
487 | unsigned count, uint32_t incr, | ||
488 | uint32_t flags) | ||
489 | { | 489 | { |
490 | trace_amdgpu_vm_set_page(pe, addr, count, incr, flags); | 490 | trace_amdgpu_vm_set_page(pe, addr, count, incr, flags); |
491 | 491 | ||
492 | if (vm_update_params->src) { | 492 | if (count < 3) { |
493 | amdgpu_vm_copy_pte(adev, vm_update_params->ib, | 493 | amdgpu_vm_write_pte(params->adev, params->ib, pe, |
494 | pe, (vm_update_params->src + (addr >> 12) * 8), count); | 494 | addr | flags, count, incr); |
495 | |||
496 | } else if (vm_update_params->pages_addr) { | ||
497 | amdgpu_vm_write_pte(adev, vm_update_params->ib, | ||
498 | vm_update_params->pages_addr, | ||
499 | pe, addr, count, incr, flags); | ||
500 | |||
501 | } else if (count < 3) { | ||
502 | amdgpu_vm_write_pte(adev, vm_update_params->ib, NULL, pe, addr, | ||
503 | count, incr, flags); | ||
504 | 495 | ||
505 | } else { | 496 | } else { |
506 | amdgpu_vm_set_pte_pde(adev, vm_update_params->ib, pe, addr, | 497 | amdgpu_vm_set_pte_pde(params->adev, params->ib, pe, addr, |
507 | count, incr, flags); | 498 | count, incr, flags); |
508 | } | 499 | } |
509 | } | 500 | } |
510 | 501 | ||
511 | /** | 502 | /** |
503 | * amdgpu_vm_do_copy_ptes - copy the PTEs from the GART | ||
504 | * | ||
505 | * @params: see amdgpu_pte_update_params definition | ||
506 | * @pe: addr of the page entry | ||
507 | * @addr: dst addr to write into pe | ||
508 | * @count: number of page entries to update | ||
509 | * @incr: increase next addr by incr bytes | ||
510 | * @flags: hw access flags | ||
511 | * | ||
512 | * Traces the parameters and calls the DMA function to copy the PTEs. | ||
513 | */ | ||
514 | static void amdgpu_vm_do_copy_ptes(struct amdgpu_pte_update_params *params, | ||
515 | uint64_t pe, uint64_t addr, | ||
516 | unsigned count, uint32_t incr, | ||
517 | uint32_t flags) | ||
518 | { | ||
519 | trace_amdgpu_vm_set_page(pe, addr, count, incr, flags); | ||
520 | |||
521 | amdgpu_vm_copy_pte(params->adev, params->ib, pe, | ||
522 | (params->src + (addr >> 12) * 8), count); | ||
523 | } | ||
524 | |||
525 | /** | ||
512 | * amdgpu_vm_clear_bo - initially clear the page dir/table | 526 | * amdgpu_vm_clear_bo - initially clear the page dir/table |
513 | * | 527 | * |
514 | * @adev: amdgpu_device pointer | 528 | * @adev: amdgpu_device pointer |
@@ -523,12 +537,11 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, | |||
523 | struct amdgpu_ring *ring; | 537 | struct amdgpu_ring *ring; |
524 | struct fence *fence = NULL; | 538 | struct fence *fence = NULL; |
525 | struct amdgpu_job *job; | 539 | struct amdgpu_job *job; |
526 | struct amdgpu_vm_update_params vm_update_params; | 540 | struct amdgpu_pte_update_params params; |
527 | unsigned entries; | 541 | unsigned entries; |
528 | uint64_t addr; | 542 | uint64_t addr; |
529 | int r; | 543 | int r; |
530 | 544 | ||
531 | memset(&vm_update_params, 0, sizeof(vm_update_params)); | ||
532 | ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); | 545 | ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); |
533 | 546 | ||
534 | r = reservation_object_reserve_shared(bo->tbo.resv); | 547 | r = reservation_object_reserve_shared(bo->tbo.resv); |
@@ -546,9 +559,10 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, | |||
546 | if (r) | 559 | if (r) |
547 | goto error; | 560 | goto error; |
548 | 561 | ||
549 | vm_update_params.ib = &job->ibs[0]; | 562 | memset(¶ms, 0, sizeof(params)); |
550 | amdgpu_vm_update_pages(adev, &vm_update_params, addr, 0, entries, | 563 | params.adev = adev; |
551 | 0, 0); | 564 | params.ib = &job->ibs[0]; |
565 | amdgpu_vm_do_set_ptes(¶ms, addr, 0, entries, 0, 0); | ||
552 | amdgpu_ring_pad_ib(ring, &job->ibs[0]); | 566 | amdgpu_ring_pad_ib(ring, &job->ibs[0]); |
553 | 567 | ||
554 | WARN_ON(job->ibs[0].length_dw > 64); | 568 | WARN_ON(job->ibs[0].length_dw > 64); |
@@ -577,55 +591,41 @@ error: | |||
577 | * Look up the physical address of the page that the pte resolves | 591 | * Look up the physical address of the page that the pte resolves |
578 | * to and return the pointer for the page table entry. | 592 | * to and return the pointer for the page table entry. |
579 | */ | 593 | */ |
580 | uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr) | 594 | static uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr) |
581 | { | 595 | { |
582 | uint64_t result; | 596 | uint64_t result; |
583 | 597 | ||
584 | if (pages_addr) { | 598 | /* page table offset */ |
585 | /* page table offset */ | 599 | result = pages_addr[addr >> PAGE_SHIFT]; |
586 | result = pages_addr[addr >> PAGE_SHIFT]; | ||
587 | |||
588 | /* in case cpu page size != gpu page size*/ | ||
589 | result |= addr & (~PAGE_MASK); | ||
590 | 600 | ||
591 | } else { | 601 | /* in case cpu page size != gpu page size*/ |
592 | /* No mapping required */ | 602 | result |= addr & (~PAGE_MASK); |
593 | result = addr; | ||
594 | } | ||
595 | 603 | ||
596 | result &= 0xFFFFFFFFFFFFF000ULL; | 604 | result &= 0xFFFFFFFFFFFFF000ULL; |
597 | 605 | ||
598 | return result; | 606 | return result; |
599 | } | 607 | } |
600 | 608 | ||
601 | /** | 609 | static int amdgpu_vm_update_pd_or_shadow(struct amdgpu_device *adev, |
602 | * amdgpu_vm_update_pdes - make sure that page directory is valid | 610 | struct amdgpu_vm *vm, |
603 | * | 611 | bool shadow) |
604 | * @adev: amdgpu_device pointer | ||
605 | * @vm: requested vm | ||
606 | * @start: start of GPU address range | ||
607 | * @end: end of GPU address range | ||
608 | * | ||
609 | * Allocates new page tables if necessary | ||
610 | * and updates the page directory. | ||
611 | * Returns 0 for success, error for failure. | ||
612 | */ | ||
613 | int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, | ||
614 | struct amdgpu_vm *vm) | ||
615 | { | 612 | { |
616 | struct amdgpu_ring *ring; | 613 | struct amdgpu_ring *ring; |
617 | struct amdgpu_bo *pd = vm->page_directory; | 614 | struct amdgpu_bo *pd = shadow ? vm->page_directory->shadow : |
618 | uint64_t pd_addr = amdgpu_bo_gpu_offset(pd); | 615 | vm->page_directory; |
616 | uint64_t pd_addr; | ||
619 | uint32_t incr = AMDGPU_VM_PTE_COUNT * 8; | 617 | uint32_t incr = AMDGPU_VM_PTE_COUNT * 8; |
620 | uint64_t last_pde = ~0, last_pt = ~0; | 618 | uint64_t last_pde = ~0, last_pt = ~0; |
621 | unsigned count = 0, pt_idx, ndw; | 619 | unsigned count = 0, pt_idx, ndw; |
622 | struct amdgpu_job *job; | 620 | struct amdgpu_job *job; |
623 | struct amdgpu_vm_update_params vm_update_params; | 621 | struct amdgpu_pte_update_params params; |
624 | struct fence *fence = NULL; | 622 | struct fence *fence = NULL; |
625 | 623 | ||
626 | int r; | 624 | int r; |
627 | 625 | ||
628 | memset(&vm_update_params, 0, sizeof(vm_update_params)); | 626 | if (!pd) |
627 | return 0; | ||
628 | pd_addr = amdgpu_bo_gpu_offset(pd); | ||
629 | ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); | 629 | ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); |
630 | 630 | ||
631 | /* padding, etc. */ | 631 | /* padding, etc. */ |
@@ -638,7 +638,9 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, | |||
638 | if (r) | 638 | if (r) |
639 | return r; | 639 | return r; |
640 | 640 | ||
641 | vm_update_params.ib = &job->ibs[0]; | 641 | memset(¶ms, 0, sizeof(params)); |
642 | params.adev = adev; | ||
643 | params.ib = &job->ibs[0]; | ||
642 | 644 | ||
643 | /* walk over the address space and update the page directory */ | 645 | /* walk over the address space and update the page directory */ |
644 | for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) { | 646 | for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) { |
@@ -649,19 +651,25 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, | |||
649 | continue; | 651 | continue; |
650 | 652 | ||
651 | pt = amdgpu_bo_gpu_offset(bo); | 653 | pt = amdgpu_bo_gpu_offset(bo); |
652 | if (vm->page_tables[pt_idx].addr == pt) | 654 | if (!shadow) { |
653 | continue; | 655 | if (vm->page_tables[pt_idx].addr == pt) |
654 | vm->page_tables[pt_idx].addr = pt; | 656 | continue; |
657 | vm->page_tables[pt_idx].addr = pt; | ||
658 | } else { | ||
659 | if (vm->page_tables[pt_idx].shadow_addr == pt) | ||
660 | continue; | ||
661 | vm->page_tables[pt_idx].shadow_addr = pt; | ||
662 | } | ||
655 | 663 | ||
656 | pde = pd_addr + pt_idx * 8; | 664 | pde = pd_addr + pt_idx * 8; |
657 | if (((last_pde + 8 * count) != pde) || | 665 | if (((last_pde + 8 * count) != pde) || |
658 | ((last_pt + incr * count) != pt)) { | 666 | ((last_pt + incr * count) != pt) || |
667 | (count == AMDGPU_VM_MAX_UPDATE_SIZE)) { | ||
659 | 668 | ||
660 | if (count) { | 669 | if (count) { |
661 | amdgpu_vm_update_pages(adev, &vm_update_params, | 670 | amdgpu_vm_do_set_ptes(¶ms, last_pde, |
662 | last_pde, last_pt, | 671 | last_pt, count, incr, |
663 | count, incr, | 672 | AMDGPU_PTE_VALID); |
664 | AMDGPU_PTE_VALID); | ||
665 | } | 673 | } |
666 | 674 | ||
667 | count = 1; | 675 | count = 1; |
@@ -673,15 +681,14 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, | |||
673 | } | 681 | } |
674 | 682 | ||
675 | if (count) | 683 | if (count) |
676 | amdgpu_vm_update_pages(adev, &vm_update_params, | 684 | amdgpu_vm_do_set_ptes(¶ms, last_pde, last_pt, |
677 | last_pde, last_pt, | 685 | count, incr, AMDGPU_PTE_VALID); |
678 | count, incr, AMDGPU_PTE_VALID); | ||
679 | 686 | ||
680 | if (vm_update_params.ib->length_dw != 0) { | 687 | if (params.ib->length_dw != 0) { |
681 | amdgpu_ring_pad_ib(ring, vm_update_params.ib); | 688 | amdgpu_ring_pad_ib(ring, params.ib); |
682 | amdgpu_sync_resv(adev, &job->sync, pd->tbo.resv, | 689 | amdgpu_sync_resv(adev, &job->sync, pd->tbo.resv, |
683 | AMDGPU_FENCE_OWNER_VM); | 690 | AMDGPU_FENCE_OWNER_VM); |
684 | WARN_ON(vm_update_params.ib->length_dw > ndw); | 691 | WARN_ON(params.ib->length_dw > ndw); |
685 | r = amdgpu_job_submit(job, ring, &vm->entity, | 692 | r = amdgpu_job_submit(job, ring, &vm->entity, |
686 | AMDGPU_FENCE_OWNER_VM, &fence); | 693 | AMDGPU_FENCE_OWNER_VM, &fence); |
687 | if (r) | 694 | if (r) |
@@ -703,92 +710,33 @@ error_free: | |||
703 | return r; | 710 | return r; |
704 | } | 711 | } |
705 | 712 | ||
706 | /** | 713 | /* |
707 | * amdgpu_vm_frag_ptes - add fragment information to PTEs | 714 | * amdgpu_vm_update_pdes - make sure that page directory is valid |
708 | * | 715 | * |
709 | * @adev: amdgpu_device pointer | 716 | * @adev: amdgpu_device pointer |
710 | * @vm_update_params: see amdgpu_vm_update_params definition | 717 | * @vm: requested vm |
711 | * @pe_start: first PTE to handle | 718 | * @start: start of GPU address range |
712 | * @pe_end: last PTE to handle | 719 | * @end: end of GPU address range |
713 | * @addr: addr those PTEs should point to | 720 | * |
714 | * @flags: hw mapping flags | 721 | * Allocates new page tables if necessary |
722 | * and updates the page directory. | ||
723 | * Returns 0 for success, error for failure. | ||
715 | */ | 724 | */ |
716 | static void amdgpu_vm_frag_ptes(struct amdgpu_device *adev, | 725 | int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, |
717 | struct amdgpu_vm_update_params | 726 | struct amdgpu_vm *vm) |
718 | *vm_update_params, | ||
719 | uint64_t pe_start, uint64_t pe_end, | ||
720 | uint64_t addr, uint32_t flags) | ||
721 | { | 727 | { |
722 | /** | 728 | int r; |
723 | * The MC L1 TLB supports variable sized pages, based on a fragment | ||
724 | * field in the PTE. When this field is set to a non-zero value, page | ||
725 | * granularity is increased from 4KB to (1 << (12 + frag)). The PTE | ||
726 | * flags are considered valid for all PTEs within the fragment range | ||
727 | * and corresponding mappings are assumed to be physically contiguous. | ||
728 | * | ||
729 | * The L1 TLB can store a single PTE for the whole fragment, | ||
730 | * significantly increasing the space available for translation | ||
731 | * caching. This leads to large improvements in throughput when the | ||
732 | * TLB is under pressure. | ||
733 | * | ||
734 | * The L2 TLB distributes small and large fragments into two | ||
735 | * asymmetric partitions. The large fragment cache is significantly | ||
736 | * larger. Thus, we try to use large fragments wherever possible. | ||
737 | * Userspace can support this by aligning virtual base address and | ||
738 | * allocation size to the fragment size. | ||
739 | */ | ||
740 | |||
741 | /* SI and newer are optimized for 64KB */ | ||
742 | uint64_t frag_flags = AMDGPU_PTE_FRAG_64KB; | ||
743 | uint64_t frag_align = 0x80; | ||
744 | |||
745 | uint64_t frag_start = ALIGN(pe_start, frag_align); | ||
746 | uint64_t frag_end = pe_end & ~(frag_align - 1); | ||
747 | |||
748 | unsigned count; | ||
749 | |||
750 | /* Abort early if there isn't anything to do */ | ||
751 | if (pe_start == pe_end) | ||
752 | return; | ||
753 | |||
754 | /* system pages are non continuously */ | ||
755 | if (vm_update_params->src || vm_update_params->pages_addr || | ||
756 | !(flags & AMDGPU_PTE_VALID) || (frag_start >= frag_end)) { | ||
757 | |||
758 | count = (pe_end - pe_start) / 8; | ||
759 | amdgpu_vm_update_pages(adev, vm_update_params, pe_start, | ||
760 | addr, count, AMDGPU_GPU_PAGE_SIZE, | ||
761 | flags); | ||
762 | return; | ||
763 | } | ||
764 | |||
765 | /* handle the 4K area at the beginning */ | ||
766 | if (pe_start != frag_start) { | ||
767 | count = (frag_start - pe_start) / 8; | ||
768 | amdgpu_vm_update_pages(adev, vm_update_params, pe_start, addr, | ||
769 | count, AMDGPU_GPU_PAGE_SIZE, flags); | ||
770 | addr += AMDGPU_GPU_PAGE_SIZE * count; | ||
771 | } | ||
772 | |||
773 | /* handle the area in the middle */ | ||
774 | count = (frag_end - frag_start) / 8; | ||
775 | amdgpu_vm_update_pages(adev, vm_update_params, frag_start, addr, count, | ||
776 | AMDGPU_GPU_PAGE_SIZE, flags | frag_flags); | ||
777 | 729 | ||
778 | /* handle the 4K area at the end */ | 730 | r = amdgpu_vm_update_pd_or_shadow(adev, vm, true); |
779 | if (frag_end != pe_end) { | 731 | if (r) |
780 | addr += AMDGPU_GPU_PAGE_SIZE * count; | 732 | return r; |
781 | count = (pe_end - frag_end) / 8; | 733 | return amdgpu_vm_update_pd_or_shadow(adev, vm, false); |
782 | amdgpu_vm_update_pages(adev, vm_update_params, frag_end, addr, | ||
783 | count, AMDGPU_GPU_PAGE_SIZE, flags); | ||
784 | } | ||
785 | } | 734 | } |
786 | 735 | ||
787 | /** | 736 | /** |
788 | * amdgpu_vm_update_ptes - make sure that page tables are valid | 737 | * amdgpu_vm_update_ptes - make sure that page tables are valid |
789 | * | 738 | * |
790 | * @adev: amdgpu_device pointer | 739 | * @params: see amdgpu_pte_update_params definition |
791 | * @vm_update_params: see amdgpu_vm_update_params definition | ||
792 | * @vm: requested vm | 740 | * @vm: requested vm |
793 | * @start: start of GPU address range | 741 | * @start: start of GPU address range |
794 | * @end: end of GPU address range | 742 | * @end: end of GPU address range |
@@ -797,16 +745,14 @@ static void amdgpu_vm_frag_ptes(struct amdgpu_device *adev, | |||
797 | * | 745 | * |
798 | * Update the page tables in the range @start - @end. | 746 | * Update the page tables in the range @start - @end. |
799 | */ | 747 | */ |
800 | static void amdgpu_vm_update_ptes(struct amdgpu_device *adev, | 748 | static void amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params, |
801 | struct amdgpu_vm_update_params | ||
802 | *vm_update_params, | ||
803 | struct amdgpu_vm *vm, | 749 | struct amdgpu_vm *vm, |
804 | uint64_t start, uint64_t end, | 750 | uint64_t start, uint64_t end, |
805 | uint64_t dst, uint32_t flags) | 751 | uint64_t dst, uint32_t flags) |
806 | { | 752 | { |
807 | const uint64_t mask = AMDGPU_VM_PTE_COUNT - 1; | 753 | const uint64_t mask = AMDGPU_VM_PTE_COUNT - 1; |
808 | 754 | ||
809 | uint64_t cur_pe_start, cur_pe_end, cur_dst; | 755 | uint64_t cur_pe_start, cur_nptes, cur_dst; |
810 | uint64_t addr; /* next GPU address to be updated */ | 756 | uint64_t addr; /* next GPU address to be updated */ |
811 | uint64_t pt_idx; | 757 | uint64_t pt_idx; |
812 | struct amdgpu_bo *pt; | 758 | struct amdgpu_bo *pt; |
@@ -817,7 +763,11 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev, | |||
817 | addr = start; | 763 | addr = start; |
818 | pt_idx = addr >> amdgpu_vm_block_size; | 764 | pt_idx = addr >> amdgpu_vm_block_size; |
819 | pt = vm->page_tables[pt_idx].entry.robj; | 765 | pt = vm->page_tables[pt_idx].entry.robj; |
820 | 766 | if (params->shadow) { | |
767 | if (!pt->shadow) | ||
768 | return; | ||
769 | pt = vm->page_tables[pt_idx].entry.robj->shadow; | ||
770 | } | ||
821 | if ((addr & ~mask) == (end & ~mask)) | 771 | if ((addr & ~mask) == (end & ~mask)) |
822 | nptes = end - addr; | 772 | nptes = end - addr; |
823 | else | 773 | else |
@@ -825,7 +775,7 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev, | |||
825 | 775 | ||
826 | cur_pe_start = amdgpu_bo_gpu_offset(pt); | 776 | cur_pe_start = amdgpu_bo_gpu_offset(pt); |
827 | cur_pe_start += (addr & mask) * 8; | 777 | cur_pe_start += (addr & mask) * 8; |
828 | cur_pe_end = cur_pe_start + 8 * nptes; | 778 | cur_nptes = nptes; |
829 | cur_dst = dst; | 779 | cur_dst = dst; |
830 | 780 | ||
831 | /* for next ptb*/ | 781 | /* for next ptb*/ |
@@ -836,6 +786,11 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev, | |||
836 | while (addr < end) { | 786 | while (addr < end) { |
837 | pt_idx = addr >> amdgpu_vm_block_size; | 787 | pt_idx = addr >> amdgpu_vm_block_size; |
838 | pt = vm->page_tables[pt_idx].entry.robj; | 788 | pt = vm->page_tables[pt_idx].entry.robj; |
789 | if (params->shadow) { | ||
790 | if (!pt->shadow) | ||
791 | return; | ||
792 | pt = vm->page_tables[pt_idx].entry.robj->shadow; | ||
793 | } | ||
839 | 794 | ||
840 | if ((addr & ~mask) == (end & ~mask)) | 795 | if ((addr & ~mask) == (end & ~mask)) |
841 | nptes = end - addr; | 796 | nptes = end - addr; |
@@ -845,19 +800,19 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev, | |||
845 | next_pe_start = amdgpu_bo_gpu_offset(pt); | 800 | next_pe_start = amdgpu_bo_gpu_offset(pt); |
846 | next_pe_start += (addr & mask) * 8; | 801 | next_pe_start += (addr & mask) * 8; |
847 | 802 | ||
848 | if (cur_pe_end == next_pe_start) { | 803 | if ((cur_pe_start + 8 * cur_nptes) == next_pe_start && |
804 | ((cur_nptes + nptes) <= AMDGPU_VM_MAX_UPDATE_SIZE)) { | ||
849 | /* The next ptb is consecutive to current ptb. | 805 | /* The next ptb is consecutive to current ptb. |
850 | * Don't call amdgpu_vm_frag_ptes now. | 806 | * Don't call the update function now. |
851 | * Will update two ptbs together in future. | 807 | * Will update two ptbs together in future. |
852 | */ | 808 | */ |
853 | cur_pe_end += 8 * nptes; | 809 | cur_nptes += nptes; |
854 | } else { | 810 | } else { |
855 | amdgpu_vm_frag_ptes(adev, vm_update_params, | 811 | params->func(params, cur_pe_start, cur_dst, cur_nptes, |
856 | cur_pe_start, cur_pe_end, | 812 | AMDGPU_GPU_PAGE_SIZE, flags); |
857 | cur_dst, flags); | ||
858 | 813 | ||
859 | cur_pe_start = next_pe_start; | 814 | cur_pe_start = next_pe_start; |
860 | cur_pe_end = next_pe_start + 8 * nptes; | 815 | cur_nptes = nptes; |
861 | cur_dst = dst; | 816 | cur_dst = dst; |
862 | } | 817 | } |
863 | 818 | ||
@@ -866,8 +821,79 @@ static void amdgpu_vm_update_ptes(struct amdgpu_device *adev, | |||
866 | dst += nptes * AMDGPU_GPU_PAGE_SIZE; | 821 | dst += nptes * AMDGPU_GPU_PAGE_SIZE; |
867 | } | 822 | } |
868 | 823 | ||
869 | amdgpu_vm_frag_ptes(adev, vm_update_params, cur_pe_start, | 824 | params->func(params, cur_pe_start, cur_dst, cur_nptes, |
870 | cur_pe_end, cur_dst, flags); | 825 | AMDGPU_GPU_PAGE_SIZE, flags); |
826 | } | ||
827 | |||
828 | /* | ||
829 | * amdgpu_vm_frag_ptes - add fragment information to PTEs | ||
830 | * | ||
831 | * @params: see amdgpu_pte_update_params definition | ||
832 | * @vm: requested vm | ||
833 | * @start: first PTE to handle | ||
834 | * @end: last PTE to handle | ||
835 | * @dst: addr those PTEs should point to | ||
836 | * @flags: hw mapping flags | ||
837 | */ | ||
838 | static void amdgpu_vm_frag_ptes(struct amdgpu_pte_update_params *params, | ||
839 | struct amdgpu_vm *vm, | ||
840 | uint64_t start, uint64_t end, | ||
841 | uint64_t dst, uint32_t flags) | ||
842 | { | ||
843 | /** | ||
844 | * The MC L1 TLB supports variable sized pages, based on a fragment | ||
845 | * field in the PTE. When this field is set to a non-zero value, page | ||
846 | * granularity is increased from 4KB to (1 << (12 + frag)). The PTE | ||
847 | * flags are considered valid for all PTEs within the fragment range | ||
848 | * and corresponding mappings are assumed to be physically contiguous. | ||
849 | * | ||
850 | * The L1 TLB can store a single PTE for the whole fragment, | ||
851 | * significantly increasing the space available for translation | ||
852 | * caching. This leads to large improvements in throughput when the | ||
853 | * TLB is under pressure. | ||
854 | * | ||
855 | * The L2 TLB distributes small and large fragments into two | ||
856 | * asymmetric partitions. The large fragment cache is significantly | ||
857 | * larger. Thus, we try to use large fragments wherever possible. | ||
858 | * Userspace can support this by aligning virtual base address and | ||
859 | * allocation size to the fragment size. | ||
860 | */ | ||
861 | |||
862 | const uint64_t frag_align = 1 << AMDGPU_LOG2_PAGES_PER_FRAG; | ||
863 | |||
864 | uint64_t frag_start = ALIGN(start, frag_align); | ||
865 | uint64_t frag_end = end & ~(frag_align - 1); | ||
866 | |||
867 | uint32_t frag; | ||
868 | |||
869 | /* system pages are non continuously */ | ||
870 | if (params->src || !(flags & AMDGPU_PTE_VALID) || | ||
871 | (frag_start >= frag_end)) { | ||
872 | |||
873 | amdgpu_vm_update_ptes(params, vm, start, end, dst, flags); | ||
874 | return; | ||
875 | } | ||
876 | |||
877 | /* use more than 64KB fragment size if possible */ | ||
878 | frag = lower_32_bits(frag_start | frag_end); | ||
879 | frag = likely(frag) ? __ffs(frag) : 31; | ||
880 | |||
881 | /* handle the 4K area at the beginning */ | ||
882 | if (start != frag_start) { | ||
883 | amdgpu_vm_update_ptes(params, vm, start, frag_start, | ||
884 | dst, flags); | ||
885 | dst += (frag_start - start) * AMDGPU_GPU_PAGE_SIZE; | ||
886 | } | ||
887 | |||
888 | /* handle the area in the middle */ | ||
889 | amdgpu_vm_update_ptes(params, vm, frag_start, frag_end, dst, | ||
890 | flags | AMDGPU_PTE_FRAG(frag)); | ||
891 | |||
892 | /* handle the 4K area at the end */ | ||
893 | if (frag_end != end) { | ||
894 | dst += (frag_end - frag_start) * AMDGPU_GPU_PAGE_SIZE; | ||
895 | amdgpu_vm_update_ptes(params, vm, frag_end, end, dst, flags); | ||
896 | } | ||
871 | } | 897 | } |
872 | 898 | ||
873 | /** | 899 | /** |
@@ -900,14 +926,19 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, | |||
900 | void *owner = AMDGPU_FENCE_OWNER_VM; | 926 | void *owner = AMDGPU_FENCE_OWNER_VM; |
901 | unsigned nptes, ncmds, ndw; | 927 | unsigned nptes, ncmds, ndw; |
902 | struct amdgpu_job *job; | 928 | struct amdgpu_job *job; |
903 | struct amdgpu_vm_update_params vm_update_params; | 929 | struct amdgpu_pte_update_params params; |
904 | struct fence *f = NULL; | 930 | struct fence *f = NULL; |
905 | int r; | 931 | int r; |
906 | 932 | ||
933 | memset(¶ms, 0, sizeof(params)); | ||
934 | params.adev = adev; | ||
935 | params.src = src; | ||
936 | |||
907 | ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); | 937 | ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); |
908 | memset(&vm_update_params, 0, sizeof(vm_update_params)); | 938 | |
909 | vm_update_params.src = src; | 939 | memset(¶ms, 0, sizeof(params)); |
910 | vm_update_params.pages_addr = pages_addr; | 940 | params.adev = adev; |
941 | params.src = src; | ||
911 | 942 | ||
912 | /* sync to everything on unmapping */ | 943 | /* sync to everything on unmapping */ |
913 | if (!(flags & AMDGPU_PTE_VALID)) | 944 | if (!(flags & AMDGPU_PTE_VALID)) |
@@ -924,30 +955,52 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, | |||
924 | /* padding, etc. */ | 955 | /* padding, etc. */ |
925 | ndw = 64; | 956 | ndw = 64; |
926 | 957 | ||
927 | if (vm_update_params.src) { | 958 | if (src) { |
928 | /* only copy commands needed */ | 959 | /* only copy commands needed */ |
929 | ndw += ncmds * 7; | 960 | ndw += ncmds * 7; |
930 | 961 | ||
931 | } else if (vm_update_params.pages_addr) { | 962 | params.func = amdgpu_vm_do_copy_ptes; |
932 | /* header for write data commands */ | 963 | |
933 | ndw += ncmds * 4; | 964 | } else if (pages_addr) { |
965 | /* copy commands needed */ | ||
966 | ndw += ncmds * 7; | ||
934 | 967 | ||
935 | /* body of write data command */ | 968 | /* and also PTEs */ |
936 | ndw += nptes * 2; | 969 | ndw += nptes * 2; |
937 | 970 | ||
971 | params.func = amdgpu_vm_do_copy_ptes; | ||
972 | |||
938 | } else { | 973 | } else { |
939 | /* set page commands needed */ | 974 | /* set page commands needed */ |
940 | ndw += ncmds * 10; | 975 | ndw += ncmds * 10; |
941 | 976 | ||
942 | /* two extra commands for begin/end of fragment */ | 977 | /* two extra commands for begin/end of fragment */ |
943 | ndw += 2 * 10; | 978 | ndw += 2 * 10; |
979 | |||
980 | params.func = amdgpu_vm_do_set_ptes; | ||
944 | } | 981 | } |
945 | 982 | ||
946 | r = amdgpu_job_alloc_with_ib(adev, ndw * 4, &job); | 983 | r = amdgpu_job_alloc_with_ib(adev, ndw * 4, &job); |
947 | if (r) | 984 | if (r) |
948 | return r; | 985 | return r; |
949 | 986 | ||
950 | vm_update_params.ib = &job->ibs[0]; | 987 | params.ib = &job->ibs[0]; |
988 | |||
989 | if (!src && pages_addr) { | ||
990 | uint64_t *pte; | ||
991 | unsigned i; | ||
992 | |||
993 | /* Put the PTEs at the end of the IB. */ | ||
994 | i = ndw - nptes * 2; | ||
995 | pte= (uint64_t *)&(job->ibs->ptr[i]); | ||
996 | params.src = job->ibs->gpu_addr + i * 4; | ||
997 | |||
998 | for (i = 0; i < nptes; ++i) { | ||
999 | pte[i] = amdgpu_vm_map_gart(pages_addr, addr + i * | ||
1000 | AMDGPU_GPU_PAGE_SIZE); | ||
1001 | pte[i] |= flags; | ||
1002 | } | ||
1003 | } | ||
951 | 1004 | ||
952 | r = amdgpu_sync_fence(adev, &job->sync, exclusive); | 1005 | r = amdgpu_sync_fence(adev, &job->sync, exclusive); |
953 | if (r) | 1006 | if (r) |
@@ -962,11 +1015,13 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, | |||
962 | if (r) | 1015 | if (r) |
963 | goto error_free; | 1016 | goto error_free; |
964 | 1017 | ||
965 | amdgpu_vm_update_ptes(adev, &vm_update_params, vm, start, | 1018 | params.shadow = true; |
966 | last + 1, addr, flags); | 1019 | amdgpu_vm_frag_ptes(¶ms, vm, start, last + 1, addr, flags); |
1020 | params.shadow = false; | ||
1021 | amdgpu_vm_frag_ptes(¶ms, vm, start, last + 1, addr, flags); | ||
967 | 1022 | ||
968 | amdgpu_ring_pad_ib(ring, vm_update_params.ib); | 1023 | amdgpu_ring_pad_ib(ring, params.ib); |
969 | WARN_ON(vm_update_params.ib->length_dw > ndw); | 1024 | WARN_ON(params.ib->length_dw > ndw); |
970 | r = amdgpu_job_submit(job, ring, &vm->entity, | 1025 | r = amdgpu_job_submit(job, ring, &vm->entity, |
971 | AMDGPU_FENCE_OWNER_VM, &f); | 1026 | AMDGPU_FENCE_OWNER_VM, &f); |
972 | if (r) | 1027 | if (r) |
@@ -1062,28 +1117,32 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, | |||
1062 | * | 1117 | * |
1063 | * @adev: amdgpu_device pointer | 1118 | * @adev: amdgpu_device pointer |
1064 | * @bo_va: requested BO and VM object | 1119 | * @bo_va: requested BO and VM object |
1065 | * @mem: ttm mem | 1120 | * @clear: if true clear the entries |
1066 | * | 1121 | * |
1067 | * Fill in the page table entries for @bo_va. | 1122 | * Fill in the page table entries for @bo_va. |
1068 | * Returns 0 for success, -EINVAL for failure. | 1123 | * Returns 0 for success, -EINVAL for failure. |
1069 | * | ||
1070 | * Object have to be reserved and mutex must be locked! | ||
1071 | */ | 1124 | */ |
1072 | int amdgpu_vm_bo_update(struct amdgpu_device *adev, | 1125 | int amdgpu_vm_bo_update(struct amdgpu_device *adev, |
1073 | struct amdgpu_bo_va *bo_va, | 1126 | struct amdgpu_bo_va *bo_va, |
1074 | struct ttm_mem_reg *mem) | 1127 | bool clear) |
1075 | { | 1128 | { |
1076 | struct amdgpu_vm *vm = bo_va->vm; | 1129 | struct amdgpu_vm *vm = bo_va->vm; |
1077 | struct amdgpu_bo_va_mapping *mapping; | 1130 | struct amdgpu_bo_va_mapping *mapping; |
1078 | dma_addr_t *pages_addr = NULL; | 1131 | dma_addr_t *pages_addr = NULL; |
1079 | uint32_t gtt_flags, flags; | 1132 | uint32_t gtt_flags, flags; |
1133 | struct ttm_mem_reg *mem; | ||
1080 | struct fence *exclusive; | 1134 | struct fence *exclusive; |
1081 | uint64_t addr; | 1135 | uint64_t addr; |
1082 | int r; | 1136 | int r; |
1083 | 1137 | ||
1084 | if (mem) { | 1138 | if (clear) { |
1139 | mem = NULL; | ||
1140 | addr = 0; | ||
1141 | exclusive = NULL; | ||
1142 | } else { | ||
1085 | struct ttm_dma_tt *ttm; | 1143 | struct ttm_dma_tt *ttm; |
1086 | 1144 | ||
1145 | mem = &bo_va->bo->tbo.mem; | ||
1087 | addr = (u64)mem->start << PAGE_SHIFT; | 1146 | addr = (u64)mem->start << PAGE_SHIFT; |
1088 | switch (mem->mem_type) { | 1147 | switch (mem->mem_type) { |
1089 | case TTM_PL_TT: | 1148 | case TTM_PL_TT: |
@@ -1101,9 +1160,6 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, | |||
1101 | } | 1160 | } |
1102 | 1161 | ||
1103 | exclusive = reservation_object_get_excl(bo_va->bo->tbo.resv); | 1162 | exclusive = reservation_object_get_excl(bo_va->bo->tbo.resv); |
1104 | } else { | ||
1105 | addr = 0; | ||
1106 | exclusive = NULL; | ||
1107 | } | 1163 | } |
1108 | 1164 | ||
1109 | flags = amdgpu_ttm_tt_pte_flags(adev, bo_va->bo->tbo.ttm, mem); | 1165 | flags = amdgpu_ttm_tt_pte_flags(adev, bo_va->bo->tbo.ttm, mem); |
@@ -1134,7 +1190,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, | |||
1134 | spin_lock(&vm->status_lock); | 1190 | spin_lock(&vm->status_lock); |
1135 | list_splice_init(&bo_va->invalids, &bo_va->valids); | 1191 | list_splice_init(&bo_va->invalids, &bo_va->valids); |
1136 | list_del_init(&bo_va->vm_status); | 1192 | list_del_init(&bo_va->vm_status); |
1137 | if (!mem) | 1193 | if (clear) |
1138 | list_add(&bo_va->vm_status, &vm->cleared); | 1194 | list_add(&bo_va->vm_status, &vm->cleared); |
1139 | spin_unlock(&vm->status_lock); | 1195 | spin_unlock(&vm->status_lock); |
1140 | 1196 | ||
@@ -1197,7 +1253,7 @@ int amdgpu_vm_clear_invalids(struct amdgpu_device *adev, | |||
1197 | struct amdgpu_bo_va, vm_status); | 1253 | struct amdgpu_bo_va, vm_status); |
1198 | spin_unlock(&vm->status_lock); | 1254 | spin_unlock(&vm->status_lock); |
1199 | 1255 | ||
1200 | r = amdgpu_vm_bo_update(adev, bo_va, NULL); | 1256 | r = amdgpu_vm_bo_update(adev, bo_va, true); |
1201 | if (r) | 1257 | if (r) |
1202 | return r; | 1258 | return r; |
1203 | 1259 | ||
@@ -1342,7 +1398,8 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, | |||
1342 | r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8, | 1398 | r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8, |
1343 | AMDGPU_GPU_PAGE_SIZE, true, | 1399 | AMDGPU_GPU_PAGE_SIZE, true, |
1344 | AMDGPU_GEM_DOMAIN_VRAM, | 1400 | AMDGPU_GEM_DOMAIN_VRAM, |
1345 | AMDGPU_GEM_CREATE_NO_CPU_ACCESS, | 1401 | AMDGPU_GEM_CREATE_NO_CPU_ACCESS | |
1402 | AMDGPU_GEM_CREATE_SHADOW, | ||
1346 | NULL, resv, &pt); | 1403 | NULL, resv, &pt); |
1347 | if (r) | 1404 | if (r) |
1348 | goto error_free; | 1405 | goto error_free; |
@@ -1541,7 +1598,8 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
1541 | 1598 | ||
1542 | r = amdgpu_bo_create(adev, pd_size, align, true, | 1599 | r = amdgpu_bo_create(adev, pd_size, align, true, |
1543 | AMDGPU_GEM_DOMAIN_VRAM, | 1600 | AMDGPU_GEM_DOMAIN_VRAM, |
1544 | AMDGPU_GEM_CREATE_NO_CPU_ACCESS, | 1601 | AMDGPU_GEM_CREATE_NO_CPU_ACCESS | |
1602 | AMDGPU_GEM_CREATE_SHADOW, | ||
1545 | NULL, NULL, &vm->page_directory); | 1603 | NULL, NULL, &vm->page_directory); |
1546 | if (r) | 1604 | if (r) |
1547 | goto error_free_sched_entity; | 1605 | goto error_free_sched_entity; |
@@ -1597,10 +1655,16 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
1597 | kfree(mapping); | 1655 | kfree(mapping); |
1598 | } | 1656 | } |
1599 | 1657 | ||
1600 | for (i = 0; i < amdgpu_vm_num_pdes(adev); i++) | 1658 | for (i = 0; i < amdgpu_vm_num_pdes(adev); i++) { |
1659 | if (vm->page_tables[i].entry.robj && | ||
1660 | vm->page_tables[i].entry.robj->shadow) | ||
1661 | amdgpu_bo_unref(&vm->page_tables[i].entry.robj->shadow); | ||
1601 | amdgpu_bo_unref(&vm->page_tables[i].entry.robj); | 1662 | amdgpu_bo_unref(&vm->page_tables[i].entry.robj); |
1663 | } | ||
1602 | drm_free_large(vm->page_tables); | 1664 | drm_free_large(vm->page_tables); |
1603 | 1665 | ||
1666 | if (vm->page_directory->shadow) | ||
1667 | amdgpu_bo_unref(&vm->page_directory->shadow); | ||
1604 | amdgpu_bo_unref(&vm->page_directory); | 1668 | amdgpu_bo_unref(&vm->page_directory); |
1605 | fence_put(vm->page_directory_fence); | 1669 | fence_put(vm->page_directory_fence); |
1606 | } | 1670 | } |
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c index 7f85c2c1d681..f81068ba4cc6 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c | |||
@@ -88,7 +88,6 @@ static int amdgpu_atombios_dp_process_aux_ch(struct amdgpu_i2c_chan *chan, | |||
88 | 88 | ||
89 | /* timeout */ | 89 | /* timeout */ |
90 | if (args.v2.ucReplyStatus == 1) { | 90 | if (args.v2.ucReplyStatus == 1) { |
91 | DRM_DEBUG_KMS("dp_aux_ch timeout\n"); | ||
92 | r = -ETIMEDOUT; | 91 | r = -ETIMEDOUT; |
93 | goto done; | 92 | goto done; |
94 | } | 93 | } |
@@ -339,22 +338,21 @@ int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector) | |||
339 | { | 338 | { |
340 | struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv; | 339 | struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv; |
341 | u8 msg[DP_DPCD_SIZE]; | 340 | u8 msg[DP_DPCD_SIZE]; |
342 | int ret, i; | 341 | int ret; |
343 | 342 | ||
344 | for (i = 0; i < 7; i++) { | 343 | ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_DPCD_REV, |
345 | ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_DPCD_REV, msg, | 344 | msg, DP_DPCD_SIZE); |
346 | DP_DPCD_SIZE); | 345 | if (ret == DP_DPCD_SIZE) { |
347 | if (ret == DP_DPCD_SIZE) { | 346 | memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); |
348 | memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); | ||
349 | 347 | ||
350 | DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd), | 348 | DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd), |
351 | dig_connector->dpcd); | 349 | dig_connector->dpcd); |
352 | 350 | ||
353 | amdgpu_atombios_dp_probe_oui(amdgpu_connector); | 351 | amdgpu_atombios_dp_probe_oui(amdgpu_connector); |
354 | 352 | ||
355 | return 0; | 353 | return 0; |
356 | } | ||
357 | } | 354 | } |
355 | |||
358 | dig_connector->dpcd[0] = 0; | 356 | dig_connector->dpcd[0] = 0; |
359 | return -EINVAL; | 357 | return -EINVAL; |
360 | } | 358 | } |
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index a5c94b482459..a0d63a293bb0 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c | |||
@@ -5874,7 +5874,10 @@ static int ci_dpm_init(struct amdgpu_device *adev) | |||
5874 | pi->pcie_dpm_key_disabled = 0; | 5874 | pi->pcie_dpm_key_disabled = 0; |
5875 | pi->thermal_sclk_dpm_enabled = 0; | 5875 | pi->thermal_sclk_dpm_enabled = 0; |
5876 | 5876 | ||
5877 | pi->caps_sclk_ds = true; | 5877 | if (amdgpu_sclk_deep_sleep_en) |
5878 | pi->caps_sclk_ds = true; | ||
5879 | else | ||
5880 | pi->caps_sclk_ds = false; | ||
5878 | 5881 | ||
5879 | pi->mclk_strobe_mode_threshold = 40000; | 5882 | pi->mclk_strobe_mode_threshold = 40000; |
5880 | pi->mclk_stutter_mode_threshold = 40000; | 5883 | pi->mclk_stutter_mode_threshold = 40000; |
diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 4efc901f658c..825de800b798 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c | |||
@@ -67,6 +67,7 @@ | |||
67 | 67 | ||
68 | #include "amdgpu_amdkfd.h" | 68 | #include "amdgpu_amdkfd.h" |
69 | #include "amdgpu_powerplay.h" | 69 | #include "amdgpu_powerplay.h" |
70 | #include "dce_virtual.h" | ||
70 | 71 | ||
71 | /* | 72 | /* |
72 | * Indirect registers accessor | 73 | * Indirect registers accessor |
@@ -1708,6 +1709,74 @@ static const struct amdgpu_ip_block_version bonaire_ip_blocks[] = | |||
1708 | }, | 1709 | }, |
1709 | }; | 1710 | }; |
1710 | 1711 | ||
1712 | static const struct amdgpu_ip_block_version bonaire_ip_blocks_vd[] = | ||
1713 | { | ||
1714 | /* ORDER MATTERS! */ | ||
1715 | { | ||
1716 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
1717 | .major = 1, | ||
1718 | .minor = 0, | ||
1719 | .rev = 0, | ||
1720 | .funcs = &cik_common_ip_funcs, | ||
1721 | }, | ||
1722 | { | ||
1723 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
1724 | .major = 7, | ||
1725 | .minor = 0, | ||
1726 | .rev = 0, | ||
1727 | .funcs = &gmc_v7_0_ip_funcs, | ||
1728 | }, | ||
1729 | { | ||
1730 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
1731 | .major = 2, | ||
1732 | .minor = 0, | ||
1733 | .rev = 0, | ||
1734 | .funcs = &cik_ih_ip_funcs, | ||
1735 | }, | ||
1736 | { | ||
1737 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
1738 | .major = 7, | ||
1739 | .minor = 0, | ||
1740 | .rev = 0, | ||
1741 | .funcs = &amdgpu_pp_ip_funcs, | ||
1742 | }, | ||
1743 | { | ||
1744 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
1745 | .major = 8, | ||
1746 | .minor = 2, | ||
1747 | .rev = 0, | ||
1748 | .funcs = &dce_virtual_ip_funcs, | ||
1749 | }, | ||
1750 | { | ||
1751 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
1752 | .major = 7, | ||
1753 | .minor = 2, | ||
1754 | .rev = 0, | ||
1755 | .funcs = &gfx_v7_0_ip_funcs, | ||
1756 | }, | ||
1757 | { | ||
1758 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
1759 | .major = 2, | ||
1760 | .minor = 0, | ||
1761 | .rev = 0, | ||
1762 | .funcs = &cik_sdma_ip_funcs, | ||
1763 | }, | ||
1764 | { | ||
1765 | .type = AMD_IP_BLOCK_TYPE_UVD, | ||
1766 | .major = 4, | ||
1767 | .minor = 2, | ||
1768 | .rev = 0, | ||
1769 | .funcs = &uvd_v4_2_ip_funcs, | ||
1770 | }, | ||
1771 | { | ||
1772 | .type = AMD_IP_BLOCK_TYPE_VCE, | ||
1773 | .major = 2, | ||
1774 | .minor = 0, | ||
1775 | .rev = 0, | ||
1776 | .funcs = &vce_v2_0_ip_funcs, | ||
1777 | }, | ||
1778 | }; | ||
1779 | |||
1711 | static const struct amdgpu_ip_block_version hawaii_ip_blocks[] = | 1780 | static const struct amdgpu_ip_block_version hawaii_ip_blocks[] = |
1712 | { | 1781 | { |
1713 | /* ORDER MATTERS! */ | 1782 | /* ORDER MATTERS! */ |
@@ -1776,6 +1845,74 @@ static const struct amdgpu_ip_block_version hawaii_ip_blocks[] = | |||
1776 | }, | 1845 | }, |
1777 | }; | 1846 | }; |
1778 | 1847 | ||
1848 | static const struct amdgpu_ip_block_version hawaii_ip_blocks_vd[] = | ||
1849 | { | ||
1850 | /* ORDER MATTERS! */ | ||
1851 | { | ||
1852 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
1853 | .major = 1, | ||
1854 | .minor = 0, | ||
1855 | .rev = 0, | ||
1856 | .funcs = &cik_common_ip_funcs, | ||
1857 | }, | ||
1858 | { | ||
1859 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
1860 | .major = 7, | ||
1861 | .minor = 0, | ||
1862 | .rev = 0, | ||
1863 | .funcs = &gmc_v7_0_ip_funcs, | ||
1864 | }, | ||
1865 | { | ||
1866 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
1867 | .major = 2, | ||
1868 | .minor = 0, | ||
1869 | .rev = 0, | ||
1870 | .funcs = &cik_ih_ip_funcs, | ||
1871 | }, | ||
1872 | { | ||
1873 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
1874 | .major = 7, | ||
1875 | .minor = 0, | ||
1876 | .rev = 0, | ||
1877 | .funcs = &amdgpu_pp_ip_funcs, | ||
1878 | }, | ||
1879 | { | ||
1880 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
1881 | .major = 8, | ||
1882 | .minor = 5, | ||
1883 | .rev = 0, | ||
1884 | .funcs = &dce_virtual_ip_funcs, | ||
1885 | }, | ||
1886 | { | ||
1887 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
1888 | .major = 7, | ||
1889 | .minor = 3, | ||
1890 | .rev = 0, | ||
1891 | .funcs = &gfx_v7_0_ip_funcs, | ||
1892 | }, | ||
1893 | { | ||
1894 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
1895 | .major = 2, | ||
1896 | .minor = 0, | ||
1897 | .rev = 0, | ||
1898 | .funcs = &cik_sdma_ip_funcs, | ||
1899 | }, | ||
1900 | { | ||
1901 | .type = AMD_IP_BLOCK_TYPE_UVD, | ||
1902 | .major = 4, | ||
1903 | .minor = 2, | ||
1904 | .rev = 0, | ||
1905 | .funcs = &uvd_v4_2_ip_funcs, | ||
1906 | }, | ||
1907 | { | ||
1908 | .type = AMD_IP_BLOCK_TYPE_VCE, | ||
1909 | .major = 2, | ||
1910 | .minor = 0, | ||
1911 | .rev = 0, | ||
1912 | .funcs = &vce_v2_0_ip_funcs, | ||
1913 | }, | ||
1914 | }; | ||
1915 | |||
1779 | static const struct amdgpu_ip_block_version kabini_ip_blocks[] = | 1916 | static const struct amdgpu_ip_block_version kabini_ip_blocks[] = |
1780 | { | 1917 | { |
1781 | /* ORDER MATTERS! */ | 1918 | /* ORDER MATTERS! */ |
@@ -1844,6 +1981,74 @@ static const struct amdgpu_ip_block_version kabini_ip_blocks[] = | |||
1844 | }, | 1981 | }, |
1845 | }; | 1982 | }; |
1846 | 1983 | ||
1984 | static const struct amdgpu_ip_block_version kabini_ip_blocks_vd[] = | ||
1985 | { | ||
1986 | /* ORDER MATTERS! */ | ||
1987 | { | ||
1988 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
1989 | .major = 1, | ||
1990 | .minor = 0, | ||
1991 | .rev = 0, | ||
1992 | .funcs = &cik_common_ip_funcs, | ||
1993 | }, | ||
1994 | { | ||
1995 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
1996 | .major = 7, | ||
1997 | .minor = 0, | ||
1998 | .rev = 0, | ||
1999 | .funcs = &gmc_v7_0_ip_funcs, | ||
2000 | }, | ||
2001 | { | ||
2002 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
2003 | .major = 2, | ||
2004 | .minor = 0, | ||
2005 | .rev = 0, | ||
2006 | .funcs = &cik_ih_ip_funcs, | ||
2007 | }, | ||
2008 | { | ||
2009 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
2010 | .major = 7, | ||
2011 | .minor = 0, | ||
2012 | .rev = 0, | ||
2013 | .funcs = &amdgpu_pp_ip_funcs, | ||
2014 | }, | ||
2015 | { | ||
2016 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
2017 | .major = 8, | ||
2018 | .minor = 3, | ||
2019 | .rev = 0, | ||
2020 | .funcs = &dce_virtual_ip_funcs, | ||
2021 | }, | ||
2022 | { | ||
2023 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
2024 | .major = 7, | ||
2025 | .minor = 2, | ||
2026 | .rev = 0, | ||
2027 | .funcs = &gfx_v7_0_ip_funcs, | ||
2028 | }, | ||
2029 | { | ||
2030 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
2031 | .major = 2, | ||
2032 | .minor = 0, | ||
2033 | .rev = 0, | ||
2034 | .funcs = &cik_sdma_ip_funcs, | ||
2035 | }, | ||
2036 | { | ||
2037 | .type = AMD_IP_BLOCK_TYPE_UVD, | ||
2038 | .major = 4, | ||
2039 | .minor = 2, | ||
2040 | .rev = 0, | ||
2041 | .funcs = &uvd_v4_2_ip_funcs, | ||
2042 | }, | ||
2043 | { | ||
2044 | .type = AMD_IP_BLOCK_TYPE_VCE, | ||
2045 | .major = 2, | ||
2046 | .minor = 0, | ||
2047 | .rev = 0, | ||
2048 | .funcs = &vce_v2_0_ip_funcs, | ||
2049 | }, | ||
2050 | }; | ||
2051 | |||
1847 | static const struct amdgpu_ip_block_version mullins_ip_blocks[] = | 2052 | static const struct amdgpu_ip_block_version mullins_ip_blocks[] = |
1848 | { | 2053 | { |
1849 | /* ORDER MATTERS! */ | 2054 | /* ORDER MATTERS! */ |
@@ -1912,6 +2117,74 @@ static const struct amdgpu_ip_block_version mullins_ip_blocks[] = | |||
1912 | }, | 2117 | }, |
1913 | }; | 2118 | }; |
1914 | 2119 | ||
2120 | static const struct amdgpu_ip_block_version mullins_ip_blocks_vd[] = | ||
2121 | { | ||
2122 | /* ORDER MATTERS! */ | ||
2123 | { | ||
2124 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
2125 | .major = 1, | ||
2126 | .minor = 0, | ||
2127 | .rev = 0, | ||
2128 | .funcs = &cik_common_ip_funcs, | ||
2129 | }, | ||
2130 | { | ||
2131 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
2132 | .major = 7, | ||
2133 | .minor = 0, | ||
2134 | .rev = 0, | ||
2135 | .funcs = &gmc_v7_0_ip_funcs, | ||
2136 | }, | ||
2137 | { | ||
2138 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
2139 | .major = 2, | ||
2140 | .minor = 0, | ||
2141 | .rev = 0, | ||
2142 | .funcs = &cik_ih_ip_funcs, | ||
2143 | }, | ||
2144 | { | ||
2145 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
2146 | .major = 7, | ||
2147 | .minor = 0, | ||
2148 | .rev = 0, | ||
2149 | .funcs = &amdgpu_pp_ip_funcs, | ||
2150 | }, | ||
2151 | { | ||
2152 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
2153 | .major = 8, | ||
2154 | .minor = 3, | ||
2155 | .rev = 0, | ||
2156 | .funcs = &dce_virtual_ip_funcs, | ||
2157 | }, | ||
2158 | { | ||
2159 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
2160 | .major = 7, | ||
2161 | .minor = 2, | ||
2162 | .rev = 0, | ||
2163 | .funcs = &gfx_v7_0_ip_funcs, | ||
2164 | }, | ||
2165 | { | ||
2166 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
2167 | .major = 2, | ||
2168 | .minor = 0, | ||
2169 | .rev = 0, | ||
2170 | .funcs = &cik_sdma_ip_funcs, | ||
2171 | }, | ||
2172 | { | ||
2173 | .type = AMD_IP_BLOCK_TYPE_UVD, | ||
2174 | .major = 4, | ||
2175 | .minor = 2, | ||
2176 | .rev = 0, | ||
2177 | .funcs = &uvd_v4_2_ip_funcs, | ||
2178 | }, | ||
2179 | { | ||
2180 | .type = AMD_IP_BLOCK_TYPE_VCE, | ||
2181 | .major = 2, | ||
2182 | .minor = 0, | ||
2183 | .rev = 0, | ||
2184 | .funcs = &vce_v2_0_ip_funcs, | ||
2185 | }, | ||
2186 | }; | ||
2187 | |||
1915 | static const struct amdgpu_ip_block_version kaveri_ip_blocks[] = | 2188 | static const struct amdgpu_ip_block_version kaveri_ip_blocks[] = |
1916 | { | 2189 | { |
1917 | /* ORDER MATTERS! */ | 2190 | /* ORDER MATTERS! */ |
@@ -1980,32 +2253,128 @@ static const struct amdgpu_ip_block_version kaveri_ip_blocks[] = | |||
1980 | }, | 2253 | }, |
1981 | }; | 2254 | }; |
1982 | 2255 | ||
2256 | static const struct amdgpu_ip_block_version kaveri_ip_blocks_vd[] = | ||
2257 | { | ||
2258 | /* ORDER MATTERS! */ | ||
2259 | { | ||
2260 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
2261 | .major = 1, | ||
2262 | .minor = 0, | ||
2263 | .rev = 0, | ||
2264 | .funcs = &cik_common_ip_funcs, | ||
2265 | }, | ||
2266 | { | ||
2267 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
2268 | .major = 7, | ||
2269 | .minor = 0, | ||
2270 | .rev = 0, | ||
2271 | .funcs = &gmc_v7_0_ip_funcs, | ||
2272 | }, | ||
2273 | { | ||
2274 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
2275 | .major = 2, | ||
2276 | .minor = 0, | ||
2277 | .rev = 0, | ||
2278 | .funcs = &cik_ih_ip_funcs, | ||
2279 | }, | ||
2280 | { | ||
2281 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
2282 | .major = 7, | ||
2283 | .minor = 0, | ||
2284 | .rev = 0, | ||
2285 | .funcs = &amdgpu_pp_ip_funcs, | ||
2286 | }, | ||
2287 | { | ||
2288 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
2289 | .major = 8, | ||
2290 | .minor = 1, | ||
2291 | .rev = 0, | ||
2292 | .funcs = &dce_virtual_ip_funcs, | ||
2293 | }, | ||
2294 | { | ||
2295 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
2296 | .major = 7, | ||
2297 | .minor = 1, | ||
2298 | .rev = 0, | ||
2299 | .funcs = &gfx_v7_0_ip_funcs, | ||
2300 | }, | ||
2301 | { | ||
2302 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
2303 | .major = 2, | ||
2304 | .minor = 0, | ||
2305 | .rev = 0, | ||
2306 | .funcs = &cik_sdma_ip_funcs, | ||
2307 | }, | ||
2308 | { | ||
2309 | .type = AMD_IP_BLOCK_TYPE_UVD, | ||
2310 | .major = 4, | ||
2311 | .minor = 2, | ||
2312 | .rev = 0, | ||
2313 | .funcs = &uvd_v4_2_ip_funcs, | ||
2314 | }, | ||
2315 | { | ||
2316 | .type = AMD_IP_BLOCK_TYPE_VCE, | ||
2317 | .major = 2, | ||
2318 | .minor = 0, | ||
2319 | .rev = 0, | ||
2320 | .funcs = &vce_v2_0_ip_funcs, | ||
2321 | }, | ||
2322 | }; | ||
2323 | |||
1983 | int cik_set_ip_blocks(struct amdgpu_device *adev) | 2324 | int cik_set_ip_blocks(struct amdgpu_device *adev) |
1984 | { | 2325 | { |
1985 | switch (adev->asic_type) { | 2326 | if (adev->enable_virtual_display) { |
1986 | case CHIP_BONAIRE: | 2327 | switch (adev->asic_type) { |
1987 | adev->ip_blocks = bonaire_ip_blocks; | 2328 | case CHIP_BONAIRE: |
1988 | adev->num_ip_blocks = ARRAY_SIZE(bonaire_ip_blocks); | 2329 | adev->ip_blocks = bonaire_ip_blocks_vd; |
1989 | break; | 2330 | adev->num_ip_blocks = ARRAY_SIZE(bonaire_ip_blocks_vd); |
1990 | case CHIP_HAWAII: | 2331 | break; |
1991 | adev->ip_blocks = hawaii_ip_blocks; | 2332 | case CHIP_HAWAII: |
1992 | adev->num_ip_blocks = ARRAY_SIZE(hawaii_ip_blocks); | 2333 | adev->ip_blocks = hawaii_ip_blocks_vd; |
1993 | break; | 2334 | adev->num_ip_blocks = ARRAY_SIZE(hawaii_ip_blocks_vd); |
1994 | case CHIP_KAVERI: | 2335 | break; |
1995 | adev->ip_blocks = kaveri_ip_blocks; | 2336 | case CHIP_KAVERI: |
1996 | adev->num_ip_blocks = ARRAY_SIZE(kaveri_ip_blocks); | 2337 | adev->ip_blocks = kaveri_ip_blocks_vd; |
1997 | break; | 2338 | adev->num_ip_blocks = ARRAY_SIZE(kaveri_ip_blocks_vd); |
1998 | case CHIP_KABINI: | 2339 | break; |
1999 | adev->ip_blocks = kabini_ip_blocks; | 2340 | case CHIP_KABINI: |
2000 | adev->num_ip_blocks = ARRAY_SIZE(kabini_ip_blocks); | 2341 | adev->ip_blocks = kabini_ip_blocks_vd; |
2001 | break; | 2342 | adev->num_ip_blocks = ARRAY_SIZE(kabini_ip_blocks_vd); |
2002 | case CHIP_MULLINS: | 2343 | break; |
2003 | adev->ip_blocks = mullins_ip_blocks; | 2344 | case CHIP_MULLINS: |
2004 | adev->num_ip_blocks = ARRAY_SIZE(mullins_ip_blocks); | 2345 | adev->ip_blocks = mullins_ip_blocks_vd; |
2005 | break; | 2346 | adev->num_ip_blocks = ARRAY_SIZE(mullins_ip_blocks_vd); |
2006 | default: | 2347 | break; |
2007 | /* FIXME: not supported yet */ | 2348 | default: |
2008 | return -EINVAL; | 2349 | /* FIXME: not supported yet */ |
2350 | return -EINVAL; | ||
2351 | } | ||
2352 | } else { | ||
2353 | switch (adev->asic_type) { | ||
2354 | case CHIP_BONAIRE: | ||
2355 | adev->ip_blocks = bonaire_ip_blocks; | ||
2356 | adev->num_ip_blocks = ARRAY_SIZE(bonaire_ip_blocks); | ||
2357 | break; | ||
2358 | case CHIP_HAWAII: | ||
2359 | adev->ip_blocks = hawaii_ip_blocks; | ||
2360 | adev->num_ip_blocks = ARRAY_SIZE(hawaii_ip_blocks); | ||
2361 | break; | ||
2362 | case CHIP_KAVERI: | ||
2363 | adev->ip_blocks = kaveri_ip_blocks; | ||
2364 | adev->num_ip_blocks = ARRAY_SIZE(kaveri_ip_blocks); | ||
2365 | break; | ||
2366 | case CHIP_KABINI: | ||
2367 | adev->ip_blocks = kabini_ip_blocks; | ||
2368 | adev->num_ip_blocks = ARRAY_SIZE(kabini_ip_blocks); | ||
2369 | break; | ||
2370 | case CHIP_MULLINS: | ||
2371 | adev->ip_blocks = mullins_ip_blocks; | ||
2372 | adev->num_ip_blocks = ARRAY_SIZE(mullins_ip_blocks); | ||
2373 | break; | ||
2374 | default: | ||
2375 | /* FIXME: not supported yet */ | ||
2376 | return -EINVAL; | ||
2377 | } | ||
2009 | } | 2378 | } |
2010 | 2379 | ||
2011 | return 0; | 2380 | return 0; |
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index ee6466912497..e71cd12104b3 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c | |||
@@ -694,24 +694,16 @@ static void cik_sdma_vm_copy_pte(struct amdgpu_ib *ib, | |||
694 | uint64_t pe, uint64_t src, | 694 | uint64_t pe, uint64_t src, |
695 | unsigned count) | 695 | unsigned count) |
696 | { | 696 | { |
697 | while (count) { | 697 | unsigned bytes = count * 8; |
698 | unsigned bytes = count * 8; | 698 | |
699 | if (bytes > 0x1FFFF8) | 699 | ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY, |
700 | bytes = 0x1FFFF8; | 700 | SDMA_WRITE_SUB_OPCODE_LINEAR, 0); |
701 | 701 | ib->ptr[ib->length_dw++] = bytes; | |
702 | ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY, | 702 | ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ |
703 | SDMA_WRITE_SUB_OPCODE_LINEAR, 0); | 703 | ib->ptr[ib->length_dw++] = lower_32_bits(src); |
704 | ib->ptr[ib->length_dw++] = bytes; | 704 | ib->ptr[ib->length_dw++] = upper_32_bits(src); |
705 | ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ | 705 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); |
706 | ib->ptr[ib->length_dw++] = lower_32_bits(src); | 706 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); |
707 | ib->ptr[ib->length_dw++] = upper_32_bits(src); | ||
708 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); | ||
709 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
710 | |||
711 | pe += bytes; | ||
712 | src += bytes; | ||
713 | count -= bytes / 8; | ||
714 | } | ||
715 | } | 707 | } |
716 | 708 | ||
717 | /** | 709 | /** |
@@ -719,39 +711,27 @@ static void cik_sdma_vm_copy_pte(struct amdgpu_ib *ib, | |||
719 | * | 711 | * |
720 | * @ib: indirect buffer to fill with commands | 712 | * @ib: indirect buffer to fill with commands |
721 | * @pe: addr of the page entry | 713 | * @pe: addr of the page entry |
722 | * @addr: dst addr to write into pe | 714 | * @value: dst addr to write into pe |
723 | * @count: number of page entries to update | 715 | * @count: number of page entries to update |
724 | * @incr: increase next addr by incr bytes | 716 | * @incr: increase next addr by incr bytes |
725 | * @flags: access flags | ||
726 | * | 717 | * |
727 | * Update PTEs by writing them manually using sDMA (CIK). | 718 | * Update PTEs by writing them manually using sDMA (CIK). |
728 | */ | 719 | */ |
729 | static void cik_sdma_vm_write_pte(struct amdgpu_ib *ib, | 720 | static void cik_sdma_vm_write_pte(struct amdgpu_ib *ib, uint64_t pe, |
730 | const dma_addr_t *pages_addr, uint64_t pe, | 721 | uint64_t value, unsigned count, |
731 | uint64_t addr, unsigned count, | 722 | uint32_t incr) |
732 | uint32_t incr, uint32_t flags) | ||
733 | { | 723 | { |
734 | uint64_t value; | 724 | unsigned ndw = count * 2; |
735 | unsigned ndw; | 725 | |
736 | 726 | ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE, | |
737 | while (count) { | 727 | SDMA_WRITE_SUB_OPCODE_LINEAR, 0); |
738 | ndw = count * 2; | 728 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); |
739 | if (ndw > 0xFFFFE) | 729 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); |
740 | ndw = 0xFFFFE; | 730 | ib->ptr[ib->length_dw++] = ndw; |
741 | 731 | for (; ndw > 0; ndw -= 2) { | |
742 | /* for non-physically contiguous pages (system) */ | 732 | ib->ptr[ib->length_dw++] = lower_32_bits(value); |
743 | ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE, | 733 | ib->ptr[ib->length_dw++] = upper_32_bits(value); |
744 | SDMA_WRITE_SUB_OPCODE_LINEAR, 0); | 734 | value += incr; |
745 | ib->ptr[ib->length_dw++] = pe; | ||
746 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
747 | ib->ptr[ib->length_dw++] = ndw; | ||
748 | for (; ndw > 0; ndw -= 2, --count, pe += 8) { | ||
749 | value = amdgpu_vm_map_gart(pages_addr, addr); | ||
750 | addr += incr; | ||
751 | value |= flags; | ||
752 | ib->ptr[ib->length_dw++] = value; | ||
753 | ib->ptr[ib->length_dw++] = upper_32_bits(value); | ||
754 | } | ||
755 | } | 735 | } |
756 | } | 736 | } |
757 | 737 | ||
@@ -767,40 +747,21 @@ static void cik_sdma_vm_write_pte(struct amdgpu_ib *ib, | |||
767 | * | 747 | * |
768 | * Update the page tables using sDMA (CIK). | 748 | * Update the page tables using sDMA (CIK). |
769 | */ | 749 | */ |
770 | static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib, | 750 | static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe, |
771 | uint64_t pe, | ||
772 | uint64_t addr, unsigned count, | 751 | uint64_t addr, unsigned count, |
773 | uint32_t incr, uint32_t flags) | 752 | uint32_t incr, uint32_t flags) |
774 | { | 753 | { |
775 | uint64_t value; | 754 | /* for physically contiguous pages (vram) */ |
776 | unsigned ndw; | 755 | ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0); |
777 | 756 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); /* dst addr */ | |
778 | while (count) { | 757 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); |
779 | ndw = count; | 758 | ib->ptr[ib->length_dw++] = flags; /* mask */ |
780 | if (ndw > 0x7FFFF) | 759 | ib->ptr[ib->length_dw++] = 0; |
781 | ndw = 0x7FFFF; | 760 | ib->ptr[ib->length_dw++] = lower_32_bits(addr); /* value */ |
782 | 761 | ib->ptr[ib->length_dw++] = upper_32_bits(addr); | |
783 | if (flags & AMDGPU_PTE_VALID) | 762 | ib->ptr[ib->length_dw++] = incr; /* increment size */ |
784 | value = addr; | 763 | ib->ptr[ib->length_dw++] = 0; |
785 | else | 764 | ib->ptr[ib->length_dw++] = count; /* number of entries */ |
786 | value = 0; | ||
787 | |||
788 | /* for physically contiguous pages (vram) */ | ||
789 | ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0); | ||
790 | ib->ptr[ib->length_dw++] = pe; /* dst addr */ | ||
791 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
792 | ib->ptr[ib->length_dw++] = flags; /* mask */ | ||
793 | ib->ptr[ib->length_dw++] = 0; | ||
794 | ib->ptr[ib->length_dw++] = value; /* value */ | ||
795 | ib->ptr[ib->length_dw++] = upper_32_bits(value); | ||
796 | ib->ptr[ib->length_dw++] = incr; /* increment size */ | ||
797 | ib->ptr[ib->length_dw++] = 0; | ||
798 | ib->ptr[ib->length_dw++] = ndw; /* number of entries */ | ||
799 | |||
800 | pe += ndw * 8; | ||
801 | addr += ndw * incr; | ||
802 | count -= ndw; | ||
803 | } | ||
804 | } | 765 | } |
805 | 766 | ||
806 | /** | 767 | /** |
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c index 2a11413ed54a..794c5f36ca68 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c | |||
@@ -435,7 +435,11 @@ static int cz_dpm_init(struct amdgpu_device *adev) | |||
435 | pi->caps_td_ramping = true; | 435 | pi->caps_td_ramping = true; |
436 | pi->caps_tcp_ramping = true; | 436 | pi->caps_tcp_ramping = true; |
437 | } | 437 | } |
438 | pi->caps_sclk_ds = true; | 438 | if (amdgpu_sclk_deep_sleep_en) |
439 | pi->caps_sclk_ds = true; | ||
440 | else | ||
441 | pi->caps_sclk_ds = false; | ||
442 | |||
439 | pi->voting_clients = 0x00c00033; | 443 | pi->voting_clients = 0x00c00033; |
440 | pi->auto_thermal_throttling_enabled = true; | 444 | pi->auto_thermal_throttling_enabled = true; |
441 | pi->bapm_enabled = false; | 445 | pi->bapm_enabled = false; |
@@ -2108,29 +2112,58 @@ static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate) | |||
2108 | /* disable clockgating so we can properly shut down the block */ | 2112 | /* disable clockgating so we can properly shut down the block */ |
2109 | ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD, | 2113 | ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD, |
2110 | AMD_CG_STATE_UNGATE); | 2114 | AMD_CG_STATE_UNGATE); |
2115 | if (ret) { | ||
2116 | DRM_ERROR("UVD DPM Power Gating failed to set clockgating state\n"); | ||
2117 | return; | ||
2118 | } | ||
2119 | |||
2111 | /* shutdown the UVD block */ | 2120 | /* shutdown the UVD block */ |
2112 | ret = amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD, | 2121 | ret = amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD, |
2113 | AMD_PG_STATE_GATE); | 2122 | AMD_PG_STATE_GATE); |
2114 | /* XXX: check for errors */ | 2123 | |
2124 | if (ret) { | ||
2125 | DRM_ERROR("UVD DPM Power Gating failed to set powergating state\n"); | ||
2126 | return; | ||
2127 | } | ||
2115 | } | 2128 | } |
2116 | cz_update_uvd_dpm(adev, gate); | 2129 | cz_update_uvd_dpm(adev, gate); |
2117 | if (pi->caps_uvd_pg) | 2130 | if (pi->caps_uvd_pg) { |
2118 | /* power off the UVD block */ | 2131 | /* power off the UVD block */ |
2119 | cz_send_msg_to_smc(adev, PPSMC_MSG_UVDPowerOFF); | 2132 | ret = cz_send_msg_to_smc(adev, PPSMC_MSG_UVDPowerOFF); |
2133 | if (ret) { | ||
2134 | DRM_ERROR("UVD DPM Power Gating failed to send SMU PowerOFF message\n"); | ||
2135 | return; | ||
2136 | } | ||
2137 | } | ||
2120 | } else { | 2138 | } else { |
2121 | if (pi->caps_uvd_pg) { | 2139 | if (pi->caps_uvd_pg) { |
2122 | /* power on the UVD block */ | 2140 | /* power on the UVD block */ |
2123 | if (pi->uvd_dynamic_pg) | 2141 | if (pi->uvd_dynamic_pg) |
2124 | cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 1); | 2142 | ret = cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 1); |
2125 | else | 2143 | else |
2126 | cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 0); | 2144 | ret = cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 0); |
2145 | |||
2146 | if (ret) { | ||
2147 | DRM_ERROR("UVD DPM Power Gating Failed to send SMU PowerON message\n"); | ||
2148 | return; | ||
2149 | } | ||
2150 | |||
2127 | /* re-init the UVD block */ | 2151 | /* re-init the UVD block */ |
2128 | ret = amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD, | 2152 | ret = amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD, |
2129 | AMD_PG_STATE_UNGATE); | 2153 | AMD_PG_STATE_UNGATE); |
2154 | |||
2155 | if (ret) { | ||
2156 | DRM_ERROR("UVD DPM Power Gating Failed to set powergating state\n"); | ||
2157 | return; | ||
2158 | } | ||
2159 | |||
2130 | /* enable clockgating. hw will dynamically gate/ungate clocks on the fly */ | 2160 | /* enable clockgating. hw will dynamically gate/ungate clocks on the fly */ |
2131 | ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD, | 2161 | ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD, |
2132 | AMD_CG_STATE_GATE); | 2162 | AMD_CG_STATE_GATE); |
2133 | /* XXX: check for errors */ | 2163 | if (ret) { |
2164 | DRM_ERROR("UVD DPM Power Gating Failed to set clockgating state\n"); | ||
2165 | return; | ||
2166 | } | ||
2134 | } | 2167 | } |
2135 | cz_update_uvd_dpm(adev, gate); | 2168 | cz_update_uvd_dpm(adev, gate); |
2136 | } | 2169 | } |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 741da36cd8b6..bc5bb4eb9625 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | |||
@@ -646,8 +646,8 @@ static void dce_v10_0_resume_mc_access(struct amdgpu_device *adev, | |||
646 | 646 | ||
647 | if (save->crtc_enabled[i]) { | 647 | if (save->crtc_enabled[i]) { |
648 | tmp = RREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i]); | 648 | tmp = RREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i]); |
649 | if (REG_GET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE) != 3) { | 649 | if (REG_GET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE) != 0) { |
650 | tmp = REG_SET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE, 3); | 650 | tmp = REG_SET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE, 0); |
651 | WREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i], tmp); | 651 | WREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i], tmp); |
652 | } | 652 | } |
653 | tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]); | 653 | tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]); |
@@ -712,6 +712,45 @@ static void dce_v10_0_set_vga_render_state(struct amdgpu_device *adev, | |||
712 | WREG32(mmVGA_RENDER_CONTROL, tmp); | 712 | WREG32(mmVGA_RENDER_CONTROL, tmp); |
713 | } | 713 | } |
714 | 714 | ||
715 | static int dce_v10_0_get_num_crtc(struct amdgpu_device *adev) | ||
716 | { | ||
717 | int num_crtc = 0; | ||
718 | |||
719 | switch (adev->asic_type) { | ||
720 | case CHIP_FIJI: | ||
721 | case CHIP_TONGA: | ||
722 | num_crtc = 6; | ||
723 | break; | ||
724 | default: | ||
725 | num_crtc = 0; | ||
726 | } | ||
727 | return num_crtc; | ||
728 | } | ||
729 | |||
730 | void dce_v10_0_disable_dce(struct amdgpu_device *adev) | ||
731 | { | ||
732 | /*Disable VGA render and enabled crtc, if has DCE engine*/ | ||
733 | if (amdgpu_atombios_has_dce_engine_info(adev)) { | ||
734 | u32 tmp; | ||
735 | int crtc_enabled, i; | ||
736 | |||
737 | dce_v10_0_set_vga_render_state(adev, false); | ||
738 | |||
739 | /*Disable crtc*/ | ||
740 | for (i = 0; i < dce_v10_0_get_num_crtc(adev); i++) { | ||
741 | crtc_enabled = REG_GET_FIELD(RREG32(mmCRTC_CONTROL + crtc_offsets[i]), | ||
742 | CRTC_CONTROL, CRTC_MASTER_EN); | ||
743 | if (crtc_enabled) { | ||
744 | WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1); | ||
745 | tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]); | ||
746 | tmp = REG_SET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN, 0); | ||
747 | WREG32(mmCRTC_CONTROL + crtc_offsets[i], tmp); | ||
748 | WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0); | ||
749 | } | ||
750 | } | ||
751 | } | ||
752 | } | ||
753 | |||
715 | static void dce_v10_0_program_fmt(struct drm_encoder *encoder) | 754 | static void dce_v10_0_program_fmt(struct drm_encoder *encoder) |
716 | { | 755 | { |
717 | struct drm_device *dev = encoder->dev; | 756 | struct drm_device *dev = encoder->dev; |
@@ -2277,8 +2316,8 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, | |||
2277 | WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, | 2316 | WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, |
2278 | (viewport_w << 16) | viewport_h); | 2317 | (viewport_w << 16) | viewport_h); |
2279 | 2318 | ||
2280 | /* set pageflip to happen only at start of vblank interval (front porch) */ | 2319 | /* set pageflip to happen anywhere in vblank interval */ |
2281 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3); | 2320 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0); |
2282 | 2321 | ||
2283 | if (!atomic && fb && fb != crtc->primary->fb) { | 2322 | if (!atomic && fb && fb != crtc->primary->fb) { |
2284 | amdgpu_fb = to_amdgpu_framebuffer(fb); | 2323 | amdgpu_fb = to_amdgpu_framebuffer(fb); |
@@ -2700,7 +2739,7 @@ static const struct drm_crtc_funcs dce_v10_0_crtc_funcs = { | |||
2700 | .gamma_set = dce_v10_0_crtc_gamma_set, | 2739 | .gamma_set = dce_v10_0_crtc_gamma_set, |
2701 | .set_config = amdgpu_crtc_set_config, | 2740 | .set_config = amdgpu_crtc_set_config, |
2702 | .destroy = dce_v10_0_crtc_destroy, | 2741 | .destroy = dce_v10_0_crtc_destroy, |
2703 | .page_flip = amdgpu_crtc_page_flip, | 2742 | .page_flip_target = amdgpu_crtc_page_flip_target, |
2704 | }; | 2743 | }; |
2705 | 2744 | ||
2706 | static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode) | 2745 | static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode) |
@@ -2964,10 +3003,11 @@ static int dce_v10_0_early_init(void *handle) | |||
2964 | dce_v10_0_set_display_funcs(adev); | 3003 | dce_v10_0_set_display_funcs(adev); |
2965 | dce_v10_0_set_irq_funcs(adev); | 3004 | dce_v10_0_set_irq_funcs(adev); |
2966 | 3005 | ||
3006 | adev->mode_info.num_crtc = dce_v10_0_get_num_crtc(adev); | ||
3007 | |||
2967 | switch (adev->asic_type) { | 3008 | switch (adev->asic_type) { |
2968 | case CHIP_FIJI: | 3009 | case CHIP_FIJI: |
2969 | case CHIP_TONGA: | 3010 | case CHIP_TONGA: |
2970 | adev->mode_info.num_crtc = 6; /* XXX 7??? */ | ||
2971 | adev->mode_info.num_hpd = 6; | 3011 | adev->mode_info.num_hpd = 6; |
2972 | adev->mode_info.num_dig = 7; | 3012 | adev->mode_info.num_dig = 7; |
2973 | break; | 3013 | break; |
@@ -3143,11 +3183,26 @@ static int dce_v10_0_wait_for_idle(void *handle) | |||
3143 | return 0; | 3183 | return 0; |
3144 | } | 3184 | } |
3145 | 3185 | ||
3186 | static int dce_v10_0_check_soft_reset(void *handle) | ||
3187 | { | ||
3188 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
3189 | |||
3190 | if (dce_v10_0_is_display_hung(adev)) | ||
3191 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang = true; | ||
3192 | else | ||
3193 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang = false; | ||
3194 | |||
3195 | return 0; | ||
3196 | } | ||
3197 | |||
3146 | static int dce_v10_0_soft_reset(void *handle) | 3198 | static int dce_v10_0_soft_reset(void *handle) |
3147 | { | 3199 | { |
3148 | u32 srbm_soft_reset = 0, tmp; | 3200 | u32 srbm_soft_reset = 0, tmp; |
3149 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 3201 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
3150 | 3202 | ||
3203 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang) | ||
3204 | return 0; | ||
3205 | |||
3151 | if (dce_v10_0_is_display_hung(adev)) | 3206 | if (dce_v10_0_is_display_hung(adev)) |
3152 | srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; | 3207 | srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; |
3153 | 3208 | ||
@@ -3514,6 +3569,7 @@ const struct amd_ip_funcs dce_v10_0_ip_funcs = { | |||
3514 | .resume = dce_v10_0_resume, | 3569 | .resume = dce_v10_0_resume, |
3515 | .is_idle = dce_v10_0_is_idle, | 3570 | .is_idle = dce_v10_0_is_idle, |
3516 | .wait_for_idle = dce_v10_0_wait_for_idle, | 3571 | .wait_for_idle = dce_v10_0_wait_for_idle, |
3572 | .check_soft_reset = dce_v10_0_check_soft_reset, | ||
3517 | .soft_reset = dce_v10_0_soft_reset, | 3573 | .soft_reset = dce_v10_0_soft_reset, |
3518 | .set_clockgating_state = dce_v10_0_set_clockgating_state, | 3574 | .set_clockgating_state = dce_v10_0_set_clockgating_state, |
3519 | .set_powergating_state = dce_v10_0_set_powergating_state, | 3575 | .set_powergating_state = dce_v10_0_set_powergating_state, |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.h b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.h index 1bfa48ddd8a6..e3dc04d293e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.h +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.h | |||
@@ -26,4 +26,6 @@ | |||
26 | 26 | ||
27 | extern const struct amd_ip_funcs dce_v10_0_ip_funcs; | 27 | extern const struct amd_ip_funcs dce_v10_0_ip_funcs; |
28 | 28 | ||
29 | void dce_v10_0_disable_dce(struct amdgpu_device *adev); | ||
30 | |||
29 | #endif | 31 | #endif |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 2282eb60aba6..b93eba077950 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | |||
@@ -673,6 +673,53 @@ static void dce_v11_0_set_vga_render_state(struct amdgpu_device *adev, | |||
673 | WREG32(mmVGA_RENDER_CONTROL, tmp); | 673 | WREG32(mmVGA_RENDER_CONTROL, tmp); |
674 | } | 674 | } |
675 | 675 | ||
676 | static int dce_v11_0_get_num_crtc (struct amdgpu_device *adev) | ||
677 | { | ||
678 | int num_crtc = 0; | ||
679 | |||
680 | switch (adev->asic_type) { | ||
681 | case CHIP_CARRIZO: | ||
682 | num_crtc = 3; | ||
683 | break; | ||
684 | case CHIP_STONEY: | ||
685 | num_crtc = 2; | ||
686 | break; | ||
687 | case CHIP_POLARIS10: | ||
688 | num_crtc = 6; | ||
689 | break; | ||
690 | case CHIP_POLARIS11: | ||
691 | num_crtc = 5; | ||
692 | break; | ||
693 | default: | ||
694 | num_crtc = 0; | ||
695 | } | ||
696 | return num_crtc; | ||
697 | } | ||
698 | |||
699 | void dce_v11_0_disable_dce(struct amdgpu_device *adev) | ||
700 | { | ||
701 | /*Disable VGA render and enabled crtc, if has DCE engine*/ | ||
702 | if (amdgpu_atombios_has_dce_engine_info(adev)) { | ||
703 | u32 tmp; | ||
704 | int crtc_enabled, i; | ||
705 | |||
706 | dce_v11_0_set_vga_render_state(adev, false); | ||
707 | |||
708 | /*Disable crtc*/ | ||
709 | for (i = 0; i < dce_v11_0_get_num_crtc(adev); i++) { | ||
710 | crtc_enabled = REG_GET_FIELD(RREG32(mmCRTC_CONTROL + crtc_offsets[i]), | ||
711 | CRTC_CONTROL, CRTC_MASTER_EN); | ||
712 | if (crtc_enabled) { | ||
713 | WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1); | ||
714 | tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]); | ||
715 | tmp = REG_SET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN, 0); | ||
716 | WREG32(mmCRTC_CONTROL + crtc_offsets[i], tmp); | ||
717 | WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0); | ||
718 | } | ||
719 | } | ||
720 | } | ||
721 | } | ||
722 | |||
676 | static void dce_v11_0_program_fmt(struct drm_encoder *encoder) | 723 | static void dce_v11_0_program_fmt(struct drm_encoder *encoder) |
677 | { | 724 | { |
678 | struct drm_device *dev = encoder->dev; | 725 | struct drm_device *dev = encoder->dev; |
@@ -2252,8 +2299,8 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, | |||
2252 | WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, | 2299 | WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, |
2253 | (viewport_w << 16) | viewport_h); | 2300 | (viewport_w << 16) | viewport_h); |
2254 | 2301 | ||
2255 | /* set pageflip to happen only at start of vblank interval (front porch) */ | 2302 | /* set pageflip to happen anywhere in vblank interval */ |
2256 | WREG32(mmCRTC_MASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3); | 2303 | WREG32(mmCRTC_MASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0); |
2257 | 2304 | ||
2258 | if (!atomic && fb && fb != crtc->primary->fb) { | 2305 | if (!atomic && fb && fb != crtc->primary->fb) { |
2259 | amdgpu_fb = to_amdgpu_framebuffer(fb); | 2306 | amdgpu_fb = to_amdgpu_framebuffer(fb); |
@@ -2710,7 +2757,7 @@ static const struct drm_crtc_funcs dce_v11_0_crtc_funcs = { | |||
2710 | .gamma_set = dce_v11_0_crtc_gamma_set, | 2757 | .gamma_set = dce_v11_0_crtc_gamma_set, |
2711 | .set_config = amdgpu_crtc_set_config, | 2758 | .set_config = amdgpu_crtc_set_config, |
2712 | .destroy = dce_v11_0_crtc_destroy, | 2759 | .destroy = dce_v11_0_crtc_destroy, |
2713 | .page_flip = amdgpu_crtc_page_flip, | 2760 | .page_flip_target = amdgpu_crtc_page_flip_target, |
2714 | }; | 2761 | }; |
2715 | 2762 | ||
2716 | static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode) | 2763 | static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode) |
@@ -3001,24 +3048,22 @@ static int dce_v11_0_early_init(void *handle) | |||
3001 | dce_v11_0_set_display_funcs(adev); | 3048 | dce_v11_0_set_display_funcs(adev); |
3002 | dce_v11_0_set_irq_funcs(adev); | 3049 | dce_v11_0_set_irq_funcs(adev); |
3003 | 3050 | ||
3051 | adev->mode_info.num_crtc = dce_v11_0_get_num_crtc(adev); | ||
3052 | |||
3004 | switch (adev->asic_type) { | 3053 | switch (adev->asic_type) { |
3005 | case CHIP_CARRIZO: | 3054 | case CHIP_CARRIZO: |
3006 | adev->mode_info.num_crtc = 3; | ||
3007 | adev->mode_info.num_hpd = 6; | 3055 | adev->mode_info.num_hpd = 6; |
3008 | adev->mode_info.num_dig = 9; | 3056 | adev->mode_info.num_dig = 9; |
3009 | break; | 3057 | break; |
3010 | case CHIP_STONEY: | 3058 | case CHIP_STONEY: |
3011 | adev->mode_info.num_crtc = 2; | ||
3012 | adev->mode_info.num_hpd = 6; | 3059 | adev->mode_info.num_hpd = 6; |
3013 | adev->mode_info.num_dig = 9; | 3060 | adev->mode_info.num_dig = 9; |
3014 | break; | 3061 | break; |
3015 | case CHIP_POLARIS10: | 3062 | case CHIP_POLARIS10: |
3016 | adev->mode_info.num_crtc = 6; | ||
3017 | adev->mode_info.num_hpd = 6; | 3063 | adev->mode_info.num_hpd = 6; |
3018 | adev->mode_info.num_dig = 6; | 3064 | adev->mode_info.num_dig = 6; |
3019 | break; | 3065 | break; |
3020 | case CHIP_POLARIS11: | 3066 | case CHIP_POLARIS11: |
3021 | adev->mode_info.num_crtc = 5; | ||
3022 | adev->mode_info.num_hpd = 5; | 3067 | adev->mode_info.num_hpd = 5; |
3023 | adev->mode_info.num_dig = 5; | 3068 | adev->mode_info.num_dig = 5; |
3024 | break; | 3069 | break; |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.h b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.h index 84e4618f5253..1f58a65ba2ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.h +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.h | |||
@@ -26,4 +26,6 @@ | |||
26 | 26 | ||
27 | extern const struct amd_ip_funcs dce_v11_0_ip_funcs; | 27 | extern const struct amd_ip_funcs dce_v11_0_ip_funcs; |
28 | 28 | ||
29 | void dce_v11_0_disable_dce(struct amdgpu_device *adev); | ||
30 | |||
29 | #endif | 31 | #endif |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 8b7ad345771f..abd5213dfe18 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | |||
@@ -604,6 +604,52 @@ static void dce_v8_0_set_vga_render_state(struct amdgpu_device *adev, | |||
604 | WREG32(mmVGA_RENDER_CONTROL, tmp); | 604 | WREG32(mmVGA_RENDER_CONTROL, tmp); |
605 | } | 605 | } |
606 | 606 | ||
607 | static int dce_v8_0_get_num_crtc(struct amdgpu_device *adev) | ||
608 | { | ||
609 | int num_crtc = 0; | ||
610 | |||
611 | switch (adev->asic_type) { | ||
612 | case CHIP_BONAIRE: | ||
613 | case CHIP_HAWAII: | ||
614 | num_crtc = 6; | ||
615 | break; | ||
616 | case CHIP_KAVERI: | ||
617 | num_crtc = 4; | ||
618 | break; | ||
619 | case CHIP_KABINI: | ||
620 | case CHIP_MULLINS: | ||
621 | num_crtc = 2; | ||
622 | break; | ||
623 | default: | ||
624 | num_crtc = 0; | ||
625 | } | ||
626 | return num_crtc; | ||
627 | } | ||
628 | |||
629 | void dce_v8_0_disable_dce(struct amdgpu_device *adev) | ||
630 | { | ||
631 | /*Disable VGA render and enabled crtc, if has DCE engine*/ | ||
632 | if (amdgpu_atombios_has_dce_engine_info(adev)) { | ||
633 | u32 tmp; | ||
634 | int crtc_enabled, i; | ||
635 | |||
636 | dce_v8_0_set_vga_render_state(adev, false); | ||
637 | |||
638 | /*Disable crtc*/ | ||
639 | for (i = 0; i < dce_v8_0_get_num_crtc(adev); i++) { | ||
640 | crtc_enabled = REG_GET_FIELD(RREG32(mmCRTC_CONTROL + crtc_offsets[i]), | ||
641 | CRTC_CONTROL, CRTC_MASTER_EN); | ||
642 | if (crtc_enabled) { | ||
643 | WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1); | ||
644 | tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]); | ||
645 | tmp = REG_SET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN, 0); | ||
646 | WREG32(mmCRTC_CONTROL + crtc_offsets[i], tmp); | ||
647 | WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0); | ||
648 | } | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | |||
607 | static void dce_v8_0_program_fmt(struct drm_encoder *encoder) | 653 | static void dce_v8_0_program_fmt(struct drm_encoder *encoder) |
608 | { | 654 | { |
609 | struct drm_device *dev = encoder->dev; | 655 | struct drm_device *dev = encoder->dev; |
@@ -1501,13 +1547,13 @@ static void dce_v8_0_audio_write_sad_regs(struct drm_encoder *encoder) | |||
1501 | 1547 | ||
1502 | if (sad->format == eld_reg_to_type[i][1]) { | 1548 | if (sad->format == eld_reg_to_type[i][1]) { |
1503 | if (sad->channels > max_channels) { | 1549 | if (sad->channels > max_channels) { |
1504 | value = (sad->channels << | 1550 | value = (sad->channels << |
1505 | AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__MAX_CHANNELS__SHIFT) | | 1551 | AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__MAX_CHANNELS__SHIFT) | |
1506 | (sad->byte2 << | 1552 | (sad->byte2 << |
1507 | AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__DESCRIPTOR_BYTE_2__SHIFT) | | 1553 | AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__DESCRIPTOR_BYTE_2__SHIFT) | |
1508 | (sad->freq << | 1554 | (sad->freq << |
1509 | AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__SUPPORTED_FREQUENCIES__SHIFT); | 1555 | AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0__SUPPORTED_FREQUENCIES__SHIFT); |
1510 | max_channels = sad->channels; | 1556 | max_channels = sad->channels; |
1511 | } | 1557 | } |
1512 | 1558 | ||
1513 | if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) | 1559 | if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) |
@@ -1613,7 +1659,7 @@ static void dce_v8_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock | |||
1613 | struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; | 1659 | struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; |
1614 | uint32_t offset = dig->afmt->offset; | 1660 | uint32_t offset = dig->afmt->offset; |
1615 | 1661 | ||
1616 | WREG32(mmHDMI_ACR_32_0 + offset, (acr.cts_32khz << HDMI_ACR_44_0__HDMI_ACR_CTS_44__SHIFT)); | 1662 | WREG32(mmHDMI_ACR_32_0 + offset, (acr.cts_32khz << HDMI_ACR_32_0__HDMI_ACR_CTS_32__SHIFT)); |
1617 | WREG32(mmHDMI_ACR_32_1 + offset, acr.n_32khz); | 1663 | WREG32(mmHDMI_ACR_32_1 + offset, acr.n_32khz); |
1618 | 1664 | ||
1619 | WREG32(mmHDMI_ACR_44_0 + offset, (acr.cts_44_1khz << HDMI_ACR_44_0__HDMI_ACR_CTS_44__SHIFT)); | 1665 | WREG32(mmHDMI_ACR_44_0 + offset, (acr.cts_44_1khz << HDMI_ACR_44_0__HDMI_ACR_CTS_44__SHIFT)); |
@@ -1693,6 +1739,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder, | |||
1693 | /* Silent, r600_hdmi_enable will raise WARN for us */ | 1739 | /* Silent, r600_hdmi_enable will raise WARN for us */ |
1694 | if (!dig->afmt->enabled) | 1740 | if (!dig->afmt->enabled) |
1695 | return; | 1741 | return; |
1742 | |||
1696 | offset = dig->afmt->offset; | 1743 | offset = dig->afmt->offset; |
1697 | 1744 | ||
1698 | /* hdmi deep color mode general control packets setup, if bpc > 8 */ | 1745 | /* hdmi deep color mode general control packets setup, if bpc > 8 */ |
@@ -1817,7 +1864,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder, | |||
1817 | 1864 | ||
1818 | WREG32_OR(mmHDMI_INFOFRAME_CONTROL0 + offset, | 1865 | WREG32_OR(mmHDMI_INFOFRAME_CONTROL0 + offset, |
1819 | HDMI_INFOFRAME_CONTROL0__HDMI_AVI_INFO_SEND_MASK | /* enable AVI info frames */ | 1866 | HDMI_INFOFRAME_CONTROL0__HDMI_AVI_INFO_SEND_MASK | /* enable AVI info frames */ |
1820 | HDMI_INFOFRAME_CONTROL0__HDMI_AVI_INFO_SEND_MASK); /* required for audio info values to be updated */ | 1867 | HDMI_INFOFRAME_CONTROL0__HDMI_AVI_INFO_CONT_MASK); /* required for audio info values to be updated */ |
1821 | 1868 | ||
1822 | WREG32_P(mmHDMI_INFOFRAME_CONTROL1 + offset, | 1869 | WREG32_P(mmHDMI_INFOFRAME_CONTROL1 + offset, |
1823 | (2 << HDMI_INFOFRAME_CONTROL1__HDMI_AVI_INFO_LINE__SHIFT), /* anything other than 0 */ | 1870 | (2 << HDMI_INFOFRAME_CONTROL1__HDMI_AVI_INFO_LINE__SHIFT), /* anything other than 0 */ |
@@ -1826,13 +1873,12 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder, | |||
1826 | WREG32_OR(mmAFMT_AUDIO_PACKET_CONTROL + offset, | 1873 | WREG32_OR(mmAFMT_AUDIO_PACKET_CONTROL + offset, |
1827 | AFMT_AUDIO_PACKET_CONTROL__AFMT_AUDIO_SAMPLE_SEND_MASK); /* send audio packets */ | 1874 | AFMT_AUDIO_PACKET_CONTROL__AFMT_AUDIO_SAMPLE_SEND_MASK); /* send audio packets */ |
1828 | 1875 | ||
1829 | /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ | ||
1830 | WREG32(mmAFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF); | 1876 | WREG32(mmAFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF); |
1831 | WREG32(mmAFMT_RAMP_CONTROL1 + offset, 0x007FFFFF); | 1877 | WREG32(mmAFMT_RAMP_CONTROL1 + offset, 0x007FFFFF); |
1832 | WREG32(mmAFMT_RAMP_CONTROL2 + offset, 0x00000001); | 1878 | WREG32(mmAFMT_RAMP_CONTROL2 + offset, 0x00000001); |
1833 | WREG32(mmAFMT_RAMP_CONTROL3 + offset, 0x00000001); | 1879 | WREG32(mmAFMT_RAMP_CONTROL3 + offset, 0x00000001); |
1834 | 1880 | ||
1835 | /* enable audio after to setting up hw */ | 1881 | /* enable audio after setting up hw */ |
1836 | dce_v8_0_audio_enable(adev, dig->afmt->pin, true); | 1882 | dce_v8_0_audio_enable(adev, dig->afmt->pin, true); |
1837 | } | 1883 | } |
1838 | 1884 | ||
@@ -2000,7 +2046,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, | |||
2000 | case DRM_FORMAT_XRGB4444: | 2046 | case DRM_FORMAT_XRGB4444: |
2001 | case DRM_FORMAT_ARGB4444: | 2047 | case DRM_FORMAT_ARGB4444: |
2002 | fb_format = ((GRPH_DEPTH_16BPP << GRPH_CONTROL__GRPH_DEPTH__SHIFT) | | 2048 | fb_format = ((GRPH_DEPTH_16BPP << GRPH_CONTROL__GRPH_DEPTH__SHIFT) | |
2003 | (GRPH_FORMAT_ARGB1555 << GRPH_CONTROL__GRPH_FORMAT__SHIFT)); | 2049 | (GRPH_FORMAT_ARGB4444 << GRPH_CONTROL__GRPH_FORMAT__SHIFT)); |
2004 | #ifdef __BIG_ENDIAN | 2050 | #ifdef __BIG_ENDIAN |
2005 | fb_swap = (GRPH_ENDIAN_8IN16 << GRPH_SWAP_CNTL__GRPH_ENDIAN_SWAP__SHIFT); | 2051 | fb_swap = (GRPH_ENDIAN_8IN16 << GRPH_SWAP_CNTL__GRPH_ENDIAN_SWAP__SHIFT); |
2006 | #endif | 2052 | #endif |
@@ -2139,8 +2185,8 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, | |||
2139 | WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, | 2185 | WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, |
2140 | (viewport_w << 16) | viewport_h); | 2186 | (viewport_w << 16) | viewport_h); |
2141 | 2187 | ||
2142 | /* set pageflip to happen only at start of vblank interval (front porch) */ | 2188 | /* set pageflip to happen anywhere in vblank interval */ |
2143 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3); | 2189 | WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 0); |
2144 | 2190 | ||
2145 | if (!atomic && fb && fb != crtc->primary->fb) { | 2191 | if (!atomic && fb && fb != crtc->primary->fb) { |
2146 | amdgpu_fb = to_amdgpu_framebuffer(fb); | 2192 | amdgpu_fb = to_amdgpu_framebuffer(fb); |
@@ -2554,7 +2600,7 @@ static const struct drm_crtc_funcs dce_v8_0_crtc_funcs = { | |||
2554 | .gamma_set = dce_v8_0_crtc_gamma_set, | 2600 | .gamma_set = dce_v8_0_crtc_gamma_set, |
2555 | .set_config = amdgpu_crtc_set_config, | 2601 | .set_config = amdgpu_crtc_set_config, |
2556 | .destroy = dce_v8_0_crtc_destroy, | 2602 | .destroy = dce_v8_0_crtc_destroy, |
2557 | .page_flip = amdgpu_crtc_page_flip, | 2603 | .page_flip_target = amdgpu_crtc_page_flip_target, |
2558 | }; | 2604 | }; |
2559 | 2605 | ||
2560 | static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode) | 2606 | static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode) |
@@ -2655,7 +2701,7 @@ static void dce_v8_0_crtc_disable(struct drm_crtc *crtc) | |||
2655 | case ATOM_PPLL2: | 2701 | case ATOM_PPLL2: |
2656 | /* disable the ppll */ | 2702 | /* disable the ppll */ |
2657 | amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id, | 2703 | amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id, |
2658 | 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); | 2704 | 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); |
2659 | break; | 2705 | break; |
2660 | case ATOM_PPLL0: | 2706 | case ATOM_PPLL0: |
2661 | /* disable the ppll */ | 2707 | /* disable the ppll */ |
@@ -2805,21 +2851,20 @@ static int dce_v8_0_early_init(void *handle) | |||
2805 | dce_v8_0_set_display_funcs(adev); | 2851 | dce_v8_0_set_display_funcs(adev); |
2806 | dce_v8_0_set_irq_funcs(adev); | 2852 | dce_v8_0_set_irq_funcs(adev); |
2807 | 2853 | ||
2854 | adev->mode_info.num_crtc = dce_v8_0_get_num_crtc(adev); | ||
2855 | |||
2808 | switch (adev->asic_type) { | 2856 | switch (adev->asic_type) { |
2809 | case CHIP_BONAIRE: | 2857 | case CHIP_BONAIRE: |
2810 | case CHIP_HAWAII: | 2858 | case CHIP_HAWAII: |
2811 | adev->mode_info.num_crtc = 6; | ||
2812 | adev->mode_info.num_hpd = 6; | 2859 | adev->mode_info.num_hpd = 6; |
2813 | adev->mode_info.num_dig = 6; | 2860 | adev->mode_info.num_dig = 6; |
2814 | break; | 2861 | break; |
2815 | case CHIP_KAVERI: | 2862 | case CHIP_KAVERI: |
2816 | adev->mode_info.num_crtc = 4; | ||
2817 | adev->mode_info.num_hpd = 6; | 2863 | adev->mode_info.num_hpd = 6; |
2818 | adev->mode_info.num_dig = 7; | 2864 | adev->mode_info.num_dig = 7; |
2819 | break; | 2865 | break; |
2820 | case CHIP_KABINI: | 2866 | case CHIP_KABINI: |
2821 | case CHIP_MULLINS: | 2867 | case CHIP_MULLINS: |
2822 | adev->mode_info.num_crtc = 2; | ||
2823 | adev->mode_info.num_hpd = 6; | 2868 | adev->mode_info.num_hpd = 6; |
2824 | adev->mode_info.num_dig = 6; /* ? */ | 2869 | adev->mode_info.num_dig = 6; /* ? */ |
2825 | break; | 2870 | break; |
@@ -3238,7 +3283,6 @@ static int dce_v8_0_crtc_irq(struct amdgpu_device *adev, | |||
3238 | drm_handle_vblank(adev->ddev, crtc); | 3283 | drm_handle_vblank(adev->ddev, crtc); |
3239 | } | 3284 | } |
3240 | DRM_DEBUG("IH: D%d vblank\n", crtc + 1); | 3285 | DRM_DEBUG("IH: D%d vblank\n", crtc + 1); |
3241 | |||
3242 | break; | 3286 | break; |
3243 | case 1: /* vline */ | 3287 | case 1: /* vline */ |
3244 | if (disp_int & interrupt_status_offsets[crtc].vline) | 3288 | if (disp_int & interrupt_status_offsets[crtc].vline) |
@@ -3247,7 +3291,6 @@ static int dce_v8_0_crtc_irq(struct amdgpu_device *adev, | |||
3247 | DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); | 3291 | DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); |
3248 | 3292 | ||
3249 | DRM_DEBUG("IH: D%d vline\n", crtc + 1); | 3293 | DRM_DEBUG("IH: D%d vline\n", crtc + 1); |
3250 | |||
3251 | break; | 3294 | break; |
3252 | default: | 3295 | default: |
3253 | DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); | 3296 | DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.h b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.h index 77016852b252..7d0770c3a49b 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.h +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.h | |||
@@ -26,4 +26,6 @@ | |||
26 | 26 | ||
27 | extern const struct amd_ip_funcs dce_v8_0_ip_funcs; | 27 | extern const struct amd_ip_funcs dce_v8_0_ip_funcs; |
28 | 28 | ||
29 | void dce_v8_0_disable_dce(struct amdgpu_device *adev); | ||
30 | |||
29 | #endif | 31 | #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 index 000000000000..00663a7b4053 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c | |||
@@ -0,0 +1,806 @@ | |||
1 | /* | ||
2 | * Copyright 2014 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #include "drmP.h" | ||
24 | #include "amdgpu.h" | ||
25 | #include "amdgpu_pm.h" | ||
26 | #include "amdgpu_i2c.h" | ||
27 | #include "atom.h" | ||
28 | #include "amdgpu_pll.h" | ||
29 | #include "amdgpu_connectors.h" | ||
30 | #ifdef CONFIG_DRM_AMDGPU_CIK | ||
31 | #include "dce_v8_0.h" | ||
32 | #endif | ||
33 | #include "dce_v10_0.h" | ||
34 | #include "dce_v11_0.h" | ||
35 | #include "dce_virtual.h" | ||
36 | |||
37 | static void dce_virtual_set_display_funcs(struct amdgpu_device *adev); | ||
38 | static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev); | ||
39 | static int dce_virtual_pageflip_irq(struct amdgpu_device *adev, | ||
40 | struct amdgpu_irq_src *source, | ||
41 | struct amdgpu_iv_entry *entry); | ||
42 | |||
43 | /** | ||
44 | * dce_virtual_vblank_wait - vblank wait asic callback. | ||
45 | * | ||
46 | * @adev: amdgpu_device pointer | ||
47 | * @crtc: crtc to wait for vblank on | ||
48 | * | ||
49 | * Wait for vblank on the requested crtc (evergreen+). | ||
50 | */ | ||
51 | static void dce_virtual_vblank_wait(struct amdgpu_device *adev, int crtc) | ||
52 | { | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | static u32 dce_virtual_vblank_get_counter(struct amdgpu_device *adev, int crtc) | ||
57 | { | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static void dce_virtual_page_flip(struct amdgpu_device *adev, | ||
62 | int crtc_id, u64 crtc_base, bool async) | ||
63 | { | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | static int dce_virtual_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, | ||
68 | u32 *vbl, u32 *position) | ||
69 | { | ||
70 | *vbl = 0; | ||
71 | *position = 0; | ||
72 | |||
73 | return -EINVAL; | ||
74 | } | ||
75 | |||
76 | static bool dce_virtual_hpd_sense(struct amdgpu_device *adev, | ||
77 | enum amdgpu_hpd_id hpd) | ||
78 | { | ||
79 | return true; | ||
80 | } | ||
81 | |||
82 | static void dce_virtual_hpd_set_polarity(struct amdgpu_device *adev, | ||
83 | enum amdgpu_hpd_id hpd) | ||
84 | { | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | static u32 dce_virtual_hpd_get_gpio_reg(struct amdgpu_device *adev) | ||
89 | { | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static bool dce_virtual_is_display_hung(struct amdgpu_device *adev) | ||
94 | { | ||
95 | return false; | ||
96 | } | ||
97 | |||
98 | void dce_virtual_stop_mc_access(struct amdgpu_device *adev, | ||
99 | struct amdgpu_mode_mc_save *save) | ||
100 | { | ||
101 | switch (adev->asic_type) { | ||
102 | case CHIP_BONAIRE: | ||
103 | case CHIP_HAWAII: | ||
104 | case CHIP_KAVERI: | ||
105 | case CHIP_KABINI: | ||
106 | case CHIP_MULLINS: | ||
107 | #ifdef CONFIG_DRM_AMDGPU_CIK | ||
108 | dce_v8_0_disable_dce(adev); | ||
109 | #endif | ||
110 | break; | ||
111 | case CHIP_FIJI: | ||
112 | case CHIP_TONGA: | ||
113 | dce_v10_0_disable_dce(adev); | ||
114 | break; | ||
115 | case CHIP_CARRIZO: | ||
116 | case CHIP_STONEY: | ||
117 | case CHIP_POLARIS11: | ||
118 | case CHIP_POLARIS10: | ||
119 | dce_v11_0_disable_dce(adev); | ||
120 | break; | ||
121 | case CHIP_TOPAZ: | ||
122 | /* no DCE */ | ||
123 | return; | ||
124 | default: | ||
125 | DRM_ERROR("Virtual display unsupported ASIC type: 0x%X\n", adev->asic_type); | ||
126 | } | ||
127 | |||
128 | return; | ||
129 | } | ||
130 | void dce_virtual_resume_mc_access(struct amdgpu_device *adev, | ||
131 | struct amdgpu_mode_mc_save *save) | ||
132 | { | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | void dce_virtual_set_vga_render_state(struct amdgpu_device *adev, | ||
137 | bool render) | ||
138 | { | ||
139 | return; | ||
140 | } | ||
141 | |||
142 | /** | ||
143 | * dce_virtual_bandwidth_update - program display watermarks | ||
144 | * | ||
145 | * @adev: amdgpu_device pointer | ||
146 | * | ||
147 | * Calculate and program the display watermarks and line | ||
148 | * buffer allocation (CIK). | ||
149 | */ | ||
150 | static void dce_virtual_bandwidth_update(struct amdgpu_device *adev) | ||
151 | { | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | static int dce_virtual_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, | ||
156 | u16 *green, u16 *blue, uint32_t size) | ||
157 | { | ||
158 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | ||
159 | int i; | ||
160 | |||
161 | /* userspace palettes are always correct as is */ | ||
162 | for (i = 0; i < size; i++) { | ||
163 | amdgpu_crtc->lut_r[i] = red[i] >> 6; | ||
164 | amdgpu_crtc->lut_g[i] = green[i] >> 6; | ||
165 | amdgpu_crtc->lut_b[i] = blue[i] >> 6; | ||
166 | } | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static void dce_virtual_crtc_destroy(struct drm_crtc *crtc) | ||
172 | { | ||
173 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | ||
174 | |||
175 | drm_crtc_cleanup(crtc); | ||
176 | kfree(amdgpu_crtc); | ||
177 | } | ||
178 | |||
179 | static const struct drm_crtc_funcs dce_virtual_crtc_funcs = { | ||
180 | .cursor_set2 = NULL, | ||
181 | .cursor_move = NULL, | ||
182 | .gamma_set = dce_virtual_crtc_gamma_set, | ||
183 | .set_config = amdgpu_crtc_set_config, | ||
184 | .destroy = dce_virtual_crtc_destroy, | ||
185 | .page_flip_target = amdgpu_crtc_page_flip_target, | ||
186 | }; | ||
187 | |||
188 | static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
189 | { | ||
190 | struct drm_device *dev = crtc->dev; | ||
191 | struct amdgpu_device *adev = dev->dev_private; | ||
192 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | ||
193 | unsigned type; | ||
194 | |||
195 | switch (mode) { | ||
196 | case DRM_MODE_DPMS_ON: | ||
197 | amdgpu_crtc->enabled = true; | ||
198 | /* Make sure VBLANK and PFLIP interrupts are still enabled */ | ||
199 | type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); | ||
200 | amdgpu_irq_update(adev, &adev->crtc_irq, type); | ||
201 | amdgpu_irq_update(adev, &adev->pageflip_irq, type); | ||
202 | drm_vblank_on(dev, amdgpu_crtc->crtc_id); | ||
203 | break; | ||
204 | case DRM_MODE_DPMS_STANDBY: | ||
205 | case DRM_MODE_DPMS_SUSPEND: | ||
206 | case DRM_MODE_DPMS_OFF: | ||
207 | drm_vblank_off(dev, amdgpu_crtc->crtc_id); | ||
208 | amdgpu_crtc->enabled = false; | ||
209 | break; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | |||
214 | static void dce_virtual_crtc_prepare(struct drm_crtc *crtc) | ||
215 | { | ||
216 | dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | ||
217 | } | ||
218 | |||
219 | static void dce_virtual_crtc_commit(struct drm_crtc *crtc) | ||
220 | { | ||
221 | dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_ON); | ||
222 | } | ||
223 | |||
224 | static void dce_virtual_crtc_disable(struct drm_crtc *crtc) | ||
225 | { | ||
226 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | ||
227 | |||
228 | dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | ||
229 | if (crtc->primary->fb) { | ||
230 | int r; | ||
231 | struct amdgpu_framebuffer *amdgpu_fb; | ||
232 | struct amdgpu_bo *rbo; | ||
233 | |||
234 | amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb); | ||
235 | rbo = gem_to_amdgpu_bo(amdgpu_fb->obj); | ||
236 | r = amdgpu_bo_reserve(rbo, false); | ||
237 | if (unlikely(r)) | ||
238 | DRM_ERROR("failed to reserve rbo before unpin\n"); | ||
239 | else { | ||
240 | amdgpu_bo_unpin(rbo); | ||
241 | amdgpu_bo_unreserve(rbo); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | amdgpu_crtc->pll_id = ATOM_PPLL_INVALID; | ||
246 | amdgpu_crtc->encoder = NULL; | ||
247 | amdgpu_crtc->connector = NULL; | ||
248 | } | ||
249 | |||
250 | static int dce_virtual_crtc_mode_set(struct drm_crtc *crtc, | ||
251 | struct drm_display_mode *mode, | ||
252 | struct drm_display_mode *adjusted_mode, | ||
253 | int x, int y, struct drm_framebuffer *old_fb) | ||
254 | { | ||
255 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | ||
256 | |||
257 | /* update the hw version fpr dpm */ | ||
258 | amdgpu_crtc->hw_mode = *adjusted_mode; | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static bool dce_virtual_crtc_mode_fixup(struct drm_crtc *crtc, | ||
264 | const struct drm_display_mode *mode, | ||
265 | struct drm_display_mode *adjusted_mode) | ||
266 | { | ||
267 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | ||
268 | struct drm_device *dev = crtc->dev; | ||
269 | struct drm_encoder *encoder; | ||
270 | |||
271 | /* assign the encoder to the amdgpu crtc to avoid repeated lookups later */ | ||
272 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
273 | if (encoder->crtc == crtc) { | ||
274 | amdgpu_crtc->encoder = encoder; | ||
275 | amdgpu_crtc->connector = amdgpu_get_connector_for_encoder(encoder); | ||
276 | break; | ||
277 | } | ||
278 | } | ||
279 | if ((amdgpu_crtc->encoder == NULL) || (amdgpu_crtc->connector == NULL)) { | ||
280 | amdgpu_crtc->encoder = NULL; | ||
281 | amdgpu_crtc->connector = NULL; | ||
282 | return false; | ||
283 | } | ||
284 | |||
285 | return true; | ||
286 | } | ||
287 | |||
288 | |||
289 | static int dce_virtual_crtc_set_base(struct drm_crtc *crtc, int x, int y, | ||
290 | struct drm_framebuffer *old_fb) | ||
291 | { | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static void dce_virtual_crtc_load_lut(struct drm_crtc *crtc) | ||
296 | { | ||
297 | return; | ||
298 | } | ||
299 | |||
300 | static int dce_virtual_crtc_set_base_atomic(struct drm_crtc *crtc, | ||
301 | struct drm_framebuffer *fb, | ||
302 | int x, int y, enum mode_set_atomic state) | ||
303 | { | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static const struct drm_crtc_helper_funcs dce_virtual_crtc_helper_funcs = { | ||
308 | .dpms = dce_virtual_crtc_dpms, | ||
309 | .mode_fixup = dce_virtual_crtc_mode_fixup, | ||
310 | .mode_set = dce_virtual_crtc_mode_set, | ||
311 | .mode_set_base = dce_virtual_crtc_set_base, | ||
312 | .mode_set_base_atomic = dce_virtual_crtc_set_base_atomic, | ||
313 | .prepare = dce_virtual_crtc_prepare, | ||
314 | .commit = dce_virtual_crtc_commit, | ||
315 | .load_lut = dce_virtual_crtc_load_lut, | ||
316 | .disable = dce_virtual_crtc_disable, | ||
317 | }; | ||
318 | |||
319 | static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index) | ||
320 | { | ||
321 | struct amdgpu_crtc *amdgpu_crtc; | ||
322 | int i; | ||
323 | |||
324 | amdgpu_crtc = kzalloc(sizeof(struct amdgpu_crtc) + | ||
325 | (AMDGPUFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); | ||
326 | if (amdgpu_crtc == NULL) | ||
327 | return -ENOMEM; | ||
328 | |||
329 | drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_virtual_crtc_funcs); | ||
330 | |||
331 | drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256); | ||
332 | amdgpu_crtc->crtc_id = index; | ||
333 | adev->mode_info.crtcs[index] = amdgpu_crtc; | ||
334 | |||
335 | for (i = 0; i < 256; i++) { | ||
336 | amdgpu_crtc->lut_r[i] = i << 2; | ||
337 | amdgpu_crtc->lut_g[i] = i << 2; | ||
338 | amdgpu_crtc->lut_b[i] = i << 2; | ||
339 | } | ||
340 | |||
341 | amdgpu_crtc->pll_id = ATOM_PPLL_INVALID; | ||
342 | amdgpu_crtc->encoder = NULL; | ||
343 | amdgpu_crtc->connector = NULL; | ||
344 | drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs); | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int dce_virtual_early_init(void *handle) | ||
350 | { | ||
351 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
352 | |||
353 | adev->mode_info.vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE; | ||
354 | dce_virtual_set_display_funcs(adev); | ||
355 | dce_virtual_set_irq_funcs(adev); | ||
356 | |||
357 | adev->mode_info.num_crtc = 1; | ||
358 | adev->mode_info.num_hpd = 1; | ||
359 | adev->mode_info.num_dig = 1; | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static bool dce_virtual_get_connector_info(struct amdgpu_device *adev) | ||
364 | { | ||
365 | struct amdgpu_i2c_bus_rec ddc_bus; | ||
366 | struct amdgpu_router router; | ||
367 | struct amdgpu_hpd hpd; | ||
368 | |||
369 | /* look up gpio for ddc, hpd */ | ||
370 | ddc_bus.valid = false; | ||
371 | hpd.hpd = AMDGPU_HPD_NONE; | ||
372 | /* needed for aux chan transactions */ | ||
373 | ddc_bus.hpd = hpd.hpd; | ||
374 | |||
375 | memset(&router, 0, sizeof(router)); | ||
376 | router.ddc_valid = false; | ||
377 | router.cd_valid = false; | ||
378 | amdgpu_display_add_connector(adev, | ||
379 | 0, | ||
380 | ATOM_DEVICE_CRT1_SUPPORT, | ||
381 | DRM_MODE_CONNECTOR_VIRTUAL, &ddc_bus, | ||
382 | CONNECTOR_OBJECT_ID_VIRTUAL, | ||
383 | &hpd, | ||
384 | &router); | ||
385 | |||
386 | amdgpu_display_add_encoder(adev, ENCODER_VIRTUAL_ENUM_VIRTUAL, | ||
387 | ATOM_DEVICE_CRT1_SUPPORT, | ||
388 | 0); | ||
389 | |||
390 | amdgpu_link_encoder_connector(adev->ddev); | ||
391 | |||
392 | return true; | ||
393 | } | ||
394 | |||
395 | static int dce_virtual_sw_init(void *handle) | ||
396 | { | ||
397 | int r, i; | ||
398 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
399 | |||
400 | r = amdgpu_irq_add_id(adev, 229, &adev->crtc_irq); | ||
401 | if (r) | ||
402 | return r; | ||
403 | |||
404 | adev->ddev->max_vblank_count = 0; | ||
405 | |||
406 | adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; | ||
407 | |||
408 | adev->ddev->mode_config.max_width = 16384; | ||
409 | adev->ddev->mode_config.max_height = 16384; | ||
410 | |||
411 | adev->ddev->mode_config.preferred_depth = 24; | ||
412 | adev->ddev->mode_config.prefer_shadow = 1; | ||
413 | |||
414 | adev->ddev->mode_config.fb_base = adev->mc.aper_base; | ||
415 | |||
416 | r = amdgpu_modeset_create_props(adev); | ||
417 | if (r) | ||
418 | return r; | ||
419 | |||
420 | adev->ddev->mode_config.max_width = 16384; | ||
421 | adev->ddev->mode_config.max_height = 16384; | ||
422 | |||
423 | /* allocate crtcs */ | ||
424 | for (i = 0; i < adev->mode_info.num_crtc; i++) { | ||
425 | r = dce_virtual_crtc_init(adev, i); | ||
426 | if (r) | ||
427 | return r; | ||
428 | } | ||
429 | |||
430 | dce_virtual_get_connector_info(adev); | ||
431 | amdgpu_print_display_setup(adev->ddev); | ||
432 | |||
433 | drm_kms_helper_poll_init(adev->ddev); | ||
434 | |||
435 | adev->mode_info.mode_config_initialized = true; | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int dce_virtual_sw_fini(void *handle) | ||
440 | { | ||
441 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
442 | |||
443 | kfree(adev->mode_info.bios_hardcoded_edid); | ||
444 | |||
445 | drm_kms_helper_poll_fini(adev->ddev); | ||
446 | |||
447 | drm_mode_config_cleanup(adev->ddev); | ||
448 | adev->mode_info.mode_config_initialized = false; | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int dce_virtual_hw_init(void *handle) | ||
453 | { | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static int dce_virtual_hw_fini(void *handle) | ||
458 | { | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int dce_virtual_suspend(void *handle) | ||
463 | { | ||
464 | return dce_virtual_hw_fini(handle); | ||
465 | } | ||
466 | |||
467 | static int dce_virtual_resume(void *handle) | ||
468 | { | ||
469 | int ret; | ||
470 | |||
471 | ret = dce_virtual_hw_init(handle); | ||
472 | |||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | static bool dce_virtual_is_idle(void *handle) | ||
477 | { | ||
478 | return true; | ||
479 | } | ||
480 | |||
481 | static int dce_virtual_wait_for_idle(void *handle) | ||
482 | { | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static int dce_virtual_soft_reset(void *handle) | ||
487 | { | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int dce_virtual_set_clockgating_state(void *handle, | ||
492 | enum amd_clockgating_state state) | ||
493 | { | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int dce_virtual_set_powergating_state(void *handle, | ||
498 | enum amd_powergating_state state) | ||
499 | { | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | const struct amd_ip_funcs dce_virtual_ip_funcs = { | ||
504 | .name = "dce_virtual", | ||
505 | .early_init = dce_virtual_early_init, | ||
506 | .late_init = NULL, | ||
507 | .sw_init = dce_virtual_sw_init, | ||
508 | .sw_fini = dce_virtual_sw_fini, | ||
509 | .hw_init = dce_virtual_hw_init, | ||
510 | .hw_fini = dce_virtual_hw_fini, | ||
511 | .suspend = dce_virtual_suspend, | ||
512 | .resume = dce_virtual_resume, | ||
513 | .is_idle = dce_virtual_is_idle, | ||
514 | .wait_for_idle = dce_virtual_wait_for_idle, | ||
515 | .soft_reset = dce_virtual_soft_reset, | ||
516 | .set_clockgating_state = dce_virtual_set_clockgating_state, | ||
517 | .set_powergating_state = dce_virtual_set_powergating_state, | ||
518 | }; | ||
519 | |||
520 | /* these are handled by the primary encoders */ | ||
521 | static void dce_virtual_encoder_prepare(struct drm_encoder *encoder) | ||
522 | { | ||
523 | return; | ||
524 | } | ||
525 | |||
526 | static void dce_virtual_encoder_commit(struct drm_encoder *encoder) | ||
527 | { | ||
528 | return; | ||
529 | } | ||
530 | |||
531 | static void | ||
532 | dce_virtual_encoder_mode_set(struct drm_encoder *encoder, | ||
533 | struct drm_display_mode *mode, | ||
534 | struct drm_display_mode *adjusted_mode) | ||
535 | { | ||
536 | return; | ||
537 | } | ||
538 | |||
539 | static void dce_virtual_encoder_disable(struct drm_encoder *encoder) | ||
540 | { | ||
541 | return; | ||
542 | } | ||
543 | |||
544 | static void | ||
545 | dce_virtual_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
546 | { | ||
547 | return; | ||
548 | } | ||
549 | |||
550 | static bool dce_virtual_encoder_mode_fixup(struct drm_encoder *encoder, | ||
551 | const struct drm_display_mode *mode, | ||
552 | struct drm_display_mode *adjusted_mode) | ||
553 | { | ||
554 | |||
555 | /* set the active encoder to connector routing */ | ||
556 | amdgpu_encoder_set_active_device(encoder); | ||
557 | |||
558 | return true; | ||
559 | } | ||
560 | |||
561 | static const struct drm_encoder_helper_funcs dce_virtual_encoder_helper_funcs = { | ||
562 | .dpms = dce_virtual_encoder_dpms, | ||
563 | .mode_fixup = dce_virtual_encoder_mode_fixup, | ||
564 | .prepare = dce_virtual_encoder_prepare, | ||
565 | .mode_set = dce_virtual_encoder_mode_set, | ||
566 | .commit = dce_virtual_encoder_commit, | ||
567 | .disable = dce_virtual_encoder_disable, | ||
568 | }; | ||
569 | |||
570 | static void dce_virtual_encoder_destroy(struct drm_encoder *encoder) | ||
571 | { | ||
572 | struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); | ||
573 | |||
574 | kfree(amdgpu_encoder->enc_priv); | ||
575 | drm_encoder_cleanup(encoder); | ||
576 | kfree(amdgpu_encoder); | ||
577 | } | ||
578 | |||
579 | static const struct drm_encoder_funcs dce_virtual_encoder_funcs = { | ||
580 | .destroy = dce_virtual_encoder_destroy, | ||
581 | }; | ||
582 | |||
583 | static void dce_virtual_encoder_add(struct amdgpu_device *adev, | ||
584 | uint32_t encoder_enum, | ||
585 | uint32_t supported_device, | ||
586 | u16 caps) | ||
587 | { | ||
588 | struct drm_device *dev = adev->ddev; | ||
589 | struct drm_encoder *encoder; | ||
590 | struct amdgpu_encoder *amdgpu_encoder; | ||
591 | |||
592 | /* see if we already added it */ | ||
593 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
594 | amdgpu_encoder = to_amdgpu_encoder(encoder); | ||
595 | if (amdgpu_encoder->encoder_enum == encoder_enum) { | ||
596 | amdgpu_encoder->devices |= supported_device; | ||
597 | return; | ||
598 | } | ||
599 | |||
600 | } | ||
601 | |||
602 | /* add a new one */ | ||
603 | amdgpu_encoder = kzalloc(sizeof(struct amdgpu_encoder), GFP_KERNEL); | ||
604 | if (!amdgpu_encoder) | ||
605 | return; | ||
606 | |||
607 | encoder = &amdgpu_encoder->base; | ||
608 | encoder->possible_crtcs = 0x1; | ||
609 | amdgpu_encoder->enc_priv = NULL; | ||
610 | amdgpu_encoder->encoder_enum = encoder_enum; | ||
611 | amdgpu_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; | ||
612 | amdgpu_encoder->devices = supported_device; | ||
613 | amdgpu_encoder->rmx_type = RMX_OFF; | ||
614 | amdgpu_encoder->underscan_type = UNDERSCAN_OFF; | ||
615 | amdgpu_encoder->is_ext_encoder = false; | ||
616 | amdgpu_encoder->caps = caps; | ||
617 | |||
618 | drm_encoder_init(dev, encoder, &dce_virtual_encoder_funcs, | ||
619 | DRM_MODE_ENCODER_VIRTUAL, NULL); | ||
620 | drm_encoder_helper_add(encoder, &dce_virtual_encoder_helper_funcs); | ||
621 | DRM_INFO("[FM]encoder: %d is VIRTUAL\n", amdgpu_encoder->encoder_id); | ||
622 | } | ||
623 | |||
624 | static const struct amdgpu_display_funcs dce_virtual_display_funcs = { | ||
625 | .set_vga_render_state = &dce_virtual_set_vga_render_state, | ||
626 | .bandwidth_update = &dce_virtual_bandwidth_update, | ||
627 | .vblank_get_counter = &dce_virtual_vblank_get_counter, | ||
628 | .vblank_wait = &dce_virtual_vblank_wait, | ||
629 | .is_display_hung = &dce_virtual_is_display_hung, | ||
630 | .backlight_set_level = NULL, | ||
631 | .backlight_get_level = NULL, | ||
632 | .hpd_sense = &dce_virtual_hpd_sense, | ||
633 | .hpd_set_polarity = &dce_virtual_hpd_set_polarity, | ||
634 | .hpd_get_gpio_reg = &dce_virtual_hpd_get_gpio_reg, | ||
635 | .page_flip = &dce_virtual_page_flip, | ||
636 | .page_flip_get_scanoutpos = &dce_virtual_crtc_get_scanoutpos, | ||
637 | .add_encoder = &dce_virtual_encoder_add, | ||
638 | .add_connector = &amdgpu_connector_add, | ||
639 | .stop_mc_access = &dce_virtual_stop_mc_access, | ||
640 | .resume_mc_access = &dce_virtual_resume_mc_access, | ||
641 | }; | ||
642 | |||
643 | static void dce_virtual_set_display_funcs(struct amdgpu_device *adev) | ||
644 | { | ||
645 | if (adev->mode_info.funcs == NULL) | ||
646 | adev->mode_info.funcs = &dce_virtual_display_funcs; | ||
647 | } | ||
648 | |||
649 | static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer) | ||
650 | { | ||
651 | struct amdgpu_mode_info *mode_info = container_of(vblank_timer, struct amdgpu_mode_info ,vblank_timer); | ||
652 | struct amdgpu_device *adev = container_of(mode_info, struct amdgpu_device ,mode_info); | ||
653 | unsigned crtc = 0; | ||
654 | drm_handle_vblank(adev->ddev, crtc); | ||
655 | dce_virtual_pageflip_irq(adev, NULL, NULL); | ||
656 | hrtimer_start(vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL); | ||
657 | return HRTIMER_NORESTART; | ||
658 | } | ||
659 | |||
660 | static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, | ||
661 | int crtc, | ||
662 | enum amdgpu_interrupt_state state) | ||
663 | { | ||
664 | if (crtc >= adev->mode_info.num_crtc) { | ||
665 | DRM_DEBUG("invalid crtc %d\n", crtc); | ||
666 | return; | ||
667 | } | ||
668 | |||
669 | if (state && !adev->mode_info.vsync_timer_enabled) { | ||
670 | DRM_DEBUG("Enable software vsync timer\n"); | ||
671 | hrtimer_init(&adev->mode_info.vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
672 | hrtimer_set_expires(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD)); | ||
673 | adev->mode_info.vblank_timer.function = dce_virtual_vblank_timer_handle; | ||
674 | hrtimer_start(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL); | ||
675 | } else if (!state && adev->mode_info.vsync_timer_enabled) { | ||
676 | DRM_DEBUG("Disable software vsync timer\n"); | ||
677 | hrtimer_cancel(&adev->mode_info.vblank_timer); | ||
678 | } | ||
679 | |||
680 | adev->mode_info.vsync_timer_enabled = state; | ||
681 | DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state); | ||
682 | } | ||
683 | |||
684 | |||
685 | static int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev, | ||
686 | struct amdgpu_irq_src *source, | ||
687 | unsigned type, | ||
688 | enum amdgpu_interrupt_state state) | ||
689 | { | ||
690 | switch (type) { | ||
691 | case AMDGPU_CRTC_IRQ_VBLANK1: | ||
692 | dce_virtual_set_crtc_vblank_interrupt_state(adev, 0, state); | ||
693 | break; | ||
694 | default: | ||
695 | break; | ||
696 | } | ||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | static void dce_virtual_crtc_vblank_int_ack(struct amdgpu_device *adev, | ||
701 | int crtc) | ||
702 | { | ||
703 | if (crtc >= adev->mode_info.num_crtc) { | ||
704 | DRM_DEBUG("invalid crtc %d\n", crtc); | ||
705 | return; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | static int dce_virtual_crtc_irq(struct amdgpu_device *adev, | ||
710 | struct amdgpu_irq_src *source, | ||
711 | struct amdgpu_iv_entry *entry) | ||
712 | { | ||
713 | unsigned crtc = 0; | ||
714 | unsigned irq_type = AMDGPU_CRTC_IRQ_VBLANK1; | ||
715 | |||
716 | dce_virtual_crtc_vblank_int_ack(adev, crtc); | ||
717 | |||
718 | if (amdgpu_irq_enabled(adev, source, irq_type)) { | ||
719 | drm_handle_vblank(adev->ddev, crtc); | ||
720 | } | ||
721 | dce_virtual_pageflip_irq(adev, NULL, NULL); | ||
722 | DRM_DEBUG("IH: D%d vblank\n", crtc + 1); | ||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | static int dce_virtual_set_pageflip_irq_state(struct amdgpu_device *adev, | ||
727 | struct amdgpu_irq_src *src, | ||
728 | unsigned type, | ||
729 | enum amdgpu_interrupt_state state) | ||
730 | { | ||
731 | if (type >= adev->mode_info.num_crtc) { | ||
732 | DRM_ERROR("invalid pageflip crtc %d\n", type); | ||
733 | return -EINVAL; | ||
734 | } | ||
735 | DRM_DEBUG("[FM]set pageflip irq type %d state %d\n", type, state); | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static int dce_virtual_pageflip_irq(struct amdgpu_device *adev, | ||
741 | struct amdgpu_irq_src *source, | ||
742 | struct amdgpu_iv_entry *entry) | ||
743 | { | ||
744 | unsigned long flags; | ||
745 | unsigned crtc_id = 0; | ||
746 | struct amdgpu_crtc *amdgpu_crtc; | ||
747 | struct amdgpu_flip_work *works; | ||
748 | |||
749 | crtc_id = 0; | ||
750 | amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; | ||
751 | |||
752 | if (crtc_id >= adev->mode_info.num_crtc) { | ||
753 | DRM_ERROR("invalid pageflip crtc %d\n", crtc_id); | ||
754 | return -EINVAL; | ||
755 | } | ||
756 | |||
757 | /* IRQ could occur when in initial stage */ | ||
758 | if (amdgpu_crtc == NULL) | ||
759 | return 0; | ||
760 | |||
761 | spin_lock_irqsave(&adev->ddev->event_lock, flags); | ||
762 | works = amdgpu_crtc->pflip_works; | ||
763 | if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) { | ||
764 | DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != " | ||
765 | "AMDGPU_FLIP_SUBMITTED(%d)\n", | ||
766 | amdgpu_crtc->pflip_status, | ||
767 | AMDGPU_FLIP_SUBMITTED); | ||
768 | spin_unlock_irqrestore(&adev->ddev->event_lock, flags); | ||
769 | return 0; | ||
770 | } | ||
771 | |||
772 | /* page flip completed. clean up */ | ||
773 | amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE; | ||
774 | amdgpu_crtc->pflip_works = NULL; | ||
775 | |||
776 | /* wakeup usersapce */ | ||
777 | if (works->event) | ||
778 | drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event); | ||
779 | |||
780 | spin_unlock_irqrestore(&adev->ddev->event_lock, flags); | ||
781 | |||
782 | drm_crtc_vblank_put(&amdgpu_crtc->base); | ||
783 | schedule_work(&works->unpin_work); | ||
784 | |||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | static const struct amdgpu_irq_src_funcs dce_virtual_crtc_irq_funcs = { | ||
789 | .set = dce_virtual_set_crtc_irq_state, | ||
790 | .process = dce_virtual_crtc_irq, | ||
791 | }; | ||
792 | |||
793 | static const struct amdgpu_irq_src_funcs dce_virtual_pageflip_irq_funcs = { | ||
794 | .set = dce_virtual_set_pageflip_irq_state, | ||
795 | .process = dce_virtual_pageflip_irq, | ||
796 | }; | ||
797 | |||
798 | static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev) | ||
799 | { | ||
800 | adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_LAST; | ||
801 | adev->crtc_irq.funcs = &dce_virtual_crtc_irq_funcs; | ||
802 | |||
803 | adev->pageflip_irq.num_types = AMDGPU_PAGEFLIP_IRQ_LAST; | ||
804 | adev->pageflip_irq.funcs = &dce_virtual_pageflip_irq_funcs; | ||
805 | } | ||
806 | |||
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.h b/drivers/gpu/drm/amd/amdgpu/dce_virtual.h new file mode 100644 index 000000000000..e239243f6ebc --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Copyright 2014 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __DCE_VIRTUAL_H__ | ||
25 | #define __DCE_VIRTUAL_H__ | ||
26 | |||
27 | extern const struct amd_ip_funcs dce_virtual_ip_funcs; | ||
28 | #define DCE_VIRTUAL_VBLANK_PERIOD 16666666 | ||
29 | |||
30 | #endif | ||
31 | |||
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index d869d058ef24..f4fbec3e224e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | |||
@@ -4465,24 +4465,21 @@ static int gfx_v7_0_sw_init(void *handle) | |||
4465 | } | 4465 | } |
4466 | 4466 | ||
4467 | /* reserve GDS, GWS and OA resource for gfx */ | 4467 | /* reserve GDS, GWS and OA resource for gfx */ |
4468 | r = amdgpu_bo_create(adev, adev->gds.mem.gfx_partition_size, | 4468 | r = amdgpu_bo_create_kernel(adev, adev->gds.mem.gfx_partition_size, |
4469 | PAGE_SIZE, true, | 4469 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_GDS, |
4470 | AMDGPU_GEM_DOMAIN_GDS, 0, | 4470 | &adev->gds.gds_gfx_bo, NULL, NULL); |
4471 | NULL, NULL, &adev->gds.gds_gfx_bo); | ||
4472 | if (r) | 4471 | if (r) |
4473 | return r; | 4472 | return r; |
4474 | 4473 | ||
4475 | r = amdgpu_bo_create(adev, adev->gds.gws.gfx_partition_size, | 4474 | r = amdgpu_bo_create_kernel(adev, adev->gds.gws.gfx_partition_size, |
4476 | PAGE_SIZE, true, | 4475 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_GWS, |
4477 | AMDGPU_GEM_DOMAIN_GWS, 0, | 4476 | &adev->gds.gws_gfx_bo, NULL, NULL); |
4478 | NULL, NULL, &adev->gds.gws_gfx_bo); | ||
4479 | if (r) | 4477 | if (r) |
4480 | return r; | 4478 | return r; |
4481 | 4479 | ||
4482 | r = amdgpu_bo_create(adev, adev->gds.oa.gfx_partition_size, | 4480 | r = amdgpu_bo_create_kernel(adev, adev->gds.oa.gfx_partition_size, |
4483 | PAGE_SIZE, true, | 4481 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_OA, |
4484 | AMDGPU_GEM_DOMAIN_OA, 0, | 4482 | &adev->gds.oa_gfx_bo, NULL, NULL); |
4485 | NULL, NULL, &adev->gds.oa_gfx_bo); | ||
4486 | if (r) | 4483 | if (r) |
4487 | return r; | 4484 | return r; |
4488 | 4485 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index b8184617ca25..c6a63c2f91e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | |||
@@ -703,7 +703,10 @@ static void gfx_v8_0_init_golden_registers(struct amdgpu_device *adev) | |||
703 | polaris10_golden_common_all, | 703 | polaris10_golden_common_all, |
704 | (const u32)ARRAY_SIZE(polaris10_golden_common_all)); | 704 | (const u32)ARRAY_SIZE(polaris10_golden_common_all)); |
705 | WREG32_SMC(ixCG_ACLK_CNTL, 0x0000001C); | 705 | WREG32_SMC(ixCG_ACLK_CNTL, 0x0000001C); |
706 | if (adev->pdev->revision == 0xc7) { | 706 | if (adev->pdev->revision == 0xc7 && |
707 | ((adev->pdev->subsystem_device == 0xb37 && adev->pdev->subsystem_vendor == 0x1002) || | ||
708 | (adev->pdev->subsystem_device == 0x4a8 && adev->pdev->subsystem_vendor == 0x1043) || | ||
709 | (adev->pdev->subsystem_device == 0x9480 && adev->pdev->subsystem_vendor == 0x1682))) { | ||
707 | amdgpu_atombios_i2c_channel_trans(adev, 0x10, 0x96, 0x1E, 0xDD); | 710 | amdgpu_atombios_i2c_channel_trans(adev, 0x10, 0x96, 0x1E, 0xDD); |
708 | amdgpu_atombios_i2c_channel_trans(adev, 0x10, 0x96, 0x1F, 0xD0); | 711 | amdgpu_atombios_i2c_channel_trans(adev, 0x10, 0x96, 0x1F, 0xD0); |
709 | } | 712 | } |
@@ -1233,10 +1236,9 @@ static void gfx_v8_0_rlc_fini(struct amdgpu_device *adev) | |||
1233 | if (adev->gfx.rlc.clear_state_obj) { | 1236 | if (adev->gfx.rlc.clear_state_obj) { |
1234 | r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false); | 1237 | r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false); |
1235 | if (unlikely(r != 0)) | 1238 | if (unlikely(r != 0)) |
1236 | dev_warn(adev->dev, "(%d) reserve RLC c bo failed\n", r); | 1239 | dev_warn(adev->dev, "(%d) reserve RLC cbs bo failed\n", r); |
1237 | amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj); | 1240 | amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj); |
1238 | amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj); | 1241 | amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj); |
1239 | |||
1240 | amdgpu_bo_unref(&adev->gfx.rlc.clear_state_obj); | 1242 | amdgpu_bo_unref(&adev->gfx.rlc.clear_state_obj); |
1241 | adev->gfx.rlc.clear_state_obj = NULL; | 1243 | adev->gfx.rlc.clear_state_obj = NULL; |
1242 | } | 1244 | } |
@@ -1248,7 +1250,6 @@ static void gfx_v8_0_rlc_fini(struct amdgpu_device *adev) | |||
1248 | dev_warn(adev->dev, "(%d) reserve RLC cp table bo failed\n", r); | 1250 | dev_warn(adev->dev, "(%d) reserve RLC cp table bo failed\n", r); |
1249 | amdgpu_bo_unpin(adev->gfx.rlc.cp_table_obj); | 1251 | amdgpu_bo_unpin(adev->gfx.rlc.cp_table_obj); |
1250 | amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); | 1252 | amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); |
1251 | |||
1252 | amdgpu_bo_unref(&adev->gfx.rlc.cp_table_obj); | 1253 | amdgpu_bo_unref(&adev->gfx.rlc.cp_table_obj); |
1253 | adev->gfx.rlc.cp_table_obj = NULL; | 1254 | adev->gfx.rlc.cp_table_obj = NULL; |
1254 | } | 1255 | } |
@@ -1290,14 +1291,14 @@ static int gfx_v8_0_rlc_init(struct amdgpu_device *adev) | |||
1290 | &adev->gfx.rlc.clear_state_gpu_addr); | 1291 | &adev->gfx.rlc.clear_state_gpu_addr); |
1291 | if (r) { | 1292 | if (r) { |
1292 | amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj); | 1293 | amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj); |
1293 | dev_warn(adev->dev, "(%d) pin RLC c bo failed\n", r); | 1294 | dev_warn(adev->dev, "(%d) pin RLC cbs bo failed\n", r); |
1294 | gfx_v8_0_rlc_fini(adev); | 1295 | gfx_v8_0_rlc_fini(adev); |
1295 | return r; | 1296 | return r; |
1296 | } | 1297 | } |
1297 | 1298 | ||
1298 | r = amdgpu_bo_kmap(adev->gfx.rlc.clear_state_obj, (void **)&adev->gfx.rlc.cs_ptr); | 1299 | r = amdgpu_bo_kmap(adev->gfx.rlc.clear_state_obj, (void **)&adev->gfx.rlc.cs_ptr); |
1299 | if (r) { | 1300 | if (r) { |
1300 | dev_warn(adev->dev, "(%d) map RLC c bo failed\n", r); | 1301 | dev_warn(adev->dev, "(%d) map RLC cbs bo failed\n", r); |
1301 | gfx_v8_0_rlc_fini(adev); | 1302 | gfx_v8_0_rlc_fini(adev); |
1302 | return r; | 1303 | return r; |
1303 | } | 1304 | } |
@@ -1332,7 +1333,7 @@ static int gfx_v8_0_rlc_init(struct amdgpu_device *adev) | |||
1332 | &adev->gfx.rlc.cp_table_gpu_addr); | 1333 | &adev->gfx.rlc.cp_table_gpu_addr); |
1333 | if (r) { | 1334 | if (r) { |
1334 | amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); | 1335 | amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); |
1335 | dev_warn(adev->dev, "(%d) pin RLC cp_table bo failed\n", r); | 1336 | dev_warn(adev->dev, "(%d) pin RLC cp table bo failed\n", r); |
1336 | return r; | 1337 | return r; |
1337 | } | 1338 | } |
1338 | r = amdgpu_bo_kmap(adev->gfx.rlc.cp_table_obj, (void **)&adev->gfx.rlc.cp_table_ptr); | 1339 | 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) | |||
1345 | 1346 | ||
1346 | amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj); | 1347 | amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj); |
1347 | amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); | 1348 | amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj); |
1348 | |||
1349 | } | 1349 | } |
1350 | 1350 | ||
1351 | return 0; | 1351 | return 0; |
@@ -1361,7 +1361,6 @@ static void gfx_v8_0_mec_fini(struct amdgpu_device *adev) | |||
1361 | dev_warn(adev->dev, "(%d) reserve HPD EOP bo failed\n", r); | 1361 | dev_warn(adev->dev, "(%d) reserve HPD EOP bo failed\n", r); |
1362 | amdgpu_bo_unpin(adev->gfx.mec.hpd_eop_obj); | 1362 | amdgpu_bo_unpin(adev->gfx.mec.hpd_eop_obj); |
1363 | amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); | 1363 | amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); |
1364 | |||
1365 | amdgpu_bo_unref(&adev->gfx.mec.hpd_eop_obj); | 1364 | amdgpu_bo_unref(&adev->gfx.mec.hpd_eop_obj); |
1366 | adev->gfx.mec.hpd_eop_obj = NULL; | 1365 | adev->gfx.mec.hpd_eop_obj = NULL; |
1367 | } | 1366 | } |
@@ -2082,24 +2081,21 @@ static int gfx_v8_0_sw_init(void *handle) | |||
2082 | } | 2081 | } |
2083 | 2082 | ||
2084 | /* reserve GDS, GWS and OA resource for gfx */ | 2083 | /* reserve GDS, GWS and OA resource for gfx */ |
2085 | r = amdgpu_bo_create(adev, adev->gds.mem.gfx_partition_size, | 2084 | r = amdgpu_bo_create_kernel(adev, adev->gds.mem.gfx_partition_size, |
2086 | PAGE_SIZE, true, | 2085 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_GDS, |
2087 | AMDGPU_GEM_DOMAIN_GDS, 0, NULL, | 2086 | &adev->gds.gds_gfx_bo, NULL, NULL); |
2088 | NULL, &adev->gds.gds_gfx_bo); | ||
2089 | if (r) | 2087 | if (r) |
2090 | return r; | 2088 | return r; |
2091 | 2089 | ||
2092 | r = amdgpu_bo_create(adev, adev->gds.gws.gfx_partition_size, | 2090 | r = amdgpu_bo_create_kernel(adev, adev->gds.gws.gfx_partition_size, |
2093 | PAGE_SIZE, true, | 2091 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_GWS, |
2094 | AMDGPU_GEM_DOMAIN_GWS, 0, NULL, | 2092 | &adev->gds.gws_gfx_bo, NULL, NULL); |
2095 | NULL, &adev->gds.gws_gfx_bo); | ||
2096 | if (r) | 2093 | if (r) |
2097 | return r; | 2094 | return r; |
2098 | 2095 | ||
2099 | r = amdgpu_bo_create(adev, adev->gds.oa.gfx_partition_size, | 2096 | r = amdgpu_bo_create_kernel(adev, adev->gds.oa.gfx_partition_size, |
2100 | PAGE_SIZE, true, | 2097 | PAGE_SIZE, AMDGPU_GEM_DOMAIN_OA, |
2101 | AMDGPU_GEM_DOMAIN_OA, 0, NULL, | 2098 | &adev->gds.oa_gfx_bo, NULL, NULL); |
2102 | NULL, &adev->gds.oa_gfx_bo); | ||
2103 | if (r) | 2099 | if (r) |
2104 | return r; | 2100 | return r; |
2105 | 2101 | ||
@@ -2127,9 +2123,7 @@ static int gfx_v8_0_sw_fini(void *handle) | |||
2127 | amdgpu_ring_fini(&adev->gfx.compute_ring[i]); | 2123 | amdgpu_ring_fini(&adev->gfx.compute_ring[i]); |
2128 | 2124 | ||
2129 | gfx_v8_0_mec_fini(adev); | 2125 | gfx_v8_0_mec_fini(adev); |
2130 | |||
2131 | gfx_v8_0_rlc_fini(adev); | 2126 | gfx_v8_0_rlc_fini(adev); |
2132 | |||
2133 | gfx_v8_0_free_microcode(adev); | 2127 | gfx_v8_0_free_microcode(adev); |
2134 | 2128 | ||
2135 | return 0; | 2129 | return 0; |
@@ -3465,19 +3459,16 @@ static void gfx_v8_0_select_se_sh(struct amdgpu_device *adev, | |||
3465 | else | 3459 | else |
3466 | data = REG_SET_FIELD(0, GRBM_GFX_INDEX, INSTANCE_INDEX, instance); | 3460 | data = REG_SET_FIELD(0, GRBM_GFX_INDEX, INSTANCE_INDEX, instance); |
3467 | 3461 | ||
3468 | if ((se_num == 0xffffffff) && (sh_num == 0xffffffff)) { | 3462 | if (se_num == 0xffffffff) |
3469 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_BROADCAST_WRITES, 1); | ||
3470 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_BROADCAST_WRITES, 1); | 3463 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_BROADCAST_WRITES, 1); |
3471 | } else if (se_num == 0xffffffff) { | 3464 | else |
3472 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_INDEX, sh_num); | ||
3473 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_BROADCAST_WRITES, 1); | ||
3474 | } else if (sh_num == 0xffffffff) { | ||
3475 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_BROADCAST_WRITES, 1); | ||
3476 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_INDEX, se_num); | 3465 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_INDEX, se_num); |
3477 | } else { | 3466 | |
3467 | if (sh_num == 0xffffffff) | ||
3468 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_BROADCAST_WRITES, 1); | ||
3469 | else | ||
3478 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_INDEX, sh_num); | 3470 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SH_INDEX, sh_num); |
3479 | data = REG_SET_FIELD(data, GRBM_GFX_INDEX, SE_INDEX, se_num); | 3471 | |
3480 | } | ||
3481 | WREG32(mmGRBM_GFX_INDEX, data); | 3472 | WREG32(mmGRBM_GFX_INDEX, data); |
3482 | } | 3473 | } |
3483 | 3474 | ||
@@ -3490,11 +3481,10 @@ static u32 gfx_v8_0_get_rb_active_bitmap(struct amdgpu_device *adev) | |||
3490 | { | 3481 | { |
3491 | u32 data, mask; | 3482 | u32 data, mask; |
3492 | 3483 | ||
3493 | data = RREG32(mmCC_RB_BACKEND_DISABLE); | 3484 | data = RREG32(mmCC_RB_BACKEND_DISABLE) | |
3494 | data |= RREG32(mmGC_USER_RB_BACKEND_DISABLE); | 3485 | RREG32(mmGC_USER_RB_BACKEND_DISABLE); |
3495 | 3486 | ||
3496 | data &= CC_RB_BACKEND_DISABLE__BACKEND_DISABLE_MASK; | 3487 | data = REG_GET_FIELD(data, GC_USER_RB_BACKEND_DISABLE, BACKEND_DISABLE); |
3497 | data >>= GC_USER_RB_BACKEND_DISABLE__BACKEND_DISABLE__SHIFT; | ||
3498 | 3488 | ||
3499 | mask = gfx_v8_0_create_bitmask(adev->gfx.config.max_backends_per_se / | 3489 | mask = gfx_v8_0_create_bitmask(adev->gfx.config.max_backends_per_se / |
3500 | adev->gfx.config.max_sh_per_se); | 3490 | adev->gfx.config.max_sh_per_se); |
@@ -3576,16 +3566,12 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) | |||
3576 | u32 tmp; | 3566 | u32 tmp; |
3577 | int i; | 3567 | int i; |
3578 | 3568 | ||
3579 | tmp = RREG32(mmGRBM_CNTL); | 3569 | WREG32_FIELD(GRBM_CNTL, READ_TIMEOUT, 0xFF); |
3580 | tmp = REG_SET_FIELD(tmp, GRBM_CNTL, READ_TIMEOUT, 0xff); | ||
3581 | WREG32(mmGRBM_CNTL, tmp); | ||
3582 | |||
3583 | WREG32(mmGB_ADDR_CONFIG, adev->gfx.config.gb_addr_config); | 3570 | WREG32(mmGB_ADDR_CONFIG, adev->gfx.config.gb_addr_config); |
3584 | WREG32(mmHDP_ADDR_CONFIG, adev->gfx.config.gb_addr_config); | 3571 | WREG32(mmHDP_ADDR_CONFIG, adev->gfx.config.gb_addr_config); |
3585 | WREG32(mmDMIF_ADDR_CALC, adev->gfx.config.gb_addr_config); | 3572 | WREG32(mmDMIF_ADDR_CALC, adev->gfx.config.gb_addr_config); |
3586 | 3573 | ||
3587 | gfx_v8_0_tiling_mode_table_init(adev); | 3574 | gfx_v8_0_tiling_mode_table_init(adev); |
3588 | |||
3589 | gfx_v8_0_setup_rb(adev); | 3575 | gfx_v8_0_setup_rb(adev); |
3590 | gfx_v8_0_get_cu_info(adev); | 3576 | gfx_v8_0_get_cu_info(adev); |
3591 | 3577 | ||
@@ -3769,9 +3755,7 @@ static int gfx_v8_0_init_save_restore_list(struct amdgpu_device *adev) | |||
3769 | sizeof(indirect_start_offsets)/sizeof(int)); | 3755 | sizeof(indirect_start_offsets)/sizeof(int)); |
3770 | 3756 | ||
3771 | /* save and restore list */ | 3757 | /* save and restore list */ |
3772 | temp = RREG32(mmRLC_SRM_CNTL); | 3758 | WREG32_FIELD(RLC_SRM_CNTL, AUTO_INCR_ADDR, 1); |
3773 | temp |= RLC_SRM_CNTL__AUTO_INCR_ADDR_MASK; | ||
3774 | WREG32(mmRLC_SRM_CNTL, temp); | ||
3775 | 3759 | ||
3776 | WREG32(mmRLC_SRM_ARAM_ADDR, 0); | 3760 | WREG32(mmRLC_SRM_ARAM_ADDR, 0); |
3777 | for (i = 0; i < adev->gfx.rlc.reg_list_size_bytes >> 2; i++) | 3761 | for (i = 0; i < adev->gfx.rlc.reg_list_size_bytes >> 2; i++) |
@@ -3808,11 +3792,7 @@ static int gfx_v8_0_init_save_restore_list(struct amdgpu_device *adev) | |||
3808 | 3792 | ||
3809 | static void gfx_v8_0_enable_save_restore_machine(struct amdgpu_device *adev) | 3793 | static void gfx_v8_0_enable_save_restore_machine(struct amdgpu_device *adev) |
3810 | { | 3794 | { |
3811 | uint32_t data; | 3795 | WREG32_FIELD(RLC_SRM_CNTL, SRM_ENABLE, 1); |
3812 | |||
3813 | data = RREG32(mmRLC_SRM_CNTL); | ||
3814 | data |= RLC_SRM_CNTL__SRM_ENABLE_MASK; | ||
3815 | WREG32(mmRLC_SRM_CNTL, data); | ||
3816 | } | 3796 | } |
3817 | 3797 | ||
3818 | static void gfx_v8_0_init_power_gating(struct amdgpu_device *adev) | 3798 | static void gfx_v8_0_init_power_gating(struct amdgpu_device *adev) |
@@ -3822,75 +3802,34 @@ static void gfx_v8_0_init_power_gating(struct amdgpu_device *adev) | |||
3822 | if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG | | 3802 | if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG | |
3823 | AMD_PG_SUPPORT_GFX_SMG | | 3803 | AMD_PG_SUPPORT_GFX_SMG | |
3824 | AMD_PG_SUPPORT_GFX_DMG)) { | 3804 | AMD_PG_SUPPORT_GFX_DMG)) { |
3825 | data = RREG32(mmCP_RB_WPTR_POLL_CNTL); | 3805 | WREG32_FIELD(CP_RB_WPTR_POLL_CNTL, IDLE_POLL_COUNT, 0x60); |
3826 | data &= ~CP_RB_WPTR_POLL_CNTL__IDLE_POLL_COUNT_MASK; | ||
3827 | data |= (0x60 << CP_RB_WPTR_POLL_CNTL__IDLE_POLL_COUNT__SHIFT); | ||
3828 | WREG32(mmCP_RB_WPTR_POLL_CNTL, data); | ||
3829 | |||
3830 | data = 0; | ||
3831 | data |= (0x10 << RLC_PG_DELAY__POWER_UP_DELAY__SHIFT); | ||
3832 | data |= (0x10 << RLC_PG_DELAY__POWER_DOWN_DELAY__SHIFT); | ||
3833 | data |= (0x10 << RLC_PG_DELAY__CMD_PROPAGATE_DELAY__SHIFT); | ||
3834 | data |= (0x10 << RLC_PG_DELAY__MEM_SLEEP_DELAY__SHIFT); | ||
3835 | WREG32(mmRLC_PG_DELAY, data); | ||
3836 | 3806 | ||
3837 | data = RREG32(mmRLC_PG_DELAY_2); | 3807 | data = REG_SET_FIELD(0, RLC_PG_DELAY, POWER_UP_DELAY, 0x10); |
3838 | data &= ~RLC_PG_DELAY_2__SERDES_CMD_DELAY_MASK; | 3808 | data = REG_SET_FIELD(data, RLC_PG_DELAY, POWER_DOWN_DELAY, 0x10); |
3839 | data |= (0x3 << RLC_PG_DELAY_2__SERDES_CMD_DELAY__SHIFT); | 3809 | data = REG_SET_FIELD(data, RLC_PG_DELAY, CMD_PROPAGATE_DELAY, 0x10); |
3840 | WREG32(mmRLC_PG_DELAY_2, data); | 3810 | data = REG_SET_FIELD(data, RLC_PG_DELAY, MEM_SLEEP_DELAY, 0x10); |
3811 | WREG32(mmRLC_PG_DELAY, data); | ||
3841 | 3812 | ||
3842 | data = RREG32(mmRLC_AUTO_PG_CTRL); | 3813 | WREG32_FIELD(RLC_PG_DELAY_2, SERDES_CMD_DELAY, 0x3); |
3843 | data &= ~RLC_AUTO_PG_CTRL__GRBM_REG_SAVE_GFX_IDLE_THRESHOLD_MASK; | 3814 | WREG32_FIELD(RLC_AUTO_PG_CTRL, GRBM_REG_SAVE_GFX_IDLE_THRESHOLD, 0x55f0); |
3844 | data |= (0x55f0 << RLC_AUTO_PG_CTRL__GRBM_REG_SAVE_GFX_IDLE_THRESHOLD__SHIFT); | ||
3845 | WREG32(mmRLC_AUTO_PG_CTRL, data); | ||
3846 | } | 3815 | } |
3847 | } | 3816 | } |
3848 | 3817 | ||
3849 | static void cz_enable_sck_slow_down_on_power_up(struct amdgpu_device *adev, | 3818 | static void cz_enable_sck_slow_down_on_power_up(struct amdgpu_device *adev, |
3850 | bool enable) | 3819 | bool enable) |
3851 | { | 3820 | { |
3852 | u32 data, orig; | 3821 | WREG32_FIELD(RLC_PG_CNTL, SMU_CLK_SLOWDOWN_ON_PU_ENABLE, enable ? 1 : 0); |
3853 | |||
3854 | orig = data = RREG32(mmRLC_PG_CNTL); | ||
3855 | |||
3856 | if (enable) | ||
3857 | data |= RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PU_ENABLE_MASK; | ||
3858 | else | ||
3859 | data &= ~RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PU_ENABLE_MASK; | ||
3860 | |||
3861 | if (orig != data) | ||
3862 | WREG32(mmRLC_PG_CNTL, data); | ||
3863 | } | 3822 | } |
3864 | 3823 | ||
3865 | static void cz_enable_sck_slow_down_on_power_down(struct amdgpu_device *adev, | 3824 | static void cz_enable_sck_slow_down_on_power_down(struct amdgpu_device *adev, |
3866 | bool enable) | 3825 | bool enable) |
3867 | { | 3826 | { |
3868 | u32 data, orig; | 3827 | WREG32_FIELD(RLC_PG_CNTL, SMU_CLK_SLOWDOWN_ON_PD_ENABLE, enable ? 1 : 0); |
3869 | |||
3870 | orig = data = RREG32(mmRLC_PG_CNTL); | ||
3871 | |||
3872 | if (enable) | ||
3873 | data |= RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PD_ENABLE_MASK; | ||
3874 | else | ||
3875 | data &= ~RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PD_ENABLE_MASK; | ||
3876 | |||
3877 | if (orig != data) | ||
3878 | WREG32(mmRLC_PG_CNTL, data); | ||
3879 | } | 3828 | } |
3880 | 3829 | ||
3881 | static void cz_enable_cp_power_gating(struct amdgpu_device *adev, bool enable) | 3830 | static void cz_enable_cp_power_gating(struct amdgpu_device *adev, bool enable) |
3882 | { | 3831 | { |
3883 | u32 data, orig; | 3832 | WREG32_FIELD(RLC_PG_CNTL, CP_PG_DISABLE, enable ? 1 : 0); |
3884 | |||
3885 | orig = data = RREG32(mmRLC_PG_CNTL); | ||
3886 | |||
3887 | if (enable) | ||
3888 | data &= ~RLC_PG_CNTL__CP_PG_DISABLE_MASK; | ||
3889 | else | ||
3890 | data |= RLC_PG_CNTL__CP_PG_DISABLE_MASK; | ||
3891 | |||
3892 | if (orig != data) | ||
3893 | WREG32(mmRLC_PG_CNTL, data); | ||
3894 | } | 3833 | } |
3895 | 3834 | ||
3896 | static void gfx_v8_0_init_pg(struct amdgpu_device *adev) | 3835 | static void gfx_v8_0_init_pg(struct amdgpu_device *adev) |
@@ -3929,34 +3868,24 @@ static void gfx_v8_0_init_pg(struct amdgpu_device *adev) | |||
3929 | 3868 | ||
3930 | void gfx_v8_0_rlc_stop(struct amdgpu_device *adev) | 3869 | void gfx_v8_0_rlc_stop(struct amdgpu_device *adev) |
3931 | { | 3870 | { |
3932 | u32 tmp = RREG32(mmRLC_CNTL); | 3871 | WREG32_FIELD(RLC_CNTL, RLC_ENABLE_F32, 0); |
3933 | |||
3934 | tmp = REG_SET_FIELD(tmp, RLC_CNTL, RLC_ENABLE_F32, 0); | ||
3935 | WREG32(mmRLC_CNTL, tmp); | ||
3936 | 3872 | ||
3937 | gfx_v8_0_enable_gui_idle_interrupt(adev, false); | 3873 | gfx_v8_0_enable_gui_idle_interrupt(adev, false); |
3938 | |||
3939 | gfx_v8_0_wait_for_rlc_serdes(adev); | 3874 | gfx_v8_0_wait_for_rlc_serdes(adev); |
3940 | } | 3875 | } |
3941 | 3876 | ||
3942 | static void gfx_v8_0_rlc_reset(struct amdgpu_device *adev) | 3877 | static void gfx_v8_0_rlc_reset(struct amdgpu_device *adev) |
3943 | { | 3878 | { |
3944 | u32 tmp = RREG32(mmGRBM_SOFT_RESET); | 3879 | WREG32_FIELD(GRBM_SOFT_RESET, SOFT_RESET_RLC, 1); |
3945 | |||
3946 | tmp = REG_SET_FIELD(tmp, GRBM_SOFT_RESET, SOFT_RESET_RLC, 1); | ||
3947 | WREG32(mmGRBM_SOFT_RESET, tmp); | ||
3948 | udelay(50); | 3880 | udelay(50); |
3949 | tmp = REG_SET_FIELD(tmp, GRBM_SOFT_RESET, SOFT_RESET_RLC, 0); | 3881 | |
3950 | WREG32(mmGRBM_SOFT_RESET, tmp); | 3882 | WREG32_FIELD(GRBM_SOFT_RESET, SOFT_RESET_RLC, 0); |
3951 | udelay(50); | 3883 | udelay(50); |
3952 | } | 3884 | } |
3953 | 3885 | ||
3954 | static void gfx_v8_0_rlc_start(struct amdgpu_device *adev) | 3886 | static void gfx_v8_0_rlc_start(struct amdgpu_device *adev) |
3955 | { | 3887 | { |
3956 | u32 tmp = RREG32(mmRLC_CNTL); | 3888 | WREG32_FIELD(RLC_CNTL, RLC_ENABLE_F32, 1); |
3957 | |||
3958 | tmp = REG_SET_FIELD(tmp, RLC_CNTL, RLC_ENABLE_F32, 1); | ||
3959 | WREG32(mmRLC_CNTL, tmp); | ||
3960 | 3889 | ||
3961 | /* carrizo do enable cp interrupt after cp inited */ | 3890 | /* carrizo do enable cp interrupt after cp inited */ |
3962 | if (!(adev->flags & AMD_IS_APU)) | 3891 | if (!(adev->flags & AMD_IS_APU)) |
@@ -3998,14 +3927,13 @@ static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev) | |||
3998 | /* disable CG */ | 3927 | /* disable CG */ |
3999 | WREG32(mmRLC_CGCG_CGLS_CTRL, 0); | 3928 | WREG32(mmRLC_CGCG_CGLS_CTRL, 0); |
4000 | if (adev->asic_type == CHIP_POLARIS11 || | 3929 | if (adev->asic_type == CHIP_POLARIS11 || |
4001 | adev->asic_type == CHIP_POLARIS10) | 3930 | adev->asic_type == CHIP_POLARIS10) |
4002 | WREG32(mmRLC_CGCG_CGLS_CTRL_3D, 0); | 3931 | WREG32(mmRLC_CGCG_CGLS_CTRL_3D, 0); |
4003 | 3932 | ||
4004 | /* disable PG */ | 3933 | /* disable PG */ |
4005 | WREG32(mmRLC_PG_CNTL, 0); | 3934 | WREG32(mmRLC_PG_CNTL, 0); |
4006 | 3935 | ||
4007 | gfx_v8_0_rlc_reset(adev); | 3936 | gfx_v8_0_rlc_reset(adev); |
4008 | |||
4009 | gfx_v8_0_init_pg(adev); | 3937 | gfx_v8_0_init_pg(adev); |
4010 | 3938 | ||
4011 | if (!adev->pp_enabled) { | 3939 | if (!adev->pp_enabled) { |
@@ -4300,12 +4228,10 @@ static int gfx_v8_0_cp_gfx_resume(struct amdgpu_device *adev) | |||
4300 | gfx_v8_0_cp_gfx_start(adev); | 4228 | gfx_v8_0_cp_gfx_start(adev); |
4301 | ring->ready = true; | 4229 | ring->ready = true; |
4302 | r = amdgpu_ring_test_ring(ring); | 4230 | r = amdgpu_ring_test_ring(ring); |
4303 | if (r) { | 4231 | if (r) |
4304 | ring->ready = false; | 4232 | ring->ready = false; |
4305 | return r; | ||
4306 | } | ||
4307 | 4233 | ||
4308 | return 0; | 4234 | return r; |
4309 | } | 4235 | } |
4310 | 4236 | ||
4311 | static void gfx_v8_0_cp_compute_enable(struct amdgpu_device *adev, bool enable) | 4237 | static void gfx_v8_0_cp_compute_enable(struct amdgpu_device *adev, bool enable) |
@@ -4980,7 +4906,6 @@ static int gfx_v8_0_hw_init(void *handle) | |||
4980 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 4906 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
4981 | 4907 | ||
4982 | gfx_v8_0_init_golden_registers(adev); | 4908 | gfx_v8_0_init_golden_registers(adev); |
4983 | |||
4984 | gfx_v8_0_gpu_init(adev); | 4909 | gfx_v8_0_gpu_init(adev); |
4985 | 4910 | ||
4986 | r = gfx_v8_0_rlc_resume(adev); | 4911 | r = gfx_v8_0_rlc_resume(adev); |
@@ -4988,8 +4913,6 @@ static int gfx_v8_0_hw_init(void *handle) | |||
4988 | return r; | 4913 | return r; |
4989 | 4914 | ||
4990 | r = gfx_v8_0_cp_resume(adev); | 4915 | r = gfx_v8_0_cp_resume(adev); |
4991 | if (r) | ||
4992 | return r; | ||
4993 | 4916 | ||
4994 | return r; | 4917 | return r; |
4995 | } | 4918 | } |
@@ -5037,25 +4960,22 @@ static bool gfx_v8_0_is_idle(void *handle) | |||
5037 | static int gfx_v8_0_wait_for_idle(void *handle) | 4960 | static int gfx_v8_0_wait_for_idle(void *handle) |
5038 | { | 4961 | { |
5039 | unsigned i; | 4962 | unsigned i; |
5040 | u32 tmp; | ||
5041 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 4963 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
5042 | 4964 | ||
5043 | for (i = 0; i < adev->usec_timeout; i++) { | 4965 | for (i = 0; i < adev->usec_timeout; i++) { |
5044 | /* read MC_STATUS */ | 4966 | if (gfx_v8_0_is_idle(handle)) |
5045 | tmp = RREG32(mmGRBM_STATUS) & GRBM_STATUS__GUI_ACTIVE_MASK; | ||
5046 | |||
5047 | if (!REG_GET_FIELD(tmp, GRBM_STATUS, GUI_ACTIVE)) | ||
5048 | return 0; | 4967 | return 0; |
4968 | |||
5049 | udelay(1); | 4969 | udelay(1); |
5050 | } | 4970 | } |
5051 | return -ETIMEDOUT; | 4971 | return -ETIMEDOUT; |
5052 | } | 4972 | } |
5053 | 4973 | ||
5054 | static int gfx_v8_0_soft_reset(void *handle) | 4974 | static int gfx_v8_0_check_soft_reset(void *handle) |
5055 | { | 4975 | { |
4976 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
5056 | u32 grbm_soft_reset = 0, srbm_soft_reset = 0; | 4977 | u32 grbm_soft_reset = 0, srbm_soft_reset = 0; |
5057 | u32 tmp; | 4978 | u32 tmp; |
5058 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
5059 | 4979 | ||
5060 | /* GRBM_STATUS */ | 4980 | /* GRBM_STATUS */ |
5061 | tmp = RREG32(mmGRBM_STATUS); | 4981 | tmp = RREG32(mmGRBM_STATUS); |
@@ -5064,16 +4984,12 @@ static int gfx_v8_0_soft_reset(void *handle) | |||
5064 | GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__VGT_BUSY_MASK | | 4984 | GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__VGT_BUSY_MASK | |
5065 | GRBM_STATUS__DB_BUSY_MASK | GRBM_STATUS__CB_BUSY_MASK | | 4985 | GRBM_STATUS__DB_BUSY_MASK | GRBM_STATUS__CB_BUSY_MASK | |
5066 | GRBM_STATUS__GDS_BUSY_MASK | GRBM_STATUS__SPI_BUSY_MASK | | 4986 | GRBM_STATUS__GDS_BUSY_MASK | GRBM_STATUS__SPI_BUSY_MASK | |
5067 | GRBM_STATUS__IA_BUSY_MASK | GRBM_STATUS__IA_BUSY_NO_DMA_MASK)) { | 4987 | GRBM_STATUS__IA_BUSY_MASK | GRBM_STATUS__IA_BUSY_NO_DMA_MASK | |
4988 | GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK)) { | ||
5068 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, | 4989 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, |
5069 | GRBM_SOFT_RESET, SOFT_RESET_CP, 1); | 4990 | GRBM_SOFT_RESET, SOFT_RESET_CP, 1); |
5070 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, | 4991 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, |
5071 | GRBM_SOFT_RESET, SOFT_RESET_GFX, 1); | 4992 | GRBM_SOFT_RESET, SOFT_RESET_GFX, 1); |
5072 | } | ||
5073 | |||
5074 | if (tmp & (GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK)) { | ||
5075 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, | ||
5076 | GRBM_SOFT_RESET, SOFT_RESET_CP, 1); | ||
5077 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, | 4993 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, |
5078 | SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1); | 4994 | SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1); |
5079 | } | 4995 | } |
@@ -5084,73 +5000,199 @@ static int gfx_v8_0_soft_reset(void *handle) | |||
5084 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, | 5000 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, |
5085 | GRBM_SOFT_RESET, SOFT_RESET_RLC, 1); | 5001 | GRBM_SOFT_RESET, SOFT_RESET_RLC, 1); |
5086 | 5002 | ||
5003 | if (REG_GET_FIELD(tmp, GRBM_STATUS2, CPF_BUSY) || | ||
5004 | REG_GET_FIELD(tmp, GRBM_STATUS2, CPC_BUSY) || | ||
5005 | REG_GET_FIELD(tmp, GRBM_STATUS2, CPG_BUSY)) { | ||
5006 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, | ||
5007 | SOFT_RESET_CPF, 1); | ||
5008 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, | ||
5009 | SOFT_RESET_CPC, 1); | ||
5010 | grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, | ||
5011 | SOFT_RESET_CPG, 1); | ||
5012 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, | ||
5013 | SOFT_RESET_GRBM, 1); | ||
5014 | } | ||
5015 | |||
5087 | /* SRBM_STATUS */ | 5016 | /* SRBM_STATUS */ |
5088 | tmp = RREG32(mmSRBM_STATUS); | 5017 | tmp = RREG32(mmSRBM_STATUS); |
5089 | if (REG_GET_FIELD(tmp, SRBM_STATUS, GRBM_RQ_PENDING)) | 5018 | if (REG_GET_FIELD(tmp, SRBM_STATUS, GRBM_RQ_PENDING)) |
5090 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, | 5019 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, |
5091 | SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1); | 5020 | SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1); |
5021 | if (REG_GET_FIELD(tmp, SRBM_STATUS, SEM_BUSY)) | ||
5022 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, | ||
5023 | SRBM_SOFT_RESET, SOFT_RESET_SEM, 1); | ||
5092 | 5024 | ||
5093 | if (grbm_soft_reset || srbm_soft_reset) { | 5025 | if (grbm_soft_reset || srbm_soft_reset) { |
5094 | /* stop the rlc */ | 5026 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang = true; |
5095 | gfx_v8_0_rlc_stop(adev); | 5027 | adev->gfx.grbm_soft_reset = grbm_soft_reset; |
5028 | adev->gfx.srbm_soft_reset = srbm_soft_reset; | ||
5029 | } else { | ||
5030 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang = false; | ||
5031 | adev->gfx.grbm_soft_reset = 0; | ||
5032 | adev->gfx.srbm_soft_reset = 0; | ||
5033 | } | ||
5034 | |||
5035 | return 0; | ||
5036 | } | ||
5096 | 5037 | ||
5038 | static void gfx_v8_0_inactive_hqd(struct amdgpu_device *adev, | ||
5039 | struct amdgpu_ring *ring) | ||
5040 | { | ||
5041 | int i; | ||
5042 | |||
5043 | vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0); | ||
5044 | if (RREG32(mmCP_HQD_ACTIVE) & CP_HQD_ACTIVE__ACTIVE_MASK) { | ||
5045 | u32 tmp; | ||
5046 | tmp = RREG32(mmCP_HQD_DEQUEUE_REQUEST); | ||
5047 | tmp = REG_SET_FIELD(tmp, CP_HQD_DEQUEUE_REQUEST, | ||
5048 | DEQUEUE_REQ, 2); | ||
5049 | WREG32(mmCP_HQD_DEQUEUE_REQUEST, tmp); | ||
5050 | for (i = 0; i < adev->usec_timeout; i++) { | ||
5051 | if (!(RREG32(mmCP_HQD_ACTIVE) & CP_HQD_ACTIVE__ACTIVE_MASK)) | ||
5052 | break; | ||
5053 | udelay(1); | ||
5054 | } | ||
5055 | } | ||
5056 | } | ||
5057 | |||
5058 | static int gfx_v8_0_pre_soft_reset(void *handle) | ||
5059 | { | ||
5060 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
5061 | u32 grbm_soft_reset = 0, srbm_soft_reset = 0; | ||
5062 | |||
5063 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang) | ||
5064 | return 0; | ||
5065 | |||
5066 | grbm_soft_reset = adev->gfx.grbm_soft_reset; | ||
5067 | srbm_soft_reset = adev->gfx.srbm_soft_reset; | ||
5068 | |||
5069 | /* stop the rlc */ | ||
5070 | gfx_v8_0_rlc_stop(adev); | ||
5071 | |||
5072 | if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) || | ||
5073 | REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX)) | ||
5097 | /* Disable GFX parsing/prefetching */ | 5074 | /* Disable GFX parsing/prefetching */ |
5098 | gfx_v8_0_cp_gfx_enable(adev, false); | 5075 | gfx_v8_0_cp_gfx_enable(adev, false); |
5099 | 5076 | ||
5077 | if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) || | ||
5078 | REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPF) || | ||
5079 | REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPC) || | ||
5080 | REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPG)) { | ||
5081 | int i; | ||
5082 | |||
5083 | for (i = 0; i < adev->gfx.num_compute_rings; i++) { | ||
5084 | struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; | ||
5085 | |||
5086 | gfx_v8_0_inactive_hqd(adev, ring); | ||
5087 | } | ||
5100 | /* Disable MEC parsing/prefetching */ | 5088 | /* Disable MEC parsing/prefetching */ |
5101 | gfx_v8_0_cp_compute_enable(adev, false); | 5089 | gfx_v8_0_cp_compute_enable(adev, false); |
5090 | } | ||
5102 | 5091 | ||
5103 | if (grbm_soft_reset || srbm_soft_reset) { | 5092 | return 0; |
5104 | tmp = RREG32(mmGMCON_DEBUG); | 5093 | } |
5105 | tmp = REG_SET_FIELD(tmp, | ||
5106 | GMCON_DEBUG, GFX_STALL, 1); | ||
5107 | tmp = REG_SET_FIELD(tmp, | ||
5108 | GMCON_DEBUG, GFX_CLEAR, 1); | ||
5109 | WREG32(mmGMCON_DEBUG, tmp); | ||
5110 | 5094 | ||
5111 | udelay(50); | 5095 | static int gfx_v8_0_soft_reset(void *handle) |
5112 | } | 5096 | { |
5097 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
5098 | u32 grbm_soft_reset = 0, srbm_soft_reset = 0; | ||
5099 | u32 tmp; | ||
5113 | 5100 | ||
5114 | if (grbm_soft_reset) { | 5101 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang) |
5115 | tmp = RREG32(mmGRBM_SOFT_RESET); | 5102 | return 0; |
5116 | tmp |= grbm_soft_reset; | ||
5117 | dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp); | ||
5118 | WREG32(mmGRBM_SOFT_RESET, tmp); | ||
5119 | tmp = RREG32(mmGRBM_SOFT_RESET); | ||
5120 | 5103 | ||
5121 | udelay(50); | 5104 | grbm_soft_reset = adev->gfx.grbm_soft_reset; |
5105 | srbm_soft_reset = adev->gfx.srbm_soft_reset; | ||
5122 | 5106 | ||
5123 | tmp &= ~grbm_soft_reset; | 5107 | if (grbm_soft_reset || srbm_soft_reset) { |
5124 | WREG32(mmGRBM_SOFT_RESET, tmp); | 5108 | tmp = RREG32(mmGMCON_DEBUG); |
5125 | tmp = RREG32(mmGRBM_SOFT_RESET); | 5109 | tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 1); |
5126 | } | 5110 | tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 1); |
5111 | WREG32(mmGMCON_DEBUG, tmp); | ||
5112 | udelay(50); | ||
5113 | } | ||
5127 | 5114 | ||
5128 | if (srbm_soft_reset) { | 5115 | if (grbm_soft_reset) { |
5129 | tmp = RREG32(mmSRBM_SOFT_RESET); | 5116 | tmp = RREG32(mmGRBM_SOFT_RESET); |
5130 | tmp |= srbm_soft_reset; | 5117 | tmp |= grbm_soft_reset; |
5131 | dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); | 5118 | dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp); |
5132 | WREG32(mmSRBM_SOFT_RESET, tmp); | 5119 | WREG32(mmGRBM_SOFT_RESET, tmp); |
5133 | tmp = RREG32(mmSRBM_SOFT_RESET); | 5120 | tmp = RREG32(mmGRBM_SOFT_RESET); |
5134 | 5121 | ||
5135 | udelay(50); | 5122 | udelay(50); |
5136 | 5123 | ||
5137 | tmp &= ~srbm_soft_reset; | 5124 | tmp &= ~grbm_soft_reset; |
5138 | WREG32(mmSRBM_SOFT_RESET, tmp); | 5125 | WREG32(mmGRBM_SOFT_RESET, tmp); |
5139 | tmp = RREG32(mmSRBM_SOFT_RESET); | 5126 | tmp = RREG32(mmGRBM_SOFT_RESET); |
5140 | } | 5127 | } |
5141 | 5128 | ||
5142 | if (grbm_soft_reset || srbm_soft_reset) { | 5129 | if (srbm_soft_reset) { |
5143 | tmp = RREG32(mmGMCON_DEBUG); | 5130 | tmp = RREG32(mmSRBM_SOFT_RESET); |
5144 | tmp = REG_SET_FIELD(tmp, | 5131 | tmp |= srbm_soft_reset; |
5145 | GMCON_DEBUG, GFX_STALL, 0); | 5132 | dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); |
5146 | tmp = REG_SET_FIELD(tmp, | 5133 | WREG32(mmSRBM_SOFT_RESET, tmp); |
5147 | GMCON_DEBUG, GFX_CLEAR, 0); | 5134 | tmp = RREG32(mmSRBM_SOFT_RESET); |
5148 | WREG32(mmGMCON_DEBUG, tmp); | ||
5149 | } | ||
5150 | 5135 | ||
5151 | /* Wait a little for things to settle down */ | ||
5152 | udelay(50); | 5136 | udelay(50); |
5137 | |||
5138 | tmp &= ~srbm_soft_reset; | ||
5139 | WREG32(mmSRBM_SOFT_RESET, tmp); | ||
5140 | tmp = RREG32(mmSRBM_SOFT_RESET); | ||
5153 | } | 5141 | } |
5142 | |||
5143 | if (grbm_soft_reset || srbm_soft_reset) { | ||
5144 | tmp = RREG32(mmGMCON_DEBUG); | ||
5145 | tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 0); | ||
5146 | tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 0); | ||
5147 | WREG32(mmGMCON_DEBUG, tmp); | ||
5148 | } | ||
5149 | |||
5150 | /* Wait a little for things to settle down */ | ||
5151 | udelay(50); | ||
5152 | |||
5153 | return 0; | ||
5154 | } | ||
5155 | |||
5156 | static void gfx_v8_0_init_hqd(struct amdgpu_device *adev, | ||
5157 | struct amdgpu_ring *ring) | ||
5158 | { | ||
5159 | vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0); | ||
5160 | WREG32(mmCP_HQD_DEQUEUE_REQUEST, 0); | ||
5161 | WREG32(mmCP_HQD_PQ_RPTR, 0); | ||
5162 | WREG32(mmCP_HQD_PQ_WPTR, 0); | ||
5163 | vi_srbm_select(adev, 0, 0, 0, 0); | ||
5164 | } | ||
5165 | |||
5166 | static int gfx_v8_0_post_soft_reset(void *handle) | ||
5167 | { | ||
5168 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
5169 | u32 grbm_soft_reset = 0, srbm_soft_reset = 0; | ||
5170 | |||
5171 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang) | ||
5172 | return 0; | ||
5173 | |||
5174 | grbm_soft_reset = adev->gfx.grbm_soft_reset; | ||
5175 | srbm_soft_reset = adev->gfx.srbm_soft_reset; | ||
5176 | |||
5177 | if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) || | ||
5178 | REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX)) | ||
5179 | gfx_v8_0_cp_gfx_resume(adev); | ||
5180 | |||
5181 | if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) || | ||
5182 | REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPF) || | ||
5183 | REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPC) || | ||
5184 | REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPG)) { | ||
5185 | int i; | ||
5186 | |||
5187 | for (i = 0; i < adev->gfx.num_compute_rings; i++) { | ||
5188 | struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; | ||
5189 | |||
5190 | gfx_v8_0_init_hqd(adev, ring); | ||
5191 | } | ||
5192 | gfx_v8_0_cp_compute_resume(adev); | ||
5193 | } | ||
5194 | gfx_v8_0_rlc_start(adev); | ||
5195 | |||
5154 | return 0; | 5196 | return 0; |
5155 | } | 5197 | } |
5156 | 5198 | ||
@@ -5269,8 +5311,6 @@ static int gfx_v8_0_late_init(void *handle) | |||
5269 | static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev, | 5311 | static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev, |
5270 | bool enable) | 5312 | bool enable) |
5271 | { | 5313 | { |
5272 | uint32_t data, temp; | ||
5273 | |||
5274 | if (adev->asic_type == CHIP_POLARIS11) | 5314 | if (adev->asic_type == CHIP_POLARIS11) |
5275 | /* Send msg to SMU via Powerplay */ | 5315 | /* Send msg to SMU via Powerplay */ |
5276 | amdgpu_set_powergating_state(adev, | 5316 | amdgpu_set_powergating_state(adev, |
@@ -5278,83 +5318,35 @@ static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *ade | |||
5278 | enable ? | 5318 | enable ? |
5279 | AMD_PG_STATE_GATE : AMD_PG_STATE_UNGATE); | 5319 | AMD_PG_STATE_GATE : AMD_PG_STATE_UNGATE); |
5280 | 5320 | ||
5281 | temp = data = RREG32(mmRLC_PG_CNTL); | 5321 | WREG32_FIELD(RLC_PG_CNTL, STATIC_PER_CU_PG_ENABLE, enable ? 1 : 0); |
5282 | /* Enable static MGPG */ | ||
5283 | if (enable) | ||
5284 | data |= RLC_PG_CNTL__STATIC_PER_CU_PG_ENABLE_MASK; | ||
5285 | else | ||
5286 | data &= ~RLC_PG_CNTL__STATIC_PER_CU_PG_ENABLE_MASK; | ||
5287 | |||
5288 | if (temp != data) | ||
5289 | WREG32(mmRLC_PG_CNTL, data); | ||
5290 | } | 5322 | } |
5291 | 5323 | ||
5292 | static void gfx_v8_0_enable_gfx_dynamic_mg_power_gating(struct amdgpu_device *adev, | 5324 | static void gfx_v8_0_enable_gfx_dynamic_mg_power_gating(struct amdgpu_device *adev, |
5293 | bool enable) | 5325 | bool enable) |
5294 | { | 5326 | { |
5295 | uint32_t data, temp; | 5327 | WREG32_FIELD(RLC_PG_CNTL, DYN_PER_CU_PG_ENABLE, enable ? 1 : 0); |
5296 | |||
5297 | temp = data = RREG32(mmRLC_PG_CNTL); | ||
5298 | /* Enable dynamic MGPG */ | ||
5299 | if (enable) | ||
5300 | data |= RLC_PG_CNTL__DYN_PER_CU_PG_ENABLE_MASK; | ||
5301 | else | ||
5302 | data &= ~RLC_PG_CNTL__DYN_PER_CU_PG_ENABLE_MASK; | ||
5303 | |||
5304 | if (temp != data) | ||
5305 | WREG32(mmRLC_PG_CNTL, data); | ||
5306 | } | 5328 | } |
5307 | 5329 | ||
5308 | static void polaris11_enable_gfx_quick_mg_power_gating(struct amdgpu_device *adev, | 5330 | static void polaris11_enable_gfx_quick_mg_power_gating(struct amdgpu_device *adev, |
5309 | bool enable) | 5331 | bool enable) |
5310 | { | 5332 | { |
5311 | uint32_t data, temp; | 5333 | WREG32_FIELD(RLC_PG_CNTL, QUICK_PG_ENABLE, enable ? 1 : 0); |
5312 | |||
5313 | temp = data = RREG32(mmRLC_PG_CNTL); | ||
5314 | /* Enable quick PG */ | ||
5315 | if (enable) | ||
5316 | data |= RLC_PG_CNTL__QUICK_PG_ENABLE_MASK; | ||
5317 | else | ||
5318 | data &= ~RLC_PG_CNTL__QUICK_PG_ENABLE_MASK; | ||
5319 | |||
5320 | if (temp != data) | ||
5321 | WREG32(mmRLC_PG_CNTL, data); | ||
5322 | } | 5334 | } |
5323 | 5335 | ||
5324 | static void cz_enable_gfx_cg_power_gating(struct amdgpu_device *adev, | 5336 | static void cz_enable_gfx_cg_power_gating(struct amdgpu_device *adev, |
5325 | bool enable) | 5337 | bool enable) |
5326 | { | 5338 | { |
5327 | u32 data, orig; | 5339 | WREG32_FIELD(RLC_PG_CNTL, GFX_POWER_GATING_ENABLE, enable ? 1 : 0); |
5328 | |||
5329 | orig = data = RREG32(mmRLC_PG_CNTL); | ||
5330 | |||
5331 | if (enable) | ||
5332 | data |= RLC_PG_CNTL__GFX_POWER_GATING_ENABLE_MASK; | ||
5333 | else | ||
5334 | data &= ~RLC_PG_CNTL__GFX_POWER_GATING_ENABLE_MASK; | ||
5335 | |||
5336 | if (orig != data) | ||
5337 | WREG32(mmRLC_PG_CNTL, data); | ||
5338 | } | 5340 | } |
5339 | 5341 | ||
5340 | static void cz_enable_gfx_pipeline_power_gating(struct amdgpu_device *adev, | 5342 | static void cz_enable_gfx_pipeline_power_gating(struct amdgpu_device *adev, |
5341 | bool enable) | 5343 | bool enable) |
5342 | { | 5344 | { |
5343 | u32 data, orig; | 5345 | WREG32_FIELD(RLC_PG_CNTL, GFX_PIPELINE_PG_ENABLE, enable ? 1 : 0); |
5344 | |||
5345 | orig = data = RREG32(mmRLC_PG_CNTL); | ||
5346 | |||
5347 | if (enable) | ||
5348 | data |= RLC_PG_CNTL__GFX_PIPELINE_PG_ENABLE_MASK; | ||
5349 | else | ||
5350 | data &= ~RLC_PG_CNTL__GFX_PIPELINE_PG_ENABLE_MASK; | ||
5351 | |||
5352 | if (orig != data) | ||
5353 | WREG32(mmRLC_PG_CNTL, data); | ||
5354 | 5346 | ||
5355 | /* Read any GFX register to wake up GFX. */ | 5347 | /* Read any GFX register to wake up GFX. */ |
5356 | if (!enable) | 5348 | if (!enable) |
5357 | data = RREG32(mmDB_RENDER_CONTROL); | 5349 | RREG32(mmDB_RENDER_CONTROL); |
5358 | } | 5350 | } |
5359 | 5351 | ||
5360 | static void cz_update_gfx_cg_power_gating(struct amdgpu_device *adev, | 5352 | static void cz_update_gfx_cg_power_gating(struct amdgpu_device *adev, |
@@ -5430,15 +5422,15 @@ static void gfx_v8_0_send_serdes_cmd(struct amdgpu_device *adev, | |||
5430 | 5422 | ||
5431 | data = RREG32(mmRLC_SERDES_WR_CTRL); | 5423 | data = RREG32(mmRLC_SERDES_WR_CTRL); |
5432 | if (adev->asic_type == CHIP_STONEY) | 5424 | if (adev->asic_type == CHIP_STONEY) |
5433 | data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK | | 5425 | data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK | |
5434 | RLC_SERDES_WR_CTRL__READ_COMMAND_MASK | | 5426 | RLC_SERDES_WR_CTRL__READ_COMMAND_MASK | |
5435 | RLC_SERDES_WR_CTRL__P1_SELECT_MASK | | 5427 | RLC_SERDES_WR_CTRL__P1_SELECT_MASK | |
5436 | RLC_SERDES_WR_CTRL__P2_SELECT_MASK | | 5428 | RLC_SERDES_WR_CTRL__P2_SELECT_MASK | |
5437 | RLC_SERDES_WR_CTRL__RDDATA_RESET_MASK | | 5429 | RLC_SERDES_WR_CTRL__RDDATA_RESET_MASK | |
5438 | RLC_SERDES_WR_CTRL__POWER_DOWN_MASK | | 5430 | RLC_SERDES_WR_CTRL__POWER_DOWN_MASK | |
5439 | RLC_SERDES_WR_CTRL__POWER_UP_MASK | | 5431 | RLC_SERDES_WR_CTRL__POWER_UP_MASK | |
5440 | RLC_SERDES_WR_CTRL__SHORT_FORMAT_MASK | | 5432 | RLC_SERDES_WR_CTRL__SHORT_FORMAT_MASK | |
5441 | RLC_SERDES_WR_CTRL__SRBM_OVERRIDE_MASK); | 5433 | RLC_SERDES_WR_CTRL__SRBM_OVERRIDE_MASK); |
5442 | else | 5434 | else |
5443 | data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK | | 5435 | data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK | |
5444 | RLC_SERDES_WR_CTRL__READ_COMMAND_MASK | | 5436 | RLC_SERDES_WR_CTRL__READ_COMMAND_MASK | |
@@ -5461,10 +5453,10 @@ static void gfx_v8_0_send_serdes_cmd(struct amdgpu_device *adev, | |||
5461 | 5453 | ||
5462 | #define MSG_ENTER_RLC_SAFE_MODE 1 | 5454 | #define MSG_ENTER_RLC_SAFE_MODE 1 |
5463 | #define MSG_EXIT_RLC_SAFE_MODE 0 | 5455 | #define MSG_EXIT_RLC_SAFE_MODE 0 |
5464 | 5456 | #define RLC_GPR_REG2__REQ_MASK 0x00000001 | |
5465 | #define RLC_GPR_REG2__REQ_MASK 0x00000001 | 5457 | #define RLC_GPR_REG2__REQ__SHIFT 0 |
5466 | #define RLC_GPR_REG2__MESSAGE__SHIFT 0x00000001 | 5458 | #define RLC_GPR_REG2__MESSAGE__SHIFT 0x00000001 |
5467 | #define RLC_GPR_REG2__MESSAGE_MASK 0x0000001e | 5459 | #define RLC_GPR_REG2__MESSAGE_MASK 0x0000001e |
5468 | 5460 | ||
5469 | static void cz_enter_rlc_safe_mode(struct amdgpu_device *adev) | 5461 | static void cz_enter_rlc_safe_mode(struct amdgpu_device *adev) |
5470 | { | 5462 | { |
@@ -5494,7 +5486,7 @@ static void cz_enter_rlc_safe_mode(struct amdgpu_device *adev) | |||
5494 | } | 5486 | } |
5495 | 5487 | ||
5496 | for (i = 0; i < adev->usec_timeout; i++) { | 5488 | for (i = 0; i < adev->usec_timeout; i++) { |
5497 | if ((RREG32(mmRLC_GPR_REG2) & RLC_GPR_REG2__REQ_MASK) == 0) | 5489 | if (!REG_GET_FIELD(RREG32(mmRLC_GPR_REG2), RLC_GPR_REG2, REQ)) |
5498 | break; | 5490 | break; |
5499 | udelay(1); | 5491 | udelay(1); |
5500 | } | 5492 | } |
@@ -5522,7 +5514,7 @@ static void cz_exit_rlc_safe_mode(struct amdgpu_device *adev) | |||
5522 | } | 5514 | } |
5523 | 5515 | ||
5524 | for (i = 0; i < adev->usec_timeout; i++) { | 5516 | for (i = 0; i < adev->usec_timeout; i++) { |
5525 | if ((RREG32(mmRLC_GPR_REG2) & RLC_GPR_REG2__REQ_MASK) == 0) | 5517 | if (!REG_GET_FIELD(RREG32(mmRLC_GPR_REG2), RLC_GPR_REG2, REQ)) |
5526 | break; | 5518 | break; |
5527 | udelay(1); | 5519 | udelay(1); |
5528 | } | 5520 | } |
@@ -5554,7 +5546,7 @@ static void iceland_enter_rlc_safe_mode(struct amdgpu_device *adev) | |||
5554 | } | 5546 | } |
5555 | 5547 | ||
5556 | for (i = 0; i < adev->usec_timeout; i++) { | 5548 | for (i = 0; i < adev->usec_timeout; i++) { |
5557 | if ((RREG32(mmRLC_SAFE_MODE) & RLC_SAFE_MODE__CMD_MASK) == 0) | 5549 | if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD)) |
5558 | break; | 5550 | break; |
5559 | udelay(1); | 5551 | udelay(1); |
5560 | } | 5552 | } |
@@ -5581,7 +5573,7 @@ static void iceland_exit_rlc_safe_mode(struct amdgpu_device *adev) | |||
5581 | } | 5573 | } |
5582 | 5574 | ||
5583 | for (i = 0; i < adev->usec_timeout; i++) { | 5575 | for (i = 0; i < adev->usec_timeout; i++) { |
5584 | if ((RREG32(mmRLC_SAFE_MODE) & RLC_SAFE_MODE__CMD_MASK) == 0) | 5576 | if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD)) |
5585 | break; | 5577 | break; |
5586 | udelay(1); | 5578 | udelay(1); |
5587 | } | 5579 | } |
@@ -5622,21 +5614,12 @@ static void gfx_v8_0_update_medium_grain_clock_gating(struct amdgpu_device *adev | |||
5622 | /* It is disabled by HW by default */ | 5614 | /* It is disabled by HW by default */ |
5623 | if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) { | 5615 | if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) { |
5624 | if (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGLS) { | 5616 | if (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGLS) { |
5625 | if (adev->cg_flags & AMD_CG_SUPPORT_GFX_RLC_LS) { | 5617 | if (adev->cg_flags & AMD_CG_SUPPORT_GFX_RLC_LS) |
5626 | /* 1 - RLC memory Light sleep */ | 5618 | /* 1 - RLC memory Light sleep */ |
5627 | temp = data = RREG32(mmRLC_MEM_SLP_CNTL); | 5619 | WREG32_FIELD(RLC_MEM_SLP_CNTL, RLC_MEM_LS_EN, 1); |
5628 | data |= RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK; | ||
5629 | if (temp != data) | ||
5630 | WREG32(mmRLC_MEM_SLP_CNTL, data); | ||
5631 | } | ||
5632 | 5620 | ||
5633 | if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CP_LS) { | 5621 | if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CP_LS) |
5634 | /* 2 - CP memory Light sleep */ | 5622 | WREG32_FIELD(CP_MEM_SLP_CNTL, CP_MEM_LS_EN, 1); |
5635 | temp = data = RREG32(mmCP_MEM_SLP_CNTL); | ||
5636 | data |= CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK; | ||
5637 | if (temp != data) | ||
5638 | WREG32(mmCP_MEM_SLP_CNTL, data); | ||
5639 | } | ||
5640 | } | 5623 | } |
5641 | 5624 | ||
5642 | /* 3 - RLC_CGTT_MGCG_OVERRIDE */ | 5625 | /* 3 - RLC_CGTT_MGCG_OVERRIDE */ |
@@ -5854,25 +5837,18 @@ static int gfx_v8_0_set_clockgating_state(void *handle, | |||
5854 | 5837 | ||
5855 | static u32 gfx_v8_0_ring_get_rptr_gfx(struct amdgpu_ring *ring) | 5838 | static u32 gfx_v8_0_ring_get_rptr_gfx(struct amdgpu_ring *ring) |
5856 | { | 5839 | { |
5857 | u32 rptr; | 5840 | return ring->adev->wb.wb[ring->rptr_offs]; |
5858 | |||
5859 | rptr = ring->adev->wb.wb[ring->rptr_offs]; | ||
5860 | |||
5861 | return rptr; | ||
5862 | } | 5841 | } |
5863 | 5842 | ||
5864 | static u32 gfx_v8_0_ring_get_wptr_gfx(struct amdgpu_ring *ring) | 5843 | static u32 gfx_v8_0_ring_get_wptr_gfx(struct amdgpu_ring *ring) |
5865 | { | 5844 | { |
5866 | struct amdgpu_device *adev = ring->adev; | 5845 | struct amdgpu_device *adev = ring->adev; |
5867 | u32 wptr; | ||
5868 | 5846 | ||
5869 | if (ring->use_doorbell) | 5847 | if (ring->use_doorbell) |
5870 | /* XXX check if swapping is necessary on BE */ | 5848 | /* XXX check if swapping is necessary on BE */ |
5871 | wptr = ring->adev->wb.wb[ring->wptr_offs]; | 5849 | return ring->adev->wb.wb[ring->wptr_offs]; |
5872 | else | 5850 | else |
5873 | wptr = RREG32(mmCP_RB0_WPTR); | 5851 | return RREG32(mmCP_RB0_WPTR); |
5874 | |||
5875 | return wptr; | ||
5876 | } | 5852 | } |
5877 | 5853 | ||
5878 | static void gfx_v8_0_ring_set_wptr_gfx(struct amdgpu_ring *ring) | 5854 | static void gfx_v8_0_ring_set_wptr_gfx(struct amdgpu_ring *ring) |
@@ -5971,9 +5947,9 @@ static void gfx_v8_0_ring_emit_ib_compute(struct amdgpu_ring *ring, | |||
5971 | amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); | 5947 | amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); |
5972 | amdgpu_ring_write(ring, | 5948 | amdgpu_ring_write(ring, |
5973 | #ifdef __BIG_ENDIAN | 5949 | #ifdef __BIG_ENDIAN |
5974 | (2 << 0) | | 5950 | (2 << 0) | |
5975 | #endif | 5951 | #endif |
5976 | (ib->gpu_addr & 0xFFFFFFFC)); | 5952 | (ib->gpu_addr & 0xFFFFFFFC)); |
5977 | amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF); | 5953 | amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF); |
5978 | amdgpu_ring_write(ring, control); | 5954 | amdgpu_ring_write(ring, control); |
5979 | } | 5955 | } |
@@ -6118,33 +6094,14 @@ static void gfx_v8_0_ring_emit_fence_compute(struct amdgpu_ring *ring, | |||
6118 | static void gfx_v8_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev, | 6094 | static void gfx_v8_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev, |
6119 | enum amdgpu_interrupt_state state) | 6095 | enum amdgpu_interrupt_state state) |
6120 | { | 6096 | { |
6121 | u32 cp_int_cntl; | 6097 | WREG32_FIELD(CP_INT_CNTL_RING0, TIME_STAMP_INT_ENABLE, |
6122 | 6098 | state == AMDGPU_IRQ_STATE_DISABLE ? 0 : 1); | |
6123 | switch (state) { | ||
6124 | case AMDGPU_IRQ_STATE_DISABLE: | ||
6125 | cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0); | ||
6126 | cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0, | ||
6127 | TIME_STAMP_INT_ENABLE, 0); | ||
6128 | WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl); | ||
6129 | break; | ||
6130 | case AMDGPU_IRQ_STATE_ENABLE: | ||
6131 | cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0); | ||
6132 | cp_int_cntl = | ||
6133 | REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0, | ||
6134 | TIME_STAMP_INT_ENABLE, 1); | ||
6135 | WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl); | ||
6136 | break; | ||
6137 | default: | ||
6138 | break; | ||
6139 | } | ||
6140 | } | 6099 | } |
6141 | 6100 | ||
6142 | static void gfx_v8_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev, | 6101 | static void gfx_v8_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev, |
6143 | int me, int pipe, | 6102 | int me, int pipe, |
6144 | enum amdgpu_interrupt_state state) | 6103 | enum amdgpu_interrupt_state state) |
6145 | { | 6104 | { |
6146 | u32 mec_int_cntl, mec_int_cntl_reg; | ||
6147 | |||
6148 | /* | 6105 | /* |
6149 | * amdgpu controls only pipe 0 of MEC1. That's why this function only | 6106 | * amdgpu controls only pipe 0 of MEC1. That's why this function only |
6150 | * handles the setting of interrupts for this specific pipe. All other | 6107 | * handles the setting of interrupts for this specific pipe. All other |
@@ -6154,7 +6111,6 @@ static void gfx_v8_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev, | |||
6154 | if (me == 1) { | 6111 | if (me == 1) { |
6155 | switch (pipe) { | 6112 | switch (pipe) { |
6156 | case 0: | 6113 | case 0: |
6157 | mec_int_cntl_reg = mmCP_ME1_PIPE0_INT_CNTL; | ||
6158 | break; | 6114 | break; |
6159 | default: | 6115 | default: |
6160 | DRM_DEBUG("invalid pipe %d\n", pipe); | 6116 | DRM_DEBUG("invalid pipe %d\n", pipe); |
@@ -6165,22 +6121,8 @@ static void gfx_v8_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev, | |||
6165 | return; | 6121 | return; |
6166 | } | 6122 | } |
6167 | 6123 | ||
6168 | switch (state) { | 6124 | WREG32_FIELD(CP_ME1_PIPE0_INT_CNTL, TIME_STAMP_INT_ENABLE, |
6169 | case AMDGPU_IRQ_STATE_DISABLE: | 6125 | state == AMDGPU_IRQ_STATE_DISABLE ? 0 : 1); |
6170 | mec_int_cntl = RREG32(mec_int_cntl_reg); | ||
6171 | mec_int_cntl = REG_SET_FIELD(mec_int_cntl, CP_ME1_PIPE0_INT_CNTL, | ||
6172 | TIME_STAMP_INT_ENABLE, 0); | ||
6173 | WREG32(mec_int_cntl_reg, mec_int_cntl); | ||
6174 | break; | ||
6175 | case AMDGPU_IRQ_STATE_ENABLE: | ||
6176 | mec_int_cntl = RREG32(mec_int_cntl_reg); | ||
6177 | mec_int_cntl = REG_SET_FIELD(mec_int_cntl, CP_ME1_PIPE0_INT_CNTL, | ||
6178 | TIME_STAMP_INT_ENABLE, 1); | ||
6179 | WREG32(mec_int_cntl_reg, mec_int_cntl); | ||
6180 | break; | ||
6181 | default: | ||
6182 | break; | ||
6183 | } | ||
6184 | } | 6126 | } |
6185 | 6127 | ||
6186 | static int gfx_v8_0_set_priv_reg_fault_state(struct amdgpu_device *adev, | 6128 | static int gfx_v8_0_set_priv_reg_fault_state(struct amdgpu_device *adev, |
@@ -6188,24 +6130,8 @@ static int gfx_v8_0_set_priv_reg_fault_state(struct amdgpu_device *adev, | |||
6188 | unsigned type, | 6130 | unsigned type, |
6189 | enum amdgpu_interrupt_state state) | 6131 | enum amdgpu_interrupt_state state) |
6190 | { | 6132 | { |
6191 | u32 cp_int_cntl; | 6133 | WREG32_FIELD(CP_INT_CNTL_RING0, PRIV_REG_INT_ENABLE, |
6192 | 6134 | state == AMDGPU_IRQ_STATE_DISABLE ? 0 : 1); | |
6193 | switch (state) { | ||
6194 | case AMDGPU_IRQ_STATE_DISABLE: | ||
6195 | cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0); | ||
6196 | cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0, | ||
6197 | PRIV_REG_INT_ENABLE, 0); | ||
6198 | WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl); | ||
6199 | break; | ||
6200 | case AMDGPU_IRQ_STATE_ENABLE: | ||
6201 | cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0); | ||
6202 | cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0, | ||
6203 | PRIV_REG_INT_ENABLE, 1); | ||
6204 | WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl); | ||
6205 | break; | ||
6206 | default: | ||
6207 | break; | ||
6208 | } | ||
6209 | 6135 | ||
6210 | return 0; | 6136 | return 0; |
6211 | } | 6137 | } |
@@ -6215,24 +6141,8 @@ static int gfx_v8_0_set_priv_inst_fault_state(struct amdgpu_device *adev, | |||
6215 | unsigned type, | 6141 | unsigned type, |
6216 | enum amdgpu_interrupt_state state) | 6142 | enum amdgpu_interrupt_state state) |
6217 | { | 6143 | { |
6218 | u32 cp_int_cntl; | 6144 | WREG32_FIELD(CP_INT_CNTL_RING0, PRIV_INSTR_INT_ENABLE, |
6219 | 6145 | state == AMDGPU_IRQ_STATE_DISABLE ? 0 : 1); | |
6220 | switch (state) { | ||
6221 | case AMDGPU_IRQ_STATE_DISABLE: | ||
6222 | cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0); | ||
6223 | cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0, | ||
6224 | PRIV_INSTR_INT_ENABLE, 0); | ||
6225 | WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl); | ||
6226 | break; | ||
6227 | case AMDGPU_IRQ_STATE_ENABLE: | ||
6228 | cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0); | ||
6229 | cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0, | ||
6230 | PRIV_INSTR_INT_ENABLE, 1); | ||
6231 | WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl); | ||
6232 | break; | ||
6233 | default: | ||
6234 | break; | ||
6235 | } | ||
6236 | 6146 | ||
6237 | return 0; | 6147 | return 0; |
6238 | } | 6148 | } |
@@ -6338,7 +6248,10 @@ const struct amd_ip_funcs gfx_v8_0_ip_funcs = { | |||
6338 | .resume = gfx_v8_0_resume, | 6248 | .resume = gfx_v8_0_resume, |
6339 | .is_idle = gfx_v8_0_is_idle, | 6249 | .is_idle = gfx_v8_0_is_idle, |
6340 | .wait_for_idle = gfx_v8_0_wait_for_idle, | 6250 | .wait_for_idle = gfx_v8_0_wait_for_idle, |
6251 | .check_soft_reset = gfx_v8_0_check_soft_reset, | ||
6252 | .pre_soft_reset = gfx_v8_0_pre_soft_reset, | ||
6341 | .soft_reset = gfx_v8_0_soft_reset, | 6253 | .soft_reset = gfx_v8_0_soft_reset, |
6254 | .post_soft_reset = gfx_v8_0_post_soft_reset, | ||
6342 | .set_clockgating_state = gfx_v8_0_set_clockgating_state, | 6255 | .set_clockgating_state = gfx_v8_0_set_clockgating_state, |
6343 | .set_powergating_state = gfx_v8_0_set_powergating_state, | 6256 | .set_powergating_state = gfx_v8_0_set_powergating_state, |
6344 | }; | 6257 | }; |
@@ -6479,15 +6392,12 @@ static u32 gfx_v8_0_get_cu_active_bitmap(struct amdgpu_device *adev) | |||
6479 | { | 6392 | { |
6480 | u32 data, mask; | 6393 | u32 data, mask; |
6481 | 6394 | ||
6482 | data = RREG32(mmCC_GC_SHADER_ARRAY_CONFIG); | 6395 | data = RREG32(mmCC_GC_SHADER_ARRAY_CONFIG) | |
6483 | data |= RREG32(mmGC_USER_SHADER_ARRAY_CONFIG); | 6396 | RREG32(mmGC_USER_SHADER_ARRAY_CONFIG); |
6484 | |||
6485 | data &= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_CUS_MASK; | ||
6486 | data >>= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_CUS__SHIFT; | ||
6487 | 6397 | ||
6488 | mask = gfx_v8_0_create_bitmask(adev->gfx.config.max_cu_per_sh); | 6398 | mask = gfx_v8_0_create_bitmask(adev->gfx.config.max_cu_per_sh); |
6489 | 6399 | ||
6490 | return (~data) & mask; | 6400 | return ~REG_GET_FIELD(data, CC_GC_SHADER_ARRAY_CONFIG, INACTIVE_CUS) & mask; |
6491 | } | 6401 | } |
6492 | 6402 | ||
6493 | static void gfx_v8_0_get_cu_info(struct amdgpu_device *adev) | 6403 | static void gfx_v8_0_get_cu_info(struct amdgpu_device *adev) |
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.h b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.h index bc82c794312c..ebed1f829297 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.h +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.h | |||
@@ -26,6 +26,4 @@ | |||
26 | 26 | ||
27 | extern const struct amd_ip_funcs gfx_v8_0_ip_funcs; | 27 | extern const struct amd_ip_funcs gfx_v8_0_ip_funcs; |
28 | 28 | ||
29 | void gfx_v8_0_select_se_sh(struct amdgpu_device *adev, u32 se_num, u32 sh_num); | ||
30 | |||
31 | #endif | 29 | #endif |
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 0b0f08641eed..aa0c4b964621 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | |||
@@ -183,7 +183,7 @@ static int gmc_v7_0_mc_load_microcode(struct amdgpu_device *adev) | |||
183 | const struct mc_firmware_header_v1_0 *hdr; | 183 | const struct mc_firmware_header_v1_0 *hdr; |
184 | const __le32 *fw_data = NULL; | 184 | const __le32 *fw_data = NULL; |
185 | const __le32 *io_mc_regs = NULL; | 185 | const __le32 *io_mc_regs = NULL; |
186 | u32 running, blackout = 0; | 186 | u32 running; |
187 | int i, ucode_size, regs_size; | 187 | int i, ucode_size, regs_size; |
188 | 188 | ||
189 | if (!adev->mc.fw) | 189 | if (!adev->mc.fw) |
@@ -203,11 +203,6 @@ static int gmc_v7_0_mc_load_microcode(struct amdgpu_device *adev) | |||
203 | running = REG_GET_FIELD(RREG32(mmMC_SEQ_SUP_CNTL), MC_SEQ_SUP_CNTL, RUN); | 203 | running = REG_GET_FIELD(RREG32(mmMC_SEQ_SUP_CNTL), MC_SEQ_SUP_CNTL, RUN); |
204 | 204 | ||
205 | if (running == 0) { | 205 | if (running == 0) { |
206 | if (running) { | ||
207 | blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL); | ||
208 | WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout | 1); | ||
209 | } | ||
210 | |||
211 | /* reset the engine and set to writable */ | 206 | /* reset the engine and set to writable */ |
212 | WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008); | 207 | WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008); |
213 | WREG32(mmMC_SEQ_SUP_CNTL, 0x00000010); | 208 | WREG32(mmMC_SEQ_SUP_CNTL, 0x00000010); |
@@ -239,9 +234,6 @@ static int gmc_v7_0_mc_load_microcode(struct amdgpu_device *adev) | |||
239 | break; | 234 | break; |
240 | udelay(1); | 235 | udelay(1); |
241 | } | 236 | } |
242 | |||
243 | if (running) | ||
244 | WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout); | ||
245 | } | 237 | } |
246 | 238 | ||
247 | return 0; | 239 | return 0; |
@@ -393,7 +385,7 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev) | |||
393 | * size equal to the 1024 or vram, whichever is larger. | 385 | * size equal to the 1024 or vram, whichever is larger. |
394 | */ | 386 | */ |
395 | if (amdgpu_gart_size == -1) | 387 | if (amdgpu_gart_size == -1) |
396 | adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size); | 388 | adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev); |
397 | else | 389 | else |
398 | adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20; | 390 | adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20; |
399 | 391 | ||
@@ -953,6 +945,11 @@ static int gmc_v7_0_sw_init(void *handle) | |||
953 | return r; | 945 | return r; |
954 | } | 946 | } |
955 | 947 | ||
948 | r = amdgpu_ttm_global_init(adev); | ||
949 | if (r) { | ||
950 | return r; | ||
951 | } | ||
952 | |||
956 | r = gmc_v7_0_mc_init(adev); | 953 | r = gmc_v7_0_mc_init(adev); |
957 | if (r) | 954 | if (r) |
958 | return r; | 955 | return r; |
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 2aee2c6f3cd5..84c10d5117a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | |||
@@ -261,7 +261,7 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev) | |||
261 | const struct mc_firmware_header_v1_0 *hdr; | 261 | const struct mc_firmware_header_v1_0 *hdr; |
262 | const __le32 *fw_data = NULL; | 262 | const __le32 *fw_data = NULL; |
263 | const __le32 *io_mc_regs = NULL; | 263 | const __le32 *io_mc_regs = NULL; |
264 | u32 running, blackout = 0; | 264 | u32 running; |
265 | int i, ucode_size, regs_size; | 265 | int i, ucode_size, regs_size; |
266 | 266 | ||
267 | if (!adev->mc.fw) | 267 | if (!adev->mc.fw) |
@@ -287,11 +287,6 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev) | |||
287 | running = REG_GET_FIELD(RREG32(mmMC_SEQ_SUP_CNTL), MC_SEQ_SUP_CNTL, RUN); | 287 | running = REG_GET_FIELD(RREG32(mmMC_SEQ_SUP_CNTL), MC_SEQ_SUP_CNTL, RUN); |
288 | 288 | ||
289 | if (running == 0) { | 289 | if (running == 0) { |
290 | if (running) { | ||
291 | blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL); | ||
292 | WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout | 1); | ||
293 | } | ||
294 | |||
295 | /* reset the engine and set to writable */ | 290 | /* reset the engine and set to writable */ |
296 | WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008); | 291 | WREG32(mmMC_SEQ_SUP_CNTL, 0x00000008); |
297 | WREG32(mmMC_SEQ_SUP_CNTL, 0x00000010); | 292 | WREG32(mmMC_SEQ_SUP_CNTL, 0x00000010); |
@@ -323,9 +318,6 @@ static int gmc_v8_0_mc_load_microcode(struct amdgpu_device *adev) | |||
323 | break; | 318 | break; |
324 | udelay(1); | 319 | udelay(1); |
325 | } | 320 | } |
326 | |||
327 | if (running) | ||
328 | WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout); | ||
329 | } | 321 | } |
330 | 322 | ||
331 | return 0; | 323 | return 0; |
@@ -477,7 +469,7 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev) | |||
477 | * size equal to the 1024 or vram, whichever is larger. | 469 | * size equal to the 1024 or vram, whichever is larger. |
478 | */ | 470 | */ |
479 | if (amdgpu_gart_size == -1) | 471 | if (amdgpu_gart_size == -1) |
480 | adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size); | 472 | adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev); |
481 | else | 473 | else |
482 | adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20; | 474 | adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20; |
483 | 475 | ||
@@ -957,6 +949,11 @@ static int gmc_v8_0_sw_init(void *handle) | |||
957 | return r; | 949 | return r; |
958 | } | 950 | } |
959 | 951 | ||
952 | r = amdgpu_ttm_global_init(adev); | ||
953 | if (r) { | ||
954 | return r; | ||
955 | } | ||
956 | |||
960 | r = gmc_v8_0_mc_init(adev); | 957 | r = gmc_v8_0_mc_init(adev); |
961 | if (r) | 958 | if (r) |
962 | return r; | 959 | return r; |
@@ -1100,9 +1097,8 @@ static int gmc_v8_0_wait_for_idle(void *handle) | |||
1100 | 1097 | ||
1101 | } | 1098 | } |
1102 | 1099 | ||
1103 | static int gmc_v8_0_soft_reset(void *handle) | 1100 | static int gmc_v8_0_check_soft_reset(void *handle) |
1104 | { | 1101 | { |
1105 | struct amdgpu_mode_mc_save save; | ||
1106 | u32 srbm_soft_reset = 0; | 1102 | u32 srbm_soft_reset = 0; |
1107 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 1103 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
1108 | u32 tmp = RREG32(mmSRBM_STATUS); | 1104 | u32 tmp = RREG32(mmSRBM_STATUS); |
@@ -1117,13 +1113,42 @@ static int gmc_v8_0_soft_reset(void *handle) | |||
1117 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, | 1113 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, |
1118 | SRBM_SOFT_RESET, SOFT_RESET_MC, 1); | 1114 | SRBM_SOFT_RESET, SOFT_RESET_MC, 1); |
1119 | } | 1115 | } |
1120 | |||
1121 | if (srbm_soft_reset) { | 1116 | if (srbm_soft_reset) { |
1122 | gmc_v8_0_mc_stop(adev, &save); | 1117 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang = true; |
1123 | if (gmc_v8_0_wait_for_idle((void *)adev)) { | 1118 | adev->mc.srbm_soft_reset = srbm_soft_reset; |
1124 | dev_warn(adev->dev, "Wait for GMC idle timed out !\n"); | 1119 | } else { |
1125 | } | 1120 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang = false; |
1121 | adev->mc.srbm_soft_reset = 0; | ||
1122 | } | ||
1123 | return 0; | ||
1124 | } | ||
1126 | 1125 | ||
1126 | static int gmc_v8_0_pre_soft_reset(void *handle) | ||
1127 | { | ||
1128 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
1129 | |||
1130 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang) | ||
1131 | return 0; | ||
1132 | |||
1133 | gmc_v8_0_mc_stop(adev, &adev->mc.save); | ||
1134 | if (gmc_v8_0_wait_for_idle(adev)) { | ||
1135 | dev_warn(adev->dev, "Wait for GMC idle timed out !\n"); | ||
1136 | } | ||
1137 | |||
1138 | return 0; | ||
1139 | } | ||
1140 | |||
1141 | static int gmc_v8_0_soft_reset(void *handle) | ||
1142 | { | ||
1143 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
1144 | u32 srbm_soft_reset; | ||
1145 | |||
1146 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang) | ||
1147 | return 0; | ||
1148 | srbm_soft_reset = adev->mc.srbm_soft_reset; | ||
1149 | |||
1150 | if (srbm_soft_reset) { | ||
1151 | u32 tmp; | ||
1127 | 1152 | ||
1128 | tmp = RREG32(mmSRBM_SOFT_RESET); | 1153 | tmp = RREG32(mmSRBM_SOFT_RESET); |
1129 | tmp |= srbm_soft_reset; | 1154 | tmp |= srbm_soft_reset; |
@@ -1139,14 +1164,22 @@ static int gmc_v8_0_soft_reset(void *handle) | |||
1139 | 1164 | ||
1140 | /* Wait a little for things to settle down */ | 1165 | /* Wait a little for things to settle down */ |
1141 | udelay(50); | 1166 | udelay(50); |
1142 | |||
1143 | gmc_v8_0_mc_resume(adev, &save); | ||
1144 | udelay(50); | ||
1145 | } | 1167 | } |
1146 | 1168 | ||
1147 | return 0; | 1169 | return 0; |
1148 | } | 1170 | } |
1149 | 1171 | ||
1172 | static int gmc_v8_0_post_soft_reset(void *handle) | ||
1173 | { | ||
1174 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
1175 | |||
1176 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang) | ||
1177 | return 0; | ||
1178 | |||
1179 | gmc_v8_0_mc_resume(adev, &adev->mc.save); | ||
1180 | return 0; | ||
1181 | } | ||
1182 | |||
1150 | static int gmc_v8_0_vm_fault_interrupt_state(struct amdgpu_device *adev, | 1183 | static int gmc_v8_0_vm_fault_interrupt_state(struct amdgpu_device *adev, |
1151 | struct amdgpu_irq_src *src, | 1184 | struct amdgpu_irq_src *src, |
1152 | unsigned type, | 1185 | unsigned type, |
@@ -1414,7 +1447,10 @@ const struct amd_ip_funcs gmc_v8_0_ip_funcs = { | |||
1414 | .resume = gmc_v8_0_resume, | 1447 | .resume = gmc_v8_0_resume, |
1415 | .is_idle = gmc_v8_0_is_idle, | 1448 | .is_idle = gmc_v8_0_is_idle, |
1416 | .wait_for_idle = gmc_v8_0_wait_for_idle, | 1449 | .wait_for_idle = gmc_v8_0_wait_for_idle, |
1450 | .check_soft_reset = gmc_v8_0_check_soft_reset, | ||
1451 | .pre_soft_reset = gmc_v8_0_pre_soft_reset, | ||
1417 | .soft_reset = gmc_v8_0_soft_reset, | 1452 | .soft_reset = gmc_v8_0_soft_reset, |
1453 | .post_soft_reset = gmc_v8_0_post_soft_reset, | ||
1418 | .set_clockgating_state = gmc_v8_0_set_clockgating_state, | 1454 | .set_clockgating_state = gmc_v8_0_set_clockgating_state, |
1419 | .set_powergating_state = gmc_v8_0_set_powergating_state, | 1455 | .set_powergating_state = gmc_v8_0_set_powergating_state, |
1420 | }; | 1456 | }; |
diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index a845e883f5fa..f8618a3881a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c | |||
@@ -2845,7 +2845,11 @@ static int kv_dpm_init(struct amdgpu_device *adev) | |||
2845 | pi->caps_tcp_ramping = true; | 2845 | pi->caps_tcp_ramping = true; |
2846 | } | 2846 | } |
2847 | 2847 | ||
2848 | pi->caps_sclk_ds = true; | 2848 | if (amdgpu_sclk_deep_sleep_en) |
2849 | pi->caps_sclk_ds = true; | ||
2850 | else | ||
2851 | pi->caps_sclk_ds = false; | ||
2852 | |||
2849 | pi->enable_auto_thermal_throttling = true; | 2853 | pi->enable_auto_thermal_throttling = true; |
2850 | pi->disable_nb_ps3_in_battery = false; | 2854 | pi->disable_nb_ps3_in_battery = false; |
2851 | if (amdgpu_bapm == 0) | 2855 | if (amdgpu_bapm == 0) |
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 1351c7e834a2..e82229686783 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | |||
@@ -749,24 +749,16 @@ static void sdma_v2_4_vm_copy_pte(struct amdgpu_ib *ib, | |||
749 | uint64_t pe, uint64_t src, | 749 | uint64_t pe, uint64_t src, |
750 | unsigned count) | 750 | unsigned count) |
751 | { | 751 | { |
752 | while (count) { | 752 | unsigned bytes = count * 8; |
753 | unsigned bytes = count * 8; | 753 | |
754 | if (bytes > 0x1FFFF8) | 754 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) | |
755 | bytes = 0x1FFFF8; | 755 | SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); |
756 | 756 | ib->ptr[ib->length_dw++] = bytes; | |
757 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) | | 757 | ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ |
758 | SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); | 758 | ib->ptr[ib->length_dw++] = lower_32_bits(src); |
759 | ib->ptr[ib->length_dw++] = bytes; | 759 | ib->ptr[ib->length_dw++] = upper_32_bits(src); |
760 | ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ | 760 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); |
761 | ib->ptr[ib->length_dw++] = lower_32_bits(src); | 761 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); |
762 | ib->ptr[ib->length_dw++] = upper_32_bits(src); | ||
763 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); | ||
764 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
765 | |||
766 | pe += bytes; | ||
767 | src += bytes; | ||
768 | count -= bytes / 8; | ||
769 | } | ||
770 | } | 762 | } |
771 | 763 | ||
772 | /** | 764 | /** |
@@ -774,39 +766,27 @@ static void sdma_v2_4_vm_copy_pte(struct amdgpu_ib *ib, | |||
774 | * | 766 | * |
775 | * @ib: indirect buffer to fill with commands | 767 | * @ib: indirect buffer to fill with commands |
776 | * @pe: addr of the page entry | 768 | * @pe: addr of the page entry |
777 | * @addr: dst addr to write into pe | 769 | * @value: dst addr to write into pe |
778 | * @count: number of page entries to update | 770 | * @count: number of page entries to update |
779 | * @incr: increase next addr by incr bytes | 771 | * @incr: increase next addr by incr bytes |
780 | * @flags: access flags | ||
781 | * | 772 | * |
782 | * Update PTEs by writing them manually using sDMA (CIK). | 773 | * Update PTEs by writing them manually using sDMA (CIK). |
783 | */ | 774 | */ |
784 | static void sdma_v2_4_vm_write_pte(struct amdgpu_ib *ib, | 775 | static void sdma_v2_4_vm_write_pte(struct amdgpu_ib *ib, uint64_t pe, |
785 | const dma_addr_t *pages_addr, uint64_t pe, | 776 | uint64_t value, unsigned count, |
786 | uint64_t addr, unsigned count, | 777 | uint32_t incr) |
787 | uint32_t incr, uint32_t flags) | ||
788 | { | 778 | { |
789 | uint64_t value; | 779 | unsigned ndw = count * 2; |
790 | unsigned ndw; | 780 | |
791 | 781 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) | | |
792 | while (count) { | 782 | SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); |
793 | ndw = count * 2; | 783 | ib->ptr[ib->length_dw++] = pe; |
794 | if (ndw > 0xFFFFE) | 784 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); |
795 | ndw = 0xFFFFE; | 785 | ib->ptr[ib->length_dw++] = ndw; |
796 | 786 | for (; ndw > 0; ndw -= 2, --count, pe += 8) { | |
797 | /* for non-physically contiguous pages (system) */ | 787 | ib->ptr[ib->length_dw++] = lower_32_bits(value); |
798 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) | | 788 | ib->ptr[ib->length_dw++] = upper_32_bits(value); |
799 | SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); | 789 | value += incr; |
800 | ib->ptr[ib->length_dw++] = pe; | ||
801 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
802 | ib->ptr[ib->length_dw++] = ndw; | ||
803 | for (; ndw > 0; ndw -= 2, --count, pe += 8) { | ||
804 | value = amdgpu_vm_map_gart(pages_addr, addr); | ||
805 | addr += incr; | ||
806 | value |= flags; | ||
807 | ib->ptr[ib->length_dw++] = value; | ||
808 | ib->ptr[ib->length_dw++] = upper_32_bits(value); | ||
809 | } | ||
810 | } | 790 | } |
811 | } | 791 | } |
812 | 792 | ||
@@ -822,40 +802,21 @@ static void sdma_v2_4_vm_write_pte(struct amdgpu_ib *ib, | |||
822 | * | 802 | * |
823 | * Update the page tables using sDMA (CIK). | 803 | * Update the page tables using sDMA (CIK). |
824 | */ | 804 | */ |
825 | static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib, | 805 | static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe, |
826 | uint64_t pe, | ||
827 | uint64_t addr, unsigned count, | 806 | uint64_t addr, unsigned count, |
828 | uint32_t incr, uint32_t flags) | 807 | uint32_t incr, uint32_t flags) |
829 | { | 808 | { |
830 | uint64_t value; | 809 | /* for physically contiguous pages (vram) */ |
831 | unsigned ndw; | 810 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_GEN_PTEPDE); |
832 | 811 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); /* dst addr */ | |
833 | while (count) { | 812 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); |
834 | ndw = count; | 813 | ib->ptr[ib->length_dw++] = flags; /* mask */ |
835 | if (ndw > 0x7FFFF) | 814 | ib->ptr[ib->length_dw++] = 0; |
836 | ndw = 0x7FFFF; | 815 | ib->ptr[ib->length_dw++] = lower_32_bits(addr); /* value */ |
837 | 816 | ib->ptr[ib->length_dw++] = upper_32_bits(addr); | |
838 | if (flags & AMDGPU_PTE_VALID) | 817 | ib->ptr[ib->length_dw++] = incr; /* increment size */ |
839 | value = addr; | 818 | ib->ptr[ib->length_dw++] = 0; |
840 | else | 819 | ib->ptr[ib->length_dw++] = count; /* number of entries */ |
841 | value = 0; | ||
842 | |||
843 | /* for physically contiguous pages (vram) */ | ||
844 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_GEN_PTEPDE); | ||
845 | ib->ptr[ib->length_dw++] = pe; /* dst addr */ | ||
846 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
847 | ib->ptr[ib->length_dw++] = flags; /* mask */ | ||
848 | ib->ptr[ib->length_dw++] = 0; | ||
849 | ib->ptr[ib->length_dw++] = value; /* value */ | ||
850 | ib->ptr[ib->length_dw++] = upper_32_bits(value); | ||
851 | ib->ptr[ib->length_dw++] = incr; /* increment size */ | ||
852 | ib->ptr[ib->length_dw++] = 0; | ||
853 | ib->ptr[ib->length_dw++] = ndw; /* number of entries */ | ||
854 | |||
855 | pe += ndw * 8; | ||
856 | addr += ndw * incr; | ||
857 | count -= ndw; | ||
858 | } | ||
859 | } | 820 | } |
860 | 821 | ||
861 | /** | 822 | /** |
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 653ce5ed55ae..bee4978bec73 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | |||
@@ -976,24 +976,16 @@ static void sdma_v3_0_vm_copy_pte(struct amdgpu_ib *ib, | |||
976 | uint64_t pe, uint64_t src, | 976 | uint64_t pe, uint64_t src, |
977 | unsigned count) | 977 | unsigned count) |
978 | { | 978 | { |
979 | while (count) { | 979 | unsigned bytes = count * 8; |
980 | unsigned bytes = count * 8; | 980 | |
981 | if (bytes > 0x1FFFF8) | 981 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) | |
982 | bytes = 0x1FFFF8; | 982 | SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); |
983 | 983 | ib->ptr[ib->length_dw++] = bytes; | |
984 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) | | 984 | ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ |
985 | SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); | 985 | ib->ptr[ib->length_dw++] = lower_32_bits(src); |
986 | ib->ptr[ib->length_dw++] = bytes; | 986 | ib->ptr[ib->length_dw++] = upper_32_bits(src); |
987 | ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ | 987 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); |
988 | ib->ptr[ib->length_dw++] = lower_32_bits(src); | 988 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); |
989 | ib->ptr[ib->length_dw++] = upper_32_bits(src); | ||
990 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); | ||
991 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
992 | |||
993 | pe += bytes; | ||
994 | src += bytes; | ||
995 | count -= bytes / 8; | ||
996 | } | ||
997 | } | 989 | } |
998 | 990 | ||
999 | /** | 991 | /** |
@@ -1001,39 +993,27 @@ static void sdma_v3_0_vm_copy_pte(struct amdgpu_ib *ib, | |||
1001 | * | 993 | * |
1002 | * @ib: indirect buffer to fill with commands | 994 | * @ib: indirect buffer to fill with commands |
1003 | * @pe: addr of the page entry | 995 | * @pe: addr of the page entry |
1004 | * @addr: dst addr to write into pe | 996 | * @value: dst addr to write into pe |
1005 | * @count: number of page entries to update | 997 | * @count: number of page entries to update |
1006 | * @incr: increase next addr by incr bytes | 998 | * @incr: increase next addr by incr bytes |
1007 | * @flags: access flags | ||
1008 | * | 999 | * |
1009 | * Update PTEs by writing them manually using sDMA (CIK). | 1000 | * Update PTEs by writing them manually using sDMA (CIK). |
1010 | */ | 1001 | */ |
1011 | static void sdma_v3_0_vm_write_pte(struct amdgpu_ib *ib, | 1002 | static void sdma_v3_0_vm_write_pte(struct amdgpu_ib *ib, uint64_t pe, |
1012 | const dma_addr_t *pages_addr, uint64_t pe, | 1003 | uint64_t value, unsigned count, |
1013 | uint64_t addr, unsigned count, | 1004 | uint32_t incr) |
1014 | uint32_t incr, uint32_t flags) | 1005 | { |
1015 | { | 1006 | unsigned ndw = count * 2; |
1016 | uint64_t value; | 1007 | |
1017 | unsigned ndw; | 1008 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) | |
1018 | 1009 | SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); | |
1019 | while (count) { | 1010 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); |
1020 | ndw = count * 2; | 1011 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); |
1021 | if (ndw > 0xFFFFE) | 1012 | ib->ptr[ib->length_dw++] = ndw; |
1022 | ndw = 0xFFFFE; | 1013 | for (; ndw > 0; ndw -= 2, --count, pe += 8) { |
1023 | 1014 | ib->ptr[ib->length_dw++] = lower_32_bits(value); | |
1024 | /* for non-physically contiguous pages (system) */ | 1015 | ib->ptr[ib->length_dw++] = upper_32_bits(value); |
1025 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) | | 1016 | value += incr; |
1026 | SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); | ||
1027 | ib->ptr[ib->length_dw++] = pe; | ||
1028 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
1029 | ib->ptr[ib->length_dw++] = ndw; | ||
1030 | for (; ndw > 0; ndw -= 2, --count, pe += 8) { | ||
1031 | value = amdgpu_vm_map_gart(pages_addr, addr); | ||
1032 | addr += incr; | ||
1033 | value |= flags; | ||
1034 | ib->ptr[ib->length_dw++] = value; | ||
1035 | ib->ptr[ib->length_dw++] = upper_32_bits(value); | ||
1036 | } | ||
1037 | } | 1017 | } |
1038 | } | 1018 | } |
1039 | 1019 | ||
@@ -1049,40 +1029,21 @@ static void sdma_v3_0_vm_write_pte(struct amdgpu_ib *ib, | |||
1049 | * | 1029 | * |
1050 | * Update the page tables using sDMA (CIK). | 1030 | * Update the page tables using sDMA (CIK). |
1051 | */ | 1031 | */ |
1052 | static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib, | 1032 | static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe, |
1053 | uint64_t pe, | ||
1054 | uint64_t addr, unsigned count, | 1033 | uint64_t addr, unsigned count, |
1055 | uint32_t incr, uint32_t flags) | 1034 | uint32_t incr, uint32_t flags) |
1056 | { | 1035 | { |
1057 | uint64_t value; | 1036 | /* for physically contiguous pages (vram) */ |
1058 | unsigned ndw; | 1037 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_GEN_PTEPDE); |
1059 | 1038 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); /* dst addr */ | |
1060 | while (count) { | 1039 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); |
1061 | ndw = count; | 1040 | ib->ptr[ib->length_dw++] = flags; /* mask */ |
1062 | if (ndw > 0x7FFFF) | 1041 | ib->ptr[ib->length_dw++] = 0; |
1063 | ndw = 0x7FFFF; | 1042 | ib->ptr[ib->length_dw++] = lower_32_bits(addr); /* value */ |
1064 | 1043 | ib->ptr[ib->length_dw++] = upper_32_bits(addr); | |
1065 | if (flags & AMDGPU_PTE_VALID) | 1044 | ib->ptr[ib->length_dw++] = incr; /* increment size */ |
1066 | value = addr; | 1045 | ib->ptr[ib->length_dw++] = 0; |
1067 | else | 1046 | ib->ptr[ib->length_dw++] = count; /* number of entries */ |
1068 | value = 0; | ||
1069 | |||
1070 | /* for physically contiguous pages (vram) */ | ||
1071 | ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_GEN_PTEPDE); | ||
1072 | ib->ptr[ib->length_dw++] = pe; /* dst addr */ | ||
1073 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
1074 | ib->ptr[ib->length_dw++] = flags; /* mask */ | ||
1075 | ib->ptr[ib->length_dw++] = 0; | ||
1076 | ib->ptr[ib->length_dw++] = value; /* value */ | ||
1077 | ib->ptr[ib->length_dw++] = upper_32_bits(value); | ||
1078 | ib->ptr[ib->length_dw++] = incr; /* increment size */ | ||
1079 | ib->ptr[ib->length_dw++] = 0; | ||
1080 | ib->ptr[ib->length_dw++] = ndw; /* number of entries */ | ||
1081 | |||
1082 | pe += ndw * 8; | ||
1083 | addr += ndw * incr; | ||
1084 | count -= ndw; | ||
1085 | } | ||
1086 | } | 1047 | } |
1087 | 1048 | ||
1088 | /** | 1049 | /** |
@@ -1320,28 +1281,79 @@ static int sdma_v3_0_wait_for_idle(void *handle) | |||
1320 | return -ETIMEDOUT; | 1281 | return -ETIMEDOUT; |
1321 | } | 1282 | } |
1322 | 1283 | ||
1323 | static int sdma_v3_0_soft_reset(void *handle) | 1284 | static int sdma_v3_0_check_soft_reset(void *handle) |
1324 | { | 1285 | { |
1325 | u32 srbm_soft_reset = 0; | ||
1326 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 1286 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
1287 | u32 srbm_soft_reset = 0; | ||
1327 | u32 tmp = RREG32(mmSRBM_STATUS2); | 1288 | u32 tmp = RREG32(mmSRBM_STATUS2); |
1328 | 1289 | ||
1329 | if (tmp & SRBM_STATUS2__SDMA_BUSY_MASK) { | 1290 | if ((tmp & SRBM_STATUS2__SDMA_BUSY_MASK) || |
1330 | /* sdma0 */ | 1291 | (tmp & SRBM_STATUS2__SDMA1_BUSY_MASK)) { |
1331 | tmp = RREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET); | ||
1332 | tmp = REG_SET_FIELD(tmp, SDMA0_F32_CNTL, HALT, 0); | ||
1333 | WREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET, tmp); | ||
1334 | srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK; | 1292 | srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK; |
1335 | } | ||
1336 | if (tmp & SRBM_STATUS2__SDMA1_BUSY_MASK) { | ||
1337 | /* sdma1 */ | ||
1338 | tmp = RREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET); | ||
1339 | tmp = REG_SET_FIELD(tmp, SDMA0_F32_CNTL, HALT, 0); | ||
1340 | WREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET, tmp); | ||
1341 | srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK; | 1293 | srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK; |
1342 | } | 1294 | } |
1343 | 1295 | ||
1344 | if (srbm_soft_reset) { | 1296 | if (srbm_soft_reset) { |
1297 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang = true; | ||
1298 | adev->sdma.srbm_soft_reset = srbm_soft_reset; | ||
1299 | } else { | ||
1300 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang = false; | ||
1301 | adev->sdma.srbm_soft_reset = 0; | ||
1302 | } | ||
1303 | |||
1304 | return 0; | ||
1305 | } | ||
1306 | |||
1307 | static int sdma_v3_0_pre_soft_reset(void *handle) | ||
1308 | { | ||
1309 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
1310 | u32 srbm_soft_reset = 0; | ||
1311 | |||
1312 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang) | ||
1313 | return 0; | ||
1314 | |||
1315 | srbm_soft_reset = adev->sdma.srbm_soft_reset; | ||
1316 | |||
1317 | if (REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA) || | ||
1318 | REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA1)) { | ||
1319 | sdma_v3_0_ctx_switch_enable(adev, false); | ||
1320 | sdma_v3_0_enable(adev, false); | ||
1321 | } | ||
1322 | |||
1323 | return 0; | ||
1324 | } | ||
1325 | |||
1326 | static int sdma_v3_0_post_soft_reset(void *handle) | ||
1327 | { | ||
1328 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
1329 | u32 srbm_soft_reset = 0; | ||
1330 | |||
1331 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang) | ||
1332 | return 0; | ||
1333 | |||
1334 | srbm_soft_reset = adev->sdma.srbm_soft_reset; | ||
1335 | |||
1336 | if (REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA) || | ||
1337 | REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA1)) { | ||
1338 | sdma_v3_0_gfx_resume(adev); | ||
1339 | sdma_v3_0_rlc_resume(adev); | ||
1340 | } | ||
1341 | |||
1342 | return 0; | ||
1343 | } | ||
1344 | |||
1345 | static int sdma_v3_0_soft_reset(void *handle) | ||
1346 | { | ||
1347 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
1348 | u32 srbm_soft_reset = 0; | ||
1349 | u32 tmp; | ||
1350 | |||
1351 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang) | ||
1352 | return 0; | ||
1353 | |||
1354 | srbm_soft_reset = adev->sdma.srbm_soft_reset; | ||
1355 | |||
1356 | if (srbm_soft_reset) { | ||
1345 | tmp = RREG32(mmSRBM_SOFT_RESET); | 1357 | tmp = RREG32(mmSRBM_SOFT_RESET); |
1346 | tmp |= srbm_soft_reset; | 1358 | tmp |= srbm_soft_reset; |
1347 | dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); | 1359 | dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); |
@@ -1559,6 +1571,9 @@ const struct amd_ip_funcs sdma_v3_0_ip_funcs = { | |||
1559 | .resume = sdma_v3_0_resume, | 1571 | .resume = sdma_v3_0_resume, |
1560 | .is_idle = sdma_v3_0_is_idle, | 1572 | .is_idle = sdma_v3_0_is_idle, |
1561 | .wait_for_idle = sdma_v3_0_wait_for_idle, | 1573 | .wait_for_idle = sdma_v3_0_wait_for_idle, |
1574 | .check_soft_reset = sdma_v3_0_check_soft_reset, | ||
1575 | .pre_soft_reset = sdma_v3_0_pre_soft_reset, | ||
1576 | .post_soft_reset = sdma_v3_0_post_soft_reset, | ||
1562 | .soft_reset = sdma_v3_0_soft_reset, | 1577 | .soft_reset = sdma_v3_0_soft_reset, |
1563 | .set_clockgating_state = sdma_v3_0_set_clockgating_state, | 1578 | .set_clockgating_state = sdma_v3_0_set_clockgating_state, |
1564 | .set_powergating_state = sdma_v3_0_set_powergating_state, | 1579 | .set_powergating_state = sdma_v3_0_set_powergating_state, |
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c index c92055805a45..d127d59f953a 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c | |||
@@ -373,10 +373,10 @@ static int tonga_ih_wait_for_idle(void *handle) | |||
373 | return -ETIMEDOUT; | 373 | return -ETIMEDOUT; |
374 | } | 374 | } |
375 | 375 | ||
376 | static int tonga_ih_soft_reset(void *handle) | 376 | static int tonga_ih_check_soft_reset(void *handle) |
377 | { | 377 | { |
378 | u32 srbm_soft_reset = 0; | ||
379 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 378 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
379 | u32 srbm_soft_reset = 0; | ||
380 | u32 tmp = RREG32(mmSRBM_STATUS); | 380 | u32 tmp = RREG32(mmSRBM_STATUS); |
381 | 381 | ||
382 | if (tmp & SRBM_STATUS__IH_BUSY_MASK) | 382 | if (tmp & SRBM_STATUS__IH_BUSY_MASK) |
@@ -384,6 +384,48 @@ static int tonga_ih_soft_reset(void *handle) | |||
384 | SOFT_RESET_IH, 1); | 384 | SOFT_RESET_IH, 1); |
385 | 385 | ||
386 | if (srbm_soft_reset) { | 386 | if (srbm_soft_reset) { |
387 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang = true; | ||
388 | adev->irq.srbm_soft_reset = srbm_soft_reset; | ||
389 | } else { | ||
390 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang = false; | ||
391 | adev->irq.srbm_soft_reset = 0; | ||
392 | } | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int tonga_ih_pre_soft_reset(void *handle) | ||
398 | { | ||
399 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
400 | |||
401 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang) | ||
402 | return 0; | ||
403 | |||
404 | return tonga_ih_hw_fini(adev); | ||
405 | } | ||
406 | |||
407 | static int tonga_ih_post_soft_reset(void *handle) | ||
408 | { | ||
409 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
410 | |||
411 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang) | ||
412 | return 0; | ||
413 | |||
414 | return tonga_ih_hw_init(adev); | ||
415 | } | ||
416 | |||
417 | static int tonga_ih_soft_reset(void *handle) | ||
418 | { | ||
419 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
420 | u32 srbm_soft_reset; | ||
421 | |||
422 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang) | ||
423 | return 0; | ||
424 | srbm_soft_reset = adev->irq.srbm_soft_reset; | ||
425 | |||
426 | if (srbm_soft_reset) { | ||
427 | u32 tmp; | ||
428 | |||
387 | tmp = RREG32(mmSRBM_SOFT_RESET); | 429 | tmp = RREG32(mmSRBM_SOFT_RESET); |
388 | tmp |= srbm_soft_reset; | 430 | tmp |= srbm_soft_reset; |
389 | dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); | 431 | dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); |
@@ -427,7 +469,10 @@ const struct amd_ip_funcs tonga_ih_ip_funcs = { | |||
427 | .resume = tonga_ih_resume, | 469 | .resume = tonga_ih_resume, |
428 | .is_idle = tonga_ih_is_idle, | 470 | .is_idle = tonga_ih_is_idle, |
429 | .wait_for_idle = tonga_ih_wait_for_idle, | 471 | .wait_for_idle = tonga_ih_wait_for_idle, |
472 | .check_soft_reset = tonga_ih_check_soft_reset, | ||
473 | .pre_soft_reset = tonga_ih_pre_soft_reset, | ||
430 | .soft_reset = tonga_ih_soft_reset, | 474 | .soft_reset = tonga_ih_soft_reset, |
475 | .post_soft_reset = tonga_ih_post_soft_reset, | ||
431 | .set_clockgating_state = tonga_ih_set_clockgating_state, | 476 | .set_clockgating_state = tonga_ih_set_clockgating_state, |
432 | .set_powergating_state = tonga_ih_set_powergating_state, | 477 | .set_powergating_state = tonga_ih_set_powergating_state, |
433 | }; | 478 | }; |
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c index 132e613ed674..10c0407dcb6e 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | |||
@@ -116,7 +116,7 @@ static int uvd_v4_2_sw_init(void *handle) | |||
116 | 116 | ||
117 | ring = &adev->uvd.ring; | 117 | ring = &adev->uvd.ring; |
118 | sprintf(ring->name, "uvd"); | 118 | sprintf(ring->name, "uvd"); |
119 | r = amdgpu_ring_init(adev, ring, 512, CP_PACKET2, 0xf, | 119 | r = amdgpu_ring_init(adev, ring, 512, PACKET0(mmUVD_NO_OP, 0), 0xf, |
120 | &adev->uvd.irq, 0, AMDGPU_RING_TYPE_UVD); | 120 | &adev->uvd.irq, 0, AMDGPU_RING_TYPE_UVD); |
121 | 121 | ||
122 | return r; | 122 | return r; |
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c index 101de136ba63..8513376062c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c | |||
@@ -112,7 +112,7 @@ static int uvd_v5_0_sw_init(void *handle) | |||
112 | 112 | ||
113 | ring = &adev->uvd.ring; | 113 | ring = &adev->uvd.ring; |
114 | sprintf(ring->name, "uvd"); | 114 | sprintf(ring->name, "uvd"); |
115 | r = amdgpu_ring_init(adev, ring, 512, CP_PACKET2, 0xf, | 115 | r = amdgpu_ring_init(adev, ring, 512, PACKET0(mmUVD_NO_OP, 0), 0xf, |
116 | &adev->uvd.irq, 0, AMDGPU_RING_TYPE_UVD); | 116 | &adev->uvd.irq, 0, AMDGPU_RING_TYPE_UVD); |
117 | 117 | ||
118 | return r; | 118 | return r; |
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 7f21102bfb99..2abe8a93c99f 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | |||
@@ -116,7 +116,7 @@ static int uvd_v6_0_sw_init(void *handle) | |||
116 | 116 | ||
117 | ring = &adev->uvd.ring; | 117 | ring = &adev->uvd.ring; |
118 | sprintf(ring->name, "uvd"); | 118 | sprintf(ring->name, "uvd"); |
119 | r = amdgpu_ring_init(adev, ring, 512, CP_PACKET2, 0xf, | 119 | r = amdgpu_ring_init(adev, ring, 512, PACKET0(mmUVD_NO_OP, 0), 0xf, |
120 | &adev->uvd.irq, 0, AMDGPU_RING_TYPE_UVD); | 120 | &adev->uvd.irq, 0, AMDGPU_RING_TYPE_UVD); |
121 | 121 | ||
122 | return r; | 122 | return r; |
@@ -396,21 +396,14 @@ static int uvd_v6_0_start(struct amdgpu_device *adev) | |||
396 | 396 | ||
397 | uvd_v6_0_mc_resume(adev); | 397 | uvd_v6_0_mc_resume(adev); |
398 | 398 | ||
399 | /* Set dynamic clock gating in S/W control mode */ | 399 | /* disable clock gating */ |
400 | if (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG) { | 400 | WREG32_FIELD(UVD_CGC_CTRL, DYN_CLOCK_MODE, 0); |
401 | uvd_v6_0_set_sw_clock_gating(adev); | ||
402 | } else { | ||
403 | /* disable clock gating */ | ||
404 | uint32_t data = RREG32(mmUVD_CGC_CTRL); | ||
405 | data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK; | ||
406 | WREG32(mmUVD_CGC_CTRL, data); | ||
407 | } | ||
408 | 401 | ||
409 | /* disable interupt */ | 402 | /* disable interupt */ |
410 | WREG32_P(mmUVD_MASTINT_EN, 0, ~UVD_MASTINT_EN__VCPU_EN_MASK); | 403 | WREG32_FIELD(UVD_MASTINT_EN, VCPU_EN, 0); |
411 | 404 | ||
412 | /* stall UMC and register bus before resetting VCPU */ | 405 | /* stall UMC and register bus before resetting VCPU */ |
413 | WREG32_P(mmUVD_LMI_CTRL2, UVD_LMI_CTRL2__STALL_ARB_UMC_MASK, ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK); | 406 | WREG32_FIELD(UVD_LMI_CTRL2, STALL_ARB_UMC, 1); |
414 | mdelay(1); | 407 | mdelay(1); |
415 | 408 | ||
416 | /* put LMI, VCPU, RBC etc... into reset */ | 409 | /* put LMI, VCPU, RBC etc... into reset */ |
@@ -426,7 +419,7 @@ static int uvd_v6_0_start(struct amdgpu_device *adev) | |||
426 | mdelay(5); | 419 | mdelay(5); |
427 | 420 | ||
428 | /* take UVD block out of reset */ | 421 | /* take UVD block out of reset */ |
429 | WREG32_P(mmSRBM_SOFT_RESET, 0, ~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK); | 422 | WREG32_FIELD(SRBM_SOFT_RESET, SOFT_RESET_UVD, 0); |
430 | mdelay(5); | 423 | mdelay(5); |
431 | 424 | ||
432 | /* initialize UVD memory controller */ | 425 | /* initialize UVD memory controller */ |
@@ -461,7 +454,7 @@ static int uvd_v6_0_start(struct amdgpu_device *adev) | |||
461 | WREG32(mmUVD_VCPU_CNTL, UVD_VCPU_CNTL__CLK_EN_MASK); | 454 | WREG32(mmUVD_VCPU_CNTL, UVD_VCPU_CNTL__CLK_EN_MASK); |
462 | 455 | ||
463 | /* enable UMC */ | 456 | /* enable UMC */ |
464 | WREG32_P(mmUVD_LMI_CTRL2, 0, ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK); | 457 | WREG32_FIELD(UVD_LMI_CTRL2, STALL_ARB_UMC, 0); |
465 | 458 | ||
466 | /* boot up the VCPU */ | 459 | /* boot up the VCPU */ |
467 | WREG32(mmUVD_SOFT_RESET, 0); | 460 | WREG32(mmUVD_SOFT_RESET, 0); |
@@ -481,11 +474,9 @@ static int uvd_v6_0_start(struct amdgpu_device *adev) | |||
481 | break; | 474 | break; |
482 | 475 | ||
483 | DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n"); | 476 | DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n"); |
484 | WREG32_P(mmUVD_SOFT_RESET, UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK, | 477 | WREG32_FIELD(UVD_SOFT_RESET, VCPU_SOFT_RESET, 1); |
485 | ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK); | ||
486 | mdelay(10); | 478 | mdelay(10); |
487 | WREG32_P(mmUVD_SOFT_RESET, 0, | 479 | WREG32_FIELD(UVD_SOFT_RESET, VCPU_SOFT_RESET, 0); |
488 | ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK); | ||
489 | mdelay(10); | 480 | mdelay(10); |
490 | r = -1; | 481 | r = -1; |
491 | } | 482 | } |
@@ -502,15 +493,14 @@ static int uvd_v6_0_start(struct amdgpu_device *adev) | |||
502 | /* clear the bit 4 of UVD_STATUS */ | 493 | /* clear the bit 4 of UVD_STATUS */ |
503 | WREG32_P(mmUVD_STATUS, 0, ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT)); | 494 | WREG32_P(mmUVD_STATUS, 0, ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT)); |
504 | 495 | ||
496 | /* force RBC into idle state */ | ||
505 | rb_bufsz = order_base_2(ring->ring_size); | 497 | rb_bufsz = order_base_2(ring->ring_size); |
506 | tmp = 0; | 498 | tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz); |
507 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz); | ||
508 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1); | 499 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1); |
509 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1); | 500 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1); |
510 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_WPTR_POLL_EN, 0); | 501 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_WPTR_POLL_EN, 0); |
511 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); | 502 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); |
512 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); | 503 | tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); |
513 | /* force RBC into idle state */ | ||
514 | WREG32(mmUVD_RBC_RB_CNTL, tmp); | 504 | WREG32(mmUVD_RBC_RB_CNTL, tmp); |
515 | 505 | ||
516 | /* set the write pointer delay */ | 506 | /* set the write pointer delay */ |
@@ -531,7 +521,7 @@ static int uvd_v6_0_start(struct amdgpu_device *adev) | |||
531 | ring->wptr = RREG32(mmUVD_RBC_RB_RPTR); | 521 | ring->wptr = RREG32(mmUVD_RBC_RB_RPTR); |
532 | WREG32(mmUVD_RBC_RB_WPTR, ring->wptr); | 522 | WREG32(mmUVD_RBC_RB_WPTR, ring->wptr); |
533 | 523 | ||
534 | WREG32_P(mmUVD_RBC_RB_CNTL, 0, ~UVD_RBC_RB_CNTL__RB_NO_FETCH_MASK); | 524 | WREG32_FIELD(UVD_RBC_RB_CNTL, RB_NO_FETCH, 0); |
535 | 525 | ||
536 | return 0; | 526 | return 0; |
537 | } | 527 | } |
@@ -748,20 +738,82 @@ static int uvd_v6_0_wait_for_idle(void *handle) | |||
748 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 738 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
749 | 739 | ||
750 | for (i = 0; i < adev->usec_timeout; i++) { | 740 | for (i = 0; i < adev->usec_timeout; i++) { |
751 | if (!(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK)) | 741 | if (uvd_v6_0_is_idle(handle)) |
752 | return 0; | 742 | return 0; |
753 | } | 743 | } |
754 | return -ETIMEDOUT; | 744 | return -ETIMEDOUT; |
755 | } | 745 | } |
756 | 746 | ||
757 | static int uvd_v6_0_soft_reset(void *handle) | 747 | #define AMDGPU_UVD_STATUS_BUSY_MASK 0xfd |
748 | static int uvd_v6_0_check_soft_reset(void *handle) | ||
758 | { | 749 | { |
759 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 750 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
751 | u32 srbm_soft_reset = 0; | ||
752 | u32 tmp = RREG32(mmSRBM_STATUS); | ||
753 | |||
754 | if (REG_GET_FIELD(tmp, SRBM_STATUS, UVD_RQ_PENDING) || | ||
755 | REG_GET_FIELD(tmp, SRBM_STATUS, UVD_BUSY) || | ||
756 | (RREG32(mmUVD_STATUS) & AMDGPU_UVD_STATUS_BUSY_MASK)) | ||
757 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_UVD, 1); | ||
758 | |||
759 | if (srbm_soft_reset) { | ||
760 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = true; | ||
761 | adev->uvd.srbm_soft_reset = srbm_soft_reset; | ||
762 | } else { | ||
763 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = false; | ||
764 | adev->uvd.srbm_soft_reset = 0; | ||
765 | } | ||
766 | return 0; | ||
767 | } | ||
768 | static int uvd_v6_0_pre_soft_reset(void *handle) | ||
769 | { | ||
770 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
771 | |||
772 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang) | ||
773 | return 0; | ||
760 | 774 | ||
761 | uvd_v6_0_stop(adev); | 775 | uvd_v6_0_stop(adev); |
776 | return 0; | ||
777 | } | ||
778 | |||
779 | static int uvd_v6_0_soft_reset(void *handle) | ||
780 | { | ||
781 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
782 | u32 srbm_soft_reset; | ||
783 | |||
784 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang) | ||
785 | return 0; | ||
786 | srbm_soft_reset = adev->uvd.srbm_soft_reset; | ||
787 | |||
788 | if (srbm_soft_reset) { | ||
789 | u32 tmp; | ||
790 | |||
791 | tmp = RREG32(mmSRBM_SOFT_RESET); | ||
792 | tmp |= srbm_soft_reset; | ||
793 | dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); | ||
794 | WREG32(mmSRBM_SOFT_RESET, tmp); | ||
795 | tmp = RREG32(mmSRBM_SOFT_RESET); | ||
796 | |||
797 | udelay(50); | ||
798 | |||
799 | tmp &= ~srbm_soft_reset; | ||
800 | WREG32(mmSRBM_SOFT_RESET, tmp); | ||
801 | tmp = RREG32(mmSRBM_SOFT_RESET); | ||
802 | |||
803 | /* Wait a little for things to settle down */ | ||
804 | udelay(50); | ||
805 | } | ||
806 | |||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | static int uvd_v6_0_post_soft_reset(void *handle) | ||
811 | { | ||
812 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
813 | |||
814 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang) | ||
815 | return 0; | ||
762 | 816 | ||
763 | WREG32_P(mmSRBM_SOFT_RESET, SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK, | ||
764 | ~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK); | ||
765 | mdelay(5); | 817 | mdelay(5); |
766 | 818 | ||
767 | return uvd_v6_0_start(adev); | 819 | return uvd_v6_0_start(adev); |
@@ -902,21 +954,15 @@ static int uvd_v6_0_set_clockgating_state(void *handle, | |||
902 | enum amd_clockgating_state state) | 954 | enum amd_clockgating_state state) |
903 | { | 955 | { |
904 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 956 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
905 | bool enable = (state == AMD_CG_STATE_GATE) ? true : false; | ||
906 | static int curstate = -1; | ||
907 | 957 | ||
908 | if (adev->asic_type == CHIP_FIJI || | 958 | if (adev->asic_type == CHIP_FIJI || |
909 | adev->asic_type == CHIP_POLARIS10) | 959 | adev->asic_type == CHIP_POLARIS10) |
910 | uvd_v6_set_bypass_mode(adev, enable); | 960 | uvd_v6_set_bypass_mode(adev, state == AMD_CG_STATE_GATE ? true : false); |
911 | 961 | ||
912 | if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) | 962 | if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) |
913 | return 0; | 963 | return 0; |
914 | 964 | ||
915 | if (curstate == state) | 965 | if (state == AMD_CG_STATE_GATE) { |
916 | return 0; | ||
917 | |||
918 | curstate = state; | ||
919 | if (enable) { | ||
920 | /* disable HW gating and enable Sw gating */ | 966 | /* disable HW gating and enable Sw gating */ |
921 | uvd_v6_0_set_sw_clock_gating(adev); | 967 | uvd_v6_0_set_sw_clock_gating(adev); |
922 | } else { | 968 | } else { |
@@ -946,6 +992,8 @@ static int uvd_v6_0_set_powergating_state(void *handle, | |||
946 | if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD)) | 992 | if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD)) |
947 | return 0; | 993 | return 0; |
948 | 994 | ||
995 | WREG32(mmUVD_POWER_STATUS, UVD_POWER_STATUS__UVD_PG_EN_MASK); | ||
996 | |||
949 | if (state == AMD_PG_STATE_GATE) { | 997 | if (state == AMD_PG_STATE_GATE) { |
950 | uvd_v6_0_stop(adev); | 998 | uvd_v6_0_stop(adev); |
951 | return 0; | 999 | return 0; |
@@ -966,7 +1014,10 @@ const struct amd_ip_funcs uvd_v6_0_ip_funcs = { | |||
966 | .resume = uvd_v6_0_resume, | 1014 | .resume = uvd_v6_0_resume, |
967 | .is_idle = uvd_v6_0_is_idle, | 1015 | .is_idle = uvd_v6_0_is_idle, |
968 | .wait_for_idle = uvd_v6_0_wait_for_idle, | 1016 | .wait_for_idle = uvd_v6_0_wait_for_idle, |
1017 | .check_soft_reset = uvd_v6_0_check_soft_reset, | ||
1018 | .pre_soft_reset = uvd_v6_0_pre_soft_reset, | ||
969 | .soft_reset = uvd_v6_0_soft_reset, | 1019 | .soft_reset = uvd_v6_0_soft_reset, |
1020 | .post_soft_reset = uvd_v6_0_post_soft_reset, | ||
970 | .set_clockgating_state = uvd_v6_0_set_clockgating_state, | 1021 | .set_clockgating_state = uvd_v6_0_set_clockgating_state, |
971 | .set_powergating_state = uvd_v6_0_set_powergating_state, | 1022 | .set_powergating_state = uvd_v6_0_set_powergating_state, |
972 | }; | 1023 | }; |
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c index 80a37a602181..5fa55b52c00e 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #define VCE_V2_0_FW_SIZE (256 * 1024) | 40 | #define VCE_V2_0_FW_SIZE (256 * 1024) |
41 | #define VCE_V2_0_STACK_SIZE (64 * 1024) | 41 | #define VCE_V2_0_STACK_SIZE (64 * 1024) |
42 | #define VCE_V2_0_DATA_SIZE (23552 * AMDGPU_MAX_VCE_HANDLES) | 42 | #define VCE_V2_0_DATA_SIZE (23552 * AMDGPU_MAX_VCE_HANDLES) |
43 | #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 | ||
43 | 44 | ||
44 | static void vce_v2_0_mc_resume(struct amdgpu_device *adev); | 45 | static void vce_v2_0_mc_resume(struct amdgpu_device *adev); |
45 | static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev); | 46 | 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) | |||
96 | WREG32(mmVCE_RB_WPTR2, ring->wptr); | 97 | WREG32(mmVCE_RB_WPTR2, ring->wptr); |
97 | } | 98 | } |
98 | 99 | ||
100 | static int vce_v2_0_lmi_clean(struct amdgpu_device *adev) | ||
101 | { | ||
102 | int i, j; | ||
103 | |||
104 | for (i = 0; i < 10; ++i) { | ||
105 | for (j = 0; j < 100; ++j) { | ||
106 | uint32_t status = RREG32(mmVCE_LMI_STATUS); | ||
107 | |||
108 | if (status & 0x337f) | ||
109 | return 0; | ||
110 | mdelay(10); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | return -ETIMEDOUT; | ||
115 | } | ||
116 | |||
117 | static int vce_v2_0_firmware_loaded(struct amdgpu_device *adev) | ||
118 | { | ||
119 | int i, j; | ||
120 | |||
121 | for (i = 0; i < 10; ++i) { | ||
122 | for (j = 0; j < 100; ++j) { | ||
123 | uint32_t status = RREG32(mmVCE_STATUS); | ||
124 | |||
125 | if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) | ||
126 | return 0; | ||
127 | mdelay(10); | ||
128 | } | ||
129 | |||
130 | DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); | ||
131 | WREG32_P(mmVCE_SOFT_RESET, | ||
132 | VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, | ||
133 | ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
134 | mdelay(10); | ||
135 | WREG32_P(mmVCE_SOFT_RESET, 0, | ||
136 | ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
137 | mdelay(10); | ||
138 | } | ||
139 | |||
140 | return -ETIMEDOUT; | ||
141 | } | ||
142 | |||
99 | /** | 143 | /** |
100 | * vce_v2_0_start - start VCE block | 144 | * vce_v2_0_start - start VCE block |
101 | * | 145 | * |
@@ -106,7 +150,7 @@ static void vce_v2_0_ring_set_wptr(struct amdgpu_ring *ring) | |||
106 | static int vce_v2_0_start(struct amdgpu_device *adev) | 150 | static int vce_v2_0_start(struct amdgpu_device *adev) |
107 | { | 151 | { |
108 | struct amdgpu_ring *ring; | 152 | struct amdgpu_ring *ring; |
109 | int i, j, r; | 153 | int r; |
110 | 154 | ||
111 | vce_v2_0_mc_resume(adev); | 155 | vce_v2_0_mc_resume(adev); |
112 | 156 | ||
@@ -127,36 +171,12 @@ static int vce_v2_0_start(struct amdgpu_device *adev) | |||
127 | WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); | 171 | WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); |
128 | WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); | 172 | WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); |
129 | 173 | ||
130 | WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, ~VCE_VCPU_CNTL__CLK_EN_MASK); | 174 | WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1); |
131 | 175 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); | |
132 | WREG32_P(mmVCE_SOFT_RESET, | ||
133 | VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, | ||
134 | ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
135 | |||
136 | mdelay(100); | 176 | mdelay(100); |
177 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); | ||
137 | 178 | ||
138 | WREG32_P(mmVCE_SOFT_RESET, 0, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | 179 | r = vce_v2_0_firmware_loaded(adev); |
139 | |||
140 | for (i = 0; i < 10; ++i) { | ||
141 | uint32_t status; | ||
142 | for (j = 0; j < 100; ++j) { | ||
143 | status = RREG32(mmVCE_STATUS); | ||
144 | if (status & 2) | ||
145 | break; | ||
146 | mdelay(10); | ||
147 | } | ||
148 | r = 0; | ||
149 | if (status & 2) | ||
150 | break; | ||
151 | |||
152 | DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); | ||
153 | WREG32_P(mmVCE_SOFT_RESET, VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, | ||
154 | ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
155 | mdelay(10); | ||
156 | WREG32_P(mmVCE_SOFT_RESET, 0, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
157 | mdelay(10); | ||
158 | r = -1; | ||
159 | } | ||
160 | 180 | ||
161 | /* clear BUSY flag */ | 181 | /* clear BUSY flag */ |
162 | WREG32_P(mmVCE_STATUS, 0, ~1); | 182 | WREG32_P(mmVCE_STATUS, 0, ~1); |
@@ -338,47 +358,50 @@ static void vce_v2_0_set_sw_cg(struct amdgpu_device *adev, bool gated) | |||
338 | 358 | ||
339 | static void vce_v2_0_set_dyn_cg(struct amdgpu_device *adev, bool gated) | 359 | static void vce_v2_0_set_dyn_cg(struct amdgpu_device *adev, bool gated) |
340 | { | 360 | { |
341 | u32 orig, tmp; | 361 | if (vce_v2_0_wait_for_idle(adev)) { |
362 | DRM_INFO("VCE is busy, Can't set clock gateing"); | ||
363 | return; | ||
364 | } | ||
342 | 365 | ||
343 | if (gated) { | 366 | WREG32_P(mmVCE_LMI_CTRL2, 0x100, ~0x100); |
344 | if (vce_v2_0_wait_for_idle(adev)) { | 367 | |
345 | DRM_INFO("VCE is busy, Can't set clock gateing"); | 368 | if (vce_v2_0_lmi_clean(adev)) { |
346 | return; | 369 | DRM_INFO("LMI is busy, Can't set clock gateing"); |
347 | } | 370 | return; |
348 | WREG32_P(mmVCE_VCPU_CNTL, 0, ~VCE_VCPU_CNTL__CLK_EN_MASK); | ||
349 | WREG32_P(mmVCE_SOFT_RESET, VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
350 | mdelay(100); | ||
351 | WREG32(mmVCE_STATUS, 0); | ||
352 | } else { | ||
353 | WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, ~VCE_VCPU_CNTL__CLK_EN_MASK); | ||
354 | WREG32_P(mmVCE_SOFT_RESET, VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
355 | mdelay(100); | ||
356 | } | 371 | } |
357 | 372 | ||
358 | tmp = RREG32(mmVCE_CLOCK_GATING_B); | 373 | WREG32_P(mmVCE_VCPU_CNTL, 0, ~VCE_VCPU_CNTL__CLK_EN_MASK); |
359 | tmp &= ~0x00060006; | 374 | WREG32_P(mmVCE_SOFT_RESET, |
375 | VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, | ||
376 | ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
377 | WREG32(mmVCE_STATUS, 0); | ||
378 | |||
379 | if (gated) | ||
380 | WREG32(mmVCE_CGTT_CLK_OVERRIDE, 0); | ||
381 | /* LMI_MC/LMI_UMC always set in dynamic, set {CGC_*_GATE_MODE, CGC_*_SW_GATE} = {0, 0} */ | ||
360 | if (gated) { | 382 | if (gated) { |
361 | tmp |= 0xe10000; | 383 | /* Force CLOCK OFF , set {CGC_*_GATE_MODE, CGC_*_SW_GATE} = {*, 1} */ |
384 | WREG32(mmVCE_CLOCK_GATING_B, 0xe90010); | ||
362 | } else { | 385 | } else { |
363 | tmp |= 0xe1; | 386 | /* Force CLOCK ON, set {CGC_*_GATE_MODE, CGC_*_SW_GATE} = {1, 0} */ |
364 | tmp &= ~0xe10000; | 387 | WREG32(mmVCE_CLOCK_GATING_B, 0x800f1); |
365 | } | 388 | } |
366 | WREG32(mmVCE_CLOCK_GATING_B, tmp); | ||
367 | 389 | ||
368 | orig = tmp = RREG32(mmVCE_UENC_CLOCK_GATING); | 390 | /* Set VCE_UENC_CLOCK_GATING always in dynamic mode {*_FORCE_ON, *_FORCE_OFF} = {0, 0}*/; |
369 | tmp &= ~0x1fe000; | 391 | WREG32(mmVCE_UENC_CLOCK_GATING, 0x40); |
370 | tmp &= ~0xff000000; | ||
371 | if (tmp != orig) | ||
372 | WREG32(mmVCE_UENC_CLOCK_GATING, tmp); | ||
373 | 392 | ||
374 | orig = tmp = RREG32(mmVCE_UENC_REG_CLOCK_GATING); | 393 | /* set VCE_UENC_REG_CLOCK_GATING always in dynamic mode */ |
375 | tmp &= ~0x3fc; | 394 | WREG32(mmVCE_UENC_REG_CLOCK_GATING, 0x00); |
376 | if (tmp != orig) | ||
377 | WREG32(mmVCE_UENC_REG_CLOCK_GATING, tmp); | ||
378 | 395 | ||
379 | if (gated) | 396 | WREG32_P(mmVCE_LMI_CTRL2, 0, ~0x100); |
380 | WREG32(mmVCE_CGTT_CLK_OVERRIDE, 0); | 397 | if(!gated) { |
381 | WREG32_P(mmVCE_SOFT_RESET, 0, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | 398 | WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, ~VCE_VCPU_CNTL__CLK_EN_MASK); |
399 | mdelay(100); | ||
400 | WREG32_P(mmVCE_SOFT_RESET, 0, ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
401 | |||
402 | vce_v2_0_firmware_loaded(adev); | ||
403 | WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); | ||
404 | } | ||
382 | } | 405 | } |
383 | 406 | ||
384 | static void vce_v2_0_disable_cg(struct amdgpu_device *adev) | 407 | static void vce_v2_0_disable_cg(struct amdgpu_device *adev) |
@@ -458,9 +481,7 @@ static void vce_v2_0_mc_resume(struct amdgpu_device *adev) | |||
458 | WREG32(mmVCE_VCPU_CACHE_SIZE2, size); | 481 | WREG32(mmVCE_VCPU_CACHE_SIZE2, size); |
459 | 482 | ||
460 | WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); | 483 | WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); |
461 | 484 | WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1); | |
462 | WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK, | ||
463 | ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); | ||
464 | 485 | ||
465 | vce_v2_0_init_cg(adev); | 486 | vce_v2_0_init_cg(adev); |
466 | } | 487 | } |
@@ -474,11 +495,11 @@ static bool vce_v2_0_is_idle(void *handle) | |||
474 | 495 | ||
475 | static int vce_v2_0_wait_for_idle(void *handle) | 496 | static int vce_v2_0_wait_for_idle(void *handle) |
476 | { | 497 | { |
477 | unsigned i; | ||
478 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 498 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
499 | unsigned i; | ||
479 | 500 | ||
480 | for (i = 0; i < adev->usec_timeout; i++) { | 501 | for (i = 0; i < adev->usec_timeout; i++) { |
481 | if (!(RREG32(mmSRBM_STATUS2) & SRBM_STATUS2__VCE_BUSY_MASK)) | 502 | if (vce_v2_0_is_idle(handle)) |
482 | return 0; | 503 | return 0; |
483 | } | 504 | } |
484 | return -ETIMEDOUT; | 505 | return -ETIMEDOUT; |
@@ -488,8 +509,7 @@ static int vce_v2_0_soft_reset(void *handle) | |||
488 | { | 509 | { |
489 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 510 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
490 | 511 | ||
491 | WREG32_P(mmSRBM_SOFT_RESET, SRBM_SOFT_RESET__SOFT_RESET_VCE_MASK, | 512 | WREG32_FIELD(SRBM_SOFT_RESET, SOFT_RESET_VCE, 1); |
492 | ~SRBM_SOFT_RESET__SOFT_RESET_VCE_MASK); | ||
493 | mdelay(5); | 513 | mdelay(5); |
494 | 514 | ||
495 | return vce_v2_0_start(adev); | 515 | return vce_v2_0_start(adev); |
@@ -516,10 +536,8 @@ static int vce_v2_0_process_interrupt(struct amdgpu_device *adev, | |||
516 | DRM_DEBUG("IH: VCE\n"); | 536 | DRM_DEBUG("IH: VCE\n"); |
517 | switch (entry->src_data) { | 537 | switch (entry->src_data) { |
518 | case 0: | 538 | case 0: |
519 | amdgpu_fence_process(&adev->vce.ring[0]); | ||
520 | break; | ||
521 | case 1: | 539 | case 1: |
522 | amdgpu_fence_process(&adev->vce.ring[1]); | 540 | amdgpu_fence_process(&adev->vce.ring[entry->src_data]); |
523 | break; | 541 | break; |
524 | default: | 542 | default: |
525 | DRM_ERROR("Unhandled interrupt: %d %d\n", | 543 | DRM_ERROR("Unhandled interrupt: %d %d\n", |
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index c271abffd8dd..615b8b16ad04 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | |||
@@ -37,6 +37,9 @@ | |||
37 | #include "gca/gfx_8_0_d.h" | 37 | #include "gca/gfx_8_0_d.h" |
38 | #include "smu/smu_7_1_2_d.h" | 38 | #include "smu/smu_7_1_2_d.h" |
39 | #include "smu/smu_7_1_2_sh_mask.h" | 39 | #include "smu/smu_7_1_2_sh_mask.h" |
40 | #include "gca/gfx_8_0_d.h" | ||
41 | #include "gca/gfx_8_0_sh_mask.h" | ||
42 | |||
40 | 43 | ||
41 | #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 | 44 | #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 |
42 | #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 | 45 | #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 |
@@ -107,102 +110,72 @@ static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) | |||
107 | 110 | ||
108 | static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) | 111 | static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) |
109 | { | 112 | { |
110 | u32 tmp, data; | 113 | WREG32_FIELD(VCE_RB_ARB_CTRL, VCE_CGTT_OVERRIDE, override ? 1 : 0); |
111 | |||
112 | tmp = data = RREG32(mmVCE_RB_ARB_CTRL); | ||
113 | if (override) | ||
114 | data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; | ||
115 | else | ||
116 | data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; | ||
117 | |||
118 | if (tmp != data) | ||
119 | WREG32(mmVCE_RB_ARB_CTRL, data); | ||
120 | } | 114 | } |
121 | 115 | ||
122 | static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, | 116 | static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, |
123 | bool gated) | 117 | bool gated) |
124 | { | 118 | { |
125 | u32 tmp, data; | 119 | u32 data; |
120 | |||
126 | /* Set Override to disable Clock Gating */ | 121 | /* Set Override to disable Clock Gating */ |
127 | vce_v3_0_override_vce_clock_gating(adev, true); | 122 | vce_v3_0_override_vce_clock_gating(adev, true); |
128 | 123 | ||
129 | if (!gated) { | 124 | /* This function enables MGCG which is controlled by firmware. |
130 | /* Force CLOCK ON for VCE_CLOCK_GATING_B, | 125 | With the clocks in the gated state the core is still |
131 | * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} | 126 | accessible but the firmware will throttle the clocks on the |
132 | * VREG can be FORCE ON or set to Dynamic, but can't be OFF | 127 | fly as necessary. |
133 | */ | 128 | */ |
134 | tmp = data = RREG32(mmVCE_CLOCK_GATING_B); | 129 | if (gated) { |
130 | data = RREG32(mmVCE_CLOCK_GATING_B); | ||
135 | data |= 0x1ff; | 131 | data |= 0x1ff; |
136 | data &= ~0xef0000; | 132 | data &= ~0xef0000; |
137 | if (tmp != data) | 133 | WREG32(mmVCE_CLOCK_GATING_B, data); |
138 | WREG32(mmVCE_CLOCK_GATING_B, data); | ||
139 | 134 | ||
140 | /* Force CLOCK ON for VCE_UENC_CLOCK_GATING, | 135 | data = RREG32(mmVCE_UENC_CLOCK_GATING); |
141 | * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} | ||
142 | */ | ||
143 | tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); | ||
144 | data |= 0x3ff000; | 136 | data |= 0x3ff000; |
145 | data &= ~0xffc00000; | 137 | data &= ~0xffc00000; |
146 | if (tmp != data) | 138 | WREG32(mmVCE_UENC_CLOCK_GATING, data); |
147 | WREG32(mmVCE_UENC_CLOCK_GATING, data); | ||
148 | 139 | ||
149 | /* set VCE_UENC_CLOCK_GATING_2 */ | 140 | data = RREG32(mmVCE_UENC_CLOCK_GATING_2); |
150 | tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); | ||
151 | data |= 0x2; | 141 | data |= 0x2; |
152 | data &= ~0x2; | 142 | data &= ~0x00010000; |
153 | if (tmp != data) | 143 | WREG32(mmVCE_UENC_CLOCK_GATING_2, data); |
154 | WREG32(mmVCE_UENC_CLOCK_GATING_2, data); | ||
155 | 144 | ||
156 | /* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */ | 145 | data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); |
157 | tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); | ||
158 | data |= 0x37f; | 146 | data |= 0x37f; |
159 | if (tmp != data) | 147 | WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); |
160 | WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); | ||
161 | 148 | ||
162 | /* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */ | 149 | data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); |
163 | tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); | ||
164 | data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | | 150 | data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | |
165 | VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | | 151 | VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | |
166 | VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | | 152 | VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | |
167 | 0x8; | 153 | 0x8; |
168 | if (tmp != data) | 154 | WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); |
169 | WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); | ||
170 | } else { | 155 | } else { |
171 | /* Force CLOCK OFF for VCE_CLOCK_GATING_B, | 156 | data = RREG32(mmVCE_CLOCK_GATING_B); |
172 | * {*, *_FORCE_OFF} = {*, 1} | ||
173 | * set VREG to Dynamic, as it can't be OFF | ||
174 | */ | ||
175 | tmp = data = RREG32(mmVCE_CLOCK_GATING_B); | ||
176 | data &= ~0x80010; | 157 | data &= ~0x80010; |
177 | data |= 0xe70008; | 158 | data |= 0xe70008; |
178 | if (tmp != data) | 159 | WREG32(mmVCE_CLOCK_GATING_B, data); |
179 | WREG32(mmVCE_CLOCK_GATING_B, data); | 160 | |
180 | /* Force CLOCK OFF for VCE_UENC_CLOCK_GATING, | 161 | data = RREG32(mmVCE_UENC_CLOCK_GATING); |
181 | * Force ClOCK OFF takes precedent over Force CLOCK ON setting. | ||
182 | * {*_FORCE_ON, *_FORCE_OFF} = {*, 1} | ||
183 | */ | ||
184 | tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); | ||
185 | data |= 0xffc00000; | 162 | data |= 0xffc00000; |
186 | if (tmp != data) | 163 | WREG32(mmVCE_UENC_CLOCK_GATING, data); |
187 | WREG32(mmVCE_UENC_CLOCK_GATING, data); | 164 | |
188 | /* Set VCE_UENC_CLOCK_GATING_2 */ | 165 | data = RREG32(mmVCE_UENC_CLOCK_GATING_2); |
189 | tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); | ||
190 | data |= 0x10000; | 166 | data |= 0x10000; |
191 | if (tmp != data) | 167 | WREG32(mmVCE_UENC_CLOCK_GATING_2, data); |
192 | WREG32(mmVCE_UENC_CLOCK_GATING_2, data); | 168 | |
193 | /* Set VCE_UENC_REG_CLOCK_GATING to dynamic */ | 169 | data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); |
194 | tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); | ||
195 | data &= ~0xffc00000; | 170 | data &= ~0xffc00000; |
196 | if (tmp != data) | 171 | WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); |
197 | WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); | 172 | |
198 | /* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */ | 173 | data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); |
199 | tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); | ||
200 | data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | | 174 | data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | |
201 | VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | | 175 | VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | |
202 | VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | | 176 | VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | |
203 | 0x8); | 177 | 0x8); |
204 | if (tmp != data) | 178 | WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); |
205 | WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); | ||
206 | } | 179 | } |
207 | vce_v3_0_override_vce_clock_gating(adev, false); | 180 | vce_v3_0_override_vce_clock_gating(adev, false); |
208 | } | 181 | } |
@@ -221,12 +194,9 @@ static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) | |||
221 | } | 194 | } |
222 | 195 | ||
223 | DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); | 196 | DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); |
224 | WREG32_P(mmVCE_SOFT_RESET, | 197 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); |
225 | VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, | ||
226 | ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
227 | mdelay(10); | 198 | mdelay(10); |
228 | WREG32_P(mmVCE_SOFT_RESET, 0, | 199 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); |
229 | ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
230 | mdelay(10); | 200 | mdelay(10); |
231 | } | 201 | } |
232 | 202 | ||
@@ -264,38 +234,22 @@ static int vce_v3_0_start(struct amdgpu_device *adev) | |||
264 | if (adev->vce.harvest_config & (1 << idx)) | 234 | if (adev->vce.harvest_config & (1 << idx)) |
265 | continue; | 235 | continue; |
266 | 236 | ||
267 | if (idx == 0) | 237 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); |
268 | WREG32_P(mmGRBM_GFX_INDEX, 0, | ||
269 | ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); | ||
270 | else | ||
271 | WREG32_P(mmGRBM_GFX_INDEX, | ||
272 | GRBM_GFX_INDEX__VCE_INSTANCE_MASK, | ||
273 | ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); | ||
274 | |||
275 | vce_v3_0_mc_resume(adev, idx); | 238 | vce_v3_0_mc_resume(adev, idx); |
276 | 239 | WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1); | |
277 | WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK, | ||
278 | ~VCE_STATUS__JOB_BUSY_MASK); | ||
279 | 240 | ||
280 | if (adev->asic_type >= CHIP_STONEY) | 241 | if (adev->asic_type >= CHIP_STONEY) |
281 | WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); | 242 | WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); |
282 | else | 243 | else |
283 | WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, | 244 | WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1); |
284 | ~VCE_VCPU_CNTL__CLK_EN_MASK); | ||
285 | |||
286 | WREG32_P(mmVCE_SOFT_RESET, 0, | ||
287 | ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
288 | 245 | ||
246 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); | ||
289 | mdelay(100); | 247 | mdelay(100); |
290 | 248 | ||
291 | r = vce_v3_0_firmware_loaded(adev); | 249 | r = vce_v3_0_firmware_loaded(adev); |
292 | 250 | ||
293 | /* clear BUSY flag */ | 251 | /* clear BUSY flag */ |
294 | WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); | 252 | WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); |
295 | |||
296 | /* Set Clock-Gating off */ | ||
297 | if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) | ||
298 | vce_v3_0_set_vce_sw_clock_gating(adev, false); | ||
299 | 253 | ||
300 | if (r) { | 254 | if (r) { |
301 | DRM_ERROR("VCE not responding, giving up!!!\n"); | 255 | DRM_ERROR("VCE not responding, giving up!!!\n"); |
@@ -304,7 +258,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev) | |||
304 | } | 258 | } |
305 | } | 259 | } |
306 | 260 | ||
307 | WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); | 261 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); |
308 | mutex_unlock(&adev->grbm_idx_mutex); | 262 | mutex_unlock(&adev->grbm_idx_mutex); |
309 | 263 | ||
310 | return 0; | 264 | return 0; |
@@ -319,33 +273,25 @@ static int vce_v3_0_stop(struct amdgpu_device *adev) | |||
319 | if (adev->vce.harvest_config & (1 << idx)) | 273 | if (adev->vce.harvest_config & (1 << idx)) |
320 | continue; | 274 | continue; |
321 | 275 | ||
322 | if (idx == 0) | 276 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); |
323 | WREG32_P(mmGRBM_GFX_INDEX, 0, | ||
324 | ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); | ||
325 | else | ||
326 | WREG32_P(mmGRBM_GFX_INDEX, | ||
327 | GRBM_GFX_INDEX__VCE_INSTANCE_MASK, | ||
328 | ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); | ||
329 | 277 | ||
330 | if (adev->asic_type >= CHIP_STONEY) | 278 | if (adev->asic_type >= CHIP_STONEY) |
331 | WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); | 279 | WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); |
332 | else | 280 | else |
333 | WREG32_P(mmVCE_VCPU_CNTL, 0, | 281 | WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 0); |
334 | ~VCE_VCPU_CNTL__CLK_EN_MASK); | 282 | |
335 | /* hold on ECPU */ | 283 | /* hold on ECPU */ |
336 | WREG32_P(mmVCE_SOFT_RESET, | 284 | WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); |
337 | VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, | ||
338 | ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); | ||
339 | 285 | ||
340 | /* clear BUSY flag */ | 286 | /* clear BUSY flag */ |
341 | WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); | 287 | WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); |
342 | 288 | ||
343 | /* Set Clock-Gating off */ | 289 | /* Set Clock-Gating off */ |
344 | if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) | 290 | if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) |
345 | vce_v3_0_set_vce_sw_clock_gating(adev, false); | 291 | vce_v3_0_set_vce_sw_clock_gating(adev, false); |
346 | } | 292 | } |
347 | 293 | ||
348 | WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); | 294 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); |
349 | mutex_unlock(&adev->grbm_idx_mutex); | 295 | mutex_unlock(&adev->grbm_idx_mutex); |
350 | 296 | ||
351 | return 0; | 297 | return 0; |
@@ -534,7 +480,7 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) | |||
534 | WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); | 480 | WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); |
535 | WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); | 481 | WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); |
536 | WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); | 482 | WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); |
537 | WREG32(mmVCE_CLOCK_GATING_B, 0xf7); | 483 | WREG32(mmVCE_CLOCK_GATING_B, 0x1FF); |
538 | 484 | ||
539 | WREG32(mmVCE_LMI_CTRL, 0x00398000); | 485 | WREG32(mmVCE_LMI_CTRL, 0x00398000); |
540 | WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); | 486 | WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); |
@@ -573,9 +519,7 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) | |||
573 | } | 519 | } |
574 | 520 | ||
575 | WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); | 521 | WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); |
576 | 522 | WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1); | |
577 | WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK, | ||
578 | ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); | ||
579 | } | 523 | } |
580 | 524 | ||
581 | static bool vce_v3_0_is_idle(void *handle) | 525 | static bool vce_v3_0_is_idle(void *handle) |
@@ -601,20 +545,108 @@ static int vce_v3_0_wait_for_idle(void *handle) | |||
601 | return -ETIMEDOUT; | 545 | return -ETIMEDOUT; |
602 | } | 546 | } |
603 | 547 | ||
548 | #define VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK 0x00000008L /* AUTO_BUSY */ | ||
549 | #define VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK 0x00000010L /* RB0_BUSY */ | ||
550 | #define VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK 0x00000020L /* RB1_BUSY */ | ||
551 | #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ | ||
552 | VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) | ||
553 | |||
554 | static int vce_v3_0_check_soft_reset(void *handle) | ||
555 | { | ||
556 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
557 | u32 srbm_soft_reset = 0; | ||
558 | |||
559 | /* According to VCE team , we should use VCE_STATUS instead | ||
560 | * SRBM_STATUS.VCE_BUSY bit for busy status checking. | ||
561 | * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE | ||
562 | * instance's registers are accessed | ||
563 | * (0 for 1st instance, 10 for 2nd instance). | ||
564 | * | ||
565 | *VCE_STATUS | ||
566 | *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | | ||
567 | *|----+----+-----------+----+----+----+----------+---------+----| | ||
568 | *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| | ||
569 | * | ||
570 | * VCE team suggest use bit 3--bit 6 for busy status check | ||
571 | */ | ||
572 | mutex_lock(&adev->grbm_idx_mutex); | ||
573 | WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); | ||
574 | if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { | ||
575 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); | ||
576 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); | ||
577 | } | ||
578 | WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); | ||
579 | if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { | ||
580 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); | ||
581 | srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); | ||
582 | } | ||
583 | WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); | ||
584 | |||
585 | if (srbm_soft_reset) { | ||
586 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true; | ||
587 | adev->vce.srbm_soft_reset = srbm_soft_reset; | ||
588 | } else { | ||
589 | adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false; | ||
590 | adev->vce.srbm_soft_reset = 0; | ||
591 | } | ||
592 | mutex_unlock(&adev->grbm_idx_mutex); | ||
593 | return 0; | ||
594 | } | ||
595 | |||
604 | static int vce_v3_0_soft_reset(void *handle) | 596 | static int vce_v3_0_soft_reset(void *handle) |
605 | { | 597 | { |
606 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 598 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
607 | u32 mask = 0; | 599 | u32 srbm_soft_reset; |
600 | |||
601 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) | ||
602 | return 0; | ||
603 | srbm_soft_reset = adev->vce.srbm_soft_reset; | ||
604 | |||
605 | if (srbm_soft_reset) { | ||
606 | u32 tmp; | ||
607 | |||
608 | tmp = RREG32(mmSRBM_SOFT_RESET); | ||
609 | tmp |= srbm_soft_reset; | ||
610 | dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); | ||
611 | WREG32(mmSRBM_SOFT_RESET, tmp); | ||
612 | tmp = RREG32(mmSRBM_SOFT_RESET); | ||
613 | |||
614 | udelay(50); | ||
615 | |||
616 | tmp &= ~srbm_soft_reset; | ||
617 | WREG32(mmSRBM_SOFT_RESET, tmp); | ||
618 | tmp = RREG32(mmSRBM_SOFT_RESET); | ||
619 | |||
620 | /* Wait a little for things to settle down */ | ||
621 | udelay(50); | ||
622 | } | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static int vce_v3_0_pre_soft_reset(void *handle) | ||
628 | { | ||
629 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
630 | |||
631 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) | ||
632 | return 0; | ||
633 | |||
634 | mdelay(5); | ||
608 | 635 | ||
609 | mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK; | 636 | return vce_v3_0_suspend(adev); |
610 | mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK; | 637 | } |
638 | |||
639 | |||
640 | static int vce_v3_0_post_soft_reset(void *handle) | ||
641 | { | ||
642 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
643 | |||
644 | if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) | ||
645 | return 0; | ||
611 | 646 | ||
612 | WREG32_P(mmSRBM_SOFT_RESET, mask, | ||
613 | ~(SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK | | ||
614 | SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK)); | ||
615 | mdelay(5); | 647 | mdelay(5); |
616 | 648 | ||
617 | return vce_v3_0_start(adev); | 649 | return vce_v3_0_resume(adev); |
618 | } | 650 | } |
619 | 651 | ||
620 | static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, | 652 | static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, |
@@ -637,9 +669,7 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, | |||
637 | { | 669 | { |
638 | DRM_DEBUG("IH: VCE\n"); | 670 | DRM_DEBUG("IH: VCE\n"); |
639 | 671 | ||
640 | WREG32_P(mmVCE_SYS_INT_STATUS, | 672 | WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1); |
641 | VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK, | ||
642 | ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK); | ||
643 | 673 | ||
644 | switch (entry->src_data) { | 674 | switch (entry->src_data) { |
645 | case 0: | 675 | case 0: |
@@ -686,13 +716,7 @@ static int vce_v3_0_set_clockgating_state(void *handle, | |||
686 | if (adev->vce.harvest_config & (1 << i)) | 716 | if (adev->vce.harvest_config & (1 << i)) |
687 | continue; | 717 | continue; |
688 | 718 | ||
689 | if (i == 0) | 719 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i); |
690 | WREG32_P(mmGRBM_GFX_INDEX, 0, | ||
691 | ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); | ||
692 | else | ||
693 | WREG32_P(mmGRBM_GFX_INDEX, | ||
694 | GRBM_GFX_INDEX__VCE_INSTANCE_MASK, | ||
695 | ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); | ||
696 | 720 | ||
697 | if (enable) { | 721 | if (enable) { |
698 | /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ | 722 | /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ |
@@ -711,7 +735,7 @@ static int vce_v3_0_set_clockgating_state(void *handle, | |||
711 | vce_v3_0_set_vce_sw_clock_gating(adev, enable); | 735 | vce_v3_0_set_vce_sw_clock_gating(adev, enable); |
712 | } | 736 | } |
713 | 737 | ||
714 | WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); | 738 | WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); |
715 | mutex_unlock(&adev->grbm_idx_mutex); | 739 | mutex_unlock(&adev->grbm_idx_mutex); |
716 | 740 | ||
717 | return 0; | 741 | return 0; |
@@ -751,7 +775,10 @@ const struct amd_ip_funcs vce_v3_0_ip_funcs = { | |||
751 | .resume = vce_v3_0_resume, | 775 | .resume = vce_v3_0_resume, |
752 | .is_idle = vce_v3_0_is_idle, | 776 | .is_idle = vce_v3_0_is_idle, |
753 | .wait_for_idle = vce_v3_0_wait_for_idle, | 777 | .wait_for_idle = vce_v3_0_wait_for_idle, |
778 | .check_soft_reset = vce_v3_0_check_soft_reset, | ||
779 | .pre_soft_reset = vce_v3_0_pre_soft_reset, | ||
754 | .soft_reset = vce_v3_0_soft_reset, | 780 | .soft_reset = vce_v3_0_soft_reset, |
781 | .post_soft_reset = vce_v3_0_post_soft_reset, | ||
755 | .set_clockgating_state = vce_v3_0_set_clockgating_state, | 782 | .set_clockgating_state = vce_v3_0_set_clockgating_state, |
756 | .set_powergating_state = vce_v3_0_set_powergating_state, | 783 | .set_powergating_state = vce_v3_0_set_powergating_state, |
757 | }; | 784 | }; |
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 03a31c53aec3..f2e8aa1a0dbd 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c | |||
@@ -77,6 +77,7 @@ | |||
77 | #if defined(CONFIG_DRM_AMD_ACP) | 77 | #if defined(CONFIG_DRM_AMD_ACP) |
78 | #include "amdgpu_acp.h" | 78 | #include "amdgpu_acp.h" |
79 | #endif | 79 | #endif |
80 | #include "dce_virtual.h" | ||
80 | 81 | ||
81 | MODULE_FIRMWARE("amdgpu/polaris10_smc.bin"); | 82 | MODULE_FIRMWARE("amdgpu/polaris10_smc.bin"); |
82 | MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin"); | 83 | MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin"); |
@@ -822,6 +823,60 @@ static const struct amdgpu_ip_block_version topaz_ip_blocks[] = | |||
822 | }, | 823 | }, |
823 | }; | 824 | }; |
824 | 825 | ||
826 | static const struct amdgpu_ip_block_version topaz_ip_blocks_vd[] = | ||
827 | { | ||
828 | /* ORDER MATTERS! */ | ||
829 | { | ||
830 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
831 | .major = 2, | ||
832 | .minor = 0, | ||
833 | .rev = 0, | ||
834 | .funcs = &vi_common_ip_funcs, | ||
835 | }, | ||
836 | { | ||
837 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
838 | .major = 7, | ||
839 | .minor = 4, | ||
840 | .rev = 0, | ||
841 | .funcs = &gmc_v7_0_ip_funcs, | ||
842 | }, | ||
843 | { | ||
844 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
845 | .major = 2, | ||
846 | .minor = 4, | ||
847 | .rev = 0, | ||
848 | .funcs = &iceland_ih_ip_funcs, | ||
849 | }, | ||
850 | { | ||
851 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
852 | .major = 7, | ||
853 | .minor = 1, | ||
854 | .rev = 0, | ||
855 | .funcs = &amdgpu_pp_ip_funcs, | ||
856 | }, | ||
857 | { | ||
858 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
859 | .major = 1, | ||
860 | .minor = 0, | ||
861 | .rev = 0, | ||
862 | .funcs = &dce_virtual_ip_funcs, | ||
863 | }, | ||
864 | { | ||
865 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
866 | .major = 8, | ||
867 | .minor = 0, | ||
868 | .rev = 0, | ||
869 | .funcs = &gfx_v8_0_ip_funcs, | ||
870 | }, | ||
871 | { | ||
872 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
873 | .major = 2, | ||
874 | .minor = 4, | ||
875 | .rev = 0, | ||
876 | .funcs = &sdma_v2_4_ip_funcs, | ||
877 | }, | ||
878 | }; | ||
879 | |||
825 | static const struct amdgpu_ip_block_version tonga_ip_blocks[] = | 880 | static const struct amdgpu_ip_block_version tonga_ip_blocks[] = |
826 | { | 881 | { |
827 | /* ORDER MATTERS! */ | 882 | /* ORDER MATTERS! */ |
@@ -890,6 +945,74 @@ static const struct amdgpu_ip_block_version tonga_ip_blocks[] = | |||
890 | }, | 945 | }, |
891 | }; | 946 | }; |
892 | 947 | ||
948 | static const struct amdgpu_ip_block_version tonga_ip_blocks_vd[] = | ||
949 | { | ||
950 | /* ORDER MATTERS! */ | ||
951 | { | ||
952 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
953 | .major = 2, | ||
954 | .minor = 0, | ||
955 | .rev = 0, | ||
956 | .funcs = &vi_common_ip_funcs, | ||
957 | }, | ||
958 | { | ||
959 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
960 | .major = 8, | ||
961 | .minor = 0, | ||
962 | .rev = 0, | ||
963 | .funcs = &gmc_v8_0_ip_funcs, | ||
964 | }, | ||
965 | { | ||
966 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
967 | .major = 3, | ||
968 | .minor = 0, | ||
969 | .rev = 0, | ||
970 | .funcs = &tonga_ih_ip_funcs, | ||
971 | }, | ||
972 | { | ||
973 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
974 | .major = 7, | ||
975 | .minor = 1, | ||
976 | .rev = 0, | ||
977 | .funcs = &amdgpu_pp_ip_funcs, | ||
978 | }, | ||
979 | { | ||
980 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
981 | .major = 10, | ||
982 | .minor = 0, | ||
983 | .rev = 0, | ||
984 | .funcs = &dce_virtual_ip_funcs, | ||
985 | }, | ||
986 | { | ||
987 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
988 | .major = 8, | ||
989 | .minor = 0, | ||
990 | .rev = 0, | ||
991 | .funcs = &gfx_v8_0_ip_funcs, | ||
992 | }, | ||
993 | { | ||
994 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
995 | .major = 3, | ||
996 | .minor = 0, | ||
997 | .rev = 0, | ||
998 | .funcs = &sdma_v3_0_ip_funcs, | ||
999 | }, | ||
1000 | { | ||
1001 | .type = AMD_IP_BLOCK_TYPE_UVD, | ||
1002 | .major = 5, | ||
1003 | .minor = 0, | ||
1004 | .rev = 0, | ||
1005 | .funcs = &uvd_v5_0_ip_funcs, | ||
1006 | }, | ||
1007 | { | ||
1008 | .type = AMD_IP_BLOCK_TYPE_VCE, | ||
1009 | .major = 3, | ||
1010 | .minor = 0, | ||
1011 | .rev = 0, | ||
1012 | .funcs = &vce_v3_0_ip_funcs, | ||
1013 | }, | ||
1014 | }; | ||
1015 | |||
893 | static const struct amdgpu_ip_block_version fiji_ip_blocks[] = | 1016 | static const struct amdgpu_ip_block_version fiji_ip_blocks[] = |
894 | { | 1017 | { |
895 | /* ORDER MATTERS! */ | 1018 | /* ORDER MATTERS! */ |
@@ -958,6 +1081,74 @@ static const struct amdgpu_ip_block_version fiji_ip_blocks[] = | |||
958 | }, | 1081 | }, |
959 | }; | 1082 | }; |
960 | 1083 | ||
1084 | static const struct amdgpu_ip_block_version fiji_ip_blocks_vd[] = | ||
1085 | { | ||
1086 | /* ORDER MATTERS! */ | ||
1087 | { | ||
1088 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
1089 | .major = 2, | ||
1090 | .minor = 0, | ||
1091 | .rev = 0, | ||
1092 | .funcs = &vi_common_ip_funcs, | ||
1093 | }, | ||
1094 | { | ||
1095 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
1096 | .major = 8, | ||
1097 | .minor = 5, | ||
1098 | .rev = 0, | ||
1099 | .funcs = &gmc_v8_0_ip_funcs, | ||
1100 | }, | ||
1101 | { | ||
1102 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
1103 | .major = 3, | ||
1104 | .minor = 0, | ||
1105 | .rev = 0, | ||
1106 | .funcs = &tonga_ih_ip_funcs, | ||
1107 | }, | ||
1108 | { | ||
1109 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
1110 | .major = 7, | ||
1111 | .minor = 1, | ||
1112 | .rev = 0, | ||
1113 | .funcs = &amdgpu_pp_ip_funcs, | ||
1114 | }, | ||
1115 | { | ||
1116 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
1117 | .major = 10, | ||
1118 | .minor = 1, | ||
1119 | .rev = 0, | ||
1120 | .funcs = &dce_virtual_ip_funcs, | ||
1121 | }, | ||
1122 | { | ||
1123 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
1124 | .major = 8, | ||
1125 | .minor = 0, | ||
1126 | .rev = 0, | ||
1127 | .funcs = &gfx_v8_0_ip_funcs, | ||
1128 | }, | ||
1129 | { | ||
1130 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
1131 | .major = 3, | ||
1132 | .minor = 0, | ||
1133 | .rev = 0, | ||
1134 | .funcs = &sdma_v3_0_ip_funcs, | ||
1135 | }, | ||
1136 | { | ||
1137 | .type = AMD_IP_BLOCK_TYPE_UVD, | ||
1138 | .major = 6, | ||
1139 | .minor = 0, | ||
1140 | .rev = 0, | ||
1141 | .funcs = &uvd_v6_0_ip_funcs, | ||
1142 | }, | ||
1143 | { | ||
1144 | .type = AMD_IP_BLOCK_TYPE_VCE, | ||
1145 | .major = 3, | ||
1146 | .minor = 0, | ||
1147 | .rev = 0, | ||
1148 | .funcs = &vce_v3_0_ip_funcs, | ||
1149 | }, | ||
1150 | }; | ||
1151 | |||
961 | static const struct amdgpu_ip_block_version polaris11_ip_blocks[] = | 1152 | static const struct amdgpu_ip_block_version polaris11_ip_blocks[] = |
962 | { | 1153 | { |
963 | /* ORDER MATTERS! */ | 1154 | /* ORDER MATTERS! */ |
@@ -1026,6 +1217,74 @@ static const struct amdgpu_ip_block_version polaris11_ip_blocks[] = | |||
1026 | }, | 1217 | }, |
1027 | }; | 1218 | }; |
1028 | 1219 | ||
1220 | static const struct amdgpu_ip_block_version polaris11_ip_blocks_vd[] = | ||
1221 | { | ||
1222 | /* ORDER MATTERS! */ | ||
1223 | { | ||
1224 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
1225 | .major = 2, | ||
1226 | .minor = 0, | ||
1227 | .rev = 0, | ||
1228 | .funcs = &vi_common_ip_funcs, | ||
1229 | }, | ||
1230 | { | ||
1231 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
1232 | .major = 8, | ||
1233 | .minor = 1, | ||
1234 | .rev = 0, | ||
1235 | .funcs = &gmc_v8_0_ip_funcs, | ||
1236 | }, | ||
1237 | { | ||
1238 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
1239 | .major = 3, | ||
1240 | .minor = 1, | ||
1241 | .rev = 0, | ||
1242 | .funcs = &tonga_ih_ip_funcs, | ||
1243 | }, | ||
1244 | { | ||
1245 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
1246 | .major = 7, | ||
1247 | .minor = 2, | ||
1248 | .rev = 0, | ||
1249 | .funcs = &amdgpu_pp_ip_funcs, | ||
1250 | }, | ||
1251 | { | ||
1252 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
1253 | .major = 11, | ||
1254 | .minor = 2, | ||
1255 | .rev = 0, | ||
1256 | .funcs = &dce_virtual_ip_funcs, | ||
1257 | }, | ||
1258 | { | ||
1259 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
1260 | .major = 8, | ||
1261 | .minor = 0, | ||
1262 | .rev = 0, | ||
1263 | .funcs = &gfx_v8_0_ip_funcs, | ||
1264 | }, | ||
1265 | { | ||
1266 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
1267 | .major = 3, | ||
1268 | .minor = 1, | ||
1269 | .rev = 0, | ||
1270 | .funcs = &sdma_v3_0_ip_funcs, | ||
1271 | }, | ||
1272 | { | ||
1273 | .type = AMD_IP_BLOCK_TYPE_UVD, | ||
1274 | .major = 6, | ||
1275 | .minor = 3, | ||
1276 | .rev = 0, | ||
1277 | .funcs = &uvd_v6_0_ip_funcs, | ||
1278 | }, | ||
1279 | { | ||
1280 | .type = AMD_IP_BLOCK_TYPE_VCE, | ||
1281 | .major = 3, | ||
1282 | .minor = 4, | ||
1283 | .rev = 0, | ||
1284 | .funcs = &vce_v3_0_ip_funcs, | ||
1285 | }, | ||
1286 | }; | ||
1287 | |||
1029 | static const struct amdgpu_ip_block_version cz_ip_blocks[] = | 1288 | static const struct amdgpu_ip_block_version cz_ip_blocks[] = |
1030 | { | 1289 | { |
1031 | /* ORDER MATTERS! */ | 1290 | /* ORDER MATTERS! */ |
@@ -1103,34 +1362,142 @@ static const struct amdgpu_ip_block_version cz_ip_blocks[] = | |||
1103 | #endif | 1362 | #endif |
1104 | }; | 1363 | }; |
1105 | 1364 | ||
1365 | static const struct amdgpu_ip_block_version cz_ip_blocks_vd[] = | ||
1366 | { | ||
1367 | /* ORDER MATTERS! */ | ||
1368 | { | ||
1369 | .type = AMD_IP_BLOCK_TYPE_COMMON, | ||
1370 | .major = 2, | ||
1371 | .minor = 0, | ||
1372 | .rev = 0, | ||
1373 | .funcs = &vi_common_ip_funcs, | ||
1374 | }, | ||
1375 | { | ||
1376 | .type = AMD_IP_BLOCK_TYPE_GMC, | ||
1377 | .major = 8, | ||
1378 | .minor = 0, | ||
1379 | .rev = 0, | ||
1380 | .funcs = &gmc_v8_0_ip_funcs, | ||
1381 | }, | ||
1382 | { | ||
1383 | .type = AMD_IP_BLOCK_TYPE_IH, | ||
1384 | .major = 3, | ||
1385 | .minor = 0, | ||
1386 | .rev = 0, | ||
1387 | .funcs = &cz_ih_ip_funcs, | ||
1388 | }, | ||
1389 | { | ||
1390 | .type = AMD_IP_BLOCK_TYPE_SMC, | ||
1391 | .major = 8, | ||
1392 | .minor = 0, | ||
1393 | .rev = 0, | ||
1394 | .funcs = &amdgpu_pp_ip_funcs | ||
1395 | }, | ||
1396 | { | ||
1397 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
1398 | .major = 11, | ||
1399 | .minor = 0, | ||
1400 | .rev = 0, | ||
1401 | .funcs = &dce_virtual_ip_funcs, | ||
1402 | }, | ||
1403 | { | ||
1404 | .type = AMD_IP_BLOCK_TYPE_GFX, | ||
1405 | .major = 8, | ||
1406 | .minor = 0, | ||
1407 | .rev = 0, | ||
1408 | .funcs = &gfx_v8_0_ip_funcs, | ||
1409 | }, | ||
1410 | { | ||
1411 | .type = AMD_IP_BLOCK_TYPE_SDMA, | ||
1412 | .major = 3, | ||
1413 | .minor = 0, | ||
1414 | .rev = 0, | ||
1415 | .funcs = &sdma_v3_0_ip_funcs, | ||
1416 | }, | ||
1417 | { | ||
1418 | .type = AMD_IP_BLOCK_TYPE_UVD, | ||
1419 | .major = 6, | ||
1420 | .minor = 0, | ||
1421 | .rev = 0, | ||
1422 | .funcs = &uvd_v6_0_ip_funcs, | ||
1423 | }, | ||
1424 | { | ||
1425 | .type = AMD_IP_BLOCK_TYPE_VCE, | ||
1426 | .major = 3, | ||
1427 | .minor = 0, | ||
1428 | .rev = 0, | ||
1429 | .funcs = &vce_v3_0_ip_funcs, | ||
1430 | }, | ||
1431 | #if defined(CONFIG_DRM_AMD_ACP) | ||
1432 | { | ||
1433 | .type = AMD_IP_BLOCK_TYPE_ACP, | ||
1434 | .major = 2, | ||
1435 | .minor = 2, | ||
1436 | .rev = 0, | ||
1437 | .funcs = &acp_ip_funcs, | ||
1438 | }, | ||
1439 | #endif | ||
1440 | }; | ||
1441 | |||
1106 | int vi_set_ip_blocks(struct amdgpu_device *adev) | 1442 | int vi_set_ip_blocks(struct amdgpu_device *adev) |
1107 | { | 1443 | { |
1108 | switch (adev->asic_type) { | 1444 | if (adev->enable_virtual_display) { |
1109 | case CHIP_TOPAZ: | 1445 | switch (adev->asic_type) { |
1110 | adev->ip_blocks = topaz_ip_blocks; | 1446 | case CHIP_TOPAZ: |
1111 | adev->num_ip_blocks = ARRAY_SIZE(topaz_ip_blocks); | 1447 | adev->ip_blocks = topaz_ip_blocks_vd; |
1112 | break; | 1448 | adev->num_ip_blocks = ARRAY_SIZE(topaz_ip_blocks_vd); |
1113 | case CHIP_FIJI: | 1449 | break; |
1114 | adev->ip_blocks = fiji_ip_blocks; | 1450 | case CHIP_FIJI: |
1115 | adev->num_ip_blocks = ARRAY_SIZE(fiji_ip_blocks); | 1451 | adev->ip_blocks = fiji_ip_blocks_vd; |
1116 | break; | 1452 | adev->num_ip_blocks = ARRAY_SIZE(fiji_ip_blocks_vd); |
1117 | case CHIP_TONGA: | 1453 | break; |
1118 | adev->ip_blocks = tonga_ip_blocks; | 1454 | case CHIP_TONGA: |
1119 | adev->num_ip_blocks = ARRAY_SIZE(tonga_ip_blocks); | 1455 | adev->ip_blocks = tonga_ip_blocks_vd; |
1120 | break; | 1456 | adev->num_ip_blocks = ARRAY_SIZE(tonga_ip_blocks_vd); |
1121 | case CHIP_POLARIS11: | 1457 | break; |
1122 | case CHIP_POLARIS10: | 1458 | case CHIP_POLARIS11: |
1123 | adev->ip_blocks = polaris11_ip_blocks; | 1459 | case CHIP_POLARIS10: |
1124 | adev->num_ip_blocks = ARRAY_SIZE(polaris11_ip_blocks); | 1460 | adev->ip_blocks = polaris11_ip_blocks_vd; |
1125 | break; | 1461 | adev->num_ip_blocks = ARRAY_SIZE(polaris11_ip_blocks_vd); |
1126 | case CHIP_CARRIZO: | 1462 | break; |
1127 | case CHIP_STONEY: | 1463 | |
1128 | adev->ip_blocks = cz_ip_blocks; | 1464 | case CHIP_CARRIZO: |
1129 | adev->num_ip_blocks = ARRAY_SIZE(cz_ip_blocks); | 1465 | case CHIP_STONEY: |
1130 | break; | 1466 | adev->ip_blocks = cz_ip_blocks_vd; |
1131 | default: | 1467 | adev->num_ip_blocks = ARRAY_SIZE(cz_ip_blocks_vd); |
1132 | /* FIXME: not supported yet */ | 1468 | break; |
1133 | return -EINVAL; | 1469 | default: |
1470 | /* FIXME: not supported yet */ | ||
1471 | return -EINVAL; | ||
1472 | } | ||
1473 | } else { | ||
1474 | switch (adev->asic_type) { | ||
1475 | case CHIP_TOPAZ: | ||
1476 | adev->ip_blocks = topaz_ip_blocks; | ||
1477 | adev->num_ip_blocks = ARRAY_SIZE(topaz_ip_blocks); | ||
1478 | break; | ||
1479 | case CHIP_FIJI: | ||
1480 | adev->ip_blocks = fiji_ip_blocks; | ||
1481 | adev->num_ip_blocks = ARRAY_SIZE(fiji_ip_blocks); | ||
1482 | break; | ||
1483 | case CHIP_TONGA: | ||
1484 | adev->ip_blocks = tonga_ip_blocks; | ||
1485 | adev->num_ip_blocks = ARRAY_SIZE(tonga_ip_blocks); | ||
1486 | break; | ||
1487 | case CHIP_POLARIS11: | ||
1488 | case CHIP_POLARIS10: | ||
1489 | adev->ip_blocks = polaris11_ip_blocks; | ||
1490 | adev->num_ip_blocks = ARRAY_SIZE(polaris11_ip_blocks); | ||
1491 | break; | ||
1492 | case CHIP_CARRIZO: | ||
1493 | case CHIP_STONEY: | ||
1494 | adev->ip_blocks = cz_ip_blocks; | ||
1495 | adev->num_ip_blocks = ARRAY_SIZE(cz_ip_blocks); | ||
1496 | break; | ||
1497 | default: | ||
1498 | /* FIXME: not supported yet */ | ||
1499 | return -EINVAL; | ||
1500 | } | ||
1134 | } | 1501 | } |
1135 | 1502 | ||
1136 | return 0; | 1503 | return 0; |
@@ -1248,8 +1615,17 @@ static int vi_common_early_init(void *handle) | |||
1248 | AMD_CG_SUPPORT_HDP_MGCG | | 1615 | AMD_CG_SUPPORT_HDP_MGCG | |
1249 | AMD_CG_SUPPORT_HDP_LS | | 1616 | AMD_CG_SUPPORT_HDP_LS | |
1250 | AMD_CG_SUPPORT_SDMA_MGCG | | 1617 | AMD_CG_SUPPORT_SDMA_MGCG | |
1251 | AMD_CG_SUPPORT_SDMA_LS; | 1618 | AMD_CG_SUPPORT_SDMA_LS | |
1619 | AMD_CG_SUPPORT_VCE_MGCG; | ||
1620 | /* rev0 hardware requires workarounds to support PG */ | ||
1252 | adev->pg_flags = 0; | 1621 | adev->pg_flags = 0; |
1622 | if (adev->rev_id != 0x00) { | ||
1623 | adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG | | ||
1624 | AMD_PG_SUPPORT_GFX_SMG | | ||
1625 | AMD_PG_SUPPORT_GFX_PIPELINE | | ||
1626 | AMD_PG_SUPPORT_UVD | | ||
1627 | AMD_PG_SUPPORT_VCE; | ||
1628 | } | ||
1253 | adev->external_rev_id = adev->rev_id + 0x1; | 1629 | adev->external_rev_id = adev->rev_id + 0x1; |
1254 | break; | 1630 | break; |
1255 | case CHIP_STONEY: | 1631 | case CHIP_STONEY: |
@@ -1267,7 +1643,13 @@ static int vi_common_early_init(void *handle) | |||
1267 | AMD_CG_SUPPORT_HDP_MGCG | | 1643 | AMD_CG_SUPPORT_HDP_MGCG | |
1268 | AMD_CG_SUPPORT_HDP_LS | | 1644 | AMD_CG_SUPPORT_HDP_LS | |
1269 | AMD_CG_SUPPORT_SDMA_MGCG | | 1645 | AMD_CG_SUPPORT_SDMA_MGCG | |
1270 | AMD_CG_SUPPORT_SDMA_LS; | 1646 | AMD_CG_SUPPORT_SDMA_LS | |
1647 | AMD_CG_SUPPORT_VCE_MGCG; | ||
1648 | adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG | | ||
1649 | AMD_PG_SUPPORT_GFX_SMG | | ||
1650 | AMD_PG_SUPPORT_GFX_PIPELINE | | ||
1651 | AMD_PG_SUPPORT_UVD | | ||
1652 | AMD_PG_SUPPORT_VCE; | ||
1271 | adev->external_rev_id = adev->rev_id + 0x1; | 1653 | adev->external_rev_id = adev->rev_id + 0x1; |
1272 | break; | 1654 | break; |
1273 | default: | 1655 | default: |
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index a74a0d2ff1ca..db710418f35f 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h | |||
@@ -159,8 +159,14 @@ struct amd_ip_funcs { | |||
159 | bool (*is_idle)(void *handle); | 159 | bool (*is_idle)(void *handle); |
160 | /* poll for idle */ | 160 | /* poll for idle */ |
161 | int (*wait_for_idle)(void *handle); | 161 | int (*wait_for_idle)(void *handle); |
162 | /* check soft reset the IP block */ | ||
163 | int (*check_soft_reset)(void *handle); | ||
164 | /* pre soft reset the IP block */ | ||
165 | int (*pre_soft_reset)(void *handle); | ||
162 | /* soft reset the IP block */ | 166 | /* soft reset the IP block */ |
163 | int (*soft_reset)(void *handle); | 167 | int (*soft_reset)(void *handle); |
168 | /* post soft reset the IP block */ | ||
169 | int (*post_soft_reset)(void *handle); | ||
164 | /* enable/disable cg for the IP block */ | 170 | /* enable/disable cg for the IP block */ |
165 | int (*set_clockgating_state)(void *handle, | 171 | int (*set_clockgating_state)(void *handle, |
166 | enum amd_clockgating_state state); | 172 | enum amd_clockgating_state state); |
diff --git a/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_4_2_d.h b/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_4_2_d.h index f3e53b118361..19802e96417e 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_4_2_d.h +++ b/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_4_2_d.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #define mmUVD_UDEC_ADDR_CONFIG 0x3bd3 | 34 | #define mmUVD_UDEC_ADDR_CONFIG 0x3bd3 |
35 | #define mmUVD_UDEC_DB_ADDR_CONFIG 0x3bd4 | 35 | #define mmUVD_UDEC_DB_ADDR_CONFIG 0x3bd4 |
36 | #define mmUVD_UDEC_DBW_ADDR_CONFIG 0x3bd5 | 36 | #define mmUVD_UDEC_DBW_ADDR_CONFIG 0x3bd5 |
37 | #define mmUVD_NO_OP 0x3bff | ||
37 | #define mmUVD_SEMA_CNTL 0x3d00 | 38 | #define mmUVD_SEMA_CNTL 0x3d00 |
38 | #define mmUVD_LMI_EXT40_ADDR 0x3d26 | 39 | #define mmUVD_LMI_EXT40_ADDR 0x3d26 |
39 | #define mmUVD_CTX_INDEX 0x3d28 | 40 | #define mmUVD_CTX_INDEX 0x3d28 |
diff --git a/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_5_0_d.h b/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_5_0_d.h index eb4cf53427da..cc972d237a7e 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_5_0_d.h +++ b/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_5_0_d.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #define mmUVD_UDEC_ADDR_CONFIG 0x3bd3 | 34 | #define mmUVD_UDEC_ADDR_CONFIG 0x3bd3 |
35 | #define mmUVD_UDEC_DB_ADDR_CONFIG 0x3bd4 | 35 | #define mmUVD_UDEC_DB_ADDR_CONFIG 0x3bd4 |
36 | #define mmUVD_UDEC_DBW_ADDR_CONFIG 0x3bd5 | 36 | #define mmUVD_UDEC_DBW_ADDR_CONFIG 0x3bd5 |
37 | #define mmUVD_NO_OP 0x3bff | ||
37 | #define mmUVD_LMI_RBC_RB_64BIT_BAR_LOW 0x3c69 | 38 | #define mmUVD_LMI_RBC_RB_64BIT_BAR_LOW 0x3c69 |
38 | #define mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH 0x3c68 | 39 | #define mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH 0x3c68 |
39 | #define mmUVD_LMI_RBC_IB_64BIT_BAR_LOW 0x3c67 | 40 | #define mmUVD_LMI_RBC_IB_64BIT_BAR_LOW 0x3c67 |
diff --git a/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_6_0_d.h b/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_6_0_d.h index ec69869c55ff..378f4b6b43da 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_6_0_d.h +++ b/drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_6_0_d.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #define mmUVD_UDEC_DB_ADDR_CONFIG 0x3bd4 | 35 | #define mmUVD_UDEC_DB_ADDR_CONFIG 0x3bd4 |
36 | #define mmUVD_UDEC_DBW_ADDR_CONFIG 0x3bd5 | 36 | #define mmUVD_UDEC_DBW_ADDR_CONFIG 0x3bd5 |
37 | #define mmUVD_POWER_STATUS_U 0x3bfd | 37 | #define mmUVD_POWER_STATUS_U 0x3bfd |
38 | #define mmUVD_NO_OP 0x3bff | ||
38 | #define mmUVD_LMI_RBC_RB_64BIT_BAR_LOW 0x3c69 | 39 | #define mmUVD_LMI_RBC_RB_64BIT_BAR_LOW 0x3c69 |
39 | #define mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH 0x3c68 | 40 | #define mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH 0x3c68 |
40 | #define mmUVD_LMI_RBC_IB_64BIT_BAR_LOW 0x3c67 | 41 | #define mmUVD_LMI_RBC_IB_64BIT_BAR_LOW 0x3c67 |
diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index abbb658bdc1e..2de34a5a85c2 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "eventmanager.h" | 31 | #include "eventmanager.h" |
32 | #include "pp_debug.h" | 32 | #include "pp_debug.h" |
33 | 33 | ||
34 | |||
34 | #define PP_CHECK(handle) \ | 35 | #define PP_CHECK(handle) \ |
35 | do { \ | 36 | do { \ |
36 | if ((handle) == NULL || (handle)->pp_valid != PP_VALID) \ | 37 | if ((handle) == NULL || (handle)->pp_valid != PP_VALID) \ |
@@ -162,12 +163,12 @@ static int pp_hw_fini(void *handle) | |||
162 | pp_handle = (struct pp_instance *)handle; | 163 | pp_handle = (struct pp_instance *)handle; |
163 | eventmgr = pp_handle->eventmgr; | 164 | eventmgr = pp_handle->eventmgr; |
164 | 165 | ||
165 | if (eventmgr != NULL || eventmgr->pp_eventmgr_fini != NULL) | 166 | if (eventmgr != NULL && eventmgr->pp_eventmgr_fini != NULL) |
166 | eventmgr->pp_eventmgr_fini(eventmgr); | 167 | eventmgr->pp_eventmgr_fini(eventmgr); |
167 | 168 | ||
168 | smumgr = pp_handle->smu_mgr; | 169 | smumgr = pp_handle->smu_mgr; |
169 | 170 | ||
170 | if (smumgr != NULL || smumgr->smumgr_funcs != NULL || | 171 | if (smumgr != NULL && smumgr->smumgr_funcs != NULL && |
171 | smumgr->smumgr_funcs->smu_fini != NULL) | 172 | smumgr->smumgr_funcs->smu_fini != NULL) |
172 | smumgr->smumgr_funcs->smu_fini(smumgr); | 173 | smumgr->smumgr_funcs->smu_fini(smumgr); |
173 | 174 | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile index f7ce4cb71346..abbcbc9f6eca 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile | |||
@@ -4,13 +4,15 @@ | |||
4 | 4 | ||
5 | HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \ | 5 | HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \ |
6 | hardwaremanager.o pp_acpi.o cz_hwmgr.o \ | 6 | hardwaremanager.o pp_acpi.o cz_hwmgr.o \ |
7 | cz_clockpowergating.o \ | 7 | cz_clockpowergating.o tonga_powertune.o\ |
8 | tonga_processpptables.o ppatomctrl.o \ | 8 | tonga_processpptables.o ppatomctrl.o \ |
9 | tonga_hwmgr.o pppcielanes.o tonga_thermal.o\ | 9 | tonga_hwmgr.o pppcielanes.o tonga_thermal.o\ |
10 | fiji_powertune.o fiji_hwmgr.o tonga_clockpowergating.o \ | 10 | fiji_powertune.o fiji_hwmgr.o tonga_clockpowergating.o \ |
11 | fiji_clockpowergating.o fiji_thermal.o \ | 11 | fiji_clockpowergating.o fiji_thermal.o \ |
12 | polaris10_hwmgr.o polaris10_powertune.o polaris10_thermal.o \ | 12 | polaris10_hwmgr.o polaris10_powertune.o polaris10_thermal.o \ |
13 | polaris10_clockpowergating.o | 13 | polaris10_clockpowergating.o iceland_hwmgr.o \ |
14 | iceland_clockpowergating.o iceland_thermal.o \ | ||
15 | iceland_powertune.o | ||
14 | 16 | ||
15 | AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) | 17 | AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) |
16 | 18 | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c index 8cc0df9b534a..5ecef1732e20 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c | |||
@@ -178,7 +178,6 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) | |||
178 | int result; | 178 | int result; |
179 | 179 | ||
180 | cz_hwmgr->gfx_ramp_step = 256*25/100; | 180 | cz_hwmgr->gfx_ramp_step = 256*25/100; |
181 | |||
182 | cz_hwmgr->gfx_ramp_delay = 1; /* by default, we delay 1us */ | 181 | cz_hwmgr->gfx_ramp_delay = 1; /* by default, we delay 1us */ |
183 | 182 | ||
184 | for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++) | 183 | for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++) |
@@ -186,33 +185,19 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) | |||
186 | 185 | ||
187 | cz_hwmgr->mgcg_cgtt_local0 = 0x00000000; | 186 | cz_hwmgr->mgcg_cgtt_local0 = 0x00000000; |
188 | cz_hwmgr->mgcg_cgtt_local1 = 0x00000000; | 187 | cz_hwmgr->mgcg_cgtt_local1 = 0x00000000; |
189 | |||
190 | cz_hwmgr->clock_slow_down_freq = 25000; | 188 | cz_hwmgr->clock_slow_down_freq = 25000; |
191 | |||
192 | cz_hwmgr->skip_clock_slow_down = 1; | 189 | cz_hwmgr->skip_clock_slow_down = 1; |
193 | |||
194 | cz_hwmgr->enable_nb_ps_policy = 1; /* disable until UNB is ready, Enabled */ | 190 | cz_hwmgr->enable_nb_ps_policy = 1; /* disable until UNB is ready, Enabled */ |
195 | |||
196 | cz_hwmgr->voltage_drop_in_dce_power_gating = 0; /* disable until fully verified */ | 191 | cz_hwmgr->voltage_drop_in_dce_power_gating = 0; /* disable until fully verified */ |
197 | |||
198 | cz_hwmgr->voting_rights_clients = 0x00C00033; | 192 | cz_hwmgr->voting_rights_clients = 0x00C00033; |
199 | |||
200 | cz_hwmgr->static_screen_threshold = 8; | 193 | cz_hwmgr->static_screen_threshold = 8; |
201 | |||
202 | cz_hwmgr->ddi_power_gating_disabled = 0; | 194 | cz_hwmgr->ddi_power_gating_disabled = 0; |
203 | |||
204 | cz_hwmgr->bapm_enabled = 1; | 195 | cz_hwmgr->bapm_enabled = 1; |
205 | |||
206 | cz_hwmgr->voltage_drop_threshold = 0; | 196 | cz_hwmgr->voltage_drop_threshold = 0; |
207 | |||
208 | cz_hwmgr->gfx_power_gating_threshold = 500; | 197 | cz_hwmgr->gfx_power_gating_threshold = 500; |
209 | |||
210 | cz_hwmgr->vce_slow_sclk_threshold = 20000; | 198 | cz_hwmgr->vce_slow_sclk_threshold = 20000; |
211 | |||
212 | cz_hwmgr->dce_slow_sclk_threshold = 30000; | 199 | cz_hwmgr->dce_slow_sclk_threshold = 30000; |
213 | |||
214 | cz_hwmgr->disable_driver_thermal_policy = 1; | 200 | cz_hwmgr->disable_driver_thermal_policy = 1; |
215 | |||
216 | cz_hwmgr->disable_nb_ps3_in_battery = 0; | 201 | cz_hwmgr->disable_nb_ps3_in_battery = 0; |
217 | 202 | ||
218 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | 203 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, |
@@ -221,9 +206,6 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) | |||
221 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 206 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
222 | PHM_PlatformCaps_NonABMSupportInPPLib); | 207 | PHM_PlatformCaps_NonABMSupportInPPLib); |
223 | 208 | ||
224 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
225 | PHM_PlatformCaps_SclkDeepSleep); | ||
226 | |||
227 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | 209 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, |
228 | PHM_PlatformCaps_DynamicM3Arbiter); | 210 | PHM_PlatformCaps_DynamicM3Arbiter); |
229 | 211 | ||
@@ -233,9 +215,7 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) | |||
233 | PHM_PlatformCaps_DynamicPatchPowerState); | 215 | PHM_PlatformCaps_DynamicPatchPowerState); |
234 | 216 | ||
235 | cz_hwmgr->thermal_auto_throttling_treshold = 0; | 217 | cz_hwmgr->thermal_auto_throttling_treshold = 0; |
236 | |||
237 | cz_hwmgr->tdr_clock = 0; | 218 | cz_hwmgr->tdr_clock = 0; |
238 | |||
239 | cz_hwmgr->disable_gfx_power_gating_in_uvd = 0; | 219 | cz_hwmgr->disable_gfx_power_gating_in_uvd = 0; |
240 | 220 | ||
241 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 221 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
@@ -450,19 +430,12 @@ static int cz_construct_boot_state(struct pp_hwmgr *hwmgr) | |||
450 | (uint8_t)cz_hwmgr->sys_info.bootup_nb_voltage_index; | 430 | (uint8_t)cz_hwmgr->sys_info.bootup_nb_voltage_index; |
451 | 431 | ||
452 | cz_hwmgr->boot_power_level.dsDividerIndex = 0; | 432 | cz_hwmgr->boot_power_level.dsDividerIndex = 0; |
453 | |||
454 | cz_hwmgr->boot_power_level.ssDividerIndex = 0; | 433 | cz_hwmgr->boot_power_level.ssDividerIndex = 0; |
455 | |||
456 | cz_hwmgr->boot_power_level.allowGnbSlow = 1; | 434 | cz_hwmgr->boot_power_level.allowGnbSlow = 1; |
457 | |||
458 | cz_hwmgr->boot_power_level.forceNBPstate = 0; | 435 | cz_hwmgr->boot_power_level.forceNBPstate = 0; |
459 | |||
460 | cz_hwmgr->boot_power_level.hysteresis_up = 0; | 436 | cz_hwmgr->boot_power_level.hysteresis_up = 0; |
461 | |||
462 | cz_hwmgr->boot_power_level.numSIMDToPowerDown = 0; | 437 | cz_hwmgr->boot_power_level.numSIMDToPowerDown = 0; |
463 | |||
464 | cz_hwmgr->boot_power_level.display_wm = 0; | 438 | cz_hwmgr->boot_power_level.display_wm = 0; |
465 | |||
466 | cz_hwmgr->boot_power_level.vce_wm = 0; | 439 | cz_hwmgr->boot_power_level.vce_wm = 0; |
467 | 440 | ||
468 | return 0; | 441 | return 0; |
@@ -749,7 +722,6 @@ static int cz_tf_update_sclk_limit(struct pp_hwmgr *hwmgr, | |||
749 | cz_hwmgr->sclk_dpm.soft_max_clk = table->entries[table->count - 1].clk; | 722 | cz_hwmgr->sclk_dpm.soft_max_clk = table->entries[table->count - 1].clk; |
750 | 723 | ||
751 | clock = hwmgr->display_config.min_core_set_clock; | 724 | clock = hwmgr->display_config.min_core_set_clock; |
752 | ; | ||
753 | if (clock == 0) | 725 | if (clock == 0) |
754 | printk(KERN_INFO "[ powerplay ] min_core_set_clock not set\n"); | 726 | printk(KERN_INFO "[ powerplay ] min_core_set_clock not set\n"); |
755 | 727 | ||
@@ -832,7 +804,7 @@ static int cz_tf_set_watermark_threshold(struct pp_hwmgr *hwmgr, | |||
832 | 804 | ||
833 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | 805 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, |
834 | PPSMC_MSG_SetWatermarkFrequency, | 806 | PPSMC_MSG_SetWatermarkFrequency, |
835 | cz_hwmgr->sclk_dpm.soft_max_clk); | 807 | cz_hwmgr->sclk_dpm.soft_max_clk); |
836 | 808 | ||
837 | return 0; | 809 | return 0; |
838 | } | 810 | } |
@@ -858,9 +830,9 @@ static int cz_tf_enable_nb_dpm(struct pp_hwmgr *hwmgr, | |||
858 | PP_DBG_LOG("enabling ALL SMU features.\n"); | 830 | PP_DBG_LOG("enabling ALL SMU features.\n"); |
859 | dpm_features |= NB_DPM_MASK; | 831 | dpm_features |= NB_DPM_MASK; |
860 | ret = smum_send_msg_to_smc_with_parameter( | 832 | ret = smum_send_msg_to_smc_with_parameter( |
861 | hwmgr->smumgr, | 833 | hwmgr->smumgr, |
862 | PPSMC_MSG_EnableAllSmuFeatures, | 834 | PPSMC_MSG_EnableAllSmuFeatures, |
863 | dpm_features); | 835 | dpm_features); |
864 | if (ret == 0) | 836 | if (ret == 0) |
865 | cz_hwmgr->is_nb_dpm_enabled = true; | 837 | cz_hwmgr->is_nb_dpm_enabled = true; |
866 | } | 838 | } |
@@ -1246,7 +1218,7 @@ static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr) | |||
1246 | 1218 | ||
1247 | static int cz_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) | 1219 | static int cz_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) |
1248 | { | 1220 | { |
1249 | if (hwmgr != NULL || hwmgr->backend != NULL) { | 1221 | if (hwmgr != NULL && hwmgr->backend != NULL) { |
1250 | kfree(hwmgr->backend); | 1222 | kfree(hwmgr->backend); |
1251 | kfree(hwmgr); | 1223 | kfree(hwmgr); |
1252 | } | 1224 | } |
@@ -1402,10 +1374,12 @@ int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate) | |||
1402 | PPSMC_MSG_SetUvdHardMin)); | 1374 | PPSMC_MSG_SetUvdHardMin)); |
1403 | 1375 | ||
1404 | cz_enable_disable_uvd_dpm(hwmgr, true); | 1376 | cz_enable_disable_uvd_dpm(hwmgr, true); |
1405 | } else | 1377 | } else { |
1406 | cz_enable_disable_uvd_dpm(hwmgr, true); | 1378 | cz_enable_disable_uvd_dpm(hwmgr, true); |
1407 | } else | 1379 | } |
1380 | } else { | ||
1408 | cz_enable_disable_uvd_dpm(hwmgr, false); | 1381 | cz_enable_disable_uvd_dpm(hwmgr, false); |
1382 | } | ||
1409 | 1383 | ||
1410 | return 0; | 1384 | return 0; |
1411 | } | 1385 | } |
@@ -1690,13 +1664,10 @@ static int cz_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, | |||
1690 | struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); | 1664 | struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); |
1691 | 1665 | ||
1692 | if (separation_time != | 1666 | if (separation_time != |
1693 | hw_data->cc6_settings.cpu_pstate_separation_time | 1667 | hw_data->cc6_settings.cpu_pstate_separation_time || |
1694 | || cc6_disable != | 1668 | cc6_disable != hw_data->cc6_settings.cpu_cc6_disable || |
1695 | hw_data->cc6_settings.cpu_cc6_disable | 1669 | pstate_disable != hw_data->cc6_settings.cpu_pstate_disable || |
1696 | || pstate_disable != | 1670 | pstate_switch_disable != hw_data->cc6_settings.nb_pstate_switch_disable) { |
1697 | hw_data->cc6_settings.cpu_pstate_disable | ||
1698 | || pstate_switch_disable != | ||
1699 | hw_data->cc6_settings.nb_pstate_switch_disable) { | ||
1700 | 1671 | ||
1701 | hw_data->cc6_settings.cc6_setting_changed = true; | 1672 | hw_data->cc6_settings.cc6_setting_changed = true; |
1702 | 1673 | ||
@@ -1799,8 +1770,7 @@ static int cz_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_p | |||
1799 | ps = cast_const_PhwCzPowerState(state); | 1770 | ps = cast_const_PhwCzPowerState(state); |
1800 | 1771 | ||
1801 | level_index = index > ps->level - 1 ? ps->level - 1 : index; | 1772 | level_index = index > ps->level - 1 ? ps->level - 1 : index; |
1802 | 1773 | level->coreClock = ps->levels[level_index].engineClock; | |
1803 | level->coreClock = ps->levels[level_index].engineClock; | ||
1804 | 1774 | ||
1805 | if (designation == PHM_PerformanceLevelDesignation_PowerContainment) { | 1775 | if (designation == PHM_PerformanceLevelDesignation_PowerContainment) { |
1806 | for (i = 1; i < ps->level; i++) { | 1776 | for (i = 1; i < ps->level; i++) { |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c index 6483d680bbc8..9368e21f5695 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c | |||
@@ -618,9 +618,6 @@ static int fiji_hwmgr_backend_init(struct pp_hwmgr *hwmgr) | |||
618 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 618 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
619 | PHM_PlatformCaps_TablelessHardwareInterface); | 619 | PHM_PlatformCaps_TablelessHardwareInterface); |
620 | 620 | ||
621 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
622 | PHM_PlatformCaps_SclkDeepSleep); | ||
623 | |||
624 | data->gpio_debug = 0; | 621 | data->gpio_debug = 0; |
625 | 622 | ||
626 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 623 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c index 44658451a8d2..f5992ea0c56f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c | |||
@@ -57,8 +57,6 @@ void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) | |||
57 | 57 | ||
58 | /* Assume disabled */ | 58 | /* Assume disabled */ |
59 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | 59 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, |
60 | PHM_PlatformCaps_PowerContainment); | ||
61 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
62 | PHM_PlatformCaps_CAC); | 60 | PHM_PlatformCaps_CAC); |
63 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | 61 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, |
64 | PHM_PlatformCaps_SQRamping); | 62 | PHM_PlatformCaps_SQRamping); |
@@ -77,9 +75,8 @@ void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) | |||
77 | 75 | ||
78 | fiji_hwmgr->fast_watermark_threshold = 100; | 76 | fiji_hwmgr->fast_watermark_threshold = 100; |
79 | 77 | ||
80 | if (hwmgr->powercontainment_enabled) { | 78 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, |
81 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 79 | PHM_PlatformCaps_PowerContainment)) { |
82 | PHM_PlatformCaps_PowerContainment); | ||
83 | tmp = 1; | 80 | tmp = 1; |
84 | fiji_hwmgr->enable_dte_feature = tmp ? false : true; | 81 | fiji_hwmgr->enable_dte_feature = tmp ? false : true; |
85 | fiji_hwmgr->enable_tdc_limit_feature = tmp ? true : false; | 82 | fiji_hwmgr->enable_tdc_limit_feature = tmp ? true : false; |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 27e07624ac28..d829076ed9ea 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | |||
@@ -39,6 +39,26 @@ extern int cz_hwmgr_init(struct pp_hwmgr *hwmgr); | |||
39 | extern int tonga_hwmgr_init(struct pp_hwmgr *hwmgr); | 39 | extern int tonga_hwmgr_init(struct pp_hwmgr *hwmgr); |
40 | extern int fiji_hwmgr_init(struct pp_hwmgr *hwmgr); | 40 | extern int fiji_hwmgr_init(struct pp_hwmgr *hwmgr); |
41 | extern int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr); | 41 | extern int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr); |
42 | extern int iceland_hwmgr_init(struct pp_hwmgr *hwmgr); | ||
43 | |||
44 | static int hwmgr_set_features_platform_caps(struct pp_hwmgr *hwmgr) | ||
45 | { | ||
46 | if (amdgpu_sclk_deep_sleep_en) | ||
47 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
48 | PHM_PlatformCaps_SclkDeepSleep); | ||
49 | else | ||
50 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
51 | PHM_PlatformCaps_SclkDeepSleep); | ||
52 | |||
53 | if (amdgpu_powercontainment) | ||
54 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
55 | PHM_PlatformCaps_PowerContainment); | ||
56 | else | ||
57 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
58 | PHM_PlatformCaps_PowerContainment); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
42 | 62 | ||
43 | int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle) | 63 | int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle) |
44 | { | 64 | { |
@@ -57,9 +77,12 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle) | |||
57 | hwmgr->chip_family = pp_init->chip_family; | 77 | hwmgr->chip_family = pp_init->chip_family; |
58 | hwmgr->chip_id = pp_init->chip_id; | 78 | hwmgr->chip_id = pp_init->chip_id; |
59 | hwmgr->hw_revision = pp_init->rev_id; | 79 | hwmgr->hw_revision = pp_init->rev_id; |
80 | hwmgr->sub_sys_id = pp_init->sub_sys_id; | ||
81 | hwmgr->sub_vendor_id = pp_init->sub_vendor_id; | ||
60 | hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT; | 82 | hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT; |
61 | hwmgr->power_source = PP_PowerSource_AC; | 83 | hwmgr->power_source = PP_PowerSource_AC; |
62 | hwmgr->powercontainment_enabled = pp_init->powercontainment_enabled; | 84 | |
85 | hwmgr_set_features_platform_caps(hwmgr); | ||
63 | 86 | ||
64 | switch (hwmgr->chip_family) { | 87 | switch (hwmgr->chip_family) { |
65 | case AMDGPU_FAMILY_CZ: | 88 | case AMDGPU_FAMILY_CZ: |
@@ -67,6 +90,9 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle) | |||
67 | break; | 90 | break; |
68 | case AMDGPU_FAMILY_VI: | 91 | case AMDGPU_FAMILY_VI: |
69 | switch (hwmgr->chip_id) { | 92 | switch (hwmgr->chip_id) { |
93 | case CHIP_TOPAZ: | ||
94 | iceland_hwmgr_init(hwmgr); | ||
95 | break; | ||
70 | case CHIP_TONGA: | 96 | case CHIP_TONGA: |
71 | tonga_hwmgr_init(hwmgr); | 97 | tonga_hwmgr_init(hwmgr); |
72 | break; | 98 | break; |
@@ -182,29 +208,7 @@ int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, | |||
182 | return 0; | 208 | return 0; |
183 | } | 209 | } |
184 | 210 | ||
185 | int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, | ||
186 | uint32_t index, uint32_t value, uint32_t mask) | ||
187 | { | ||
188 | uint32_t i; | ||
189 | uint32_t cur_value; | ||
190 | 211 | ||
191 | if (hwmgr == NULL || hwmgr->device == NULL) { | ||
192 | printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!"); | ||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | for (i = 0; i < hwmgr->usec_timeout; i++) { | ||
197 | cur_value = cgs_read_register(hwmgr->device, index); | ||
198 | if ((cur_value & mask) != (value & mask)) | ||
199 | break; | ||
200 | udelay(1); | ||
201 | } | ||
202 | |||
203 | /* timeout means wrong logic*/ | ||
204 | if (i == hwmgr->usec_timeout) | ||
205 | return -1; | ||
206 | return 0; | ||
207 | } | ||
208 | 212 | ||
209 | 213 | ||
210 | /** | 214 | /** |
@@ -227,21 +231,7 @@ void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, | |||
227 | phm_wait_on_register(hwmgr, indirect_port + 1, mask, value); | 231 | phm_wait_on_register(hwmgr, indirect_port + 1, mask, value); |
228 | } | 232 | } |
229 | 233 | ||
230 | void phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr, | ||
231 | uint32_t indirect_port, | ||
232 | uint32_t index, | ||
233 | uint32_t value, | ||
234 | uint32_t mask) | ||
235 | { | ||
236 | if (hwmgr == NULL || hwmgr->device == NULL) { | ||
237 | printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!"); | ||
238 | return; | ||
239 | } | ||
240 | 234 | ||
241 | cgs_write_register(hwmgr->device, indirect_port, index); | ||
242 | phm_wait_for_register_unequal(hwmgr, indirect_port + 1, | ||
243 | value, mask); | ||
244 | } | ||
245 | 235 | ||
246 | bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr) | 236 | bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr) |
247 | { | 237 | { |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_clockpowergating.c new file mode 100644 index 000000000000..47949f5cd073 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_clockpowergating.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include "hwmgr.h" | ||
27 | #include "iceland_clockpowergating.h" | ||
28 | #include "ppsmc.h" | ||
29 | #include "iceland_hwmgr.h" | ||
30 | |||
31 | int iceland_phm_powerdown_uvd(struct pp_hwmgr *hwmgr) | ||
32 | { | ||
33 | /* iceland does not have MM hardware block */ | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static int iceland_phm_powerup_uvd(struct pp_hwmgr *hwmgr) | ||
38 | { | ||
39 | /* iceland does not have MM hardware block */ | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static int iceland_phm_powerdown_vce(struct pp_hwmgr *hwmgr) | ||
44 | { | ||
45 | /* iceland does not have MM hardware block */ | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static int iceland_phm_powerup_vce(struct pp_hwmgr *hwmgr) | ||
50 | { | ||
51 | /* iceland does not have MM hardware block */ | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | int iceland_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum | ||
56 | PHM_AsicBlock block, enum PHM_ClockGateSetting gating) | ||
57 | { | ||
58 | int ret = 0; | ||
59 | |||
60 | switch (block) { | ||
61 | case PHM_AsicBlock_UVD_MVC: | ||
62 | case PHM_AsicBlock_UVD: | ||
63 | case PHM_AsicBlock_UVD_HD: | ||
64 | case PHM_AsicBlock_UVD_SD: | ||
65 | if (gating == PHM_ClockGateSetting_StaticOff) | ||
66 | ret = iceland_phm_powerdown_uvd(hwmgr); | ||
67 | else | ||
68 | ret = iceland_phm_powerup_uvd(hwmgr); | ||
69 | break; | ||
70 | case PHM_AsicBlock_GFX: | ||
71 | default: | ||
72 | break; | ||
73 | } | ||
74 | |||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | int iceland_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr) | ||
79 | { | ||
80 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
81 | |||
82 | data->uvd_power_gated = false; | ||
83 | data->vce_power_gated = false; | ||
84 | |||
85 | iceland_phm_powerup_uvd(hwmgr); | ||
86 | iceland_phm_powerup_vce(hwmgr); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | int iceland_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate) | ||
92 | { | ||
93 | if (bgate) { | ||
94 | iceland_update_uvd_dpm(hwmgr, true); | ||
95 | iceland_phm_powerdown_uvd(hwmgr); | ||
96 | } else { | ||
97 | iceland_phm_powerup_uvd(hwmgr); | ||
98 | iceland_update_uvd_dpm(hwmgr, false); | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | int iceland_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) | ||
105 | { | ||
106 | if (bgate) | ||
107 | return iceland_phm_powerdown_vce(hwmgr); | ||
108 | else | ||
109 | return iceland_phm_powerup_vce(hwmgr); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | int iceland_phm_update_clock_gatings(struct pp_hwmgr *hwmgr, | ||
115 | const uint32_t *msg_id) | ||
116 | { | ||
117 | /* iceland does not have MM hardware block */ | ||
118 | return 0; | ||
119 | } | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_clockpowergating.h new file mode 100644 index 000000000000..ff5ef00c7c68 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_clockpowergating.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #ifndef _ICELAND_CLOCK_POWER_GATING_H_ | ||
27 | #define _ICELAND_CLOCK_POWER_GATING_H_ | ||
28 | |||
29 | #include "iceland_hwmgr.h" | ||
30 | #include "pp_asicblocks.h" | ||
31 | |||
32 | extern int iceland_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating); | ||
33 | extern int iceland_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate); | ||
34 | extern int iceland_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate); | ||
35 | extern int iceland_phm_powerdown_uvd(struct pp_hwmgr *hwmgr); | ||
36 | extern int iceland_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr); | ||
37 | extern int iceland_phm_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id); | ||
38 | #endif /* _ICELAND_CLOCK_POWER_GATING_H_ */ | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_dyn_defaults.h b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_dyn_defaults.h new file mode 100644 index 000000000000..a7b4bc6caea2 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_dyn_defaults.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef ICELAND_DYN_DEFAULTS_H | ||
2 | #define ICELAND_DYN_DEFAULTS_H | ||
3 | |||
4 | enum ICELANDdpm_TrendDetection | ||
5 | { | ||
6 | ICELANDdpm_TrendDetection_AUTO, | ||
7 | ICELANDdpm_TrendDetection_UP, | ||
8 | ICELANDdpm_TrendDetection_DOWN | ||
9 | }; | ||
10 | typedef enum ICELANDdpm_TrendDetection ICELANDdpm_TrendDetection; | ||
11 | |||
12 | |||
13 | #define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 | ||
14 | #define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT1 0x000400 | ||
15 | #define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080 | ||
16 | #define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200 | ||
17 | #define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680 | ||
18 | #define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033 | ||
19 | #define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033 | ||
20 | #define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000 | ||
21 | |||
22 | |||
23 | #define PPICELAND_THERMALPROTECTCOUNTER_DFLT 0x200 | ||
24 | |||
25 | #define PPICELAND_STATICSCREENTHRESHOLDUNIT_DFLT 0 | ||
26 | |||
27 | #define PPICELAND_STATICSCREENTHRESHOLD_DFLT 0x00C8 | ||
28 | |||
29 | #define PPICELAND_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200 | ||
30 | |||
31 | #define PPICELAND_REFERENCEDIVIDER_DFLT 4 | ||
32 | |||
33 | #define PPICELAND_ULVVOLTAGECHANGEDELAY_DFLT 1687 | ||
34 | |||
35 | #define PPICELAND_CGULVPARAMETER_DFLT 0x00040035 | ||
36 | #define PPICELAND_CGULVCONTROL_DFLT 0x00007450 | ||
37 | #define PPICELAND_TARGETACTIVITY_DFLT 30 | ||
38 | #define PPICELAND_MCLK_TARGETACTIVITY_DFLT 10 | ||
39 | |||
40 | #endif | ||
41 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.c new file mode 100644 index 000000000000..8a7ada50551c --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.c | |||
@@ -0,0 +1,5692 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/fb.h> | ||
28 | #include "linux/delay.h" | ||
29 | #include "pp_acpi.h" | ||
30 | #include "hwmgr.h" | ||
31 | #include <atombios.h> | ||
32 | #include "iceland_hwmgr.h" | ||
33 | #include "pptable.h" | ||
34 | #include "processpptables.h" | ||
35 | #include "pp_debug.h" | ||
36 | #include "ppsmc.h" | ||
37 | #include "cgs_common.h" | ||
38 | #include "pppcielanes.h" | ||
39 | #include "iceland_dyn_defaults.h" | ||
40 | #include "smumgr.h" | ||
41 | #include "iceland_smumgr.h" | ||
42 | #include "iceland_clockpowergating.h" | ||
43 | #include "iceland_thermal.h" | ||
44 | #include "iceland_powertune.h" | ||
45 | |||
46 | #include "gmc/gmc_8_1_d.h" | ||
47 | #include "gmc/gmc_8_1_sh_mask.h" | ||
48 | |||
49 | #include "bif/bif_5_0_d.h" | ||
50 | #include "bif/bif_5_0_sh_mask.h" | ||
51 | |||
52 | #include "smu/smu_7_1_1_d.h" | ||
53 | #include "smu/smu_7_1_1_sh_mask.h" | ||
54 | |||
55 | #include "cgs_linux.h" | ||
56 | #include "eventmgr.h" | ||
57 | #include "amd_pcie_helpers.h" | ||
58 | |||
59 | #define MC_CG_ARB_FREQ_F0 0x0a | ||
60 | #define MC_CG_ARB_FREQ_F1 0x0b | ||
61 | #define MC_CG_ARB_FREQ_F2 0x0c | ||
62 | #define MC_CG_ARB_FREQ_F3 0x0d | ||
63 | |||
64 | #define MC_CG_SEQ_DRAMCONF_S0 0x05 | ||
65 | #define MC_CG_SEQ_DRAMCONF_S1 0x06 | ||
66 | #define MC_CG_SEQ_YCLK_SUSPEND 0x04 | ||
67 | #define MC_CG_SEQ_YCLK_RESUME 0x0a | ||
68 | |||
69 | #define PCIE_BUS_CLK 10000 | ||
70 | #define TCLK (PCIE_BUS_CLK / 10) | ||
71 | |||
72 | #define SMC_RAM_END 0x40000 | ||
73 | #define SMC_CG_IND_START 0xc0030000 | ||
74 | #define SMC_CG_IND_END 0xc0040000 /* First byte after SMC_CG_IND*/ | ||
75 | |||
76 | #define VOLTAGE_SCALE 4 | ||
77 | #define VOLTAGE_VID_OFFSET_SCALE1 625 | ||
78 | #define VOLTAGE_VID_OFFSET_SCALE2 100 | ||
79 | |||
80 | const uint32_t iceland_magic = (uint32_t)(PHM_VIslands_Magic); | ||
81 | |||
82 | #define MC_SEQ_MISC0_GDDR5_SHIFT 28 | ||
83 | #define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000 | ||
84 | #define MC_SEQ_MISC0_GDDR5_VALUE 5 | ||
85 | |||
86 | /** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */ | ||
87 | enum DPM_EVENT_SRC { | ||
88 | DPM_EVENT_SRC_ANALOG = 0, /* Internal analog trip point */ | ||
89 | DPM_EVENT_SRC_EXTERNAL = 1, /* External (GPIO 17) signal */ | ||
90 | DPM_EVENT_SRC_DIGITAL = 2, /* Internal digital trip point (DIG_THERM_DPM) */ | ||
91 | DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3, /* Internal analog or external */ | ||
92 | DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4 /* Internal digital or external */ | ||
93 | }; | ||
94 | |||
95 | static int iceland_read_clock_registers(struct pp_hwmgr *hwmgr) | ||
96 | { | ||
97 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
98 | |||
99 | data->clock_registers.vCG_SPLL_FUNC_CNTL = | ||
100 | cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL); | ||
101 | data->clock_registers.vCG_SPLL_FUNC_CNTL_2 = | ||
102 | cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_2); | ||
103 | data->clock_registers.vCG_SPLL_FUNC_CNTL_3 = | ||
104 | cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_3); | ||
105 | data->clock_registers.vCG_SPLL_FUNC_CNTL_4 = | ||
106 | cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_4); | ||
107 | data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM = | ||
108 | cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM); | ||
109 | data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 = | ||
110 | cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM_2); | ||
111 | data->clock_registers.vDLL_CNTL = | ||
112 | cgs_read_register(hwmgr->device, mmDLL_CNTL); | ||
113 | data->clock_registers.vMCLK_PWRMGT_CNTL = | ||
114 | cgs_read_register(hwmgr->device, mmMCLK_PWRMGT_CNTL); | ||
115 | data->clock_registers.vMPLL_AD_FUNC_CNTL = | ||
116 | cgs_read_register(hwmgr->device, mmMPLL_AD_FUNC_CNTL); | ||
117 | data->clock_registers.vMPLL_DQ_FUNC_CNTL = | ||
118 | cgs_read_register(hwmgr->device, mmMPLL_DQ_FUNC_CNTL); | ||
119 | data->clock_registers.vMPLL_FUNC_CNTL = | ||
120 | cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL); | ||
121 | data->clock_registers.vMPLL_FUNC_CNTL_1 = | ||
122 | cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_1); | ||
123 | data->clock_registers.vMPLL_FUNC_CNTL_2 = | ||
124 | cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_2); | ||
125 | data->clock_registers.vMPLL_SS1 = | ||
126 | cgs_read_register(hwmgr->device, mmMPLL_SS1); | ||
127 | data->clock_registers.vMPLL_SS2 = | ||
128 | cgs_read_register(hwmgr->device, mmMPLL_SS2); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * Find out if memory is GDDR5. | ||
135 | * | ||
136 | * @param hwmgr the address of the powerplay hardware manager. | ||
137 | * @return always 0 | ||
138 | */ | ||
139 | int iceland_get_memory_type(struct pp_hwmgr *hwmgr) | ||
140 | { | ||
141 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
142 | uint32_t temp; | ||
143 | |||
144 | temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0); | ||
145 | |||
146 | data->is_memory_GDDR5 = (MC_SEQ_MISC0_GDDR5_VALUE == | ||
147 | ((temp & MC_SEQ_MISC0_GDDR5_MASK) >> | ||
148 | MC_SEQ_MISC0_GDDR5_SHIFT)); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | int iceland_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate) | ||
154 | { | ||
155 | /* iceland does not have MM hardware blocks */ | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * Enables Dynamic Power Management by SMC | ||
161 | * | ||
162 | * @param hwmgr the address of the powerplay hardware manager. | ||
163 | * @return always 0 | ||
164 | */ | ||
165 | int iceland_enable_acpi_power_management(struct pp_hwmgr *hwmgr) | ||
166 | { | ||
167 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, STATIC_PM_EN, 1); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * Find the MC microcode version and store it in the HwMgr struct | ||
174 | * | ||
175 | * @param hwmgr the address of the powerplay hardware manager. | ||
176 | * @return always 0 | ||
177 | */ | ||
178 | int iceland_get_mc_microcode_version(struct pp_hwmgr *hwmgr) | ||
179 | { | ||
180 | cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX, 0x9F); | ||
181 | |||
182 | hwmgr->microcode_version_info.MC = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int iceland_init_sclk_threshold(struct pp_hwmgr *hwmgr) | ||
188 | { | ||
189 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
190 | |||
191 | data->low_sclk_interrupt_threshold = 0; | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | |||
197 | static int iceland_setup_asic_task(struct pp_hwmgr *hwmgr) | ||
198 | { | ||
199 | int tmp_result, result = 0; | ||
200 | |||
201 | tmp_result = iceland_read_clock_registers(hwmgr); | ||
202 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
203 | "Failed to read clock registers!", result = tmp_result); | ||
204 | |||
205 | tmp_result = iceland_get_memory_type(hwmgr); | ||
206 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
207 | "Failed to get memory type!", result = tmp_result); | ||
208 | |||
209 | tmp_result = iceland_enable_acpi_power_management(hwmgr); | ||
210 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
211 | "Failed to enable ACPI power management!", result = tmp_result); | ||
212 | |||
213 | tmp_result = iceland_get_mc_microcode_version(hwmgr); | ||
214 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
215 | "Failed to get MC microcode version!", result = tmp_result); | ||
216 | |||
217 | tmp_result = iceland_init_sclk_threshold(hwmgr); | ||
218 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
219 | "Failed to init sclk threshold!", result = tmp_result); | ||
220 | |||
221 | return result; | ||
222 | } | ||
223 | |||
224 | static bool cf_iceland_voltage_control(struct pp_hwmgr *hwmgr) | ||
225 | { | ||
226 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
227 | |||
228 | return ICELAND_VOLTAGE_CONTROL_NONE != data->voltage_control; | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * -------------- Voltage Tables ---------------------- | ||
233 | * If the voltage table would be bigger than what will fit into the | ||
234 | * state table on the SMC keep only the higher entries. | ||
235 | */ | ||
236 | |||
237 | static void iceland_trim_voltage_table_to_fit_state_table( | ||
238 | struct pp_hwmgr *hwmgr, | ||
239 | uint32_t max_voltage_steps, | ||
240 | pp_atomctrl_voltage_table *voltage_table) | ||
241 | { | ||
242 | unsigned int i, diff; | ||
243 | |||
244 | if (voltage_table->count <= max_voltage_steps) { | ||
245 | return; | ||
246 | } | ||
247 | |||
248 | diff = voltage_table->count - max_voltage_steps; | ||
249 | |||
250 | for (i = 0; i < max_voltage_steps; i++) { | ||
251 | voltage_table->entries[i] = voltage_table->entries[i + diff]; | ||
252 | } | ||
253 | |||
254 | voltage_table->count = max_voltage_steps; | ||
255 | |||
256 | return; | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * Enable voltage control | ||
261 | * | ||
262 | * @param hwmgr the address of the powerplay hardware manager. | ||
263 | * @return always 0 | ||
264 | */ | ||
265 | int iceland_enable_voltage_control(struct pp_hwmgr *hwmgr) | ||
266 | { | ||
267 | /* enable voltage control */ | ||
268 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int iceland_get_svi2_voltage_table(struct pp_hwmgr *hwmgr, | ||
274 | struct phm_clock_voltage_dependency_table *voltage_dependency_table, | ||
275 | pp_atomctrl_voltage_table *voltage_table) | ||
276 | { | ||
277 | uint32_t i; | ||
278 | |||
279 | PP_ASSERT_WITH_CODE((NULL != voltage_table), | ||
280 | "Voltage Dependency Table empty.", return -EINVAL;); | ||
281 | |||
282 | voltage_table->mask_low = 0; | ||
283 | voltage_table->phase_delay = 0; | ||
284 | voltage_table->count = voltage_dependency_table->count; | ||
285 | |||
286 | for (i = 0; i < voltage_dependency_table->count; i++) { | ||
287 | voltage_table->entries[i].value = | ||
288 | voltage_dependency_table->entries[i].v; | ||
289 | voltage_table->entries[i].smio_low = 0; | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * Create Voltage Tables. | ||
297 | * | ||
298 | * @param hwmgr the address of the powerplay hardware manager. | ||
299 | * @return always 0 | ||
300 | */ | ||
301 | int iceland_construct_voltage_tables(struct pp_hwmgr *hwmgr) | ||
302 | { | ||
303 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
304 | int result; | ||
305 | |||
306 | /* GPIO voltage */ | ||
307 | if (ICELAND_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) { | ||
308 | result = atomctrl_get_voltage_table_v3(hwmgr, | ||
309 | VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT, | ||
310 | &data->vddc_voltage_table); | ||
311 | PP_ASSERT_WITH_CODE((0 == result), | ||
312 | "Failed to retrieve VDDC table.", return result;); | ||
313 | } else if (ICELAND_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) { | ||
314 | /* SVI2 VDDC voltage */ | ||
315 | result = iceland_get_svi2_voltage_table(hwmgr, | ||
316 | hwmgr->dyn_state.vddc_dependency_on_mclk, | ||
317 | &data->vddc_voltage_table); | ||
318 | PP_ASSERT_WITH_CODE((0 == result), | ||
319 | "Failed to retrieve SVI2 VDDC table from dependancy table.", return result;); | ||
320 | } | ||
321 | |||
322 | PP_ASSERT_WITH_CODE( | ||
323 | (data->vddc_voltage_table.count <= (SMU71_MAX_LEVELS_VDDC)), | ||
324 | "Too many voltage values for VDDC. Trimming to fit state table.", | ||
325 | iceland_trim_voltage_table_to_fit_state_table(hwmgr, | ||
326 | SMU71_MAX_LEVELS_VDDC, &(data->vddc_voltage_table)); | ||
327 | ); | ||
328 | |||
329 | /* GPIO */ | ||
330 | if (ICELAND_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) { | ||
331 | result = atomctrl_get_voltage_table_v3(hwmgr, | ||
332 | VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT, &(data->vddci_voltage_table)); | ||
333 | PP_ASSERT_WITH_CODE((0 == result), | ||
334 | "Failed to retrieve VDDCI table.", return result;); | ||
335 | } | ||
336 | |||
337 | /* SVI2 VDDCI voltage */ | ||
338 | if (ICELAND_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) { | ||
339 | result = iceland_get_svi2_voltage_table(hwmgr, | ||
340 | hwmgr->dyn_state.vddci_dependency_on_mclk, | ||
341 | &data->vddci_voltage_table); | ||
342 | PP_ASSERT_WITH_CODE((0 == result), | ||
343 | "Failed to retrieve SVI2 VDDCI table from dependancy table.", return result;); | ||
344 | } | ||
345 | |||
346 | PP_ASSERT_WITH_CODE( | ||
347 | (data->vddci_voltage_table.count <= (SMU71_MAX_LEVELS_VDDCI)), | ||
348 | "Too many voltage values for VDDCI. Trimming to fit state table.", | ||
349 | iceland_trim_voltage_table_to_fit_state_table(hwmgr, | ||
350 | SMU71_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table)); | ||
351 | ); | ||
352 | |||
353 | |||
354 | /* GPIO */ | ||
355 | if (ICELAND_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) { | ||
356 | result = atomctrl_get_voltage_table_v3(hwmgr, | ||
357 | VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT, &(data->mvdd_voltage_table)); | ||
358 | PP_ASSERT_WITH_CODE((0 == result), | ||
359 | "Failed to retrieve table.", return result;); | ||
360 | } | ||
361 | |||
362 | /* SVI2 voltage control */ | ||
363 | if (ICELAND_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) { | ||
364 | result = iceland_get_svi2_voltage_table(hwmgr, | ||
365 | hwmgr->dyn_state.mvdd_dependency_on_mclk, | ||
366 | &data->mvdd_voltage_table); | ||
367 | PP_ASSERT_WITH_CODE((0 == result), | ||
368 | "Failed to retrieve SVI2 MVDD table from dependancy table.", return result;); | ||
369 | } | ||
370 | |||
371 | PP_ASSERT_WITH_CODE( | ||
372 | (data->mvdd_voltage_table.count <= (SMU71_MAX_LEVELS_MVDD)), | ||
373 | "Too many voltage values for MVDD. Trimming to fit state table.", | ||
374 | iceland_trim_voltage_table_to_fit_state_table(hwmgr, | ||
375 | SMU71_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table)); | ||
376 | ); | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /*---------------------------MC----------------------------*/ | ||
382 | |||
383 | uint8_t iceland_get_memory_module_index(struct pp_hwmgr *hwmgr) | ||
384 | { | ||
385 | return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16)); | ||
386 | } | ||
387 | |||
388 | bool iceland_check_s0_mc_reg_index(uint16_t inReg, uint16_t *outReg) | ||
389 | { | ||
390 | bool result = true; | ||
391 | |||
392 | switch (inReg) { | ||
393 | case mmMC_SEQ_RAS_TIMING: | ||
394 | *outReg = mmMC_SEQ_RAS_TIMING_LP; | ||
395 | break; | ||
396 | |||
397 | case mmMC_SEQ_DLL_STBY: | ||
398 | *outReg = mmMC_SEQ_DLL_STBY_LP; | ||
399 | break; | ||
400 | |||
401 | case mmMC_SEQ_G5PDX_CMD0: | ||
402 | *outReg = mmMC_SEQ_G5PDX_CMD0_LP; | ||
403 | break; | ||
404 | |||
405 | case mmMC_SEQ_G5PDX_CMD1: | ||
406 | *outReg = mmMC_SEQ_G5PDX_CMD1_LP; | ||
407 | break; | ||
408 | |||
409 | case mmMC_SEQ_G5PDX_CTRL: | ||
410 | *outReg = mmMC_SEQ_G5PDX_CTRL_LP; | ||
411 | break; | ||
412 | |||
413 | case mmMC_SEQ_CAS_TIMING: | ||
414 | *outReg = mmMC_SEQ_CAS_TIMING_LP; | ||
415 | break; | ||
416 | |||
417 | case mmMC_SEQ_MISC_TIMING: | ||
418 | *outReg = mmMC_SEQ_MISC_TIMING_LP; | ||
419 | break; | ||
420 | |||
421 | case mmMC_SEQ_MISC_TIMING2: | ||
422 | *outReg = mmMC_SEQ_MISC_TIMING2_LP; | ||
423 | break; | ||
424 | |||
425 | case mmMC_SEQ_PMG_DVS_CMD: | ||
426 | *outReg = mmMC_SEQ_PMG_DVS_CMD_LP; | ||
427 | break; | ||
428 | |||
429 | case mmMC_SEQ_PMG_DVS_CTL: | ||
430 | *outReg = mmMC_SEQ_PMG_DVS_CTL_LP; | ||
431 | break; | ||
432 | |||
433 | case mmMC_SEQ_RD_CTL_D0: | ||
434 | *outReg = mmMC_SEQ_RD_CTL_D0_LP; | ||
435 | break; | ||
436 | |||
437 | case mmMC_SEQ_RD_CTL_D1: | ||
438 | *outReg = mmMC_SEQ_RD_CTL_D1_LP; | ||
439 | break; | ||
440 | |||
441 | case mmMC_SEQ_WR_CTL_D0: | ||
442 | *outReg = mmMC_SEQ_WR_CTL_D0_LP; | ||
443 | break; | ||
444 | |||
445 | case mmMC_SEQ_WR_CTL_D1: | ||
446 | *outReg = mmMC_SEQ_WR_CTL_D1_LP; | ||
447 | break; | ||
448 | |||
449 | case mmMC_PMG_CMD_EMRS: | ||
450 | *outReg = mmMC_SEQ_PMG_CMD_EMRS_LP; | ||
451 | break; | ||
452 | |||
453 | case mmMC_PMG_CMD_MRS: | ||
454 | *outReg = mmMC_SEQ_PMG_CMD_MRS_LP; | ||
455 | break; | ||
456 | |||
457 | case mmMC_PMG_CMD_MRS1: | ||
458 | *outReg = mmMC_SEQ_PMG_CMD_MRS1_LP; | ||
459 | break; | ||
460 | |||
461 | case mmMC_SEQ_PMG_TIMING: | ||
462 | *outReg = mmMC_SEQ_PMG_TIMING_LP; | ||
463 | break; | ||
464 | |||
465 | case mmMC_PMG_CMD_MRS2: | ||
466 | *outReg = mmMC_SEQ_PMG_CMD_MRS2_LP; | ||
467 | break; | ||
468 | |||
469 | case mmMC_SEQ_WR_CTL_2: | ||
470 | *outReg = mmMC_SEQ_WR_CTL_2_LP; | ||
471 | break; | ||
472 | |||
473 | default: | ||
474 | result = false; | ||
475 | break; | ||
476 | } | ||
477 | |||
478 | return result; | ||
479 | } | ||
480 | |||
481 | int iceland_set_s0_mc_reg_index(phw_iceland_mc_reg_table *table) | ||
482 | { | ||
483 | uint32_t i; | ||
484 | uint16_t address; | ||
485 | |||
486 | for (i = 0; i < table->last; i++) { | ||
487 | table->mc_reg_address[i].s0 = | ||
488 | iceland_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) | ||
489 | ? address : table->mc_reg_address[i].s1; | ||
490 | } | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | int iceland_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table, phw_iceland_mc_reg_table *ni_table) | ||
495 | { | ||
496 | uint8_t i, j; | ||
497 | |||
498 | PP_ASSERT_WITH_CODE((table->last <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE), | ||
499 | "Invalid VramInfo table.", return -1); | ||
500 | PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES), | ||
501 | "Invalid VramInfo table.", return -1); | ||
502 | |||
503 | for (i = 0; i < table->last; i++) { | ||
504 | ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1; | ||
505 | } | ||
506 | ni_table->last = table->last; | ||
507 | |||
508 | for (i = 0; i < table->num_entries; i++) { | ||
509 | ni_table->mc_reg_table_entry[i].mclk_max = | ||
510 | table->mc_reg_table_entry[i].mclk_max; | ||
511 | for (j = 0; j < table->last; j++) { | ||
512 | ni_table->mc_reg_table_entry[i].mc_data[j] = | ||
513 | table->mc_reg_table_entry[i].mc_data[j]; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | ni_table->num_entries = table->num_entries; | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | /** | ||
523 | * VBIOS omits some information to reduce size, we need to recover them here. | ||
524 | * 1. when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0]. | ||
525 | * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0] | ||
526 | * 2. when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0]. | ||
527 | * 3. need to set these data for each clock range | ||
528 | * | ||
529 | * @param hwmgr the address of the powerplay hardware manager. | ||
530 | * @param table the address of MCRegTable | ||
531 | * @return always 0 | ||
532 | */ | ||
533 | static int iceland_set_mc_special_registers(struct pp_hwmgr *hwmgr, phw_iceland_mc_reg_table *table) | ||
534 | { | ||
535 | uint8_t i, j, k; | ||
536 | uint32_t temp_reg; | ||
537 | const iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
538 | |||
539 | for (i = 0, j = table->last; i < table->last; i++) { | ||
540 | PP_ASSERT_WITH_CODE((j < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE), | ||
541 | "Invalid VramInfo table.", return -1); | ||
542 | switch (table->mc_reg_address[i].s1) { | ||
543 | /* | ||
544 | * mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write | ||
545 | * to mmMC_PMG_CMD_EMRS/_LP[15:0]. Bit[15:0] MRS, need | ||
546 | * to be update mmMC_PMG_CMD_MRS/_LP[15:0] | ||
547 | */ | ||
548 | case mmMC_SEQ_MISC1: | ||
549 | temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS); | ||
550 | table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS; | ||
551 | table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP; | ||
552 | for (k = 0; k < table->num_entries; k++) { | ||
553 | table->mc_reg_table_entry[k].mc_data[j] = | ||
554 | ((temp_reg & 0xffff0000)) | | ||
555 | ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16); | ||
556 | } | ||
557 | j++; | ||
558 | PP_ASSERT_WITH_CODE((j < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE), | ||
559 | "Invalid VramInfo table.", return -1); | ||
560 | |||
561 | temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS); | ||
562 | table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS; | ||
563 | table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP; | ||
564 | for (k = 0; k < table->num_entries; k++) { | ||
565 | table->mc_reg_table_entry[k].mc_data[j] = | ||
566 | (temp_reg & 0xffff0000) | | ||
567 | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); | ||
568 | |||
569 | if (!data->is_memory_GDDR5) { | ||
570 | table->mc_reg_table_entry[k].mc_data[j] |= 0x100; | ||
571 | } | ||
572 | } | ||
573 | j++; | ||
574 | PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE), | ||
575 | "Invalid VramInfo table.", return -1); | ||
576 | |||
577 | if (!data->is_memory_GDDR5) { | ||
578 | table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD; | ||
579 | table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD; | ||
580 | for (k = 0; k < table->num_entries; k++) { | ||
581 | table->mc_reg_table_entry[k].mc_data[j] = | ||
582 | (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16; | ||
583 | } | ||
584 | j++; | ||
585 | PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE), | ||
586 | "Invalid VramInfo table.", return -1); | ||
587 | } | ||
588 | |||
589 | break; | ||
590 | |||
591 | case mmMC_SEQ_RESERVE_M: | ||
592 | temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1); | ||
593 | table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1; | ||
594 | table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP; | ||
595 | for (k = 0; k < table->num_entries; k++) { | ||
596 | table->mc_reg_table_entry[k].mc_data[j] = | ||
597 | (temp_reg & 0xffff0000) | | ||
598 | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); | ||
599 | } | ||
600 | j++; | ||
601 | PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE), | ||
602 | "Invalid VramInfo table.", return -1); | ||
603 | break; | ||
604 | |||
605 | default: | ||
606 | break; | ||
607 | } | ||
608 | |||
609 | } | ||
610 | |||
611 | table->last = j; | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | |||
617 | static int iceland_set_valid_flag(phw_iceland_mc_reg_table *table) | ||
618 | { | ||
619 | uint8_t i, j; | ||
620 | for (i = 0; i < table->last; i++) { | ||
621 | for (j = 1; j < table->num_entries; j++) { | ||
622 | if (table->mc_reg_table_entry[j-1].mc_data[i] != | ||
623 | table->mc_reg_table_entry[j].mc_data[i]) { | ||
624 | table->validflag |= (1<<i); | ||
625 | break; | ||
626 | } | ||
627 | } | ||
628 | } | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) | ||
634 | { | ||
635 | int result; | ||
636 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
637 | pp_atomctrl_mc_reg_table *table; | ||
638 | phw_iceland_mc_reg_table *ni_table = &data->iceland_mc_reg_table; | ||
639 | uint8_t module_index = iceland_get_memory_module_index(hwmgr); | ||
640 | |||
641 | table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL); | ||
642 | |||
643 | if (NULL == table) | ||
644 | return -ENOMEM; | ||
645 | |||
646 | /* Program additional LP registers that are no longer programmed by VBIOS */ | ||
647 | cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING)); | ||
648 | cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING)); | ||
649 | cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY)); | ||
650 | cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0)); | ||
651 | cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1)); | ||
652 | cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL)); | ||
653 | cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD)); | ||
654 | cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL)); | ||
655 | cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING)); | ||
656 | cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2)); | ||
657 | cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS)); | ||
658 | cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS)); | ||
659 | cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1)); | ||
660 | cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0)); | ||
661 | cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1)); | ||
662 | cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0)); | ||
663 | cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1)); | ||
664 | cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING)); | ||
665 | cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2)); | ||
666 | cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2)); | ||
667 | |||
668 | memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table)); | ||
669 | |||
670 | result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table); | ||
671 | |||
672 | if (0 == result) | ||
673 | result = iceland_copy_vbios_smc_reg_table(table, ni_table); | ||
674 | |||
675 | if (0 == result) { | ||
676 | iceland_set_s0_mc_reg_index(ni_table); | ||
677 | result = iceland_set_mc_special_registers(hwmgr, ni_table); | ||
678 | } | ||
679 | |||
680 | if (0 == result) | ||
681 | iceland_set_valid_flag(ni_table); | ||
682 | |||
683 | kfree(table); | ||
684 | return result; | ||
685 | } | ||
686 | |||
687 | /** | ||
688 | * Programs static screed detection parameters | ||
689 | * | ||
690 | * @param hwmgr the address of the powerplay hardware manager. | ||
691 | * @return always 0 | ||
692 | */ | ||
693 | int iceland_program_static_screen_threshold_parameters(struct pp_hwmgr *hwmgr) | ||
694 | { | ||
695 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
696 | |||
697 | /* Set static screen threshold unit*/ | ||
698 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, | ||
699 | CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT, | ||
700 | data->static_screen_threshold_unit); | ||
701 | /* Set static screen threshold*/ | ||
702 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, | ||
703 | CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD, | ||
704 | data->static_screen_threshold); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | /** | ||
710 | * Setup display gap for glitch free memory clock switching. | ||
711 | * | ||
712 | * @param hwmgr the address of the powerplay hardware manager. | ||
713 | * @return always 0 | ||
714 | */ | ||
715 | int iceland_enable_display_gap(struct pp_hwmgr *hwmgr) | ||
716 | { | ||
717 | uint32_t display_gap = cgs_read_ind_register(hwmgr->device, | ||
718 | CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL); | ||
719 | |||
720 | display_gap = PHM_SET_FIELD(display_gap, | ||
721 | CG_DISPLAY_GAP_CNTL, DISP_GAP, DISPLAY_GAP_IGNORE); | ||
722 | |||
723 | display_gap = PHM_SET_FIELD(display_gap, | ||
724 | CG_DISPLAY_GAP_CNTL, DISP_GAP_MCHG, DISPLAY_GAP_VBLANK); | ||
725 | |||
726 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
727 | ixCG_DISPLAY_GAP_CNTL, display_gap); | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | /** | ||
733 | * Programs activity state transition voting clients | ||
734 | * | ||
735 | * @param hwmgr the address of the powerplay hardware manager. | ||
736 | * @return always 0 | ||
737 | */ | ||
738 | int iceland_program_voting_clients(struct pp_hwmgr *hwmgr) | ||
739 | { | ||
740 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
741 | |||
742 | /* Clear reset for voting clients before enabling DPM */ | ||
743 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, | ||
744 | SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0); | ||
745 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, | ||
746 | SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0); | ||
747 | |||
748 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
749 | ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0); | ||
750 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
751 | ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1); | ||
752 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
753 | ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2); | ||
754 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
755 | ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3); | ||
756 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
757 | ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4); | ||
758 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
759 | ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5); | ||
760 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
761 | ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6); | ||
762 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
763 | ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7); | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | static int iceland_upload_firmware(struct pp_hwmgr *hwmgr) | ||
769 | { | ||
770 | int ret = 0; | ||
771 | |||
772 | if (!iceland_is_smc_ram_running(hwmgr->smumgr)) | ||
773 | ret = iceland_smu_upload_firmware_image(hwmgr->smumgr); | ||
774 | |||
775 | return ret; | ||
776 | } | ||
777 | |||
778 | /** | ||
779 | * Get the location of various tables inside the FW image. | ||
780 | * | ||
781 | * @param hwmgr the address of the powerplay hardware manager. | ||
782 | * @return always 0 | ||
783 | */ | ||
784 | int iceland_process_firmware_header(struct pp_hwmgr *hwmgr) | ||
785 | { | ||
786 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
787 | |||
788 | uint32_t tmp; | ||
789 | int result; | ||
790 | bool error = 0; | ||
791 | |||
792 | result = iceland_read_smc_sram_dword(hwmgr->smumgr, | ||
793 | SMU71_FIRMWARE_HEADER_LOCATION + | ||
794 | offsetof(SMU71_Firmware_Header, DpmTable), | ||
795 | &tmp, data->sram_end); | ||
796 | |||
797 | if (0 == result) { | ||
798 | data->dpm_table_start = tmp; | ||
799 | } | ||
800 | |||
801 | error |= (0 != result); | ||
802 | |||
803 | result = iceland_read_smc_sram_dword(hwmgr->smumgr, | ||
804 | SMU71_FIRMWARE_HEADER_LOCATION + | ||
805 | offsetof(SMU71_Firmware_Header, SoftRegisters), | ||
806 | &tmp, data->sram_end); | ||
807 | |||
808 | if (0 == result) { | ||
809 | data->soft_regs_start = tmp; | ||
810 | } | ||
811 | |||
812 | error |= (0 != result); | ||
813 | |||
814 | |||
815 | result = iceland_read_smc_sram_dword(hwmgr->smumgr, | ||
816 | SMU71_FIRMWARE_HEADER_LOCATION + | ||
817 | offsetof(SMU71_Firmware_Header, mcRegisterTable), | ||
818 | &tmp, data->sram_end); | ||
819 | |||
820 | if (0 == result) { | ||
821 | data->mc_reg_table_start = tmp; | ||
822 | } | ||
823 | |||
824 | result = iceland_read_smc_sram_dword(hwmgr->smumgr, | ||
825 | SMU71_FIRMWARE_HEADER_LOCATION + | ||
826 | offsetof(SMU71_Firmware_Header, FanTable), | ||
827 | &tmp, data->sram_end); | ||
828 | |||
829 | if (0 == result) { | ||
830 | data->fan_table_start = tmp; | ||
831 | } | ||
832 | |||
833 | error |= (0 != result); | ||
834 | |||
835 | result = iceland_read_smc_sram_dword(hwmgr->smumgr, | ||
836 | SMU71_FIRMWARE_HEADER_LOCATION + | ||
837 | offsetof(SMU71_Firmware_Header, mcArbDramTimingTable), | ||
838 | &tmp, data->sram_end); | ||
839 | |||
840 | if (0 == result) { | ||
841 | data->arb_table_start = tmp; | ||
842 | } | ||
843 | |||
844 | error |= (0 != result); | ||
845 | |||
846 | |||
847 | result = iceland_read_smc_sram_dword(hwmgr->smumgr, | ||
848 | SMU71_FIRMWARE_HEADER_LOCATION + | ||
849 | offsetof(SMU71_Firmware_Header, Version), | ||
850 | &tmp, data->sram_end); | ||
851 | |||
852 | if (0 == result) { | ||
853 | hwmgr->microcode_version_info.SMC = tmp; | ||
854 | } | ||
855 | |||
856 | error |= (0 != result); | ||
857 | |||
858 | result = iceland_read_smc_sram_dword(hwmgr->smumgr, | ||
859 | SMU71_FIRMWARE_HEADER_LOCATION + | ||
860 | offsetof(SMU71_Firmware_Header, UlvSettings), | ||
861 | &tmp, data->sram_end); | ||
862 | |||
863 | if (0 == result) { | ||
864 | data->ulv_settings_start = tmp; | ||
865 | } | ||
866 | |||
867 | error |= (0 != result); | ||
868 | |||
869 | return error ? 1 : 0; | ||
870 | } | ||
871 | |||
872 | /* | ||
873 | * Copy one arb setting to another and then switch the active set. | ||
874 | * arbFreqSrc and arbFreqDest is one of the MC_CG_ARB_FREQ_Fx constants. | ||
875 | */ | ||
876 | int iceland_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr, | ||
877 | uint32_t arbFreqSrc, uint32_t arbFreqDest) | ||
878 | { | ||
879 | uint32_t mc_arb_dram_timing; | ||
880 | uint32_t mc_arb_dram_timing2; | ||
881 | uint32_t burst_time; | ||
882 | uint32_t mc_cg_config; | ||
883 | |||
884 | switch (arbFreqSrc) { | ||
885 | case MC_CG_ARB_FREQ_F0: | ||
886 | mc_arb_dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING); | ||
887 | mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2); | ||
888 | burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0); | ||
889 | break; | ||
890 | |||
891 | case MC_CG_ARB_FREQ_F1: | ||
892 | mc_arb_dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1); | ||
893 | mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1); | ||
894 | burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1); | ||
895 | break; | ||
896 | |||
897 | default: | ||
898 | return -1; | ||
899 | } | ||
900 | |||
901 | switch (arbFreqDest) { | ||
902 | case MC_CG_ARB_FREQ_F0: | ||
903 | cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing); | ||
904 | cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2); | ||
905 | PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time); | ||
906 | break; | ||
907 | |||
908 | case MC_CG_ARB_FREQ_F1: | ||
909 | cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing); | ||
910 | cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2); | ||
911 | PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time); | ||
912 | break; | ||
913 | |||
914 | default: | ||
915 | return -1; | ||
916 | } | ||
917 | |||
918 | mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG); | ||
919 | mc_cg_config |= 0x0000000F; | ||
920 | cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config); | ||
921 | PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arbFreqDest); | ||
922 | |||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | /** | ||
927 | * Initial switch from ARB F0->F1 | ||
928 | * | ||
929 | * @param hwmgr the address of the powerplay hardware manager. | ||
930 | * @return always 0 | ||
931 | * This function is to be called from the SetPowerState table. | ||
932 | */ | ||
933 | int iceland_initial_switch_from_arb_f0_to_f1(struct pp_hwmgr *hwmgr) | ||
934 | { | ||
935 | return iceland_copy_and_switch_arb_sets(hwmgr, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1); | ||
936 | } | ||
937 | |||
938 | /* ---------------------------------------- ULV related functions ----------------------------------------------------*/ | ||
939 | |||
940 | |||
941 | static int iceland_reset_single_dpm_table( | ||
942 | struct pp_hwmgr *hwmgr, | ||
943 | struct iceland_single_dpm_table *dpm_table, | ||
944 | uint32_t count) | ||
945 | { | ||
946 | uint32_t i; | ||
947 | if (!(count <= MAX_REGULAR_DPM_NUMBER)) | ||
948 | printk(KERN_ERR "[ powerplay ] Fatal error, can not set up single DPM \ | ||
949 | table entries to exceed max number! \n"); | ||
950 | |||
951 | dpm_table->count = count; | ||
952 | for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++) { | ||
953 | dpm_table->dpm_levels[i].enabled = 0; | ||
954 | } | ||
955 | |||
956 | return 0; | ||
957 | } | ||
958 | |||
959 | static void iceland_setup_pcie_table_entry( | ||
960 | struct iceland_single_dpm_table *dpm_table, | ||
961 | uint32_t index, uint32_t pcie_gen, | ||
962 | uint32_t pcie_lanes) | ||
963 | { | ||
964 | dpm_table->dpm_levels[index].value = pcie_gen; | ||
965 | dpm_table->dpm_levels[index].param1 = pcie_lanes; | ||
966 | dpm_table->dpm_levels[index].enabled = 1; | ||
967 | } | ||
968 | |||
969 | /* | ||
970 | * Set up the PCIe DPM table as follows: | ||
971 | * | ||
972 | * A = Performance State, Max, Gen Speed | ||
973 | * C = Performance State, Min, Gen Speed | ||
974 | * 1 = Performance State, Max, Lane # | ||
975 | * 3 = Performance State, Min, Lane # | ||
976 | * | ||
977 | * B = Power Saving State, Max, Gen Speed | ||
978 | * D = Power Saving State, Min, Gen Speed | ||
979 | * 2 = Power Saving State, Max, Lane # | ||
980 | * 4 = Power Saving State, Min, Lane # | ||
981 | * | ||
982 | * | ||
983 | * DPM Index Gen Speed Lane # | ||
984 | * 5 A 1 | ||
985 | * 4 B 2 | ||
986 | * 3 C 1 | ||
987 | * 2 D 2 | ||
988 | * 1 C 3 | ||
989 | * 0 D 4 | ||
990 | * | ||
991 | */ | ||
992 | static int iceland_setup_default_pcie_tables(struct pp_hwmgr *hwmgr) | ||
993 | { | ||
994 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
995 | |||
996 | PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels || | ||
997 | data->use_pcie_power_saving_levels), | ||
998 | "No pcie performance levels!", return -EINVAL); | ||
999 | |||
1000 | if (data->use_pcie_performance_levels && !data->use_pcie_power_saving_levels) { | ||
1001 | data->pcie_gen_power_saving = data->pcie_gen_performance; | ||
1002 | data->pcie_lane_power_saving = data->pcie_lane_performance; | ||
1003 | } else if (!data->use_pcie_performance_levels && data->use_pcie_power_saving_levels) { | ||
1004 | data->pcie_gen_performance = data->pcie_gen_power_saving; | ||
1005 | data->pcie_lane_performance = data->pcie_lane_power_saving; | ||
1006 | } | ||
1007 | |||
1008 | iceland_reset_single_dpm_table(hwmgr, &data->dpm_table.pcie_speed_table, SMU71_MAX_LEVELS_LINK); | ||
1009 | |||
1010 | /* Hardcode Pcie Table */ | ||
1011 | iceland_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0, | ||
1012 | get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen), | ||
1013 | get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane)); | ||
1014 | iceland_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1, | ||
1015 | get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen), | ||
1016 | get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane)); | ||
1017 | iceland_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2, | ||
1018 | get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen), | ||
1019 | get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane)); | ||
1020 | iceland_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3, | ||
1021 | get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen), | ||
1022 | get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane)); | ||
1023 | iceland_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4, | ||
1024 | get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen), | ||
1025 | get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane)); | ||
1026 | iceland_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5, | ||
1027 | get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen), | ||
1028 | get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane)); | ||
1029 | data->dpm_table.pcie_speed_table.count = 6; | ||
1030 | |||
1031 | return 0; | ||
1032 | |||
1033 | } | ||
1034 | |||
1035 | |||
1036 | /* | ||
1037 | * This function is to initalize all DPM state tables for SMU7 based on the dependency table. | ||
1038 | * Dynamic state patching function will then trim these state tables to the allowed range based | ||
1039 | * on the power policy or external client requests, such as UVD request, etc. | ||
1040 | */ | ||
1041 | static int iceland_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) | ||
1042 | { | ||
1043 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
1044 | uint32_t i; | ||
1045 | |||
1046 | struct phm_clock_voltage_dependency_table *allowed_vdd_sclk_table = | ||
1047 | hwmgr->dyn_state.vddc_dependency_on_sclk; | ||
1048 | struct phm_clock_voltage_dependency_table *allowed_vdd_mclk_table = | ||
1049 | hwmgr->dyn_state.vddc_dependency_on_mclk; | ||
1050 | struct phm_cac_leakage_table *std_voltage_table = | ||
1051 | hwmgr->dyn_state.cac_leakage_table; | ||
1052 | |||
1053 | PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, | ||
1054 | "SCLK dependency table is missing. This table is mandatory", return -1); | ||
1055 | PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table->count >= 1, | ||
1056 | "SCLK dependency table has to have is missing. This table is mandatory", return -1); | ||
1057 | |||
1058 | PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL, | ||
1059 | "MCLK dependency table is missing. This table is mandatory", return -1); | ||
1060 | PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table->count >= 1, | ||
1061 | "VMCLK dependency table has to have is missing. This table is mandatory", return -1); | ||
1062 | |||
1063 | /* clear the state table to reset everything to default */ | ||
1064 | memset(&(data->dpm_table), 0x00, sizeof(data->dpm_table)); | ||
1065 | iceland_reset_single_dpm_table(hwmgr, &data->dpm_table.sclk_table, SMU71_MAX_LEVELS_GRAPHICS); | ||
1066 | iceland_reset_single_dpm_table(hwmgr, &data->dpm_table.mclk_table, SMU71_MAX_LEVELS_MEMORY); | ||
1067 | iceland_reset_single_dpm_table(hwmgr, &data->dpm_table.vddc_table, SMU71_MAX_LEVELS_VDDC); | ||
1068 | iceland_reset_single_dpm_table(hwmgr, &data->dpm_table.vdd_ci_table, SMU71_MAX_LEVELS_VDDCI); | ||
1069 | iceland_reset_single_dpm_table(hwmgr, &data->dpm_table.mvdd_table, SMU71_MAX_LEVELS_MVDD); | ||
1070 | |||
1071 | PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, | ||
1072 | "SCLK dependency table is missing. This table is mandatory", return -1); | ||
1073 | /* Initialize Sclk DPM table based on allow Sclk values*/ | ||
1074 | data->dpm_table.sclk_table.count = 0; | ||
1075 | |||
1076 | for (i = 0; i < allowed_vdd_sclk_table->count; i++) { | ||
1077 | if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != | ||
1078 | allowed_vdd_sclk_table->entries[i].clk) { | ||
1079 | data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = | ||
1080 | allowed_vdd_sclk_table->entries[i].clk; | ||
1081 | data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; to do */ | ||
1082 | data->dpm_table.sclk_table.count++; | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL, | ||
1087 | "MCLK dependency table is missing. This table is mandatory", return -1); | ||
1088 | /* Initialize Mclk DPM table based on allow Mclk values */ | ||
1089 | data->dpm_table.mclk_table.count = 0; | ||
1090 | for (i = 0; i < allowed_vdd_mclk_table->count; i++) { | ||
1091 | if (i == 0 || data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count-1].value != | ||
1092 | allowed_vdd_mclk_table->entries[i].clk) { | ||
1093 | data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value = | ||
1094 | allowed_vdd_mclk_table->entries[i].clk; | ||
1095 | data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; */ | ||
1096 | data->dpm_table.mclk_table.count++; | ||
1097 | } | ||
1098 | } | ||
1099 | |||
1100 | /* Initialize Vddc DPM table based on allow Vddc values. And populate corresponding std values. */ | ||
1101 | for (i = 0; i < allowed_vdd_sclk_table->count; i++) { | ||
1102 | data->dpm_table.vddc_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v; | ||
1103 | data->dpm_table.vddc_table.dpm_levels[i].param1 = std_voltage_table->entries[i].Leakage; | ||
1104 | /* param1 is for corresponding std voltage */ | ||
1105 | data->dpm_table.vddc_table.dpm_levels[i].enabled = 1; | ||
1106 | } | ||
1107 | |||
1108 | data->dpm_table.vddc_table.count = allowed_vdd_sclk_table->count; | ||
1109 | allowed_vdd_mclk_table = hwmgr->dyn_state.vddci_dependency_on_mclk; | ||
1110 | |||
1111 | if (NULL != allowed_vdd_mclk_table) { | ||
1112 | /* Initialize Vddci DPM table based on allow Mclk values */ | ||
1113 | for (i = 0; i < allowed_vdd_mclk_table->count; i++) { | ||
1114 | data->dpm_table.vdd_ci_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v; | ||
1115 | data->dpm_table.vdd_ci_table.dpm_levels[i].enabled = 1; | ||
1116 | } | ||
1117 | data->dpm_table.vdd_ci_table.count = allowed_vdd_mclk_table->count; | ||
1118 | } | ||
1119 | |||
1120 | allowed_vdd_mclk_table = hwmgr->dyn_state.mvdd_dependency_on_mclk; | ||
1121 | |||
1122 | if (NULL != allowed_vdd_mclk_table) { | ||
1123 | /* | ||
1124 | * Initialize MVDD DPM table based on allow Mclk | ||
1125 | * values | ||
1126 | */ | ||
1127 | for (i = 0; i < allowed_vdd_mclk_table->count; i++) { | ||
1128 | data->dpm_table.mvdd_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v; | ||
1129 | data->dpm_table.mvdd_table.dpm_levels[i].enabled = 1; | ||
1130 | } | ||
1131 | data->dpm_table.mvdd_table.count = allowed_vdd_mclk_table->count; | ||
1132 | } | ||
1133 | |||
1134 | /* setup PCIE gen speed levels*/ | ||
1135 | iceland_setup_default_pcie_tables(hwmgr); | ||
1136 | |||
1137 | /* save a copy of the default DPM table*/ | ||
1138 | memcpy(&(data->golden_dpm_table), &(data->dpm_table), sizeof(struct iceland_dpm_table)); | ||
1139 | |||
1140 | return 0; | ||
1141 | } | ||
1142 | |||
1143 | /** | ||
1144 | * @brief PhwIceland_GetVoltageOrder | ||
1145 | * Returns index of requested voltage record in lookup(table) | ||
1146 | * @param hwmgr - pointer to hardware manager | ||
1147 | * @param lookutab - lookup list to search in | ||
1148 | * @param voltage - voltage to look for | ||
1149 | * @return 0 on success | ||
1150 | */ | ||
1151 | uint8_t iceland_get_voltage_index(phm_ppt_v1_voltage_lookup_table *look_up_table, | ||
1152 | uint16_t voltage) | ||
1153 | { | ||
1154 | uint8_t count = (uint8_t) (look_up_table->count); | ||
1155 | uint8_t i; | ||
1156 | |||
1157 | PP_ASSERT_WITH_CODE((NULL != look_up_table), "Lookup Table empty.", return 0;); | ||
1158 | PP_ASSERT_WITH_CODE((0 != count), "Lookup Table empty.", return 0;); | ||
1159 | |||
1160 | for (i = 0; i < count; i++) { | ||
1161 | /* find first voltage equal or bigger than requested */ | ||
1162 | if (look_up_table->entries[i].us_vdd >= voltage) | ||
1163 | return i; | ||
1164 | } | ||
1165 | |||
1166 | /* voltage is bigger than max voltage in the table */ | ||
1167 | return i-1; | ||
1168 | } | ||
1169 | |||
1170 | |||
1171 | static int iceland_get_std_voltage_value_sidd(struct pp_hwmgr *hwmgr, | ||
1172 | pp_atomctrl_voltage_table_entry *tab, uint16_t *hi, | ||
1173 | uint16_t *lo) | ||
1174 | { | ||
1175 | uint16_t v_index; | ||
1176 | bool vol_found = false; | ||
1177 | *hi = tab->value * VOLTAGE_SCALE; | ||
1178 | *lo = tab->value * VOLTAGE_SCALE; | ||
1179 | |||
1180 | /* SCLK/VDDC Dependency Table has to exist. */ | ||
1181 | PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.vddc_dependency_on_sclk, | ||
1182 | "The SCLK/VDDC Dependency Table does not exist.\n", | ||
1183 | return -EINVAL); | ||
1184 | |||
1185 | if (NULL == hwmgr->dyn_state.cac_leakage_table) { | ||
1186 | pr_warning("CAC Leakage Table does not exist, using vddc.\n"); | ||
1187 | return 0; | ||
1188 | } | ||
1189 | |||
1190 | /* | ||
1191 | * Since voltage in the sclk/vddc dependency table is not | ||
1192 | * necessarily in ascending order because of ELB voltage | ||
1193 | * patching, loop through entire list to find exact voltage. | ||
1194 | */ | ||
1195 | for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) { | ||
1196 | if (tab->value == hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) { | ||
1197 | vol_found = true; | ||
1198 | if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) { | ||
1199 | *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE; | ||
1200 | *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage * VOLTAGE_SCALE); | ||
1201 | } else { | ||
1202 | pr_warning("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index, using maximum index from CAC table.\n"); | ||
1203 | *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE; | ||
1204 | *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE); | ||
1205 | } | ||
1206 | break; | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | /* | ||
1211 | * If voltage is not found in the first pass, loop again to | ||
1212 | * find the best match, equal or higher value. | ||
1213 | */ | ||
1214 | if (!vol_found) { | ||
1215 | for (v_index = 0; (uint32_t)v_index < hwmgr->dyn_state.vddc_dependency_on_sclk->count; v_index++) { | ||
1216 | if (tab->value <= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[v_index].v) { | ||
1217 | vol_found = true; | ||
1218 | if ((uint32_t)v_index < hwmgr->dyn_state.cac_leakage_table->count) { | ||
1219 | *lo = hwmgr->dyn_state.cac_leakage_table->entries[v_index].Vddc * VOLTAGE_SCALE; | ||
1220 | *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[v_index].Leakage) * VOLTAGE_SCALE; | ||
1221 | } else { | ||
1222 | pr_warning("Index from SCLK/VDDC Dependency Table exceeds the CAC Leakage Table index in second look up, using maximum index from CAC table."); | ||
1223 | *lo = hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Vddc * VOLTAGE_SCALE; | ||
1224 | *hi = (uint16_t)(hwmgr->dyn_state.cac_leakage_table->entries[hwmgr->dyn_state.cac_leakage_table->count - 1].Leakage * VOLTAGE_SCALE); | ||
1225 | } | ||
1226 | break; | ||
1227 | } | ||
1228 | } | ||
1229 | |||
1230 | if (!vol_found) | ||
1231 | pr_warning("Unable to get std_vddc from SCLK/VDDC Dependency Table, using vddc.\n"); | ||
1232 | } | ||
1233 | |||
1234 | return 0; | ||
1235 | } | ||
1236 | |||
1237 | static int iceland_populate_smc_voltage_table(struct pp_hwmgr *hwmgr, | ||
1238 | pp_atomctrl_voltage_table_entry *tab, | ||
1239 | SMU71_Discrete_VoltageLevel *smc_voltage_tab) { | ||
1240 | int result; | ||
1241 | |||
1242 | |||
1243 | result = iceland_get_std_voltage_value_sidd(hwmgr, tab, | ||
1244 | &smc_voltage_tab->StdVoltageHiSidd, | ||
1245 | &smc_voltage_tab->StdVoltageLoSidd); | ||
1246 | if (0 != result) { | ||
1247 | smc_voltage_tab->StdVoltageHiSidd = tab->value * VOLTAGE_SCALE; | ||
1248 | smc_voltage_tab->StdVoltageLoSidd = tab->value * VOLTAGE_SCALE; | ||
1249 | } | ||
1250 | |||
1251 | smc_voltage_tab->Voltage = PP_HOST_TO_SMC_US(tab->value * VOLTAGE_SCALE); | ||
1252 | CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageHiSidd); | ||
1253 | CONVERT_FROM_HOST_TO_SMC_US(smc_voltage_tab->StdVoltageHiSidd); | ||
1254 | |||
1255 | return 0; | ||
1256 | } | ||
1257 | |||
1258 | /** | ||
1259 | * Vddc table preparation for SMC. | ||
1260 | * | ||
1261 | * @param hwmgr the address of the hardware manager | ||
1262 | * @param table the SMC DPM table structure to be populated | ||
1263 | * @return always 0 | ||
1264 | */ | ||
1265 | static int iceland_populate_smc_vddc_table(struct pp_hwmgr *hwmgr, | ||
1266 | SMU71_Discrete_DpmTable *table) | ||
1267 | { | ||
1268 | unsigned int count; | ||
1269 | int result; | ||
1270 | |||
1271 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
1272 | |||
1273 | table->VddcLevelCount = data->vddc_voltage_table.count; | ||
1274 | for (count = 0; count < table->VddcLevelCount; count++) { | ||
1275 | result = iceland_populate_smc_voltage_table(hwmgr, | ||
1276 | &data->vddc_voltage_table.entries[count], | ||
1277 | &table->VddcLevel[count]); | ||
1278 | PP_ASSERT_WITH_CODE(0 == result, "do not populate SMC VDDC voltage table", return -EINVAL); | ||
1279 | |||
1280 | /* GPIO voltage control */ | ||
1281 | if (ICELAND_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) | ||
1282 | table->VddcLevel[count].Smio |= data->vddc_voltage_table.entries[count].smio_low; | ||
1283 | else if (ICELAND_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) | ||
1284 | table->VddcLevel[count].Smio = 0; | ||
1285 | } | ||
1286 | |||
1287 | CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount); | ||
1288 | |||
1289 | return 0; | ||
1290 | } | ||
1291 | |||
1292 | /** | ||
1293 | * Vddci table preparation for SMC. | ||
1294 | * | ||
1295 | * @param *hwmgr The address of the hardware manager. | ||
1296 | * @param *table The SMC DPM table structure to be populated. | ||
1297 | * @return 0 | ||
1298 | */ | ||
1299 | static int iceland_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr, | ||
1300 | SMU71_Discrete_DpmTable *table) | ||
1301 | { | ||
1302 | int result; | ||
1303 | uint32_t count; | ||
1304 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
1305 | |||
1306 | table->VddciLevelCount = data->vddci_voltage_table.count; | ||
1307 | for (count = 0; count < table->VddciLevelCount; count++) { | ||
1308 | result = iceland_populate_smc_voltage_table(hwmgr, | ||
1309 | &data->vddci_voltage_table.entries[count], | ||
1310 | &table->VddciLevel[count]); | ||
1311 | PP_ASSERT_WITH_CODE(0 == result, "do not populate SMC VDDCI voltage table", return -EINVAL); | ||
1312 | |||
1313 | /* GPIO voltage control */ | ||
1314 | if (ICELAND_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) | ||
1315 | table->VddciLevel[count].Smio |= data->vddci_voltage_table.entries[count].smio_low; | ||
1316 | else | ||
1317 | table->VddciLevel[count].Smio = 0; | ||
1318 | } | ||
1319 | |||
1320 | CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount); | ||
1321 | |||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1325 | /** | ||
1326 | * Mvdd table preparation for SMC. | ||
1327 | * | ||
1328 | * @param *hwmgr The address of the hardware manager. | ||
1329 | * @param *table The SMC DPM table structure to be populated. | ||
1330 | * @return 0 | ||
1331 | */ | ||
1332 | static int iceland_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr, | ||
1333 | SMU71_Discrete_DpmTable *table) | ||
1334 | { | ||
1335 | int result; | ||
1336 | uint32_t count; | ||
1337 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
1338 | |||
1339 | table->MvddLevelCount = data->mvdd_voltage_table.count; | ||
1340 | for (count = 0; count < table->MvddLevelCount; count++) { | ||
1341 | result = iceland_populate_smc_voltage_table(hwmgr, | ||
1342 | &data->mvdd_voltage_table.entries[count], | ||
1343 | &table->MvddLevel[count]); | ||
1344 | PP_ASSERT_WITH_CODE(0 == result, "do not populate SMC VDDCI voltage table", return -EINVAL); | ||
1345 | |||
1346 | /* GPIO voltage control */ | ||
1347 | if (ICELAND_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) | ||
1348 | table->MvddLevel[count].Smio |= data->mvdd_voltage_table.entries[count].smio_low; | ||
1349 | else | ||
1350 | table->MvddLevel[count].Smio = 0; | ||
1351 | } | ||
1352 | |||
1353 | CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount); | ||
1354 | |||
1355 | return 0; | ||
1356 | } | ||
1357 | |||
1358 | /** | ||
1359 | * Convert a voltage value in mv unit to VID number required by SMU firmware | ||
1360 | */ | ||
1361 | static uint8_t convert_to_vid(uint16_t vddc) | ||
1362 | { | ||
1363 | return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25); | ||
1364 | } | ||
1365 | |||
1366 | int iceland_populate_bapm_vddc_vid_sidd(struct pp_hwmgr *hwmgr) | ||
1367 | { | ||
1368 | int i; | ||
1369 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
1370 | uint8_t * hi_vid = data->power_tune_table.BapmVddCVidHiSidd; | ||
1371 | uint8_t * lo_vid = data->power_tune_table.BapmVddCVidLoSidd; | ||
1372 | |||
1373 | PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.cac_leakage_table, | ||
1374 | "The CAC Leakage table does not exist!", return -EINVAL); | ||
1375 | PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count <= 8, | ||
1376 | "There should never be more than 8 entries for BapmVddcVid!!!", return -EINVAL); | ||
1377 | PP_ASSERT_WITH_CODE(hwmgr->dyn_state.cac_leakage_table->count == hwmgr->dyn_state.vddc_dependency_on_sclk->count, | ||
1378 | "CACLeakageTable->count and VddcDependencyOnSCLk->count not equal", return -EINVAL); | ||
1379 | |||
1380 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EVV)) { | ||
1381 | for (i = 0; (uint32_t) i < hwmgr->dyn_state.cac_leakage_table->count; i++) { | ||
1382 | lo_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc1); | ||
1383 | hi_vid[i] = convert_to_vid(hwmgr->dyn_state.cac_leakage_table->entries[i].Vddc2); | ||
1384 | } | ||
1385 | } else { | ||
1386 | PP_ASSERT_WITH_CODE(false, "Iceland should always support EVV", return -EINVAL); | ||
1387 | } | ||
1388 | |||
1389 | return 0; | ||
1390 | } | ||
1391 | |||
1392 | int iceland_populate_vddc_vid(struct pp_hwmgr *hwmgr) | ||
1393 | { | ||
1394 | int i; | ||
1395 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
1396 | uint8_t *vid = data->power_tune_table.VddCVid; | ||
1397 | |||
1398 | PP_ASSERT_WITH_CODE(data->vddc_voltage_table.count <= 8, | ||
1399 | "There should never be more than 8 entries for VddcVid!!!", | ||
1400 | return -EINVAL); | ||
1401 | |||
1402 | for (i = 0; i < (int)data->vddc_voltage_table.count; i++) { | ||
1403 | vid[i] = convert_to_vid(data->vddc_voltage_table.entries[i].value); | ||
1404 | } | ||
1405 | |||
1406 | return 0; | ||
1407 | } | ||
1408 | |||
1409 | /** | ||
1410 | * Preparation of voltage tables for SMC. | ||
1411 | * | ||
1412 | * @param hwmgr the address of the hardware manager | ||
1413 | * @param table the SMC DPM table structure to be populated | ||
1414 | * @return always 0 | ||
1415 | */ | ||
1416 | |||
1417 | int iceland_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr, | ||
1418 | SMU71_Discrete_DpmTable *table) | ||
1419 | { | ||
1420 | int result; | ||
1421 | |||
1422 | result = iceland_populate_smc_vddc_table(hwmgr, table); | ||
1423 | PP_ASSERT_WITH_CODE(0 == result, | ||
1424 | "can not populate VDDC voltage table to SMC", return -1); | ||
1425 | |||
1426 | result = iceland_populate_smc_vdd_ci_table(hwmgr, table); | ||
1427 | PP_ASSERT_WITH_CODE(0 == result, | ||
1428 | "can not populate VDDCI voltage table to SMC", return -1); | ||
1429 | |||
1430 | result = iceland_populate_smc_mvdd_table(hwmgr, table); | ||
1431 | PP_ASSERT_WITH_CODE(0 == result, | ||
1432 | "can not populate MVDD voltage table to SMC", return -1); | ||
1433 | |||
1434 | return 0; | ||
1435 | } | ||
1436 | |||
1437 | |||
1438 | /** | ||
1439 | * Re-generate the DPM level mask value | ||
1440 | * @param hwmgr the address of the hardware manager | ||
1441 | */ | ||
1442 | static uint32_t iceland_get_dpm_level_enable_mask_value( | ||
1443 | struct iceland_single_dpm_table * dpm_table) | ||
1444 | { | ||
1445 | uint32_t i; | ||
1446 | uint32_t mask_value = 0; | ||
1447 | |||
1448 | for (i = dpm_table->count; i > 0; i--) { | ||
1449 | mask_value = mask_value << 1; | ||
1450 | |||
1451 | if (dpm_table->dpm_levels[i-1].enabled) | ||
1452 | mask_value |= 0x1; | ||
1453 | else | ||
1454 | mask_value &= 0xFFFFFFFE; | ||
1455 | } | ||
1456 | return mask_value; | ||
1457 | } | ||
1458 | |||
1459 | int iceland_populate_memory_timing_parameters( | ||
1460 | struct pp_hwmgr *hwmgr, | ||
1461 | uint32_t engine_clock, | ||
1462 | uint32_t memory_clock, | ||
1463 | struct SMU71_Discrete_MCArbDramTimingTableEntry *arb_regs | ||
1464 | ) | ||
1465 | { | ||
1466 | uint32_t dramTiming; | ||
1467 | uint32_t dramTiming2; | ||
1468 | uint32_t burstTime; | ||
1469 | int result; | ||
1470 | |||
1471 | result = atomctrl_set_engine_dram_timings_rv770(hwmgr, | ||
1472 | engine_clock, memory_clock); | ||
1473 | |||
1474 | PP_ASSERT_WITH_CODE(result == 0, | ||
1475 | "Error calling VBIOS to set DRAM_TIMING.", return result); | ||
1476 | |||
1477 | dramTiming = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING); | ||
1478 | dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2); | ||
1479 | burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0); | ||
1480 | |||
1481 | arb_regs->McArbDramTiming = PP_HOST_TO_SMC_UL(dramTiming); | ||
1482 | arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2); | ||
1483 | arb_regs->McArbBurstTime = (uint8_t)burstTime; | ||
1484 | |||
1485 | return 0; | ||
1486 | } | ||
1487 | |||
1488 | /** | ||
1489 | * Setup parameters for the MC ARB. | ||
1490 | * | ||
1491 | * @param hwmgr the address of the powerplay hardware manager. | ||
1492 | * @return always 0 | ||
1493 | * This function is to be called from the SetPowerState table. | ||
1494 | */ | ||
1495 | int iceland_program_memory_timing_parameters(struct pp_hwmgr *hwmgr) | ||
1496 | { | ||
1497 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
1498 | int result = 0; | ||
1499 | SMU71_Discrete_MCArbDramTimingTable arb_regs; | ||
1500 | uint32_t i, j; | ||
1501 | |||
1502 | memset(&arb_regs, 0x00, sizeof(SMU71_Discrete_MCArbDramTimingTable)); | ||
1503 | |||
1504 | for (i = 0; i < data->dpm_table.sclk_table.count; i++) { | ||
1505 | for (j = 0; j < data->dpm_table.mclk_table.count; j++) { | ||
1506 | result = iceland_populate_memory_timing_parameters | ||
1507 | (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value, | ||
1508 | data->dpm_table.mclk_table.dpm_levels[j].value, | ||
1509 | &arb_regs.entries[i][j]); | ||
1510 | |||
1511 | if (0 != result) { | ||
1512 | break; | ||
1513 | } | ||
1514 | } | ||
1515 | } | ||
1516 | |||
1517 | if (0 == result) { | ||
1518 | result = iceland_copy_bytes_to_smc( | ||
1519 | hwmgr->smumgr, | ||
1520 | data->arb_table_start, | ||
1521 | (uint8_t *)&arb_regs, | ||
1522 | sizeof(SMU71_Discrete_MCArbDramTimingTable), | ||
1523 | data->sram_end | ||
1524 | ); | ||
1525 | } | ||
1526 | |||
1527 | return result; | ||
1528 | } | ||
1529 | |||
1530 | static int iceland_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU71_Discrete_DpmTable *table) | ||
1531 | { | ||
1532 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
1533 | struct iceland_dpm_table *dpm_table = &data->dpm_table; | ||
1534 | uint32_t i; | ||
1535 | |||
1536 | /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */ | ||
1537 | for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) { | ||
1538 | table->LinkLevel[i].PcieGenSpeed = | ||
1539 | (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value; | ||
1540 | table->LinkLevel[i].PcieLaneCount = | ||
1541 | (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1); | ||
1542 | table->LinkLevel[i].EnabledForActivity = | ||
1543 | 1; | ||
1544 | table->LinkLevel[i].SPC = | ||
1545 | (uint8_t)(data->pcie_spc_cap & 0xff); | ||
1546 | table->LinkLevel[i].DownThreshold = | ||
1547 | PP_HOST_TO_SMC_UL(5); | ||
1548 | table->LinkLevel[i].UpThreshold = | ||
1549 | PP_HOST_TO_SMC_UL(30); | ||
1550 | } | ||
1551 | |||
1552 | data->smc_state_table.LinkLevelCount = | ||
1553 | (uint8_t)dpm_table->pcie_speed_table.count; | ||
1554 | data->dpm_level_enable_mask.pcie_dpm_enable_mask = | ||
1555 | iceland_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table); | ||
1556 | |||
1557 | return 0; | ||
1558 | } | ||
1559 | |||
1560 | static int iceland_populate_smc_uvd_level(struct pp_hwmgr *hwmgr, | ||
1561 | SMU71_Discrete_DpmTable *table) | ||
1562 | { | ||
1563 | return 0; | ||
1564 | } | ||
1565 | |||
1566 | uint8_t iceland_get_voltage_id(pp_atomctrl_voltage_table *voltage_table, | ||
1567 | uint32_t voltage) | ||
1568 | { | ||
1569 | uint8_t count = (uint8_t) (voltage_table->count); | ||
1570 | uint8_t i = 0; | ||
1571 | |||
1572 | PP_ASSERT_WITH_CODE((NULL != voltage_table), | ||
1573 | "Voltage Table empty.", return 0;); | ||
1574 | PP_ASSERT_WITH_CODE((0 != count), | ||
1575 | "Voltage Table empty.", return 0;); | ||
1576 | |||
1577 | for (i = 0; i < count; i++) { | ||
1578 | /* find first voltage bigger than requested */ | ||
1579 | if (voltage_table->entries[i].value >= voltage) | ||
1580 | return i; | ||
1581 | } | ||
1582 | |||
1583 | /* voltage is bigger than max voltage in the table */ | ||
1584 | return i - 1; | ||
1585 | } | ||
1586 | |||
1587 | static int iceland_populate_smc_vce_level(struct pp_hwmgr *hwmgr, | ||
1588 | SMU71_Discrete_DpmTable *table) | ||
1589 | { | ||
1590 | return 0; | ||
1591 | } | ||
1592 | |||
1593 | static int iceland_populate_smc_acp_level(struct pp_hwmgr *hwmgr, | ||
1594 | SMU71_Discrete_DpmTable *table) | ||
1595 | { | ||
1596 | return 0; | ||
1597 | } | ||
1598 | |||
1599 | static int iceland_populate_smc_samu_level(struct pp_hwmgr *hwmgr, | ||
1600 | SMU71_Discrete_DpmTable *table) | ||
1601 | { | ||
1602 | return 0; | ||
1603 | } | ||
1604 | |||
1605 | |||
1606 | static int iceland_populate_smc_svi2_config(struct pp_hwmgr *hwmgr, | ||
1607 | SMU71_Discrete_DpmTable *tab) | ||
1608 | { | ||
1609 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
1610 | |||
1611 | if(ICELAND_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) | ||
1612 | tab->SVI2Enable |= VDDC_ON_SVI2; | ||
1613 | |||
1614 | if(ICELAND_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) | ||
1615 | tab->SVI2Enable |= VDDCI_ON_SVI2; | ||
1616 | else | ||
1617 | tab->MergedVddci = 1; | ||
1618 | |||
1619 | if(ICELAND_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) | ||
1620 | tab->SVI2Enable |= MVDD_ON_SVI2; | ||
1621 | |||
1622 | PP_ASSERT_WITH_CODE( tab->SVI2Enable != (VDDC_ON_SVI2 | VDDCI_ON_SVI2 | MVDD_ON_SVI2) && | ||
1623 | (tab->SVI2Enable & VDDC_ON_SVI2), "SVI2 domain configuration is incorrect!", return -EINVAL); | ||
1624 | |||
1625 | return 0; | ||
1626 | } | ||
1627 | |||
1628 | static int iceland_get_dependecy_volt_by_clk(struct pp_hwmgr *hwmgr, | ||
1629 | struct phm_clock_voltage_dependency_table *allowed_clock_voltage_table, | ||
1630 | uint32_t clock, uint32_t *vol) | ||
1631 | { | ||
1632 | uint32_t i = 0; | ||
1633 | |||
1634 | /* clock - voltage dependency table is empty table */ | ||
1635 | if (allowed_clock_voltage_table->count == 0) | ||
1636 | return -EINVAL; | ||
1637 | |||
1638 | for (i = 0; i < allowed_clock_voltage_table->count; i++) { | ||
1639 | /* find first sclk bigger than request */ | ||
1640 | if (allowed_clock_voltage_table->entries[i].clk >= clock) { | ||
1641 | *vol = allowed_clock_voltage_table->entries[i].v; | ||
1642 | return 0; | ||
1643 | } | ||
1644 | } | ||
1645 | |||
1646 | /* sclk is bigger than max sclk in the dependence table */ | ||
1647 | *vol = allowed_clock_voltage_table->entries[i - 1].v; | ||
1648 | |||
1649 | return 0; | ||
1650 | } | ||
1651 | |||
1652 | static uint8_t iceland_get_mclk_frequency_ratio(uint32_t memory_clock, | ||
1653 | bool strobe_mode) | ||
1654 | { | ||
1655 | uint8_t mc_para_index; | ||
1656 | |||
1657 | if (strobe_mode) { | ||
1658 | if (memory_clock < 12500) { | ||
1659 | mc_para_index = 0x00; | ||
1660 | } else if (memory_clock > 47500) { | ||
1661 | mc_para_index = 0x0f; | ||
1662 | } else { | ||
1663 | mc_para_index = (uint8_t)((memory_clock - 10000) / 2500); | ||
1664 | } | ||
1665 | } else { | ||
1666 | if (memory_clock < 65000) { | ||
1667 | mc_para_index = 0x00; | ||
1668 | } else if (memory_clock > 135000) { | ||
1669 | mc_para_index = 0x0f; | ||
1670 | } else { | ||
1671 | mc_para_index = (uint8_t)((memory_clock - 60000) / 5000); | ||
1672 | } | ||
1673 | } | ||
1674 | |||
1675 | return mc_para_index; | ||
1676 | } | ||
1677 | |||
1678 | static uint8_t iceland_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock) | ||
1679 | { | ||
1680 | uint8_t mc_para_index; | ||
1681 | |||
1682 | if (memory_clock < 10000) { | ||
1683 | mc_para_index = 0; | ||
1684 | } else if (memory_clock >= 80000) { | ||
1685 | mc_para_index = 0x0f; | ||
1686 | } else { | ||
1687 | mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1); | ||
1688 | } | ||
1689 | |||
1690 | return mc_para_index; | ||
1691 | } | ||
1692 | |||
1693 | static int iceland_populate_phase_value_based_on_sclk(struct pp_hwmgr *hwmgr, const struct phm_phase_shedding_limits_table *pl, | ||
1694 | uint32_t sclk, uint32_t *p_shed) | ||
1695 | { | ||
1696 | unsigned int i; | ||
1697 | |||
1698 | /* use the minimum phase shedding */ | ||
1699 | *p_shed = 1; | ||
1700 | |||
1701 | /* | ||
1702 | * PPGen ensures the phase shedding limits table is sorted | ||
1703 | * from lowest voltage/sclk/mclk to highest voltage/sclk/mclk. | ||
1704 | * VBIOS ensures the phase shedding masks table is sorted from | ||
1705 | * least phases enabled (phase shedding on) to most phases | ||
1706 | * enabled (phase shedding off). | ||
1707 | */ | ||
1708 | for (i = 0; i < pl->count; i++) { | ||
1709 | if (sclk < pl->entries[i].Sclk) { | ||
1710 | /* Enable phase shedding */ | ||
1711 | *p_shed = i; | ||
1712 | break; | ||
1713 | } | ||
1714 | } | ||
1715 | |||
1716 | return 0; | ||
1717 | } | ||
1718 | |||
1719 | static int iceland_populate_phase_value_based_on_mclk(struct pp_hwmgr *hwmgr, const struct phm_phase_shedding_limits_table *pl, | ||
1720 | uint32_t memory_clock, uint32_t *p_shed) | ||
1721 | { | ||
1722 | unsigned int i; | ||
1723 | |||
1724 | /* use the minimum phase shedding */ | ||
1725 | *p_shed = 1; | ||
1726 | |||
1727 | /* | ||
1728 | * PPGen ensures the phase shedding limits table is sorted | ||
1729 | * from lowest voltage/sclk/mclk to highest voltage/sclk/mclk. | ||
1730 | * VBIOS ensures the phase shedding masks table is sorted from | ||
1731 | * least phases enabled (phase shedding on) to most phases | ||
1732 | * enabled (phase shedding off). | ||
1733 | */ | ||
1734 | for (i = 0; i < pl->count; i++) { | ||
1735 | if (memory_clock < pl->entries[i].Mclk) { | ||
1736 | /* Enable phase shedding */ | ||
1737 | *p_shed = i; | ||
1738 | break; | ||
1739 | } | ||
1740 | } | ||
1741 | |||
1742 | return 0; | ||
1743 | } | ||
1744 | |||
1745 | /** | ||
1746 | * Populates the SMC MCLK structure using the provided memory clock | ||
1747 | * | ||
1748 | * @param hwmgr the address of the hardware manager | ||
1749 | * @param memory_clock the memory clock to use to populate the structure | ||
1750 | * @param sclk the SMC SCLK structure to be populated | ||
1751 | */ | ||
1752 | static int iceland_calculate_mclk_params( | ||
1753 | struct pp_hwmgr *hwmgr, | ||
1754 | uint32_t memory_clock, | ||
1755 | SMU71_Discrete_MemoryLevel *mclk, | ||
1756 | bool strobe_mode, | ||
1757 | bool dllStateOn | ||
1758 | ) | ||
1759 | { | ||
1760 | const iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
1761 | uint32_t dll_cntl = data->clock_registers.vDLL_CNTL; | ||
1762 | uint32_t mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL; | ||
1763 | uint32_t mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL; | ||
1764 | uint32_t mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL; | ||
1765 | uint32_t mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL; | ||
1766 | uint32_t mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1; | ||
1767 | uint32_t mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2; | ||
1768 | uint32_t mpll_ss1 = data->clock_registers.vMPLL_SS1; | ||
1769 | uint32_t mpll_ss2 = data->clock_registers.vMPLL_SS2; | ||
1770 | |||
1771 | pp_atomctrl_memory_clock_param mpll_param; | ||
1772 | int result; | ||
1773 | |||
1774 | result = atomctrl_get_memory_pll_dividers_si(hwmgr, | ||
1775 | memory_clock, &mpll_param, strobe_mode); | ||
1776 | PP_ASSERT_WITH_CODE(0 == result, | ||
1777 | "Error retrieving Memory Clock Parameters from VBIOS.", return result); | ||
1778 | |||
1779 | /* MPLL_FUNC_CNTL setup*/ | ||
1780 | mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL, mpll_param.bw_ctrl); | ||
1781 | |||
1782 | /* MPLL_FUNC_CNTL_1 setup*/ | ||
1783 | mpll_func_cntl_1 = PHM_SET_FIELD(mpll_func_cntl_1, | ||
1784 | MPLL_FUNC_CNTL_1, CLKF, mpll_param.mpll_fb_divider.cl_kf); | ||
1785 | mpll_func_cntl_1 = PHM_SET_FIELD(mpll_func_cntl_1, | ||
1786 | MPLL_FUNC_CNTL_1, CLKFRAC, mpll_param.mpll_fb_divider.clk_frac); | ||
1787 | mpll_func_cntl_1 = PHM_SET_FIELD(mpll_func_cntl_1, | ||
1788 | MPLL_FUNC_CNTL_1, VCO_MODE, mpll_param.vco_mode); | ||
1789 | |||
1790 | /* MPLL_AD_FUNC_CNTL setup*/ | ||
1791 | mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl, | ||
1792 | MPLL_AD_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider); | ||
1793 | |||
1794 | if (data->is_memory_GDDR5) { | ||
1795 | /* MPLL_DQ_FUNC_CNTL setup*/ | ||
1796 | mpll_dq_func_cntl = PHM_SET_FIELD(mpll_dq_func_cntl, | ||
1797 | MPLL_DQ_FUNC_CNTL, YCLK_SEL, mpll_param.yclk_sel); | ||
1798 | mpll_dq_func_cntl = PHM_SET_FIELD(mpll_dq_func_cntl, | ||
1799 | MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider); | ||
1800 | } | ||
1801 | |||
1802 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
1803 | PHM_PlatformCaps_MemorySpreadSpectrumSupport)) { | ||
1804 | /* | ||
1805 | ************************************ | ||
1806 | Fref = Reference Frequency | ||
1807 | NF = Feedback divider ratio | ||
1808 | NR = Reference divider ratio | ||
1809 | Fnom = Nominal VCO output frequency = Fref * NF / NR | ||
1810 | Fs = Spreading Rate | ||
1811 | D = Percentage down-spread / 2 | ||
1812 | Fint = Reference input frequency to PFD = Fref / NR | ||
1813 | NS = Spreading rate divider ratio = int(Fint / (2 * Fs)) | ||
1814 | CLKS = NS - 1 = ISS_STEP_NUM[11:0] | ||
1815 | NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2) | ||
1816 | CLKV = 65536 * NV = ISS_STEP_SIZE[25:0] | ||
1817 | ************************************* | ||
1818 | */ | ||
1819 | pp_atomctrl_internal_ss_info ss_info; | ||
1820 | uint32_t freq_nom; | ||
1821 | uint32_t tmp; | ||
1822 | uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr); | ||
1823 | |||
1824 | /* for GDDR5 for all modes and DDR3 */ | ||
1825 | if (1 == mpll_param.qdr) | ||
1826 | freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider); | ||
1827 | else | ||
1828 | freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider); | ||
1829 | |||
1830 | /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2 Note: S.I. reference_divider = 1*/ | ||
1831 | tmp = (freq_nom / reference_clock); | ||
1832 | tmp = tmp * tmp; | ||
1833 | |||
1834 | if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) { | ||
1835 | /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */ | ||
1836 | /* ss.Info.speed_spectrum_rate -- in unit of khz */ | ||
1837 | /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */ | ||
1838 | /* = reference_clock * 5 / speed_spectrum_rate */ | ||
1839 | uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate; | ||
1840 | |||
1841 | /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */ | ||
1842 | /* = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */ | ||
1843 | uint32_t clkv = | ||
1844 | (uint32_t)((((131 * ss_info.speed_spectrum_percentage * | ||
1845 | ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom); | ||
1846 | |||
1847 | mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv); | ||
1848 | mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks); | ||
1849 | } | ||
1850 | } | ||
1851 | |||
1852 | /* MCLK_PWRMGT_CNTL setup */ | ||
1853 | mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl, | ||
1854 | MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed); | ||
1855 | mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl, | ||
1856 | MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn); | ||
1857 | mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl, | ||
1858 | MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn); | ||
1859 | |||
1860 | |||
1861 | /* Save the result data to outpupt memory level structure */ | ||
1862 | mclk->MclkFrequency = memory_clock; | ||
1863 | mclk->MpllFuncCntl = mpll_func_cntl; | ||
1864 | mclk->MpllFuncCntl_1 = mpll_func_cntl_1; | ||
1865 | mclk->MpllFuncCntl_2 = mpll_func_cntl_2; | ||
1866 | mclk->MpllAdFuncCntl = mpll_ad_func_cntl; | ||
1867 | mclk->MpllDqFuncCntl = mpll_dq_func_cntl; | ||
1868 | mclk->MclkPwrmgtCntl = mclk_pwrmgt_cntl; | ||
1869 | mclk->DllCntl = dll_cntl; | ||
1870 | mclk->MpllSs1 = mpll_ss1; | ||
1871 | mclk->MpllSs2 = mpll_ss2; | ||
1872 | |||
1873 | return 0; | ||
1874 | } | ||
1875 | |||
1876 | static int iceland_populate_single_memory_level( | ||
1877 | struct pp_hwmgr *hwmgr, | ||
1878 | uint32_t memory_clock, | ||
1879 | SMU71_Discrete_MemoryLevel *memory_level | ||
1880 | ) | ||
1881 | { | ||
1882 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
1883 | int result = 0; | ||
1884 | bool dllStateOn; | ||
1885 | struct cgs_display_info info = {0}; | ||
1886 | |||
1887 | |||
1888 | if (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) { | ||
1889 | result = iceland_get_dependecy_volt_by_clk(hwmgr, | ||
1890 | hwmgr->dyn_state.vddc_dependency_on_mclk, memory_clock, &memory_level->MinVddc); | ||
1891 | PP_ASSERT_WITH_CODE((0 == result), | ||
1892 | "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result); | ||
1893 | } | ||
1894 | |||
1895 | if (data->vdd_ci_control == ICELAND_VOLTAGE_CONTROL_NONE) { | ||
1896 | memory_level->MinVddci = memory_level->MinVddc; | ||
1897 | } else if (NULL != hwmgr->dyn_state.vddci_dependency_on_mclk) { | ||
1898 | result = iceland_get_dependecy_volt_by_clk(hwmgr, | ||
1899 | hwmgr->dyn_state.vddci_dependency_on_mclk, | ||
1900 | memory_clock, | ||
1901 | &memory_level->MinVddci); | ||
1902 | PP_ASSERT_WITH_CODE((0 == result), | ||
1903 | "can not find MinVddci voltage value from memory VDDCI voltage dependency table", return result); | ||
1904 | } | ||
1905 | |||
1906 | if (NULL != hwmgr->dyn_state.mvdd_dependency_on_mclk) { | ||
1907 | result = iceland_get_dependecy_volt_by_clk(hwmgr, | ||
1908 | hwmgr->dyn_state.mvdd_dependency_on_mclk, memory_clock, &memory_level->MinMvdd); | ||
1909 | PP_ASSERT_WITH_CODE((0 == result), | ||
1910 | "can not find MinMVDD voltage value from memory MVDD voltage dependency table", return result); | ||
1911 | } | ||
1912 | |||
1913 | memory_level->MinVddcPhases = 1; | ||
1914 | |||
1915 | if (data->vddc_phase_shed_control) { | ||
1916 | iceland_populate_phase_value_based_on_mclk(hwmgr, hwmgr->dyn_state.vddc_phase_shed_limits_table, | ||
1917 | memory_clock, &memory_level->MinVddcPhases); | ||
1918 | } | ||
1919 | |||
1920 | memory_level->EnabledForThrottle = 1; | ||
1921 | memory_level->EnabledForActivity = 1; | ||
1922 | memory_level->UpHyst = 0; | ||
1923 | memory_level->DownHyst = 100; | ||
1924 | memory_level->VoltageDownHyst = 0; | ||
1925 | |||
1926 | /* Indicates maximum activity level for this performance level.*/ | ||
1927 | memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target; | ||
1928 | memory_level->StutterEnable = 0; | ||
1929 | memory_level->StrobeEnable = 0; | ||
1930 | memory_level->EdcReadEnable = 0; | ||
1931 | memory_level->EdcWriteEnable = 0; | ||
1932 | memory_level->RttEnable = 0; | ||
1933 | |||
1934 | /* default set to low watermark. Highest level will be set to high later.*/ | ||
1935 | memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; | ||
1936 | |||
1937 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
1938 | data->display_timing.num_existing_displays = info.display_count; | ||
1939 | |||
1940 | //if ((data->mclk_stutter_mode_threshold != 0) && | ||
1941 | // (memory_clock <= data->mclk_stutter_mode_threshold) && | ||
1942 | // (data->is_uvd_enabled == 0) | ||
1943 | // && (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL, STUTTER_ENABLE) & 0x1) | ||
1944 | // && (data->display_timing.num_existing_displays <= 2) | ||
1945 | // && (data->display_timing.num_existing_displays != 0)) | ||
1946 | // memory_level->StutterEnable = 1; | ||
1947 | |||
1948 | /* decide strobe mode*/ | ||
1949 | memory_level->StrobeEnable = (data->mclk_strobe_mode_threshold != 0) && | ||
1950 | (memory_clock <= data->mclk_strobe_mode_threshold); | ||
1951 | |||
1952 | /* decide EDC mode and memory clock ratio*/ | ||
1953 | if (data->is_memory_GDDR5) { | ||
1954 | memory_level->StrobeRatio = iceland_get_mclk_frequency_ratio(memory_clock, | ||
1955 | memory_level->StrobeEnable); | ||
1956 | |||
1957 | if ((data->mclk_edc_enable_threshold != 0) && | ||
1958 | (memory_clock > data->mclk_edc_enable_threshold)) { | ||
1959 | memory_level->EdcReadEnable = 1; | ||
1960 | } | ||
1961 | |||
1962 | if ((data->mclk_edc_wr_enable_threshold != 0) && | ||
1963 | (memory_clock > data->mclk_edc_wr_enable_threshold)) { | ||
1964 | memory_level->EdcWriteEnable = 1; | ||
1965 | } | ||
1966 | |||
1967 | if (memory_level->StrobeEnable) { | ||
1968 | if (iceland_get_mclk_frequency_ratio(memory_clock, 1) >= | ||
1969 | ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf)) { | ||
1970 | dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0; | ||
1971 | } else { | ||
1972 | dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0; | ||
1973 | } | ||
1974 | |||
1975 | } else { | ||
1976 | dllStateOn = data->dll_defaule_on; | ||
1977 | } | ||
1978 | } else { | ||
1979 | memory_level->StrobeRatio = | ||
1980 | iceland_get_ddr3_mclk_frequency_ratio(memory_clock); | ||
1981 | dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0; | ||
1982 | } | ||
1983 | |||
1984 | result = iceland_calculate_mclk_params(hwmgr, | ||
1985 | memory_clock, memory_level, memory_level->StrobeEnable, dllStateOn); | ||
1986 | |||
1987 | if (0 == result) { | ||
1988 | memory_level->MinVddc = PP_HOST_TO_SMC_UL(memory_level->MinVddc * VOLTAGE_SCALE); | ||
1989 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinVddcPhases); | ||
1990 | memory_level->MinVddci = PP_HOST_TO_SMC_UL(memory_level->MinVddci * VOLTAGE_SCALE); | ||
1991 | memory_level->MinMvdd = PP_HOST_TO_SMC_UL(memory_level->MinMvdd * VOLTAGE_SCALE); | ||
1992 | /* MCLK frequency in units of 10KHz*/ | ||
1993 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency); | ||
1994 | /* Indicates maximum activity level for this performance level.*/ | ||
1995 | CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel); | ||
1996 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl); | ||
1997 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1); | ||
1998 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2); | ||
1999 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl); | ||
2000 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl); | ||
2001 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl); | ||
2002 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl); | ||
2003 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1); | ||
2004 | CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2); | ||
2005 | } | ||
2006 | |||
2007 | return result; | ||
2008 | } | ||
2009 | |||
2010 | /** | ||
2011 | * Populates the SMC MVDD structure using the provided memory clock. | ||
2012 | * | ||
2013 | * @param hwmgr the address of the hardware manager | ||
2014 | * @param mclk the MCLK value to be used in the decision if MVDD should be high or low. | ||
2015 | * @param voltage the SMC VOLTAGE structure to be populated | ||
2016 | */ | ||
2017 | int iceland_populate_mvdd_value(struct pp_hwmgr *hwmgr, uint32_t mclk, SMU71_Discrete_VoltageLevel *voltage) | ||
2018 | { | ||
2019 | const iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2020 | uint32_t i = 0; | ||
2021 | |||
2022 | if (ICELAND_VOLTAGE_CONTROL_NONE != data->mvdd_control) { | ||
2023 | /* find mvdd value which clock is more than request */ | ||
2024 | for (i = 0; i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count; i++) { | ||
2025 | if (mclk <= hwmgr->dyn_state.mvdd_dependency_on_mclk->entries[i].clk) { | ||
2026 | /* Always round to higher voltage. */ | ||
2027 | voltage->Voltage = data->mvdd_voltage_table.entries[i].value; | ||
2028 | break; | ||
2029 | } | ||
2030 | } | ||
2031 | |||
2032 | PP_ASSERT_WITH_CODE(i < hwmgr->dyn_state.mvdd_dependency_on_mclk->count, | ||
2033 | "MVDD Voltage is outside the supported range.", return -1); | ||
2034 | |||
2035 | } else { | ||
2036 | return -1; | ||
2037 | } | ||
2038 | |||
2039 | return 0; | ||
2040 | } | ||
2041 | |||
2042 | |||
2043 | static int iceland_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, | ||
2044 | SMU71_Discrete_DpmTable *table) | ||
2045 | { | ||
2046 | int result = 0; | ||
2047 | const iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2048 | pp_atomctrl_clock_dividers_vi dividers; | ||
2049 | SMU71_Discrete_VoltageLevel voltage_level; | ||
2050 | uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL; | ||
2051 | uint32_t spll_func_cntl_2 = data->clock_registers.vCG_SPLL_FUNC_CNTL_2; | ||
2052 | uint32_t dll_cntl = data->clock_registers.vDLL_CNTL; | ||
2053 | uint32_t mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL; | ||
2054 | |||
2055 | /* The ACPI state should not do DPM on DC (or ever).*/ | ||
2056 | table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC; | ||
2057 | |||
2058 | if (data->acpi_vddc) | ||
2059 | table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->acpi_vddc * VOLTAGE_SCALE); | ||
2060 | else | ||
2061 | table->ACPILevel.MinVddc = PP_HOST_TO_SMC_UL(data->min_vddc_in_pp_table * VOLTAGE_SCALE); | ||
2062 | |||
2063 | table->ACPILevel.MinVddcPhases = (data->vddc_phase_shed_control) ? 0 : 1; | ||
2064 | |||
2065 | /* assign zero for now*/ | ||
2066 | table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr); | ||
2067 | |||
2068 | /* get the engine clock dividers for this clock value*/ | ||
2069 | result = atomctrl_get_engine_pll_dividers_vi(hwmgr, | ||
2070 | table->ACPILevel.SclkFrequency, ÷rs); | ||
2071 | |||
2072 | PP_ASSERT_WITH_CODE(result == 0, | ||
2073 | "Error retrieving Engine Clock dividers from VBIOS.", return result); | ||
2074 | |||
2075 | /* divider ID for required SCLK*/ | ||
2076 | table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider; | ||
2077 | table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; | ||
2078 | table->ACPILevel.DeepSleepDivId = 0; | ||
2079 | |||
2080 | spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, | ||
2081 | CG_SPLL_FUNC_CNTL, SPLL_PWRON, 0); | ||
2082 | spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, | ||
2083 | CG_SPLL_FUNC_CNTL, SPLL_RESET, 1); | ||
2084 | spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, | ||
2085 | CG_SPLL_FUNC_CNTL_2, SCLK_MUX_SEL, 4); | ||
2086 | |||
2087 | table->ACPILevel.CgSpllFuncCntl = spll_func_cntl; | ||
2088 | table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2; | ||
2089 | table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3; | ||
2090 | table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4; | ||
2091 | table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM; | ||
2092 | table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2; | ||
2093 | table->ACPILevel.CcPwrDynRm = 0; | ||
2094 | table->ACPILevel.CcPwrDynRm1 = 0; | ||
2095 | |||
2096 | |||
2097 | /* For various features to be enabled/disabled while this level is active.*/ | ||
2098 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags); | ||
2099 | /* SCLK frequency in units of 10KHz*/ | ||
2100 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency); | ||
2101 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl); | ||
2102 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2); | ||
2103 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3); | ||
2104 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4); | ||
2105 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum); | ||
2106 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2); | ||
2107 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm); | ||
2108 | CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1); | ||
2109 | |||
2110 | table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc; | ||
2111 | table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases; | ||
2112 | |||
2113 | /* CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/ | ||
2114 | |||
2115 | if (0 == iceland_populate_mvdd_value(hwmgr, 0, &voltage_level)) | ||
2116 | table->MemoryACPILevel.MinMvdd = | ||
2117 | PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE); | ||
2118 | else | ||
2119 | table->MemoryACPILevel.MinMvdd = 0; | ||
2120 | |||
2121 | /* Force reset on DLL*/ | ||
2122 | mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl, | ||
2123 | MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1); | ||
2124 | mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl, | ||
2125 | MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1); | ||
2126 | |||
2127 | /* Disable DLL in ACPIState*/ | ||
2128 | mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl, | ||
2129 | MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0); | ||
2130 | mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl, | ||
2131 | MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0); | ||
2132 | |||
2133 | /* Enable DLL bypass signal*/ | ||
2134 | dll_cntl = PHM_SET_FIELD(dll_cntl, | ||
2135 | DLL_CNTL, MRDCK0_BYPASS, 0); | ||
2136 | dll_cntl = PHM_SET_FIELD(dll_cntl, | ||
2137 | DLL_CNTL, MRDCK1_BYPASS, 0); | ||
2138 | |||
2139 | table->MemoryACPILevel.DllCntl = | ||
2140 | PP_HOST_TO_SMC_UL(dll_cntl); | ||
2141 | table->MemoryACPILevel.MclkPwrmgtCntl = | ||
2142 | PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl); | ||
2143 | table->MemoryACPILevel.MpllAdFuncCntl = | ||
2144 | PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL); | ||
2145 | table->MemoryACPILevel.MpllDqFuncCntl = | ||
2146 | PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL); | ||
2147 | table->MemoryACPILevel.MpllFuncCntl = | ||
2148 | PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL); | ||
2149 | table->MemoryACPILevel.MpllFuncCntl_1 = | ||
2150 | PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1); | ||
2151 | table->MemoryACPILevel.MpllFuncCntl_2 = | ||
2152 | PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2); | ||
2153 | table->MemoryACPILevel.MpllSs1 = | ||
2154 | PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1); | ||
2155 | table->MemoryACPILevel.MpllSs2 = | ||
2156 | PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2); | ||
2157 | |||
2158 | table->MemoryACPILevel.EnabledForThrottle = 0; | ||
2159 | table->MemoryACPILevel.EnabledForActivity = 0; | ||
2160 | table->MemoryACPILevel.UpHyst = 0; | ||
2161 | table->MemoryACPILevel.DownHyst = 100; | ||
2162 | table->MemoryACPILevel.VoltageDownHyst = 0; | ||
2163 | /* Indicates maximum activity level for this performance level.*/ | ||
2164 | table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); | ||
2165 | |||
2166 | table->MemoryACPILevel.StutterEnable = 0; | ||
2167 | table->MemoryACPILevel.StrobeEnable = 0; | ||
2168 | table->MemoryACPILevel.EdcReadEnable = 0; | ||
2169 | table->MemoryACPILevel.EdcWriteEnable = 0; | ||
2170 | table->MemoryACPILevel.RttEnable = 0; | ||
2171 | |||
2172 | return result; | ||
2173 | } | ||
2174 | |||
2175 | static int iceland_find_boot_level(struct iceland_single_dpm_table *table, uint32_t value, uint32_t *boot_level) | ||
2176 | { | ||
2177 | int result = 0; | ||
2178 | uint32_t i; | ||
2179 | |||
2180 | for (i = 0; i < table->count; i++) { | ||
2181 | if (value == table->dpm_levels[i].value) { | ||
2182 | *boot_level = i; | ||
2183 | result = 0; | ||
2184 | } | ||
2185 | } | ||
2186 | return result; | ||
2187 | } | ||
2188 | |||
2189 | /** | ||
2190 | * Calculates the SCLK dividers using the provided engine clock | ||
2191 | * | ||
2192 | * @param hwmgr the address of the hardware manager | ||
2193 | * @param engine_clock the engine clock to use to populate the structure | ||
2194 | * @param sclk the SMC SCLK structure to be populated | ||
2195 | */ | ||
2196 | int iceland_calculate_sclk_params(struct pp_hwmgr *hwmgr, | ||
2197 | uint32_t engine_clock, SMU71_Discrete_GraphicsLevel *sclk) | ||
2198 | { | ||
2199 | const iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2200 | pp_atomctrl_clock_dividers_vi dividers; | ||
2201 | uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL; | ||
2202 | uint32_t spll_func_cntl_3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3; | ||
2203 | uint32_t spll_func_cntl_4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4; | ||
2204 | uint32_t cg_spll_spread_spectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM; | ||
2205 | uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2; | ||
2206 | uint32_t reference_clock; | ||
2207 | uint32_t reference_divider; | ||
2208 | uint32_t fbdiv; | ||
2209 | int result; | ||
2210 | |||
2211 | /* get the engine clock dividers for this clock value*/ | ||
2212 | result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock, ÷rs); | ||
2213 | |||
2214 | PP_ASSERT_WITH_CODE(result == 0, | ||
2215 | "Error retrieving Engine Clock dividers from VBIOS.", return result); | ||
2216 | |||
2217 | /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/ | ||
2218 | reference_clock = atomctrl_get_reference_clock(hwmgr); | ||
2219 | |||
2220 | reference_divider = 1 + dividers.uc_pll_ref_div; | ||
2221 | |||
2222 | /* low 14 bits is fraction and high 12 bits is divider*/ | ||
2223 | fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF; | ||
2224 | |||
2225 | /* SPLL_FUNC_CNTL setup*/ | ||
2226 | spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, | ||
2227 | CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div); | ||
2228 | spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, | ||
2229 | CG_SPLL_FUNC_CNTL, SPLL_PDIV_A, dividers.uc_pll_post_div); | ||
2230 | |||
2231 | /* SPLL_FUNC_CNTL_3 setup*/ | ||
2232 | spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, | ||
2233 | CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv); | ||
2234 | |||
2235 | /* set to use fractional accumulation*/ | ||
2236 | spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, | ||
2237 | CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1); | ||
2238 | |||
2239 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2240 | PHM_PlatformCaps_EngineSpreadSpectrumSupport)) { | ||
2241 | pp_atomctrl_internal_ss_info ss_info; | ||
2242 | |||
2243 | uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div; | ||
2244 | if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) { | ||
2245 | /* | ||
2246 | * ss_info.speed_spectrum_percentage -- in unit of 0.01% | ||
2247 | * ss_info.speed_spectrum_rate -- in unit of khz | ||
2248 | */ | ||
2249 | /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */ | ||
2250 | uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate); | ||
2251 | |||
2252 | /* clkv = 2 * D * fbdiv / NS */ | ||
2253 | uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000); | ||
2254 | |||
2255 | cg_spll_spread_spectrum = | ||
2256 | PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS); | ||
2257 | cg_spll_spread_spectrum = | ||
2258 | PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1); | ||
2259 | cg_spll_spread_spectrum_2 = | ||
2260 | PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV); | ||
2261 | } | ||
2262 | } | ||
2263 | |||
2264 | sclk->SclkFrequency = engine_clock; | ||
2265 | sclk->CgSpllFuncCntl3 = spll_func_cntl_3; | ||
2266 | sclk->CgSpllFuncCntl4 = spll_func_cntl_4; | ||
2267 | sclk->SpllSpreadSpectrum = cg_spll_spread_spectrum; | ||
2268 | sclk->SpllSpreadSpectrum2 = cg_spll_spread_spectrum_2; | ||
2269 | sclk->SclkDid = (uint8_t)dividers.pll_post_divider; | ||
2270 | |||
2271 | return 0; | ||
2272 | } | ||
2273 | |||
2274 | static uint8_t iceland_get_sleep_divider_id_from_clock(struct pp_hwmgr *hwmgr, | ||
2275 | uint32_t engine_clock, uint32_t min_engine_clock_in_sr) | ||
2276 | { | ||
2277 | uint32_t i, temp; | ||
2278 | uint32_t min = (min_engine_clock_in_sr > ICELAND_MINIMUM_ENGINE_CLOCK) ? | ||
2279 | min_engine_clock_in_sr : ICELAND_MINIMUM_ENGINE_CLOCK; | ||
2280 | |||
2281 | PP_ASSERT_WITH_CODE((engine_clock >= min), | ||
2282 | "Engine clock can't satisfy stutter requirement!", return 0); | ||
2283 | |||
2284 | for (i = ICELAND_MAX_DEEPSLEEP_DIVIDER_ID;; i--) { | ||
2285 | temp = engine_clock / (1 << i); | ||
2286 | |||
2287 | if(temp >= min || i == 0) | ||
2288 | break; | ||
2289 | } | ||
2290 | return (uint8_t)i; | ||
2291 | } | ||
2292 | |||
2293 | /** | ||
2294 | * Populates single SMC SCLK structure using the provided engine clock | ||
2295 | * | ||
2296 | * @param hwmgr the address of the hardware manager | ||
2297 | * @param engine_clock the engine clock to use to populate the structure | ||
2298 | * @param sclk the SMC SCLK structure to be populated | ||
2299 | */ | ||
2300 | static int iceland_populate_single_graphic_level(struct pp_hwmgr *hwmgr, | ||
2301 | uint32_t engine_clock, uint16_t sclk_activity_level_threshold, | ||
2302 | SMU71_Discrete_GraphicsLevel *graphic_level) | ||
2303 | { | ||
2304 | int result; | ||
2305 | uint32_t threshold; | ||
2306 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2307 | |||
2308 | result = iceland_calculate_sclk_params(hwmgr, engine_clock, graphic_level); | ||
2309 | |||
2310 | |||
2311 | /* populate graphics levels*/ | ||
2312 | result = iceland_get_dependecy_volt_by_clk(hwmgr, | ||
2313 | hwmgr->dyn_state.vddc_dependency_on_sclk, engine_clock, &graphic_level->MinVddc); | ||
2314 | PP_ASSERT_WITH_CODE((0 == result), | ||
2315 | "can not find VDDC voltage value for VDDC engine clock dependency table", return result); | ||
2316 | |||
2317 | /* SCLK frequency in units of 10KHz*/ | ||
2318 | graphic_level->SclkFrequency = engine_clock; | ||
2319 | |||
2320 | /* | ||
2321 | * Minimum VDDC phases required to support this level, it | ||
2322 | * should get from dependence table. | ||
2323 | */ | ||
2324 | graphic_level->MinVddcPhases = 1; | ||
2325 | |||
2326 | if (data->vddc_phase_shed_control) { | ||
2327 | iceland_populate_phase_value_based_on_sclk(hwmgr, | ||
2328 | hwmgr->dyn_state.vddc_phase_shed_limits_table, | ||
2329 | engine_clock, | ||
2330 | &graphic_level->MinVddcPhases); | ||
2331 | } | ||
2332 | |||
2333 | /* Indicates maximum activity level for this performance level. 50% for now*/ | ||
2334 | graphic_level->ActivityLevel = sclk_activity_level_threshold; | ||
2335 | |||
2336 | graphic_level->CcPwrDynRm = 0; | ||
2337 | graphic_level->CcPwrDynRm1 = 0; | ||
2338 | /* this level can be used if activity is high enough.*/ | ||
2339 | graphic_level->EnabledForActivity = 1; | ||
2340 | /* this level can be used for throttling.*/ | ||
2341 | graphic_level->EnabledForThrottle = 1; | ||
2342 | graphic_level->UpHyst = 0; | ||
2343 | graphic_level->DownHyst = 100; | ||
2344 | graphic_level->VoltageDownHyst = 0; | ||
2345 | graphic_level->PowerThrottle = 0; | ||
2346 | |||
2347 | threshold = engine_clock * data->fast_watermark_threshold / 100; | ||
2348 | |||
2349 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2350 | PHM_PlatformCaps_SclkDeepSleep)) { | ||
2351 | graphic_level->DeepSleepDivId = | ||
2352 | iceland_get_sleep_divider_id_from_clock(hwmgr, engine_clock, | ||
2353 | data->display_timing.min_clock_insr); | ||
2354 | } | ||
2355 | |||
2356 | /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/ | ||
2357 | graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; | ||
2358 | |||
2359 | if (0 == result) { | ||
2360 | graphic_level->MinVddc = PP_HOST_TO_SMC_UL(graphic_level->MinVddc * VOLTAGE_SCALE); | ||
2361 | /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/ | ||
2362 | CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases); | ||
2363 | CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency); | ||
2364 | CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel); | ||
2365 | CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3); | ||
2366 | CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4); | ||
2367 | CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum); | ||
2368 | CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2); | ||
2369 | CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm); | ||
2370 | CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1); | ||
2371 | } | ||
2372 | |||
2373 | return result; | ||
2374 | } | ||
2375 | |||
2376 | /** | ||
2377 | * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states | ||
2378 | * | ||
2379 | * @param hwmgr the address of the hardware manager | ||
2380 | */ | ||
2381 | static int iceland_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) | ||
2382 | { | ||
2383 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2384 | struct iceland_dpm_table *dpm_table = &data->dpm_table; | ||
2385 | int result = 0; | ||
2386 | uint32_t level_array_adress = data->dpm_table_start + | ||
2387 | offsetof(SMU71_Discrete_DpmTable, GraphicsLevel); | ||
2388 | |||
2389 | uint32_t level_array_size = sizeof(SMU71_Discrete_GraphicsLevel) * SMU71_MAX_LEVELS_GRAPHICS; | ||
2390 | SMU71_Discrete_GraphicsLevel *levels = data->smc_state_table.GraphicsLevel; | ||
2391 | uint32_t i; | ||
2392 | uint8_t highest_pcie_level_enabled = 0, lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0, count = 0; | ||
2393 | memset(levels, 0x00, level_array_size); | ||
2394 | |||
2395 | for (i = 0; i < dpm_table->sclk_table.count; i++) { | ||
2396 | result = iceland_populate_single_graphic_level(hwmgr, | ||
2397 | dpm_table->sclk_table.dpm_levels[i].value, | ||
2398 | (uint16_t)data->activity_target[i], | ||
2399 | &(data->smc_state_table.GraphicsLevel[i])); | ||
2400 | if (0 != result) | ||
2401 | return result; | ||
2402 | |||
2403 | /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */ | ||
2404 | if (i > 1) | ||
2405 | data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0; | ||
2406 | } | ||
2407 | |||
2408 | /* set highest level watermark to high */ | ||
2409 | if (dpm_table->sclk_table.count > 1) | ||
2410 | data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark = | ||
2411 | PPSMC_DISPLAY_WATERMARK_HIGH; | ||
2412 | |||
2413 | data->smc_state_table.GraphicsDpmLevelCount = | ||
2414 | (uint8_t)dpm_table->sclk_table.count; | ||
2415 | data->dpm_level_enable_mask.sclk_dpm_enable_mask = | ||
2416 | iceland_get_dpm_level_enable_mask_value(&dpm_table->sclk_table); | ||
2417 | |||
2418 | while ((data->dpm_level_enable_mask.pcie_dpm_enable_mask & | ||
2419 | (1 << (highest_pcie_level_enabled + 1))) != 0) { | ||
2420 | highest_pcie_level_enabled++; | ||
2421 | } | ||
2422 | |||
2423 | while ((data->dpm_level_enable_mask.pcie_dpm_enable_mask & | ||
2424 | (1 << lowest_pcie_level_enabled)) == 0) { | ||
2425 | lowest_pcie_level_enabled++; | ||
2426 | } | ||
2427 | |||
2428 | while ((count < highest_pcie_level_enabled) && | ||
2429 | ((data->dpm_level_enable_mask.pcie_dpm_enable_mask & | ||
2430 | (1 << (lowest_pcie_level_enabled + 1 + count))) == 0)) { | ||
2431 | count++; | ||
2432 | } | ||
2433 | |||
2434 | mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ? | ||
2435 | (lowest_pcie_level_enabled + 1 + count) : highest_pcie_level_enabled; | ||
2436 | |||
2437 | /* set pcieDpmLevel to highest_pcie_level_enabled*/ | ||
2438 | for (i = 2; i < dpm_table->sclk_table.count; i++) { | ||
2439 | data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled; | ||
2440 | } | ||
2441 | |||
2442 | /* set pcieDpmLevel to lowest_pcie_level_enabled*/ | ||
2443 | data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled; | ||
2444 | |||
2445 | /* set pcieDpmLevel to mid_pcie_level_enabled*/ | ||
2446 | data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled; | ||
2447 | |||
2448 | /* level count will send to smc once at init smc table and never change*/ | ||
2449 | result = iceland_copy_bytes_to_smc(hwmgr->smumgr, level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end); | ||
2450 | |||
2451 | if (0 != result) | ||
2452 | return result; | ||
2453 | |||
2454 | return 0; | ||
2455 | } | ||
2456 | |||
2457 | /** | ||
2458 | * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states | ||
2459 | * | ||
2460 | * @param hwmgr the address of the hardware manager | ||
2461 | */ | ||
2462 | |||
2463 | static int iceland_populate_all_memory_levels(struct pp_hwmgr *hwmgr) | ||
2464 | { | ||
2465 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2466 | struct iceland_dpm_table *dpm_table = &data->dpm_table; | ||
2467 | int result; | ||
2468 | /* populate MCLK dpm table to SMU7 */ | ||
2469 | uint32_t level_array_adress = data->dpm_table_start + offsetof(SMU71_Discrete_DpmTable, MemoryLevel); | ||
2470 | uint32_t level_array_size = sizeof(SMU71_Discrete_MemoryLevel) * SMU71_MAX_LEVELS_MEMORY; | ||
2471 | SMU71_Discrete_MemoryLevel *levels = data->smc_state_table.MemoryLevel; | ||
2472 | uint32_t i; | ||
2473 | |||
2474 | memset(levels, 0x00, level_array_size); | ||
2475 | |||
2476 | for (i = 0; i < dpm_table->mclk_table.count; i++) { | ||
2477 | PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value), | ||
2478 | "can not populate memory level as memory clock is zero", return -1); | ||
2479 | result = iceland_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value, | ||
2480 | &(data->smc_state_table.MemoryLevel[i])); | ||
2481 | if (0 != result) { | ||
2482 | return result; | ||
2483 | } | ||
2484 | } | ||
2485 | |||
2486 | /* Only enable level 0 for now.*/ | ||
2487 | data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; | ||
2488 | |||
2489 | /* | ||
2490 | * in order to prevent MC activity from stutter mode to push DPM up. | ||
2491 | * the UVD change complements this by putting the MCLK in a higher state | ||
2492 | * by default such that we are not effected by up threshold or and MCLK DPM latency. | ||
2493 | */ | ||
2494 | data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F; | ||
2495 | CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.MemoryLevel[0].ActivityLevel); | ||
2496 | |||
2497 | data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count; | ||
2498 | data->dpm_level_enable_mask.mclk_dpm_enable_mask = iceland_get_dpm_level_enable_mask_value(&dpm_table->mclk_table); | ||
2499 | /* set highest level watermark to high*/ | ||
2500 | data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; | ||
2501 | |||
2502 | /* level count will send to smc once at init smc table and never change*/ | ||
2503 | result = iceland_copy_bytes_to_smc(hwmgr->smumgr, | ||
2504 | level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end); | ||
2505 | |||
2506 | if (0 != result) { | ||
2507 | return result; | ||
2508 | } | ||
2509 | |||
2510 | return 0; | ||
2511 | } | ||
2512 | |||
2513 | struct ICELAND_DLL_SPEED_SETTING | ||
2514 | { | ||
2515 | uint16_t Min; /* Minimum Data Rate*/ | ||
2516 | uint16_t Max; /* Maximum Data Rate*/ | ||
2517 | uint32_t dll_speed; /* The desired DLL_SPEED setting*/ | ||
2518 | }; | ||
2519 | |||
2520 | static int iceland_populate_ulv_level(struct pp_hwmgr *hwmgr, SMU71_Discrete_Ulv *pstate) | ||
2521 | { | ||
2522 | int result = 0; | ||
2523 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2524 | uint32_t voltage_response_time, ulv_voltage; | ||
2525 | |||
2526 | pstate->CcPwrDynRm = 0; | ||
2527 | pstate->CcPwrDynRm1 = 0; | ||
2528 | |||
2529 | //backbiasResponseTime is use for ULV state voltage value. | ||
2530 | result = pp_tables_get_response_times(hwmgr, &voltage_response_time, &ulv_voltage); | ||
2531 | PP_ASSERT_WITH_CODE((0 == result), "can not get ULV voltage value", return result;); | ||
2532 | |||
2533 | if(!ulv_voltage) { | ||
2534 | data->ulv.ulv_supported = false; | ||
2535 | return 0; | ||
2536 | } | ||
2537 | |||
2538 | if (ICELAND_VOLTAGE_CONTROL_BY_SVID2 != data->voltage_control) { | ||
2539 | /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */ | ||
2540 | if (ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v) { | ||
2541 | pstate->VddcOffset = 0; | ||
2542 | } | ||
2543 | else { | ||
2544 | /* used in SMIO Mode. not implemented for now. this is backup only for CI. */ | ||
2545 | pstate->VddcOffset = (uint16_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage); | ||
2546 | } | ||
2547 | } else { | ||
2548 | /* use minimum voltage if ulv voltage in pptable is bigger than minimum voltage */ | ||
2549 | if(ulv_voltage > hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v) { | ||
2550 | pstate->VddcOffsetVid = 0; | ||
2551 | } else { | ||
2552 | /* used in SVI2 Mode */ | ||
2553 | pstate->VddcOffsetVid = (uint8_t)((hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].v - ulv_voltage) * VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1); | ||
2554 | } | ||
2555 | } | ||
2556 | |||
2557 | /* used in SVI2 Mode to shed phase */ | ||
2558 | pstate->VddcPhase = (data->vddc_phase_shed_control) ? 0 : 1; | ||
2559 | |||
2560 | if (0 == result) { | ||
2561 | CONVERT_FROM_HOST_TO_SMC_UL(pstate->CcPwrDynRm); | ||
2562 | CONVERT_FROM_HOST_TO_SMC_UL(pstate->CcPwrDynRm1); | ||
2563 | CONVERT_FROM_HOST_TO_SMC_US(pstate->VddcOffset); | ||
2564 | } | ||
2565 | |||
2566 | return result; | ||
2567 | } | ||
2568 | |||
2569 | static int iceland_populate_ulv_state(struct pp_hwmgr *hwmgr, SMU71_Discrete_Ulv *ulv) | ||
2570 | { | ||
2571 | return iceland_populate_ulv_level(hwmgr, ulv); | ||
2572 | } | ||
2573 | |||
2574 | static int iceland_populate_smc_initial_state(struct pp_hwmgr *hwmgr) | ||
2575 | { | ||
2576 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2577 | uint8_t count, level; | ||
2578 | |||
2579 | count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_sclk->count); | ||
2580 | |||
2581 | for (level = 0; level < count; level++) { | ||
2582 | if (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[level].clk | ||
2583 | >= data->vbios_boot_state.sclk_bootup_value) { | ||
2584 | data->smc_state_table.GraphicsBootLevel = level; | ||
2585 | break; | ||
2586 | } | ||
2587 | } | ||
2588 | |||
2589 | count = (uint8_t)(hwmgr->dyn_state.vddc_dependency_on_mclk->count); | ||
2590 | |||
2591 | for (level = 0; level < count; level++) { | ||
2592 | if (hwmgr->dyn_state.vddc_dependency_on_mclk->entries[level].clk | ||
2593 | >= data->vbios_boot_state.mclk_bootup_value) { | ||
2594 | data->smc_state_table.MemoryBootLevel = level; | ||
2595 | break; | ||
2596 | } | ||
2597 | } | ||
2598 | |||
2599 | return 0; | ||
2600 | } | ||
2601 | |||
2602 | /** | ||
2603 | * Initializes the SMC table and uploads it | ||
2604 | * | ||
2605 | * @param hwmgr the address of the powerplay hardware manager. | ||
2606 | * @param pInput the pointer to input data (PowerState) | ||
2607 | * @return always 0 | ||
2608 | */ | ||
2609 | int iceland_init_smc_table(struct pp_hwmgr *hwmgr) | ||
2610 | { | ||
2611 | int result; | ||
2612 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2613 | SMU71_Discrete_DpmTable *table = &(data->smc_state_table); | ||
2614 | const struct phw_iceland_ulv_parm *ulv = &(data->ulv); | ||
2615 | |||
2616 | result = iceland_setup_default_dpm_tables(hwmgr); | ||
2617 | PP_ASSERT_WITH_CODE(0 == result, | ||
2618 | "Failed to setup default DPM tables!", return result;); | ||
2619 | memset(&(data->smc_state_table), 0x00, sizeof(data->smc_state_table)); | ||
2620 | |||
2621 | if (ICELAND_VOLTAGE_CONTROL_NONE != data->voltage_control) { | ||
2622 | iceland_populate_smc_voltage_tables(hwmgr, table); | ||
2623 | } | ||
2624 | |||
2625 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2626 | PHM_PlatformCaps_AutomaticDCTransition)) { | ||
2627 | table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; | ||
2628 | } | ||
2629 | |||
2630 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2631 | PHM_PlatformCaps_StepVddc)) { | ||
2632 | table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; | ||
2633 | } | ||
2634 | |||
2635 | if (data->is_memory_GDDR5) { | ||
2636 | table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5; | ||
2637 | } | ||
2638 | |||
2639 | if (ulv->ulv_supported) { | ||
2640 | result = iceland_populate_ulv_state(hwmgr, &data->ulv_setting); | ||
2641 | PP_ASSERT_WITH_CODE(0 == result, | ||
2642 | "Failed to initialize ULV state!", return result;); | ||
2643 | |||
2644 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
2645 | ixCG_ULV_PARAMETER, ulv->ch_ulv_parameter); | ||
2646 | } | ||
2647 | |||
2648 | result = iceland_populate_smc_link_level(hwmgr, table); | ||
2649 | PP_ASSERT_WITH_CODE(0 == result, | ||
2650 | "Failed to initialize Link Level!", return result;); | ||
2651 | |||
2652 | result = iceland_populate_all_graphic_levels(hwmgr); | ||
2653 | PP_ASSERT_WITH_CODE(0 == result, | ||
2654 | "Failed to initialize Graphics Level!", return result;); | ||
2655 | |||
2656 | result = iceland_populate_all_memory_levels(hwmgr); | ||
2657 | PP_ASSERT_WITH_CODE(0 == result, | ||
2658 | "Failed to initialize Memory Level!", return result;); | ||
2659 | |||
2660 | result = iceland_populate_smc_acpi_level(hwmgr, table); | ||
2661 | PP_ASSERT_WITH_CODE(0 == result, | ||
2662 | "Failed to initialize ACPI Level!", return result;); | ||
2663 | |||
2664 | result = iceland_populate_smc_vce_level(hwmgr, table); | ||
2665 | PP_ASSERT_WITH_CODE(0 == result, | ||
2666 | "Failed to initialize VCE Level!", return result;); | ||
2667 | |||
2668 | result = iceland_populate_smc_acp_level(hwmgr, table); | ||
2669 | PP_ASSERT_WITH_CODE(0 == result, | ||
2670 | "Failed to initialize ACP Level!", return result;); | ||
2671 | |||
2672 | result = iceland_populate_smc_samu_level(hwmgr, table); | ||
2673 | PP_ASSERT_WITH_CODE(0 == result, | ||
2674 | "Failed to initialize SAMU Level!", return result;); | ||
2675 | |||
2676 | /* | ||
2677 | * Since only the initial state is completely set up at this | ||
2678 | * point (the other states are just copies of the boot state) | ||
2679 | * we only need to populate the ARB settings for the initial | ||
2680 | * state. | ||
2681 | */ | ||
2682 | result = iceland_program_memory_timing_parameters(hwmgr); | ||
2683 | PP_ASSERT_WITH_CODE(0 == result, | ||
2684 | "Failed to Write ARB settings for the initial state.", return result;); | ||
2685 | |||
2686 | result = iceland_populate_smc_uvd_level(hwmgr, table); | ||
2687 | PP_ASSERT_WITH_CODE(0 == result, | ||
2688 | "Failed to initialize UVD Level!", return result;); | ||
2689 | |||
2690 | table->GraphicsBootLevel = 0; | ||
2691 | table->MemoryBootLevel = 0; | ||
2692 | |||
2693 | /* find boot level from dpm table */ | ||
2694 | result = iceland_find_boot_level(&(data->dpm_table.sclk_table), | ||
2695 | data->vbios_boot_state.sclk_bootup_value, | ||
2696 | (uint32_t *)&(data->smc_state_table.GraphicsBootLevel)); | ||
2697 | |||
2698 | if (result) | ||
2699 | pr_warning("VBIOS did not find boot engine clock value in dependency table.\n"); | ||
2700 | |||
2701 | result = iceland_find_boot_level(&(data->dpm_table.mclk_table), | ||
2702 | data->vbios_boot_state.mclk_bootup_value, | ||
2703 | (uint32_t *)&(data->smc_state_table.MemoryBootLevel)); | ||
2704 | |||
2705 | if (result) | ||
2706 | pr_warning("VBIOS did not find boot memory clock value in dependency table.\n"); | ||
2707 | |||
2708 | table->BootVddc = data->vbios_boot_state.vddc_bootup_value; | ||
2709 | if (ICELAND_VOLTAGE_CONTROL_NONE == data->vdd_ci_control) { | ||
2710 | table->BootVddci = table->BootVddc; | ||
2711 | } | ||
2712 | else { | ||
2713 | table->BootVddci = data->vbios_boot_state.vddci_bootup_value; | ||
2714 | } | ||
2715 | table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value; | ||
2716 | |||
2717 | result = iceland_populate_smc_initial_state(hwmgr); | ||
2718 | PP_ASSERT_WITH_CODE(0 == result, "Failed to initialize Boot State!", return result); | ||
2719 | |||
2720 | result = iceland_populate_bapm_parameters_in_dpm_table(hwmgr); | ||
2721 | PP_ASSERT_WITH_CODE(0 == result, "Failed to populate BAPM Parameters!", return result); | ||
2722 | |||
2723 | table->GraphicsVoltageChangeEnable = 1; | ||
2724 | table->GraphicsThermThrottleEnable = 1; | ||
2725 | table->GraphicsInterval = 1; | ||
2726 | table->VoltageInterval = 1; | ||
2727 | table->ThermalInterval = 1; | ||
2728 | table->TemperatureLimitHigh = | ||
2729 | (data->thermal_temp_setting.temperature_high * | ||
2730 | ICELAND_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | ||
2731 | table->TemperatureLimitLow = | ||
2732 | (data->thermal_temp_setting.temperature_low * | ||
2733 | ICELAND_Q88_FORMAT_CONVERSION_UNIT) / PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | ||
2734 | table->MemoryVoltageChangeEnable = 1; | ||
2735 | table->MemoryInterval = 1; | ||
2736 | table->VoltageResponseTime = 0; | ||
2737 | table->PhaseResponseTime = 0; | ||
2738 | table->MemoryThermThrottleEnable = 1; | ||
2739 | table->PCIeBootLinkLevel = 0; | ||
2740 | table->PCIeGenInterval = 1; | ||
2741 | |||
2742 | result = iceland_populate_smc_svi2_config(hwmgr, table); | ||
2743 | PP_ASSERT_WITH_CODE(0 == result, | ||
2744 | "Failed to populate SVI2 setting!", return result); | ||
2745 | |||
2746 | table->ThermGpio = 17; | ||
2747 | table->SclkStepSize = 0x4000; | ||
2748 | |||
2749 | CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags); | ||
2750 | CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcVid); | ||
2751 | CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcPhase); | ||
2752 | CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddciVid); | ||
2753 | CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskMvddVid); | ||
2754 | CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize); | ||
2755 | CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh); | ||
2756 | CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow); | ||
2757 | CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime); | ||
2758 | CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime); | ||
2759 | |||
2760 | table->BootVddc = PP_HOST_TO_SMC_US(table->BootVddc * VOLTAGE_SCALE); | ||
2761 | table->BootVddci = PP_HOST_TO_SMC_US(table->BootVddci * VOLTAGE_SCALE); | ||
2762 | table->BootMVdd = PP_HOST_TO_SMC_US(table->BootMVdd * VOLTAGE_SCALE); | ||
2763 | |||
2764 | /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */ | ||
2765 | result = iceland_copy_bytes_to_smc(hwmgr->smumgr, data->dpm_table_start + | ||
2766 | offsetof(SMU71_Discrete_DpmTable, SystemFlags), | ||
2767 | (uint8_t *)&(table->SystemFlags), | ||
2768 | sizeof(SMU71_Discrete_DpmTable) - 3 * sizeof(SMU71_PIDController), | ||
2769 | data->sram_end); | ||
2770 | |||
2771 | PP_ASSERT_WITH_CODE(0 == result, | ||
2772 | "Failed to upload dpm data to SMC memory!", return result); | ||
2773 | |||
2774 | /* Upload all ulv setting to SMC memory.(dpm level, dpm level count etc) */ | ||
2775 | result = iceland_copy_bytes_to_smc(hwmgr->smumgr, | ||
2776 | data->ulv_settings_start, | ||
2777 | (uint8_t *)&(data->ulv_setting), | ||
2778 | sizeof(SMU71_Discrete_Ulv), | ||
2779 | data->sram_end); | ||
2780 | |||
2781 | #if 0 | ||
2782 | /* Notify SMC to follow new GPIO scheme */ | ||
2783 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2784 | PHM_PlatformCaps_AutomaticDCTransition)) { | ||
2785 | if (0 == iceland_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_UseNewGPIOScheme)) | ||
2786 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
2787 | PHM_PlatformCaps_SMCtoPPLIBAcdcGpioScheme); | ||
2788 | } | ||
2789 | #endif | ||
2790 | |||
2791 | return result; | ||
2792 | } | ||
2793 | |||
2794 | int iceland_populate_mc_reg_address(struct pp_hwmgr *hwmgr, SMU71_Discrete_MCRegisters *mc_reg_table) | ||
2795 | { | ||
2796 | const struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
2797 | |||
2798 | uint32_t i, j; | ||
2799 | |||
2800 | for (i = 0, j = 0; j < data->iceland_mc_reg_table.last; j++) { | ||
2801 | if (data->iceland_mc_reg_table.validflag & 1<<j) { | ||
2802 | PP_ASSERT_WITH_CODE(i < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE, | ||
2803 | "Index of mc_reg_table->address[] array out of boundary", return -1); | ||
2804 | mc_reg_table->address[i].s0 = | ||
2805 | PP_HOST_TO_SMC_US(data->iceland_mc_reg_table.mc_reg_address[j].s0); | ||
2806 | mc_reg_table->address[i].s1 = | ||
2807 | PP_HOST_TO_SMC_US(data->iceland_mc_reg_table.mc_reg_address[j].s1); | ||
2808 | i++; | ||
2809 | } | ||
2810 | } | ||
2811 | |||
2812 | mc_reg_table->last = (uint8_t)i; | ||
2813 | |||
2814 | return 0; | ||
2815 | } | ||
2816 | |||
2817 | /* convert register values from driver to SMC format */ | ||
2818 | void iceland_convert_mc_registers( | ||
2819 | const phw_iceland_mc_reg_entry * pEntry, | ||
2820 | SMU71_Discrete_MCRegisterSet *pData, | ||
2821 | uint32_t numEntries, uint32_t validflag) | ||
2822 | { | ||
2823 | uint32_t i, j; | ||
2824 | |||
2825 | for (i = 0, j = 0; j < numEntries; j++) { | ||
2826 | if (validflag & 1<<j) { | ||
2827 | pData->value[i] = PP_HOST_TO_SMC_UL(pEntry->mc_data[j]); | ||
2828 | i++; | ||
2829 | } | ||
2830 | } | ||
2831 | } | ||
2832 | |||
2833 | /* find the entry in the memory range table, then populate the value to SMC's iceland_mc_reg_table */ | ||
2834 | int iceland_convert_mc_reg_table_entry_to_smc( | ||
2835 | struct pp_hwmgr *hwmgr, | ||
2836 | const uint32_t memory_clock, | ||
2837 | SMU71_Discrete_MCRegisterSet *mc_reg_table_data | ||
2838 | ) | ||
2839 | { | ||
2840 | const iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
2841 | uint32_t i = 0; | ||
2842 | |||
2843 | for (i = 0; i < data->iceland_mc_reg_table.num_entries; i++) { | ||
2844 | if (memory_clock <= | ||
2845 | data->iceland_mc_reg_table.mc_reg_table_entry[i].mclk_max) { | ||
2846 | break; | ||
2847 | } | ||
2848 | } | ||
2849 | |||
2850 | if ((i == data->iceland_mc_reg_table.num_entries) && (i > 0)) | ||
2851 | --i; | ||
2852 | |||
2853 | iceland_convert_mc_registers(&data->iceland_mc_reg_table.mc_reg_table_entry[i], | ||
2854 | mc_reg_table_data, data->iceland_mc_reg_table.last, data->iceland_mc_reg_table.validflag); | ||
2855 | |||
2856 | return 0; | ||
2857 | } | ||
2858 | |||
2859 | int iceland_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr, | ||
2860 | SMU71_Discrete_MCRegisters *mc_reg_table) | ||
2861 | { | ||
2862 | int result = 0; | ||
2863 | iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
2864 | int res; | ||
2865 | uint32_t i; | ||
2866 | |||
2867 | for (i = 0; i < data->dpm_table.mclk_table.count; i++) { | ||
2868 | res = iceland_convert_mc_reg_table_entry_to_smc( | ||
2869 | hwmgr, | ||
2870 | data->dpm_table.mclk_table.dpm_levels[i].value, | ||
2871 | &mc_reg_table->data[i] | ||
2872 | ); | ||
2873 | |||
2874 | if (0 != res) | ||
2875 | result = res; | ||
2876 | } | ||
2877 | |||
2878 | return result; | ||
2879 | } | ||
2880 | |||
2881 | int iceland_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr) | ||
2882 | { | ||
2883 | int result; | ||
2884 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
2885 | |||
2886 | memset(&data->mc_reg_table, 0x00, sizeof(SMU71_Discrete_MCRegisters)); | ||
2887 | result = iceland_populate_mc_reg_address(hwmgr, &(data->mc_reg_table)); | ||
2888 | PP_ASSERT_WITH_CODE(0 == result, | ||
2889 | "Failed to initialize MCRegTable for the MC register addresses!", return result;); | ||
2890 | |||
2891 | result = iceland_convert_mc_reg_table_to_smc(hwmgr, &data->mc_reg_table); | ||
2892 | PP_ASSERT_WITH_CODE(0 == result, | ||
2893 | "Failed to initialize MCRegTable for driver state!", return result;); | ||
2894 | |||
2895 | return iceland_copy_bytes_to_smc(hwmgr->smumgr, data->mc_reg_table_start, | ||
2896 | (uint8_t *)&data->mc_reg_table, sizeof(SMU71_Discrete_MCRegisters), data->sram_end); | ||
2897 | } | ||
2898 | |||
2899 | int iceland_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display) | ||
2900 | { | ||
2901 | PPSMC_Msg msg = has_display? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay; | ||
2902 | |||
2903 | return (smum_send_msg_to_smc(hwmgr->smumgr, msg) == 0) ? 0 : -1; | ||
2904 | } | ||
2905 | |||
2906 | int iceland_enable_sclk_control(struct pp_hwmgr *hwmgr) | ||
2907 | { | ||
2908 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, 0); | ||
2909 | |||
2910 | return 0; | ||
2911 | } | ||
2912 | |||
2913 | int iceland_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr) | ||
2914 | { | ||
2915 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2916 | |||
2917 | /* enable SCLK dpm */ | ||
2918 | if (0 == data->sclk_dpm_key_disabled) { | ||
2919 | PP_ASSERT_WITH_CODE( | ||
2920 | (0 == smum_send_msg_to_smc(hwmgr->smumgr, | ||
2921 | PPSMC_MSG_DPM_Enable)), | ||
2922 | "Failed to enable SCLK DPM during DPM Start Function!", | ||
2923 | return -1); | ||
2924 | } | ||
2925 | |||
2926 | /* enable MCLK dpm */ | ||
2927 | if (0 == data->mclk_dpm_key_disabled) { | ||
2928 | PP_ASSERT_WITH_CODE( | ||
2929 | (0 == smum_send_msg_to_smc(hwmgr->smumgr, | ||
2930 | PPSMC_MSG_MCLKDPM_Enable)), | ||
2931 | "Failed to enable MCLK DPM during DPM Start Function!", | ||
2932 | return -1); | ||
2933 | |||
2934 | PHM_WRITE_FIELD(hwmgr->device, MC_SEQ_CNTL_3, CAC_EN, 0x1); | ||
2935 | |||
2936 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
2937 | ixLCAC_MC0_CNTL, 0x05);/* CH0,1 read */ | ||
2938 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
2939 | ixLCAC_MC1_CNTL, 0x05);/* CH2,3 read */ | ||
2940 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
2941 | ixLCAC_CPL_CNTL, 0x100005);/*Read */ | ||
2942 | |||
2943 | udelay(10); | ||
2944 | |||
2945 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
2946 | ixLCAC_MC0_CNTL, 0x400005);/* CH0,1 write */ | ||
2947 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
2948 | ixLCAC_MC1_CNTL, 0x400005);/* CH2,3 write */ | ||
2949 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
2950 | ixLCAC_CPL_CNTL, 0x500005);/* write */ | ||
2951 | |||
2952 | } | ||
2953 | |||
2954 | return 0; | ||
2955 | } | ||
2956 | |||
2957 | int iceland_start_dpm(struct pp_hwmgr *hwmgr) | ||
2958 | { | ||
2959 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
2960 | |||
2961 | /* enable general power management */ | ||
2962 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, 1); | ||
2963 | /* enable sclk deep sleep */ | ||
2964 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, DYNAMIC_PM_EN, 1); | ||
2965 | |||
2966 | /* prepare for PCIE DPM */ | ||
2967 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SOFT_REGISTERS_TABLE_12, VoltageChangeTimeout, 0x1000); | ||
2968 | |||
2969 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE, SWRST_COMMAND_1, RESETLC, 0x0); | ||
2970 | |||
2971 | PP_ASSERT_WITH_CODE( | ||
2972 | (0 == smum_send_msg_to_smc(hwmgr->smumgr, | ||
2973 | PPSMC_MSG_Voltage_Cntl_Enable)), | ||
2974 | "Failed to enable voltage DPM during DPM Start Function!", | ||
2975 | return -1); | ||
2976 | |||
2977 | if (0 != iceland_enable_sclk_mclk_dpm(hwmgr)) { | ||
2978 | PP_ASSERT_WITH_CODE(0, "Failed to enable Sclk DPM and Mclk DPM!", return -1); | ||
2979 | } | ||
2980 | |||
2981 | /* enable PCIE dpm */ | ||
2982 | if (0 == data->pcie_dpm_key_disabled) { | ||
2983 | PP_ASSERT_WITH_CODE( | ||
2984 | (0 == smum_send_msg_to_smc(hwmgr->smumgr, | ||
2985 | PPSMC_MSG_PCIeDPM_Enable)), | ||
2986 | "Failed to enable pcie DPM during DPM Start Function!", | ||
2987 | return -1 | ||
2988 | ); | ||
2989 | } | ||
2990 | |||
2991 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
2992 | PHM_PlatformCaps_Falcon_QuickTransition)) { | ||
2993 | smum_send_msg_to_smc(hwmgr->smumgr, | ||
2994 | PPSMC_MSG_EnableACDCGPIOInterrupt); | ||
2995 | } | ||
2996 | |||
2997 | return 0; | ||
2998 | } | ||
2999 | |||
3000 | static void iceland_set_dpm_event_sources(struct pp_hwmgr *hwmgr, | ||
3001 | uint32_t sources) | ||
3002 | { | ||
3003 | bool protection; | ||
3004 | enum DPM_EVENT_SRC src; | ||
3005 | |||
3006 | switch (sources) { | ||
3007 | default: | ||
3008 | printk(KERN_ERR "Unknown throttling event sources."); | ||
3009 | /* fall through */ | ||
3010 | case 0: | ||
3011 | protection = false; | ||
3012 | /* src is unused */ | ||
3013 | break; | ||
3014 | case (1 << PHM_AutoThrottleSource_Thermal): | ||
3015 | protection = true; | ||
3016 | src = DPM_EVENT_SRC_DIGITAL; | ||
3017 | break; | ||
3018 | case (1 << PHM_AutoThrottleSource_External): | ||
3019 | protection = true; | ||
3020 | src = DPM_EVENT_SRC_EXTERNAL; | ||
3021 | break; | ||
3022 | case (1 << PHM_AutoThrottleSource_External) | | ||
3023 | (1 << PHM_AutoThrottleSource_Thermal): | ||
3024 | protection = true; | ||
3025 | src = DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL; | ||
3026 | break; | ||
3027 | } | ||
3028 | /* Order matters - don't enable thermal protection for the wrong source. */ | ||
3029 | if (protection) { | ||
3030 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, | ||
3031 | DPM_EVENT_SRC, src); | ||
3032 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, | ||
3033 | THERMAL_PROTECTION_DIS, | ||
3034 | !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3035 | PHM_PlatformCaps_ThermalController)); | ||
3036 | } else | ||
3037 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, | ||
3038 | THERMAL_PROTECTION_DIS, 1); | ||
3039 | } | ||
3040 | |||
3041 | static int iceland_enable_auto_throttle_source(struct pp_hwmgr *hwmgr, | ||
3042 | PHM_AutoThrottleSource source) | ||
3043 | { | ||
3044 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
3045 | |||
3046 | if (!(data->active_auto_throttle_sources & (1 << source))) { | ||
3047 | data->active_auto_throttle_sources |= 1 << source; | ||
3048 | iceland_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources); | ||
3049 | } | ||
3050 | return 0; | ||
3051 | } | ||
3052 | |||
3053 | static int iceland_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr) | ||
3054 | { | ||
3055 | return iceland_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal); | ||
3056 | } | ||
3057 | |||
3058 | static int iceland_tf_start_smc(struct pp_hwmgr *hwmgr) | ||
3059 | { | ||
3060 | int ret = 0; | ||
3061 | |||
3062 | if (!iceland_is_smc_ram_running(hwmgr->smumgr)) | ||
3063 | ret = iceland_smu_start_smc(hwmgr->smumgr); | ||
3064 | |||
3065 | return ret; | ||
3066 | } | ||
3067 | |||
3068 | /** | ||
3069 | * Programs the Deep Sleep registers | ||
3070 | * | ||
3071 | * @param pHwMgr the address of the powerplay hardware manager. | ||
3072 | * @param pInput the pointer to input data (PhwEvergreen_DisplayConfiguration) | ||
3073 | * @param pOutput the pointer to output data (unused) | ||
3074 | * @param pStorage the pointer to temporary storage (unused) | ||
3075 | * @param Result the last failure code (unused) | ||
3076 | * @return always 0 | ||
3077 | */ | ||
3078 | static int iceland_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr) | ||
3079 | { | ||
3080 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3081 | PHM_PlatformCaps_SclkDeepSleep)) { | ||
3082 | if (smum_send_msg_to_smc(hwmgr->smumgr, | ||
3083 | PPSMC_MSG_MASTER_DeepSleep_ON) != 0) | ||
3084 | PP_ASSERT_WITH_CODE(false, | ||
3085 | "Attempt to enable Master Deep Sleep switch failed!", | ||
3086 | return -EINVAL); | ||
3087 | } else { | ||
3088 | if (smum_send_msg_to_smc(hwmgr->smumgr, | ||
3089 | PPSMC_MSG_MASTER_DeepSleep_OFF) != 0) | ||
3090 | PP_ASSERT_WITH_CODE(false, | ||
3091 | "Attempt to disable Master Deep Sleep switch failed!", | ||
3092 | return -EINVAL); | ||
3093 | } | ||
3094 | |||
3095 | return 0; | ||
3096 | } | ||
3097 | |||
3098 | static int iceland_enable_dpm_tasks(struct pp_hwmgr *hwmgr) | ||
3099 | { | ||
3100 | int tmp_result, result = 0; | ||
3101 | |||
3102 | if (cf_iceland_voltage_control(hwmgr)) { | ||
3103 | tmp_result = iceland_enable_voltage_control(hwmgr); | ||
3104 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3105 | "Failed to enable voltage control!", return tmp_result); | ||
3106 | |||
3107 | tmp_result = iceland_construct_voltage_tables(hwmgr); | ||
3108 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3109 | "Failed to contruct voltage tables!", return tmp_result); | ||
3110 | } | ||
3111 | |||
3112 | tmp_result = iceland_initialize_mc_reg_table(hwmgr); | ||
3113 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3114 | "Failed to initialize MC reg table!", return tmp_result); | ||
3115 | |||
3116 | tmp_result = iceland_program_static_screen_threshold_parameters(hwmgr); | ||
3117 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3118 | "Failed to program static screen threshold parameters!", return tmp_result); | ||
3119 | |||
3120 | tmp_result = iceland_enable_display_gap(hwmgr); | ||
3121 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3122 | "Failed to enable display gap!", return tmp_result); | ||
3123 | |||
3124 | tmp_result = iceland_program_voting_clients(hwmgr); | ||
3125 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3126 | "Failed to program voting clients!", return tmp_result); | ||
3127 | |||
3128 | tmp_result = iceland_upload_firmware(hwmgr); | ||
3129 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3130 | "Failed to upload firmware header!", return tmp_result); | ||
3131 | |||
3132 | tmp_result = iceland_process_firmware_header(hwmgr); | ||
3133 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3134 | "Failed to process firmware header!", return tmp_result); | ||
3135 | |||
3136 | tmp_result = iceland_initial_switch_from_arb_f0_to_f1(hwmgr); | ||
3137 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3138 | "Failed to initialize switch from ArbF0 to F1!", return tmp_result); | ||
3139 | |||
3140 | tmp_result = iceland_init_smc_table(hwmgr); | ||
3141 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3142 | "Failed to initialize SMC table!", return tmp_result); | ||
3143 | |||
3144 | tmp_result = iceland_populate_initial_mc_reg_table(hwmgr); | ||
3145 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3146 | "Failed to populate initialize MC Reg table!", return tmp_result); | ||
3147 | |||
3148 | tmp_result = iceland_populate_pm_fuses(hwmgr); | ||
3149 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3150 | "Failed to populate PM fuses!", return tmp_result); | ||
3151 | |||
3152 | /* start SMC */ | ||
3153 | tmp_result = iceland_tf_start_smc(hwmgr); | ||
3154 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3155 | "Failed to start SMC!", return tmp_result); | ||
3156 | |||
3157 | /* enable SCLK control */ | ||
3158 | tmp_result = iceland_enable_sclk_control(hwmgr); | ||
3159 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3160 | "Failed to enable SCLK control!", return tmp_result); | ||
3161 | |||
3162 | tmp_result = iceland_enable_deep_sleep_master_switch(hwmgr); | ||
3163 | PP_ASSERT_WITH_CODE((tmp_result == 0), | ||
3164 | "Failed to enable deep sleep!", return tmp_result); | ||
3165 | |||
3166 | /* enable DPM */ | ||
3167 | tmp_result = iceland_start_dpm(hwmgr); | ||
3168 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3169 | "Failed to start DPM!", return tmp_result); | ||
3170 | |||
3171 | tmp_result = iceland_enable_smc_cac(hwmgr); | ||
3172 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3173 | "Failed to enable SMC CAC!", return tmp_result); | ||
3174 | |||
3175 | tmp_result = iceland_enable_power_containment(hwmgr); | ||
3176 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3177 | "Failed to enable power containment!", return tmp_result); | ||
3178 | |||
3179 | tmp_result = iceland_power_control_set_level(hwmgr); | ||
3180 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3181 | "Failed to power control set level!", result = tmp_result); | ||
3182 | |||
3183 | tmp_result = iceland_enable_thermal_auto_throttle(hwmgr); | ||
3184 | PP_ASSERT_WITH_CODE((0 == tmp_result), | ||
3185 | "Failed to enable thermal auto throttle!", result = tmp_result); | ||
3186 | |||
3187 | return result; | ||
3188 | } | ||
3189 | |||
3190 | static int iceland_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) | ||
3191 | { | ||
3192 | return phm_hwmgr_backend_fini(hwmgr); | ||
3193 | } | ||
3194 | |||
3195 | static void iceland_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) | ||
3196 | { | ||
3197 | iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
3198 | struct phw_iceland_ulv_parm *ulv; | ||
3199 | |||
3200 | ulv = &data->ulv; | ||
3201 | ulv->ch_ulv_parameter = PPICELAND_CGULVPARAMETER_DFLT; | ||
3202 | data->voting_rights_clients0 = PPICELAND_VOTINGRIGHTSCLIENTS_DFLT0; | ||
3203 | data->voting_rights_clients1 = PPICELAND_VOTINGRIGHTSCLIENTS_DFLT1; | ||
3204 | data->voting_rights_clients2 = PPICELAND_VOTINGRIGHTSCLIENTS_DFLT2; | ||
3205 | data->voting_rights_clients3 = PPICELAND_VOTINGRIGHTSCLIENTS_DFLT3; | ||
3206 | data->voting_rights_clients4 = PPICELAND_VOTINGRIGHTSCLIENTS_DFLT4; | ||
3207 | data->voting_rights_clients5 = PPICELAND_VOTINGRIGHTSCLIENTS_DFLT5; | ||
3208 | data->voting_rights_clients6 = PPICELAND_VOTINGRIGHTSCLIENTS_DFLT6; | ||
3209 | data->voting_rights_clients7 = PPICELAND_VOTINGRIGHTSCLIENTS_DFLT7; | ||
3210 | |||
3211 | data->static_screen_threshold_unit = PPICELAND_STATICSCREENTHRESHOLDUNIT_DFLT; | ||
3212 | data->static_screen_threshold = PPICELAND_STATICSCREENTHRESHOLD_DFLT; | ||
3213 | |||
3214 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3215 | PHM_PlatformCaps_ABM); | ||
3216 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3217 | PHM_PlatformCaps_NonABMSupportInPPLib); | ||
3218 | |||
3219 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3220 | PHM_PlatformCaps_DynamicACTiming); | ||
3221 | |||
3222 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3223 | PHM_PlatformCaps_DisableMemoryTransition); | ||
3224 | |||
3225 | iceland_initialize_power_tune_defaults(hwmgr); | ||
3226 | |||
3227 | data->mclk_strobe_mode_threshold = 40000; | ||
3228 | data->mclk_stutter_mode_threshold = 30000; | ||
3229 | data->mclk_edc_enable_threshold = 40000; | ||
3230 | data->mclk_edc_wr_enable_threshold = 40000; | ||
3231 | |||
3232 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3233 | PHM_PlatformCaps_DisableMCLS); | ||
3234 | |||
3235 | data->pcie_gen_performance.max = PP_PCIEGen1; | ||
3236 | data->pcie_gen_performance.min = PP_PCIEGen3; | ||
3237 | data->pcie_gen_power_saving.max = PP_PCIEGen1; | ||
3238 | data->pcie_gen_power_saving.min = PP_PCIEGen3; | ||
3239 | |||
3240 | data->pcie_lane_performance.max = 0; | ||
3241 | data->pcie_lane_performance.min = 16; | ||
3242 | data->pcie_lane_power_saving.max = 0; | ||
3243 | data->pcie_lane_power_saving.min = 16; | ||
3244 | |||
3245 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3246 | PHM_PlatformCaps_SclkThrottleLowNotification); | ||
3247 | } | ||
3248 | |||
3249 | static int iceland_get_evv_voltage(struct pp_hwmgr *hwmgr) | ||
3250 | { | ||
3251 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
3252 | uint16_t virtual_voltage_id; | ||
3253 | uint16_t vddc = 0; | ||
3254 | uint16_t i; | ||
3255 | |||
3256 | /* the count indicates actual number of entries */ | ||
3257 | data->vddc_leakage.count = 0; | ||
3258 | data->vddci_leakage.count = 0; | ||
3259 | |||
3260 | if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EVV)) { | ||
3261 | pr_err("Iceland should always support EVV\n"); | ||
3262 | return -EINVAL; | ||
3263 | } | ||
3264 | |||
3265 | /* retrieve voltage for leakage ID (0xff01 + i) */ | ||
3266 | for (i = 0; i < ICELAND_MAX_LEAKAGE_COUNT; i++) { | ||
3267 | virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i; | ||
3268 | |||
3269 | PP_ASSERT_WITH_CODE((0 == atomctrl_get_voltage_evv(hwmgr, virtual_voltage_id, &vddc)), | ||
3270 | "Error retrieving EVV voltage value!\n", continue); | ||
3271 | |||
3272 | if (vddc >= 2000) | ||
3273 | pr_warning("Invalid VDDC value!\n"); | ||
3274 | |||
3275 | if (vddc != 0 && vddc != virtual_voltage_id) { | ||
3276 | data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = vddc; | ||
3277 | data->vddc_leakage.leakage_id[data->vddc_leakage.count] = virtual_voltage_id; | ||
3278 | data->vddc_leakage.count++; | ||
3279 | } | ||
3280 | } | ||
3281 | |||
3282 | return 0; | ||
3283 | } | ||
3284 | |||
3285 | static void iceland_patch_with_vddc_leakage(struct pp_hwmgr *hwmgr, | ||
3286 | uint32_t *vddc) | ||
3287 | { | ||
3288 | iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
3289 | uint32_t leakage_index; | ||
3290 | struct phw_iceland_leakage_voltage *leakage_table = &data->vddc_leakage; | ||
3291 | |||
3292 | /* search for leakage voltage ID 0xff01 ~ 0xff08 */ | ||
3293 | for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) { | ||
3294 | /* | ||
3295 | * If this voltage matches a leakage voltage ID, patch | ||
3296 | * with actual leakage voltage. | ||
3297 | */ | ||
3298 | if (leakage_table->leakage_id[leakage_index] == *vddc) { | ||
3299 | /* | ||
3300 | * Need to make sure vddc is less than 2v or | ||
3301 | * else, it could burn the ASIC. | ||
3302 | */ | ||
3303 | if (leakage_table->actual_voltage[leakage_index] >= 2000) | ||
3304 | pr_warning("Invalid VDDC value!\n"); | ||
3305 | *vddc = leakage_table->actual_voltage[leakage_index]; | ||
3306 | /* we found leakage voltage */ | ||
3307 | break; | ||
3308 | } | ||
3309 | } | ||
3310 | |||
3311 | if (*vddc >= ATOM_VIRTUAL_VOLTAGE_ID0) | ||
3312 | pr_warning("Voltage value looks like a Leakage ID but it's not patched\n"); | ||
3313 | } | ||
3314 | |||
3315 | static void iceland_patch_with_vddci_leakage(struct pp_hwmgr *hwmgr, | ||
3316 | uint32_t *vddci) | ||
3317 | { | ||
3318 | iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
3319 | uint32_t leakage_index; | ||
3320 | struct phw_iceland_leakage_voltage *leakage_table = &data->vddci_leakage; | ||
3321 | |||
3322 | /* search for leakage voltage ID 0xff01 ~ 0xff08 */ | ||
3323 | for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) { | ||
3324 | /* | ||
3325 | * If this voltage matches a leakage voltage ID, patch | ||
3326 | * with actual leakage voltage. | ||
3327 | */ | ||
3328 | if (leakage_table->leakage_id[leakage_index] == *vddci) { | ||
3329 | *vddci = leakage_table->actual_voltage[leakage_index]; | ||
3330 | /* we found leakage voltage */ | ||
3331 | break; | ||
3332 | } | ||
3333 | } | ||
3334 | |||
3335 | if (*vddci >= ATOM_VIRTUAL_VOLTAGE_ID0) | ||
3336 | pr_warning("Voltage value looks like a Leakage ID but it's not patched\n"); | ||
3337 | } | ||
3338 | |||
3339 | static int iceland_patch_vddc(struct pp_hwmgr *hwmgr, | ||
3340 | struct phm_clock_voltage_dependency_table *tab) | ||
3341 | { | ||
3342 | uint16_t i; | ||
3343 | |||
3344 | if (tab) | ||
3345 | for (i = 0; i < tab->count; i++) | ||
3346 | iceland_patch_with_vddc_leakage(hwmgr, &tab->entries[i].v); | ||
3347 | |||
3348 | return 0; | ||
3349 | } | ||
3350 | |||
3351 | static int iceland_patch_vddci(struct pp_hwmgr *hwmgr, | ||
3352 | struct phm_clock_voltage_dependency_table *tab) | ||
3353 | { | ||
3354 | uint16_t i; | ||
3355 | |||
3356 | if (tab) | ||
3357 | for (i = 0; i < tab->count; i++) | ||
3358 | iceland_patch_with_vddci_leakage(hwmgr, &tab->entries[i].v); | ||
3359 | |||
3360 | return 0; | ||
3361 | } | ||
3362 | |||
3363 | static int iceland_patch_vce_vddc(struct pp_hwmgr *hwmgr, | ||
3364 | struct phm_vce_clock_voltage_dependency_table *tab) | ||
3365 | { | ||
3366 | uint16_t i; | ||
3367 | |||
3368 | if (tab) | ||
3369 | for (i = 0; i < tab->count; i++) | ||
3370 | iceland_patch_with_vddc_leakage(hwmgr, &tab->entries[i].v); | ||
3371 | |||
3372 | return 0; | ||
3373 | } | ||
3374 | |||
3375 | |||
3376 | static int iceland_patch_uvd_vddc(struct pp_hwmgr *hwmgr, | ||
3377 | struct phm_uvd_clock_voltage_dependency_table *tab) | ||
3378 | { | ||
3379 | uint16_t i; | ||
3380 | |||
3381 | if (tab) | ||
3382 | for (i = 0; i < tab->count; i++) | ||
3383 | iceland_patch_with_vddc_leakage(hwmgr, &tab->entries[i].v); | ||
3384 | |||
3385 | return 0; | ||
3386 | } | ||
3387 | |||
3388 | static int iceland_patch_vddc_shed_limit(struct pp_hwmgr *hwmgr, | ||
3389 | struct phm_phase_shedding_limits_table *tab) | ||
3390 | { | ||
3391 | uint16_t i; | ||
3392 | |||
3393 | if (tab) | ||
3394 | for (i = 0; i < tab->count; i++) | ||
3395 | iceland_patch_with_vddc_leakage(hwmgr, &tab->entries[i].Voltage); | ||
3396 | |||
3397 | return 0; | ||
3398 | } | ||
3399 | |||
3400 | static int iceland_patch_samu_vddc(struct pp_hwmgr *hwmgr, | ||
3401 | struct phm_samu_clock_voltage_dependency_table *tab) | ||
3402 | { | ||
3403 | uint16_t i; | ||
3404 | |||
3405 | if (tab) | ||
3406 | for (i = 0; i < tab->count; i++) | ||
3407 | iceland_patch_with_vddc_leakage(hwmgr, &tab->entries[i].v); | ||
3408 | |||
3409 | return 0; | ||
3410 | } | ||
3411 | |||
3412 | static int iceland_patch_acp_vddc(struct pp_hwmgr *hwmgr, | ||
3413 | struct phm_acp_clock_voltage_dependency_table *tab) | ||
3414 | { | ||
3415 | uint16_t i; | ||
3416 | |||
3417 | if (tab) | ||
3418 | for (i = 0; i < tab->count; i++) | ||
3419 | iceland_patch_with_vddc_leakage(hwmgr, &tab->entries[i].v); | ||
3420 | |||
3421 | return 0; | ||
3422 | } | ||
3423 | |||
3424 | static int iceland_patch_limits_vddc(struct pp_hwmgr *hwmgr, | ||
3425 | struct phm_clock_and_voltage_limits *tab) | ||
3426 | { | ||
3427 | if (tab) { | ||
3428 | iceland_patch_with_vddc_leakage(hwmgr, (uint32_t *)&tab->vddc); | ||
3429 | iceland_patch_with_vddci_leakage(hwmgr, (uint32_t *)&tab->vddci); | ||
3430 | } | ||
3431 | |||
3432 | return 0; | ||
3433 | } | ||
3434 | |||
3435 | static int iceland_patch_cac_vddc(struct pp_hwmgr *hwmgr, struct phm_cac_leakage_table *tab) | ||
3436 | { | ||
3437 | uint32_t i; | ||
3438 | uint32_t vddc; | ||
3439 | |||
3440 | if (tab) { | ||
3441 | for (i = 0; i < tab->count; i++) { | ||
3442 | vddc = (uint32_t)(tab->entries[i].Vddc); | ||
3443 | iceland_patch_with_vddc_leakage(hwmgr, &vddc); | ||
3444 | tab->entries[i].Vddc = (uint16_t)vddc; | ||
3445 | } | ||
3446 | } | ||
3447 | |||
3448 | return 0; | ||
3449 | } | ||
3450 | |||
3451 | static int iceland_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) | ||
3452 | { | ||
3453 | int tmp; | ||
3454 | |||
3455 | tmp = iceland_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_sclk); | ||
3456 | if(tmp) | ||
3457 | return -EINVAL; | ||
3458 | |||
3459 | tmp = iceland_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_mclk); | ||
3460 | if(tmp) | ||
3461 | return -EINVAL; | ||
3462 | |||
3463 | tmp = iceland_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dep_on_dal_pwrl); | ||
3464 | if(tmp) | ||
3465 | return -EINVAL; | ||
3466 | |||
3467 | tmp = iceland_patch_vddci(hwmgr, hwmgr->dyn_state.vddci_dependency_on_mclk); | ||
3468 | if(tmp) | ||
3469 | return -EINVAL; | ||
3470 | |||
3471 | tmp = iceland_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table); | ||
3472 | if(tmp) | ||
3473 | return -EINVAL; | ||
3474 | |||
3475 | tmp = iceland_patch_uvd_vddc(hwmgr, hwmgr->dyn_state.uvd_clock_voltage_dependency_table); | ||
3476 | if(tmp) | ||
3477 | return -EINVAL; | ||
3478 | |||
3479 | tmp = iceland_patch_samu_vddc(hwmgr, hwmgr->dyn_state.samu_clock_voltage_dependency_table); | ||
3480 | if(tmp) | ||
3481 | return -EINVAL; | ||
3482 | |||
3483 | tmp = iceland_patch_acp_vddc(hwmgr, hwmgr->dyn_state.acp_clock_voltage_dependency_table); | ||
3484 | if(tmp) | ||
3485 | return -EINVAL; | ||
3486 | |||
3487 | tmp = iceland_patch_vddc_shed_limit(hwmgr, hwmgr->dyn_state.vddc_phase_shed_limits_table); | ||
3488 | if(tmp) | ||
3489 | return -EINVAL; | ||
3490 | |||
3491 | tmp = iceland_patch_limits_vddc(hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_ac); | ||
3492 | if(tmp) | ||
3493 | return -EINVAL; | ||
3494 | |||
3495 | tmp = iceland_patch_limits_vddc(hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_dc); | ||
3496 | if(tmp) | ||
3497 | return -EINVAL; | ||
3498 | |||
3499 | tmp = iceland_patch_cac_vddc(hwmgr, hwmgr->dyn_state.cac_leakage_table); | ||
3500 | if(tmp) | ||
3501 | return -EINVAL; | ||
3502 | |||
3503 | return 0; | ||
3504 | } | ||
3505 | |||
3506 | static int iceland_set_private_var_based_on_pptale(struct pp_hwmgr *hwmgr) | ||
3507 | { | ||
3508 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
3509 | |||
3510 | struct phm_clock_voltage_dependency_table *allowed_sclk_vddc_table = hwmgr->dyn_state.vddc_dependency_on_sclk; | ||
3511 | struct phm_clock_voltage_dependency_table *allowed_mclk_vddc_table = hwmgr->dyn_state.vddc_dependency_on_mclk; | ||
3512 | struct phm_clock_voltage_dependency_table *allowed_mclk_vddci_table = hwmgr->dyn_state.vddci_dependency_on_mclk; | ||
3513 | |||
3514 | PP_ASSERT_WITH_CODE(allowed_sclk_vddc_table != NULL, | ||
3515 | "VDDC dependency on SCLK table is missing. This table is mandatory\n", return -EINVAL); | ||
3516 | PP_ASSERT_WITH_CODE(allowed_sclk_vddc_table->count >= 1, | ||
3517 | "VDDC dependency on SCLK table has to have is missing. This table is mandatory\n", return -EINVAL); | ||
3518 | |||
3519 | PP_ASSERT_WITH_CODE(allowed_mclk_vddc_table != NULL, | ||
3520 | "VDDC dependency on MCLK table is missing. This table is mandatory\n", return -EINVAL); | ||
3521 | PP_ASSERT_WITH_CODE(allowed_mclk_vddc_table->count >= 1, | ||
3522 | "VDD dependency on MCLK table has to have is missing. This table is mandatory\n", return -EINVAL); | ||
3523 | |||
3524 | data->min_vddc_in_pp_table = (uint16_t)allowed_sclk_vddc_table->entries[0].v; | ||
3525 | data->max_vddc_in_pp_table = (uint16_t)allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v; | ||
3526 | |||
3527 | hwmgr->dyn_state.max_clock_voltage_on_ac.sclk = | ||
3528 | allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk; | ||
3529 | hwmgr->dyn_state.max_clock_voltage_on_ac.mclk = | ||
3530 | allowed_mclk_vddc_table->entries[allowed_mclk_vddc_table->count - 1].clk; | ||
3531 | hwmgr->dyn_state.max_clock_voltage_on_ac.vddc = | ||
3532 | allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v; | ||
3533 | |||
3534 | if (allowed_mclk_vddci_table != NULL && allowed_mclk_vddci_table->count >= 1) { | ||
3535 | data->min_vddci_in_pp_table = (uint16_t)allowed_mclk_vddci_table->entries[0].v; | ||
3536 | data->max_vddci_in_pp_table = (uint16_t)allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v; | ||
3537 | } | ||
3538 | |||
3539 | if (hwmgr->dyn_state.vddci_dependency_on_mclk != NULL && hwmgr->dyn_state.vddci_dependency_on_mclk->count > 1) | ||
3540 | 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; | ||
3541 | |||
3542 | return 0; | ||
3543 | } | ||
3544 | |||
3545 | static int iceland_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr) | ||
3546 | { | ||
3547 | uint32_t table_size; | ||
3548 | struct phm_clock_voltage_dependency_table *table_clk_vlt; | ||
3549 | |||
3550 | hwmgr->dyn_state.mclk_sclk_ratio = 4; | ||
3551 | hwmgr->dyn_state.sclk_mclk_delta = 15000; /* 150 MHz */ | ||
3552 | hwmgr->dyn_state.vddc_vddci_delta = 200; /* 200mV */ | ||
3553 | |||
3554 | /* initialize vddc_dep_on_dal_pwrl table */ | ||
3555 | table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record); | ||
3556 | table_clk_vlt = (struct phm_clock_voltage_dependency_table *)kzalloc(table_size, GFP_KERNEL); | ||
3557 | |||
3558 | if (NULL == table_clk_vlt) { | ||
3559 | pr_err("[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n"); | ||
3560 | return -ENOMEM; | ||
3561 | } else { | ||
3562 | table_clk_vlt->count = 4; | ||
3563 | table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW; | ||
3564 | table_clk_vlt->entries[0].v = 0; | ||
3565 | table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW; | ||
3566 | table_clk_vlt->entries[1].v = 720; | ||
3567 | table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL; | ||
3568 | table_clk_vlt->entries[2].v = 810; | ||
3569 | table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE; | ||
3570 | table_clk_vlt->entries[3].v = 900; | ||
3571 | hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; | ||
3572 | } | ||
3573 | |||
3574 | return 0; | ||
3575 | } | ||
3576 | |||
3577 | /** | ||
3578 | * Initializes the Volcanic Islands Hardware Manager | ||
3579 | * | ||
3580 | * @param hwmgr the address of the powerplay hardware manager. | ||
3581 | * @return 1 if success; otherwise appropriate error code. | ||
3582 | */ | ||
3583 | static int iceland_hwmgr_backend_init(struct pp_hwmgr *hwmgr) | ||
3584 | { | ||
3585 | int result = 0; | ||
3586 | SMU71_Discrete_DpmTable *table = NULL; | ||
3587 | iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
3588 | pp_atomctrl_gpio_pin_assignment gpio_pin_assignment; | ||
3589 | bool stay_in_boot; | ||
3590 | struct phw_iceland_ulv_parm *ulv; | ||
3591 | struct cgs_system_info sys_info = {0}; | ||
3592 | |||
3593 | PP_ASSERT_WITH_CODE((NULL != hwmgr), | ||
3594 | "Invalid Parameter!", return -EINVAL;); | ||
3595 | |||
3596 | data->dll_defaule_on = 0; | ||
3597 | data->sram_end = SMC_RAM_END; | ||
3598 | |||
3599 | data->activity_target[0] = PPICELAND_TARGETACTIVITY_DFLT; | ||
3600 | data->activity_target[1] = PPICELAND_TARGETACTIVITY_DFLT; | ||
3601 | data->activity_target[2] = PPICELAND_TARGETACTIVITY_DFLT; | ||
3602 | data->activity_target[3] = PPICELAND_TARGETACTIVITY_DFLT; | ||
3603 | data->activity_target[4] = PPICELAND_TARGETACTIVITY_DFLT; | ||
3604 | data->activity_target[5] = PPICELAND_TARGETACTIVITY_DFLT; | ||
3605 | data->activity_target[6] = PPICELAND_TARGETACTIVITY_DFLT; | ||
3606 | data->activity_target[7] = PPICELAND_TARGETACTIVITY_DFLT; | ||
3607 | |||
3608 | data->mclk_activity_target = PPICELAND_MCLK_TARGETACTIVITY_DFLT; | ||
3609 | |||
3610 | data->sclk_dpm_key_disabled = 0; | ||
3611 | data->mclk_dpm_key_disabled = 0; | ||
3612 | data->pcie_dpm_key_disabled = 0; | ||
3613 | data->pcc_monitor_enabled = 0; | ||
3614 | |||
3615 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3616 | PHM_PlatformCaps_UnTabledHardwareInterface); | ||
3617 | |||
3618 | data->gpio_debug = 0; | ||
3619 | data->engine_clock_data = 0; | ||
3620 | data->memory_clock_data = 0; | ||
3621 | |||
3622 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3623 | PHM_PlatformCaps_SclkDeepSleepAboveLow); | ||
3624 | |||
3625 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3626 | PHM_PlatformCaps_DynamicPatchPowerState); | ||
3627 | |||
3628 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3629 | PHM_PlatformCaps_TablelessHardwareInterface); | ||
3630 | |||
3631 | /* Initializes DPM default values. */ | ||
3632 | iceland_initialize_dpm_defaults(hwmgr); | ||
3633 | |||
3634 | /* Enable Platform EVV support. */ | ||
3635 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3636 | PHM_PlatformCaps_EVV); | ||
3637 | |||
3638 | /* Get leakage voltage based on leakage ID. */ | ||
3639 | result = iceland_get_evv_voltage(hwmgr); | ||
3640 | if (result) | ||
3641 | goto failed; | ||
3642 | |||
3643 | /** | ||
3644 | * Patch our voltage dependency table with actual leakage | ||
3645 | * voltage. We need to perform leakage translation before it's | ||
3646 | * used by other functions such as | ||
3647 | * iceland_set_hwmgr_variables_based_on_pptable. | ||
3648 | */ | ||
3649 | result = iceland_patch_dependency_tables_with_leakage(hwmgr); | ||
3650 | if (result) | ||
3651 | goto failed; | ||
3652 | |||
3653 | /* Parse pptable data read from VBIOS. */ | ||
3654 | result = iceland_set_private_var_based_on_pptale(hwmgr); | ||
3655 | if (result) | ||
3656 | goto failed; | ||
3657 | |||
3658 | /* ULV support */ | ||
3659 | ulv = &(data->ulv); | ||
3660 | ulv->ulv_supported = 1; | ||
3661 | |||
3662 | /* Initalize Dynamic State Adjustment Rule Settings*/ | ||
3663 | result = iceland_initializa_dynamic_state_adjustment_rule_settings(hwmgr); | ||
3664 | if (result) { | ||
3665 | pr_err("[ powerplay ] iceland_initializa_dynamic_state_adjustment_rule_settings failed!\n"); | ||
3666 | goto failed; | ||
3667 | } | ||
3668 | |||
3669 | data->voltage_control = ICELAND_VOLTAGE_CONTROL_NONE; | ||
3670 | data->vdd_ci_control = ICELAND_VOLTAGE_CONTROL_NONE; | ||
3671 | data->mvdd_control = ICELAND_VOLTAGE_CONTROL_NONE; | ||
3672 | |||
3673 | /* | ||
3674 | * Hardcode thermal temperature settings for now, these will | ||
3675 | * be overwritten if a custom policy exists. | ||
3676 | */ | ||
3677 | data->thermal_temp_setting.temperature_low = 99500; | ||
3678 | data->thermal_temp_setting.temperature_high = 100000; | ||
3679 | data->thermal_temp_setting.temperature_shutdown = 104000; | ||
3680 | data->uvd_enabled = false; | ||
3681 | |||
3682 | table = &data->smc_state_table; | ||
3683 | |||
3684 | if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, | ||
3685 | &gpio_pin_assignment)) { | ||
3686 | table->VRHotGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift; | ||
3687 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3688 | PHM_PlatformCaps_RegulatorHot); | ||
3689 | } else { | ||
3690 | table->VRHotGpio = ICELAND_UNUSED_GPIO_PIN; | ||
3691 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3692 | PHM_PlatformCaps_RegulatorHot); | ||
3693 | } | ||
3694 | |||
3695 | if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID, | ||
3696 | &gpio_pin_assignment)) { | ||
3697 | table->AcDcGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift; | ||
3698 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3699 | PHM_PlatformCaps_AutomaticDCTransition); | ||
3700 | } else { | ||
3701 | table->AcDcGpio = ICELAND_UNUSED_GPIO_PIN; | ||
3702 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3703 | PHM_PlatformCaps_AutomaticDCTransition); | ||
3704 | } | ||
3705 | |||
3706 | /* | ||
3707 | * If ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable, Peak. | ||
3708 | * Current Control feature is enabled and we should program | ||
3709 | * PCC HW register | ||
3710 | */ | ||
3711 | if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_PCC_GPIO_PINID, | ||
3712 | &gpio_pin_assignment)) { | ||
3713 | uint32_t temp_reg = cgs_read_ind_register(hwmgr->device, | ||
3714 | CGS_IND_REG__SMC, | ||
3715 | ixCNB_PWRMGT_CNTL); | ||
3716 | |||
3717 | switch (gpio_pin_assignment.uc_gpio_pin_bit_shift) { | ||
3718 | case 0: | ||
3719 | temp_reg = PHM_SET_FIELD(temp_reg, | ||
3720 | CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x1); | ||
3721 | break; | ||
3722 | case 1: | ||
3723 | temp_reg = PHM_SET_FIELD(temp_reg, | ||
3724 | CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x2); | ||
3725 | break; | ||
3726 | case 2: | ||
3727 | temp_reg = PHM_SET_FIELD(temp_reg, | ||
3728 | CNB_PWRMGT_CNTL, GNB_SLOW, 0x1); | ||
3729 | break; | ||
3730 | case 3: | ||
3731 | temp_reg = PHM_SET_FIELD(temp_reg, | ||
3732 | CNB_PWRMGT_CNTL, FORCE_NB_PS1, 0x1); | ||
3733 | break; | ||
3734 | case 4: | ||
3735 | temp_reg = PHM_SET_FIELD(temp_reg, | ||
3736 | CNB_PWRMGT_CNTL, DPM_ENABLED, 0x1); | ||
3737 | break; | ||
3738 | default: | ||
3739 | pr_warning("[ powerplay ] Failed to setup PCC HW register! Wrong GPIO assigned for VDDC_PCC_GPIO_PINID!\n"); | ||
3740 | break; | ||
3741 | } | ||
3742 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, | ||
3743 | ixCNB_PWRMGT_CNTL, temp_reg); | ||
3744 | } | ||
3745 | |||
3746 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3747 | PHM_PlatformCaps_EnableSMU7ThermalManagement); | ||
3748 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3749 | PHM_PlatformCaps_SMU7); | ||
3750 | |||
3751 | if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr, | ||
3752 | VOLTAGE_TYPE_VDDC, | ||
3753 | VOLTAGE_OBJ_GPIO_LUT)) | ||
3754 | data->voltage_control = ICELAND_VOLTAGE_CONTROL_BY_GPIO; | ||
3755 | else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr, | ||
3756 | VOLTAGE_TYPE_VDDC, | ||
3757 | VOLTAGE_OBJ_SVID2)) | ||
3758 | data->voltage_control = ICELAND_VOLTAGE_CONTROL_BY_SVID2; | ||
3759 | |||
3760 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3761 | PHM_PlatformCaps_ControlVDDCI)) { | ||
3762 | if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr, | ||
3763 | VOLTAGE_TYPE_VDDCI, | ||
3764 | VOLTAGE_OBJ_GPIO_LUT)) | ||
3765 | data->vdd_ci_control = ICELAND_VOLTAGE_CONTROL_BY_GPIO; | ||
3766 | else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr, | ||
3767 | VOLTAGE_TYPE_VDDCI, | ||
3768 | VOLTAGE_OBJ_SVID2)) | ||
3769 | data->vdd_ci_control = ICELAND_VOLTAGE_CONTROL_BY_SVID2; | ||
3770 | } | ||
3771 | |||
3772 | if (data->vdd_ci_control == ICELAND_VOLTAGE_CONTROL_NONE) | ||
3773 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3774 | PHM_PlatformCaps_ControlVDDCI); | ||
3775 | |||
3776 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3777 | PHM_PlatformCaps_EnableMVDDControl)) { | ||
3778 | if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr, | ||
3779 | VOLTAGE_TYPE_MVDDC, | ||
3780 | VOLTAGE_OBJ_GPIO_LUT)) | ||
3781 | data->mvdd_control = ICELAND_VOLTAGE_CONTROL_BY_GPIO; | ||
3782 | else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr, | ||
3783 | VOLTAGE_TYPE_MVDDC, | ||
3784 | VOLTAGE_OBJ_SVID2)) | ||
3785 | data->mvdd_control = ICELAND_VOLTAGE_CONTROL_BY_SVID2; | ||
3786 | } | ||
3787 | |||
3788 | if (data->mvdd_control == ICELAND_VOLTAGE_CONTROL_NONE) | ||
3789 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3790 | PHM_PlatformCaps_EnableMVDDControl); | ||
3791 | |||
3792 | data->vddc_phase_shed_control = false; | ||
3793 | |||
3794 | stay_in_boot = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
3795 | PHM_PlatformCaps_StayInBootState); | ||
3796 | |||
3797 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3798 | PHM_PlatformCaps_DynamicPowerManagement); | ||
3799 | |||
3800 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3801 | PHM_PlatformCaps_ActivityReporting); | ||
3802 | |||
3803 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3804 | PHM_PlatformCaps_GFXClockGatingSupport); | ||
3805 | |||
3806 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3807 | PHM_PlatformCaps_MemorySpreadSpectrumSupport); | ||
3808 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3809 | PHM_PlatformCaps_EngineSpreadSpectrumSupport); | ||
3810 | |||
3811 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3812 | PHM_PlatformCaps_DynamicPCIEGen2Support); | ||
3813 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3814 | PHM_PlatformCaps_SMC); | ||
3815 | |||
3816 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3817 | PHM_PlatformCaps_DisablePowerGating); | ||
3818 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3819 | PHM_PlatformCaps_BACO); | ||
3820 | |||
3821 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3822 | PHM_PlatformCaps_ThermalAutoThrottling); | ||
3823 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3824 | PHM_PlatformCaps_DisableLSClockGating); | ||
3825 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3826 | PHM_PlatformCaps_SamuDPM); | ||
3827 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3828 | PHM_PlatformCaps_AcpDPM); | ||
3829 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3830 | PHM_PlatformCaps_OD6inACSupport); | ||
3831 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3832 | PHM_PlatformCaps_EnablePlatformPowerManagement); | ||
3833 | |||
3834 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3835 | PHM_PlatformCaps_PauseMMSessions); | ||
3836 | |||
3837 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3838 | PHM_PlatformCaps_OD6PlusinACSupport); | ||
3839 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3840 | PHM_PlatformCaps_PauseMMSessions); | ||
3841 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3842 | PHM_PlatformCaps_GFXClockGatingManagedInCAIL); | ||
3843 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3844 | PHM_PlatformCaps_IcelandULPSSWWorkAround); | ||
3845 | |||
3846 | |||
3847 | /* iceland doesn't support UVD and VCE */ | ||
3848 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3849 | PHM_PlatformCaps_UVDPowerGating); | ||
3850 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
3851 | PHM_PlatformCaps_VCEPowerGating); | ||
3852 | |||
3853 | sys_info.size = sizeof(struct cgs_system_info); | ||
3854 | sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS; | ||
3855 | result = cgs_query_system_info(hwmgr->device, &sys_info); | ||
3856 | if (!result) { | ||
3857 | if (sys_info.value & AMD_PG_SUPPORT_UVD) | ||
3858 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3859 | PHM_PlatformCaps_UVDPowerGating); | ||
3860 | if (sys_info.value & AMD_PG_SUPPORT_VCE) | ||
3861 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
3862 | PHM_PlatformCaps_VCEPowerGating); | ||
3863 | |||
3864 | data->is_tlu_enabled = false; | ||
3865 | hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = | ||
3866 | ICELAND_MAX_HARDWARE_POWERLEVELS; | ||
3867 | hwmgr->platform_descriptor.hardwarePerformanceLevels = 2; | ||
3868 | hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; | ||
3869 | |||
3870 | sys_info.size = sizeof(struct cgs_system_info); | ||
3871 | sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO; | ||
3872 | result = cgs_query_system_info(hwmgr->device, &sys_info); | ||
3873 | if (result) | ||
3874 | data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK; | ||
3875 | else | ||
3876 | data->pcie_gen_cap = (uint32_t)sys_info.value; | ||
3877 | if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) | ||
3878 | data->pcie_spc_cap = 20; | ||
3879 | sys_info.size = sizeof(struct cgs_system_info); | ||
3880 | sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW; | ||
3881 | result = cgs_query_system_info(hwmgr->device, &sys_info); | ||
3882 | if (result) | ||
3883 | data->pcie_lane_cap = AMDGPU_DEFAULT_PCIE_MLW_MASK; | ||
3884 | else | ||
3885 | data->pcie_lane_cap = (uint32_t)sys_info.value; | ||
3886 | } else { | ||
3887 | /* Ignore return value in here, we are cleaning up a mess. */ | ||
3888 | iceland_hwmgr_backend_fini(hwmgr); | ||
3889 | } | ||
3890 | |||
3891 | return 0; | ||
3892 | failed: | ||
3893 | return result; | ||
3894 | } | ||
3895 | |||
3896 | static int iceland_get_num_of_entries(struct pp_hwmgr *hwmgr) | ||
3897 | { | ||
3898 | int result; | ||
3899 | unsigned long ret = 0; | ||
3900 | |||
3901 | result = pp_tables_get_num_of_entries(hwmgr, &ret); | ||
3902 | |||
3903 | return result ? 0 : ret; | ||
3904 | } | ||
3905 | |||
3906 | static const unsigned long PhwIceland_Magic = (unsigned long)(PHM_VIslands_Magic); | ||
3907 | |||
3908 | struct iceland_power_state *cast_phw_iceland_power_state( | ||
3909 | struct pp_hw_power_state *hw_ps) | ||
3910 | { | ||
3911 | if (hw_ps == NULL) | ||
3912 | return NULL; | ||
3913 | |||
3914 | PP_ASSERT_WITH_CODE((PhwIceland_Magic == hw_ps->magic), | ||
3915 | "Invalid Powerstate Type!", | ||
3916 | return NULL); | ||
3917 | |||
3918 | return (struct iceland_power_state *)hw_ps; | ||
3919 | } | ||
3920 | |||
3921 | static int iceland_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, | ||
3922 | struct pp_power_state *prequest_ps, | ||
3923 | const struct pp_power_state *pcurrent_ps) | ||
3924 | { | ||
3925 | struct iceland_power_state *iceland_ps = | ||
3926 | cast_phw_iceland_power_state(&prequest_ps->hardware); | ||
3927 | |||
3928 | uint32_t sclk; | ||
3929 | uint32_t mclk; | ||
3930 | struct PP_Clocks minimum_clocks = {0}; | ||
3931 | bool disable_mclk_switching; | ||
3932 | bool disable_mclk_switching_for_frame_lock; | ||
3933 | struct cgs_display_info info = {0}; | ||
3934 | const struct phm_clock_and_voltage_limits *max_limits; | ||
3935 | uint32_t i; | ||
3936 | iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
3937 | |||
3938 | int32_t count; | ||
3939 | int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0; | ||
3940 | |||
3941 | data->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label); | ||
3942 | |||
3943 | PP_ASSERT_WITH_CODE(iceland_ps->performance_level_count == 2, | ||
3944 | "VI should always have 2 performance levels", | ||
3945 | ); | ||
3946 | |||
3947 | max_limits = (PP_PowerSource_AC == hwmgr->power_source) ? | ||
3948 | &(hwmgr->dyn_state.max_clock_voltage_on_ac) : | ||
3949 | &(hwmgr->dyn_state.max_clock_voltage_on_dc); | ||
3950 | |||
3951 | if (PP_PowerSource_DC == hwmgr->power_source) { | ||
3952 | for (i = 0; i < iceland_ps->performance_level_count; i++) { | ||
3953 | if (iceland_ps->performance_levels[i].memory_clock > max_limits->mclk) | ||
3954 | iceland_ps->performance_levels[i].memory_clock = max_limits->mclk; | ||
3955 | if (iceland_ps->performance_levels[i].engine_clock > max_limits->sclk) | ||
3956 | iceland_ps->performance_levels[i].engine_clock = max_limits->sclk; | ||
3957 | } | ||
3958 | } | ||
3959 | |||
3960 | iceland_ps->vce_clocks.EVCLK = hwmgr->vce_arbiter.evclk; | ||
3961 | iceland_ps->vce_clocks.ECCLK = hwmgr->vce_arbiter.ecclk; | ||
3962 | |||
3963 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
3964 | |||
3965 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) { | ||
3966 | |||
3967 | max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac); | ||
3968 | stable_pstate_sclk = (max_limits->sclk * 75) / 100; | ||
3969 | |||
3970 | for (count = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1; count >= 0; count--) { | ||
3971 | if (stable_pstate_sclk >= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk) { | ||
3972 | stable_pstate_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk; | ||
3973 | break; | ||
3974 | } | ||
3975 | } | ||
3976 | |||
3977 | if (count < 0) | ||
3978 | stable_pstate_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].clk; | ||
3979 | |||
3980 | stable_pstate_mclk = max_limits->mclk; | ||
3981 | |||
3982 | minimum_clocks.engineClock = stable_pstate_sclk; | ||
3983 | minimum_clocks.memoryClock = stable_pstate_mclk; | ||
3984 | } | ||
3985 | |||
3986 | if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk) | ||
3987 | minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk; | ||
3988 | |||
3989 | if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk) | ||
3990 | minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk; | ||
3991 | |||
3992 | iceland_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold; | ||
3993 | |||
3994 | if (0 != hwmgr->gfx_arbiter.sclk_over_drive) { | ||
3995 | PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.engineClock), | ||
3996 | "Overdrive sclk exceeds limit", | ||
3997 | hwmgr->gfx_arbiter.sclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.engineClock); | ||
3998 | |||
3999 | if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk) | ||
4000 | iceland_ps->performance_levels[1].engine_clock = hwmgr->gfx_arbiter.sclk_over_drive; | ||
4001 | } | ||
4002 | |||
4003 | if (0 != hwmgr->gfx_arbiter.mclk_over_drive) { | ||
4004 | PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.memoryClock), | ||
4005 | "Overdrive mclk exceeds limit", | ||
4006 | hwmgr->gfx_arbiter.mclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.memoryClock); | ||
4007 | |||
4008 | if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk) | ||
4009 | iceland_ps->performance_levels[1].memory_clock = hwmgr->gfx_arbiter.mclk_over_drive; | ||
4010 | } | ||
4011 | |||
4012 | disable_mclk_switching_for_frame_lock = phm_cap_enabled( | ||
4013 | hwmgr->platform_descriptor.platformCaps, | ||
4014 | PHM_PlatformCaps_DisableMclkSwitchingForFrameLock); | ||
4015 | |||
4016 | disable_mclk_switching = (1 < info.display_count) || | ||
4017 | disable_mclk_switching_for_frame_lock; | ||
4018 | |||
4019 | sclk = iceland_ps->performance_levels[0].engine_clock; | ||
4020 | mclk = iceland_ps->performance_levels[0].memory_clock; | ||
4021 | |||
4022 | if (disable_mclk_switching) | ||
4023 | mclk = iceland_ps->performance_levels[iceland_ps->performance_level_count - 1].memory_clock; | ||
4024 | |||
4025 | if (sclk < minimum_clocks.engineClock) | ||
4026 | sclk = (minimum_clocks.engineClock > max_limits->sclk) ? max_limits->sclk : minimum_clocks.engineClock; | ||
4027 | |||
4028 | if (mclk < minimum_clocks.memoryClock) | ||
4029 | mclk = (minimum_clocks.memoryClock > max_limits->mclk) ? max_limits->mclk : minimum_clocks.memoryClock; | ||
4030 | |||
4031 | iceland_ps->performance_levels[0].engine_clock = sclk; | ||
4032 | iceland_ps->performance_levels[0].memory_clock = mclk; | ||
4033 | |||
4034 | iceland_ps->performance_levels[1].engine_clock = | ||
4035 | (iceland_ps->performance_levels[1].engine_clock >= iceland_ps->performance_levels[0].engine_clock) ? | ||
4036 | iceland_ps->performance_levels[1].engine_clock : | ||
4037 | iceland_ps->performance_levels[0].engine_clock; | ||
4038 | |||
4039 | if (disable_mclk_switching) { | ||
4040 | if (mclk < iceland_ps->performance_levels[1].memory_clock) | ||
4041 | mclk = iceland_ps->performance_levels[1].memory_clock; | ||
4042 | |||
4043 | iceland_ps->performance_levels[0].memory_clock = mclk; | ||
4044 | iceland_ps->performance_levels[1].memory_clock = mclk; | ||
4045 | } else { | ||
4046 | if (iceland_ps->performance_levels[1].memory_clock < iceland_ps->performance_levels[0].memory_clock) | ||
4047 | iceland_ps->performance_levels[1].memory_clock = iceland_ps->performance_levels[0].memory_clock; | ||
4048 | } | ||
4049 | |||
4050 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) { | ||
4051 | for (i=0; i < iceland_ps->performance_level_count; i++) { | ||
4052 | iceland_ps->performance_levels[i].engine_clock = stable_pstate_sclk; | ||
4053 | iceland_ps->performance_levels[i].memory_clock = stable_pstate_mclk; | ||
4054 | iceland_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max; | ||
4055 | iceland_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max; | ||
4056 | } | ||
4057 | } | ||
4058 | |||
4059 | return 0; | ||
4060 | } | ||
4061 | |||
4062 | static bool iceland_is_dpm_running(struct pp_hwmgr *hwmgr) | ||
4063 | { | ||
4064 | /* | ||
4065 | * We return the status of Voltage Control instead of checking SCLK/MCLK DPM | ||
4066 | * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM, | ||
4067 | * whereas voltage control is a fundemental change that will not be disabled | ||
4068 | */ | ||
4069 | return (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, | ||
4070 | FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) ? 1 : 0); | ||
4071 | } | ||
4072 | |||
4073 | /** | ||
4074 | * force DPM power State | ||
4075 | * | ||
4076 | * @param hwmgr: the address of the powerplay hardware manager. | ||
4077 | * @param n : DPM level | ||
4078 | * @return The response that came from the SMC. | ||
4079 | */ | ||
4080 | int iceland_dpm_force_state(struct pp_hwmgr *hwmgr, uint32_t n) | ||
4081 | { | ||
4082 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
4083 | |||
4084 | /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */ | ||
4085 | PP_ASSERT_WITH_CODE(0 == iceland_is_dpm_running(hwmgr), | ||
4086 | "Trying to force SCLK when DPM is disabled", return -1;); | ||
4087 | if (0 == data->sclk_dpm_key_disabled) | ||
4088 | return (0 == smum_send_msg_to_smc_with_parameter( | ||
4089 | hwmgr->smumgr, | ||
4090 | PPSMC_MSG_DPM_ForceState, | ||
4091 | n) ? 0 : 1); | ||
4092 | |||
4093 | return 0; | ||
4094 | } | ||
4095 | |||
4096 | /** | ||
4097 | * force DPM power State | ||
4098 | * | ||
4099 | * @param hwmgr: the address of the powerplay hardware manager. | ||
4100 | * @param n : DPM level | ||
4101 | * @return The response that came from the SMC. | ||
4102 | */ | ||
4103 | int iceland_dpm_force_state_mclk(struct pp_hwmgr *hwmgr, uint32_t n) | ||
4104 | { | ||
4105 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
4106 | |||
4107 | /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */ | ||
4108 | PP_ASSERT_WITH_CODE(0 == iceland_is_dpm_running(hwmgr), | ||
4109 | "Trying to Force MCLK when DPM is disabled", return -1;); | ||
4110 | if (0 == data->mclk_dpm_key_disabled) | ||
4111 | return (0 == smum_send_msg_to_smc_with_parameter( | ||
4112 | hwmgr->smumgr, | ||
4113 | PPSMC_MSG_MCLKDPM_ForceState, | ||
4114 | n) ? 0 : 1); | ||
4115 | |||
4116 | return 0; | ||
4117 | } | ||
4118 | |||
4119 | /** | ||
4120 | * force DPM power State | ||
4121 | * | ||
4122 | * @param hwmgr: the address of the powerplay hardware manager. | ||
4123 | * @param n : DPM level | ||
4124 | * @return The response that came from the SMC. | ||
4125 | */ | ||
4126 | int iceland_dpm_force_state_pcie(struct pp_hwmgr *hwmgr, uint32_t n) | ||
4127 | { | ||
4128 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
4129 | |||
4130 | /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/ | ||
4131 | PP_ASSERT_WITH_CODE(0 == iceland_is_dpm_running(hwmgr), | ||
4132 | "Trying to Force PCIE level when DPM is disabled", return -1;); | ||
4133 | if (0 == data->pcie_dpm_key_disabled) | ||
4134 | return (0 == smum_send_msg_to_smc_with_parameter( | ||
4135 | hwmgr->smumgr, | ||
4136 | PPSMC_MSG_PCIeDPM_ForceLevel, | ||
4137 | n) ? 0 : 1); | ||
4138 | |||
4139 | return 0; | ||
4140 | } | ||
4141 | |||
4142 | static int iceland_force_dpm_highest(struct pp_hwmgr *hwmgr) | ||
4143 | { | ||
4144 | uint32_t level, tmp; | ||
4145 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
4146 | |||
4147 | if (0 == data->sclk_dpm_key_disabled) { | ||
4148 | /* SCLK */ | ||
4149 | if (data->dpm_level_enable_mask.sclk_dpm_enable_mask != 0) { | ||
4150 | level = 0; | ||
4151 | tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask; | ||
4152 | while (tmp >>= 1) | ||
4153 | level++ ; | ||
4154 | |||
4155 | if (0 != level) { | ||
4156 | PP_ASSERT_WITH_CODE((0 == iceland_dpm_force_state(hwmgr, level)), | ||
4157 | "force highest sclk dpm state failed!", return -1); | ||
4158 | PHM_WAIT_INDIRECT_FIELD(hwmgr->device, | ||
4159 | SMC_IND, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX, level); | ||
4160 | } | ||
4161 | } | ||
4162 | } | ||
4163 | |||
4164 | if (0 == data->mclk_dpm_key_disabled) { | ||
4165 | /* MCLK */ | ||
4166 | if (data->dpm_level_enable_mask.mclk_dpm_enable_mask != 0) { | ||
4167 | level = 0; | ||
4168 | tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask; | ||
4169 | while (tmp >>= 1) | ||
4170 | level++ ; | ||
4171 | |||
4172 | if (0 != level) { | ||
4173 | PP_ASSERT_WITH_CODE((0 == iceland_dpm_force_state_mclk(hwmgr, level)), | ||
4174 | "force highest mclk dpm state failed!", return -1); | ||
4175 | PHM_WAIT_INDIRECT_FIELD(hwmgr->device, SMC_IND, | ||
4176 | TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX, level); | ||
4177 | } | ||
4178 | } | ||
4179 | } | ||
4180 | |||
4181 | if (0 == data->pcie_dpm_key_disabled) { | ||
4182 | /* PCIE */ | ||
4183 | if (data->dpm_level_enable_mask.pcie_dpm_enable_mask != 0) { | ||
4184 | level = 0; | ||
4185 | tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask; | ||
4186 | while (tmp >>= 1) | ||
4187 | level++ ; | ||
4188 | |||
4189 | if (0 != level) { | ||
4190 | PP_ASSERT_WITH_CODE((0 == iceland_dpm_force_state_pcie(hwmgr, level)), | ||
4191 | "force highest pcie dpm state failed!", return -1); | ||
4192 | } | ||
4193 | } | ||
4194 | } | ||
4195 | |||
4196 | return 0; | ||
4197 | } | ||
4198 | |||
4199 | static uint32_t iceland_get_lowest_enable_level(struct pp_hwmgr *hwmgr, | ||
4200 | uint32_t level_mask) | ||
4201 | { | ||
4202 | uint32_t level = 0; | ||
4203 | |||
4204 | while (0 == (level_mask & (1 << level))) | ||
4205 | level++; | ||
4206 | |||
4207 | return level; | ||
4208 | } | ||
4209 | |||
4210 | static int iceland_force_dpm_lowest(struct pp_hwmgr *hwmgr) | ||
4211 | { | ||
4212 | uint32_t level; | ||
4213 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
4214 | |||
4215 | /* for now force only sclk */ | ||
4216 | if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) { | ||
4217 | level = iceland_get_lowest_enable_level(hwmgr, | ||
4218 | data->dpm_level_enable_mask.sclk_dpm_enable_mask); | ||
4219 | |||
4220 | PP_ASSERT_WITH_CODE((0 == iceland_dpm_force_state(hwmgr, level)), | ||
4221 | "force sclk dpm state failed!", return -1); | ||
4222 | |||
4223 | PHM_WAIT_INDIRECT_FIELD(hwmgr->device, SMC_IND, | ||
4224 | TARGET_AND_CURRENT_PROFILE_INDEX, | ||
4225 | CURR_SCLK_INDEX, | ||
4226 | level); | ||
4227 | } | ||
4228 | |||
4229 | return 0; | ||
4230 | } | ||
4231 | |||
4232 | int iceland_unforce_dpm_levels(struct pp_hwmgr *hwmgr) | ||
4233 | { | ||
4234 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
4235 | |||
4236 | PP_ASSERT_WITH_CODE (0 == iceland_is_dpm_running(hwmgr), | ||
4237 | "Trying to Unforce DPM when DPM is disabled. Returning without sending SMC message.", | ||
4238 | return -1); | ||
4239 | |||
4240 | if (0 == data->sclk_dpm_key_disabled) { | ||
4241 | PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc( | ||
4242 | hwmgr->smumgr, | ||
4243 | PPSMC_MSG_NoForcedLevel)), | ||
4244 | "unforce sclk dpm state failed!", | ||
4245 | return -1); | ||
4246 | } | ||
4247 | |||
4248 | if (0 == data->mclk_dpm_key_disabled) { | ||
4249 | PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc( | ||
4250 | hwmgr->smumgr, | ||
4251 | PPSMC_MSG_MCLKDPM_NoForcedLevel)), | ||
4252 | "unforce mclk dpm state failed!", | ||
4253 | return -1); | ||
4254 | } | ||
4255 | |||
4256 | if (0 == data->pcie_dpm_key_disabled) { | ||
4257 | PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc( | ||
4258 | hwmgr->smumgr, | ||
4259 | PPSMC_MSG_PCIeDPM_UnForceLevel)), | ||
4260 | "unforce pcie level failed!", | ||
4261 | return -1); | ||
4262 | } | ||
4263 | |||
4264 | return 0; | ||
4265 | } | ||
4266 | |||
4267 | static int iceland_force_dpm_level(struct pp_hwmgr *hwmgr, | ||
4268 | enum amd_dpm_forced_level level) | ||
4269 | { | ||
4270 | int ret = 0; | ||
4271 | |||
4272 | switch (level) { | ||
4273 | case AMD_DPM_FORCED_LEVEL_HIGH: | ||
4274 | ret = iceland_force_dpm_highest(hwmgr); | ||
4275 | if (ret) | ||
4276 | return ret; | ||
4277 | break; | ||
4278 | case AMD_DPM_FORCED_LEVEL_LOW: | ||
4279 | ret = iceland_force_dpm_lowest(hwmgr); | ||
4280 | if (ret) | ||
4281 | return ret; | ||
4282 | break; | ||
4283 | case AMD_DPM_FORCED_LEVEL_AUTO: | ||
4284 | ret = iceland_unforce_dpm_levels(hwmgr); | ||
4285 | if (ret) | ||
4286 | return ret; | ||
4287 | break; | ||
4288 | default: | ||
4289 | break; | ||
4290 | } | ||
4291 | |||
4292 | hwmgr->dpm_level = level; | ||
4293 | return ret; | ||
4294 | } | ||
4295 | |||
4296 | const struct iceland_power_state *cast_const_phw_iceland_power_state( | ||
4297 | const struct pp_hw_power_state *hw_ps) | ||
4298 | { | ||
4299 | if (hw_ps == NULL) | ||
4300 | return NULL; | ||
4301 | |||
4302 | PP_ASSERT_WITH_CODE((PhwIceland_Magic == hw_ps->magic), | ||
4303 | "Invalid Powerstate Type!", | ||
4304 | return NULL); | ||
4305 | |||
4306 | return (const struct iceland_power_state *)hw_ps; | ||
4307 | } | ||
4308 | |||
4309 | static int iceland_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input) | ||
4310 | { | ||
4311 | const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input; | ||
4312 | const struct iceland_power_state *iceland_ps = cast_const_phw_iceland_power_state(states->pnew_state); | ||
4313 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4314 | struct iceland_single_dpm_table *psclk_table = &(data->dpm_table.sclk_table); | ||
4315 | uint32_t sclk = iceland_ps->performance_levels[iceland_ps->performance_level_count-1].engine_clock; | ||
4316 | struct iceland_single_dpm_table *pmclk_table = &(data->dpm_table.mclk_table); | ||
4317 | uint32_t mclk = iceland_ps->performance_levels[iceland_ps->performance_level_count-1].memory_clock; | ||
4318 | struct PP_Clocks min_clocks = {0}; | ||
4319 | uint32_t i; | ||
4320 | struct cgs_display_info info = {0}; | ||
4321 | |||
4322 | data->need_update_smu7_dpm_table = 0; | ||
4323 | |||
4324 | for (i = 0; i < psclk_table->count; i++) { | ||
4325 | if (sclk == psclk_table->dpm_levels[i].value) | ||
4326 | break; | ||
4327 | } | ||
4328 | |||
4329 | if (i >= psclk_table->count) | ||
4330 | data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; | ||
4331 | else { | ||
4332 | /* | ||
4333 | * TODO: Check SCLK in DAL's minimum clocks in case DeepSleep | ||
4334 | * divider update is required. | ||
4335 | */ | ||
4336 | if(data->display_timing.min_clock_insr != min_clocks.engineClockInSR) | ||
4337 | data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK; | ||
4338 | } | ||
4339 | |||
4340 | for (i = 0; i < pmclk_table->count; i++) { | ||
4341 | if (mclk == pmclk_table->dpm_levels[i].value) | ||
4342 | break; | ||
4343 | } | ||
4344 | |||
4345 | if (i >= pmclk_table->count) | ||
4346 | data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; | ||
4347 | |||
4348 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
4349 | |||
4350 | if (data->display_timing.num_existing_displays != info.display_count) | ||
4351 | data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK; | ||
4352 | |||
4353 | return 0; | ||
4354 | } | ||
4355 | |||
4356 | static uint16_t iceland_get_maximum_link_speed(struct pp_hwmgr *hwmgr, const struct iceland_power_state *hw_ps) | ||
4357 | { | ||
4358 | uint32_t i; | ||
4359 | uint32_t pcie_speed, max_speed = 0; | ||
4360 | |||
4361 | for (i = 0; i < hw_ps->performance_level_count; i++) { | ||
4362 | pcie_speed = hw_ps->performance_levels[i].pcie_gen; | ||
4363 | if (max_speed < pcie_speed) | ||
4364 | max_speed = pcie_speed; | ||
4365 | } | ||
4366 | |||
4367 | return max_speed; | ||
4368 | } | ||
4369 | |||
4370 | static uint16_t iceland_get_current_pcie_speed(struct pp_hwmgr *hwmgr) | ||
4371 | { | ||
4372 | uint32_t speed_cntl = 0; | ||
4373 | |||
4374 | speed_cntl = cgs_read_ind_register(hwmgr->device, | ||
4375 | CGS_IND_REG__PCIE, | ||
4376 | ixPCIE_LC_SPEED_CNTL); | ||
4377 | return((uint16_t)PHM_GET_FIELD(speed_cntl, | ||
4378 | PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE)); | ||
4379 | } | ||
4380 | |||
4381 | |||
4382 | static int iceland_request_link_speed_change_before_state_change(struct pp_hwmgr *hwmgr, const void *input) | ||
4383 | { | ||
4384 | const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input; | ||
4385 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4386 | const struct iceland_power_state *iceland_nps = cast_const_phw_iceland_power_state(states->pnew_state); | ||
4387 | const struct iceland_power_state *iceland_cps = cast_const_phw_iceland_power_state(states->pcurrent_state); | ||
4388 | |||
4389 | uint16_t target_link_speed = iceland_get_maximum_link_speed(hwmgr, iceland_nps); | ||
4390 | uint16_t current_link_speed; | ||
4391 | |||
4392 | if (data->force_pcie_gen == PP_PCIEGenInvalid) | ||
4393 | current_link_speed = iceland_get_maximum_link_speed(hwmgr, iceland_cps); | ||
4394 | else | ||
4395 | current_link_speed = data->force_pcie_gen; | ||
4396 | |||
4397 | data->force_pcie_gen = PP_PCIEGenInvalid; | ||
4398 | data->pspp_notify_required = false; | ||
4399 | if (target_link_speed > current_link_speed) { | ||
4400 | switch(target_link_speed) { | ||
4401 | case PP_PCIEGen3: | ||
4402 | if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false)) | ||
4403 | break; | ||
4404 | data->force_pcie_gen = PP_PCIEGen2; | ||
4405 | if (current_link_speed == PP_PCIEGen2) | ||
4406 | break; | ||
4407 | case PP_PCIEGen2: | ||
4408 | if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false)) | ||
4409 | break; | ||
4410 | default: | ||
4411 | data->force_pcie_gen = iceland_get_current_pcie_speed(hwmgr); | ||
4412 | break; | ||
4413 | } | ||
4414 | } else { | ||
4415 | if (target_link_speed < current_link_speed) | ||
4416 | data->pspp_notify_required = true; | ||
4417 | } | ||
4418 | |||
4419 | return 0; | ||
4420 | } | ||
4421 | |||
4422 | static int iceland_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr) | ||
4423 | { | ||
4424 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4425 | |||
4426 | if (0 == data->need_update_smu7_dpm_table) | ||
4427 | return 0; | ||
4428 | |||
4429 | if ((0 == data->sclk_dpm_key_disabled) && | ||
4430 | (data->need_update_smu7_dpm_table & | ||
4431 | (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) { | ||
4432 | PP_ASSERT_WITH_CODE( | ||
4433 | 0 == iceland_is_dpm_running(hwmgr), | ||
4434 | "Trying to freeze SCLK DPM when DPM is disabled", | ||
4435 | ); | ||
4436 | PP_ASSERT_WITH_CODE( | ||
4437 | 0 == smum_send_msg_to_smc(hwmgr->smumgr, | ||
4438 | PPSMC_MSG_SCLKDPM_FreezeLevel), | ||
4439 | "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!", | ||
4440 | return -1); | ||
4441 | } | ||
4442 | |||
4443 | if ((0 == data->mclk_dpm_key_disabled) && | ||
4444 | (data->need_update_smu7_dpm_table & | ||
4445 | DPMTABLE_OD_UPDATE_MCLK)) { | ||
4446 | PP_ASSERT_WITH_CODE(0 == iceland_is_dpm_running(hwmgr), | ||
4447 | "Trying to freeze MCLK DPM when DPM is disabled", | ||
4448 | ); | ||
4449 | PP_ASSERT_WITH_CODE( | ||
4450 | 0 == smum_send_msg_to_smc(hwmgr->smumgr, | ||
4451 | PPSMC_MSG_MCLKDPM_FreezeLevel), | ||
4452 | "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!", | ||
4453 | return -1); | ||
4454 | } | ||
4455 | |||
4456 | return 0; | ||
4457 | } | ||
4458 | |||
4459 | static int iceland_populate_and_upload_sclk_mclk_dpm_levels(struct pp_hwmgr *hwmgr, const void *input) | ||
4460 | { | ||
4461 | int result = 0; | ||
4462 | |||
4463 | const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input; | ||
4464 | const struct iceland_power_state *iceland_ps = cast_const_phw_iceland_power_state(states->pnew_state); | ||
4465 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4466 | uint32_t sclk = iceland_ps->performance_levels[iceland_ps->performance_level_count-1].engine_clock; | ||
4467 | uint32_t mclk = iceland_ps->performance_levels[iceland_ps->performance_level_count-1].memory_clock; | ||
4468 | struct iceland_dpm_table *pdpm_table = &data->dpm_table; | ||
4469 | |||
4470 | struct iceland_dpm_table *pgolden_dpm_table = &data->golden_dpm_table; | ||
4471 | uint32_t dpm_count, clock_percent; | ||
4472 | uint32_t i; | ||
4473 | |||
4474 | if (0 == data->need_update_smu7_dpm_table) | ||
4475 | return 0; | ||
4476 | |||
4477 | if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) { | ||
4478 | pdpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value = sclk; | ||
4479 | |||
4480 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) || | ||
4481 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) { | ||
4482 | /* | ||
4483 | * Need to do calculation based on the golden DPM table | ||
4484 | * as the Heatmap GPU Clock axis is also based on the default values | ||
4485 | */ | ||
4486 | PP_ASSERT_WITH_CODE( | ||
4487 | (pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value != 0), | ||
4488 | "Divide by 0!", | ||
4489 | return -1); | ||
4490 | dpm_count = pdpm_table->sclk_table.count < 2 ? 0 : pdpm_table->sclk_table.count-2; | ||
4491 | for (i = dpm_count; i > 1; i--) { | ||
4492 | if (sclk > pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value) { | ||
4493 | clock_percent = ((sclk - pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value)*100) / | ||
4494 | pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value; | ||
4495 | |||
4496 | pdpm_table->sclk_table.dpm_levels[i].value = | ||
4497 | pgolden_dpm_table->sclk_table.dpm_levels[i].value + | ||
4498 | (pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100; | ||
4499 | |||
4500 | } else if (pgolden_dpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value > sclk) { | ||
4501 | clock_percent = ((pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value - sclk)*100) / | ||
4502 | pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value; | ||
4503 | |||
4504 | pdpm_table->sclk_table.dpm_levels[i].value = | ||
4505 | pgolden_dpm_table->sclk_table.dpm_levels[i].value - | ||
4506 | (pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100; | ||
4507 | } else | ||
4508 | pdpm_table->sclk_table.dpm_levels[i].value = | ||
4509 | pgolden_dpm_table->sclk_table.dpm_levels[i].value; | ||
4510 | } | ||
4511 | } | ||
4512 | } | ||
4513 | |||
4514 | if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) { | ||
4515 | pdpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value = mclk; | ||
4516 | |||
4517 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) || | ||
4518 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) { | ||
4519 | |||
4520 | PP_ASSERT_WITH_CODE( | ||
4521 | (pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value != 0), | ||
4522 | "Divide by 0!", | ||
4523 | return -1); | ||
4524 | dpm_count = pdpm_table->mclk_table.count < 2? 0 : pdpm_table->mclk_table.count-2; | ||
4525 | for (i = dpm_count; i > 1; i--) { | ||
4526 | if (mclk > pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value) { | ||
4527 | clock_percent = ((mclk - pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value)*100) / | ||
4528 | pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value; | ||
4529 | |||
4530 | pdpm_table->mclk_table.dpm_levels[i].value = | ||
4531 | pgolden_dpm_table->mclk_table.dpm_levels[i].value + | ||
4532 | (pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100; | ||
4533 | |||
4534 | } else if (pgolden_dpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value > mclk) { | ||
4535 | clock_percent = ((pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value - mclk)*100) / | ||
4536 | pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value; | ||
4537 | |||
4538 | pdpm_table->mclk_table.dpm_levels[i].value = | ||
4539 | pgolden_dpm_table->mclk_table.dpm_levels[i].value - | ||
4540 | (pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100; | ||
4541 | } else | ||
4542 | pdpm_table->mclk_table.dpm_levels[i].value = pgolden_dpm_table->mclk_table.dpm_levels[i].value; | ||
4543 | } | ||
4544 | } | ||
4545 | } | ||
4546 | |||
4547 | |||
4548 | if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) { | ||
4549 | result = iceland_populate_all_graphic_levels(hwmgr); | ||
4550 | PP_ASSERT_WITH_CODE((0 == result), | ||
4551 | "Failed to populate SCLK during PopulateNewDPMClocksStates Function!", | ||
4552 | return result); | ||
4553 | } | ||
4554 | |||
4555 | if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) { | ||
4556 | /*populate MCLK dpm table to SMU7 */ | ||
4557 | result = iceland_populate_all_memory_levels(hwmgr); | ||
4558 | PP_ASSERT_WITH_CODE((0 == result), | ||
4559 | "Failed to populate MCLK during PopulateNewDPMClocksStates Function!", | ||
4560 | return result); | ||
4561 | } | ||
4562 | |||
4563 | return result; | ||
4564 | } | ||
4565 | |||
4566 | static int iceland_trim_single_dpm_states(struct pp_hwmgr *hwmgr, | ||
4567 | struct iceland_single_dpm_table *pdpm_table, | ||
4568 | uint32_t low_limit, uint32_t high_limit) | ||
4569 | { | ||
4570 | uint32_t i; | ||
4571 | |||
4572 | for (i = 0; i < pdpm_table->count; i++) { | ||
4573 | if ((pdpm_table->dpm_levels[i].value < low_limit) || | ||
4574 | (pdpm_table->dpm_levels[i].value > high_limit)) | ||
4575 | pdpm_table->dpm_levels[i].enabled = false; | ||
4576 | else | ||
4577 | pdpm_table->dpm_levels[i].enabled = true; | ||
4578 | } | ||
4579 | return 0; | ||
4580 | } | ||
4581 | |||
4582 | static int iceland_trim_dpm_states(struct pp_hwmgr *hwmgr, const struct iceland_power_state *hw_state) | ||
4583 | { | ||
4584 | int result = 0; | ||
4585 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4586 | uint32_t high_limit_count; | ||
4587 | |||
4588 | PP_ASSERT_WITH_CODE((hw_state->performance_level_count >= 1), | ||
4589 | "power state did not have any performance level", | ||
4590 | return -1); | ||
4591 | |||
4592 | high_limit_count = (1 == hw_state->performance_level_count) ? 0: 1; | ||
4593 | |||
4594 | iceland_trim_single_dpm_states(hwmgr, &(data->dpm_table.sclk_table), | ||
4595 | hw_state->performance_levels[0].engine_clock, | ||
4596 | hw_state->performance_levels[high_limit_count].engine_clock); | ||
4597 | |||
4598 | iceland_trim_single_dpm_states(hwmgr, &(data->dpm_table.mclk_table), | ||
4599 | hw_state->performance_levels[0].memory_clock, | ||
4600 | hw_state->performance_levels[high_limit_count].memory_clock); | ||
4601 | |||
4602 | return result; | ||
4603 | } | ||
4604 | |||
4605 | static int iceland_generate_dpm_level_enable_mask(struct pp_hwmgr *hwmgr, const void *input) | ||
4606 | { | ||
4607 | int result; | ||
4608 | const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input; | ||
4609 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4610 | const struct iceland_power_state *iceland_ps = cast_const_phw_iceland_power_state(states->pnew_state); | ||
4611 | |||
4612 | result = iceland_trim_dpm_states(hwmgr, iceland_ps); | ||
4613 | if (0 != result) | ||
4614 | return result; | ||
4615 | |||
4616 | data->dpm_level_enable_mask.sclk_dpm_enable_mask = iceland_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table); | ||
4617 | data->dpm_level_enable_mask.mclk_dpm_enable_mask = iceland_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table); | ||
4618 | data->last_mclk_dpm_enable_mask = data->dpm_level_enable_mask.mclk_dpm_enable_mask; | ||
4619 | if (data->uvd_enabled && (data->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)) | ||
4620 | data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE; | ||
4621 | |||
4622 | data->dpm_level_enable_mask.pcie_dpm_enable_mask = iceland_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table); | ||
4623 | |||
4624 | return 0; | ||
4625 | } | ||
4626 | |||
4627 | static int iceland_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input) | ||
4628 | { | ||
4629 | return 0; | ||
4630 | } | ||
4631 | |||
4632 | int iceland_update_sclk_threshold(struct pp_hwmgr *hwmgr) | ||
4633 | { | ||
4634 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
4635 | |||
4636 | int result = 0; | ||
4637 | uint32_t low_sclk_interrupt_threshold = 0; | ||
4638 | |||
4639 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
4640 | PHM_PlatformCaps_SclkThrottleLowNotification) | ||
4641 | && (hwmgr->gfx_arbiter.sclk_threshold != data->low_sclk_interrupt_threshold)) { | ||
4642 | data->low_sclk_interrupt_threshold = hwmgr->gfx_arbiter.sclk_threshold; | ||
4643 | low_sclk_interrupt_threshold = data->low_sclk_interrupt_threshold; | ||
4644 | |||
4645 | CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold); | ||
4646 | |||
4647 | result = iceland_copy_bytes_to_smc( | ||
4648 | hwmgr->smumgr, | ||
4649 | data->dpm_table_start + offsetof(SMU71_Discrete_DpmTable, | ||
4650 | LowSclkInterruptThreshold), | ||
4651 | (uint8_t *)&low_sclk_interrupt_threshold, | ||
4652 | sizeof(uint32_t), | ||
4653 | data->sram_end | ||
4654 | ); | ||
4655 | } | ||
4656 | |||
4657 | return result; | ||
4658 | } | ||
4659 | |||
4660 | static int iceland_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr) | ||
4661 | { | ||
4662 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4663 | |||
4664 | uint32_t address; | ||
4665 | int32_t result; | ||
4666 | |||
4667 | if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) | ||
4668 | return 0; | ||
4669 | |||
4670 | |||
4671 | memset(&data->mc_reg_table, 0, sizeof(SMU71_Discrete_MCRegisters)); | ||
4672 | |||
4673 | result = iceland_convert_mc_reg_table_to_smc(hwmgr, &(data->mc_reg_table)); | ||
4674 | |||
4675 | if(result != 0) | ||
4676 | return result; | ||
4677 | |||
4678 | |||
4679 | address = data->mc_reg_table_start + (uint32_t)offsetof(SMU71_Discrete_MCRegisters, data[0]); | ||
4680 | |||
4681 | return iceland_copy_bytes_to_smc(hwmgr->smumgr, address, | ||
4682 | (uint8_t *)&data->mc_reg_table.data[0], | ||
4683 | sizeof(SMU71_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count, | ||
4684 | data->sram_end); | ||
4685 | } | ||
4686 | |||
4687 | static int iceland_program_memory_timing_parameters_conditionally(struct pp_hwmgr *hwmgr) | ||
4688 | { | ||
4689 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4690 | |||
4691 | if (data->need_update_smu7_dpm_table & | ||
4692 | (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK)) | ||
4693 | return iceland_program_memory_timing_parameters(hwmgr); | ||
4694 | |||
4695 | return 0; | ||
4696 | } | ||
4697 | |||
4698 | static int iceland_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr) | ||
4699 | { | ||
4700 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4701 | |||
4702 | if (0 == data->need_update_smu7_dpm_table) | ||
4703 | return 0; | ||
4704 | |||
4705 | if ((0 == data->sclk_dpm_key_disabled) && | ||
4706 | (data->need_update_smu7_dpm_table & | ||
4707 | (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) { | ||
4708 | |||
4709 | PP_ASSERT_WITH_CODE(0 == iceland_is_dpm_running(hwmgr), | ||
4710 | "Trying to Unfreeze SCLK DPM when DPM is disabled", | ||
4711 | ); | ||
4712 | PP_ASSERT_WITH_CODE( | ||
4713 | 0 == smum_send_msg_to_smc(hwmgr->smumgr, | ||
4714 | PPSMC_MSG_SCLKDPM_UnfreezeLevel), | ||
4715 | "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!", | ||
4716 | return -1); | ||
4717 | } | ||
4718 | |||
4719 | if ((0 == data->mclk_dpm_key_disabled) && | ||
4720 | (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) { | ||
4721 | |||
4722 | PP_ASSERT_WITH_CODE( | ||
4723 | 0 == iceland_is_dpm_running(hwmgr), | ||
4724 | "Trying to Unfreeze MCLK DPM when DPM is disabled", | ||
4725 | ); | ||
4726 | PP_ASSERT_WITH_CODE( | ||
4727 | 0 == smum_send_msg_to_smc(hwmgr->smumgr, | ||
4728 | PPSMC_MSG_MCLKDPM_UnfreezeLevel), | ||
4729 | "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!", | ||
4730 | return -1); | ||
4731 | } | ||
4732 | |||
4733 | data->need_update_smu7_dpm_table = 0; | ||
4734 | |||
4735 | return 0; | ||
4736 | } | ||
4737 | |||
4738 | static int iceland_notify_link_speed_change_after_state_change(struct pp_hwmgr *hwmgr, const void *input) | ||
4739 | { | ||
4740 | const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input; | ||
4741 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4742 | const struct iceland_power_state *iceland_ps = cast_const_phw_iceland_power_state(states->pnew_state); | ||
4743 | uint16_t target_link_speed = iceland_get_maximum_link_speed(hwmgr, iceland_ps); | ||
4744 | uint8_t request; | ||
4745 | |||
4746 | if (data->pspp_notify_required || | ||
4747 | data->pcie_performance_request) { | ||
4748 | if (target_link_speed == PP_PCIEGen3) | ||
4749 | request = PCIE_PERF_REQ_GEN3; | ||
4750 | else if (target_link_speed == PP_PCIEGen2) | ||
4751 | request = PCIE_PERF_REQ_GEN2; | ||
4752 | else | ||
4753 | request = PCIE_PERF_REQ_GEN1; | ||
4754 | |||
4755 | if(request == PCIE_PERF_REQ_GEN1 && iceland_get_current_pcie_speed(hwmgr) > 0) { | ||
4756 | data->pcie_performance_request = false; | ||
4757 | return 0; | ||
4758 | } | ||
4759 | |||
4760 | if (0 != acpi_pcie_perf_request(hwmgr->device, request, false)) { | ||
4761 | if (PP_PCIEGen2 == target_link_speed) | ||
4762 | printk("PSPP request to switch to Gen2 from Gen3 Failed!"); | ||
4763 | else | ||
4764 | printk("PSPP request to switch to Gen1 from Gen2 Failed!"); | ||
4765 | } | ||
4766 | } | ||
4767 | |||
4768 | data->pcie_performance_request = false; | ||
4769 | return 0; | ||
4770 | } | ||
4771 | |||
4772 | int iceland_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) | ||
4773 | { | ||
4774 | PPSMC_Result result; | ||
4775 | iceland_hwmgr *data = (iceland_hwmgr *)(hwmgr->backend); | ||
4776 | |||
4777 | if (0 == data->sclk_dpm_key_disabled) { | ||
4778 | /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/ | ||
4779 | if (0 != iceland_is_dpm_running(hwmgr)) | ||
4780 | printk(KERN_ERR "[ powerplay ] Trying to set Enable Sclk Mask when DPM is disabled \n"); | ||
4781 | |||
4782 | if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) { | ||
4783 | result = smum_send_msg_to_smc_with_parameter( | ||
4784 | hwmgr->smumgr, | ||
4785 | (PPSMC_Msg)PPSMC_MSG_SCLKDPM_SetEnabledMask, | ||
4786 | data->dpm_level_enable_mask.sclk_dpm_enable_mask); | ||
4787 | PP_ASSERT_WITH_CODE((0 == result), | ||
4788 | "Set Sclk Dpm enable Mask failed", return -1); | ||
4789 | } | ||
4790 | } | ||
4791 | |||
4792 | if (0 == data->mclk_dpm_key_disabled) { | ||
4793 | /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/ | ||
4794 | if (0 != iceland_is_dpm_running(hwmgr)) | ||
4795 | printk(KERN_ERR "[ powerplay ] Trying to set Enable Mclk Mask when DPM is disabled \n"); | ||
4796 | |||
4797 | if (0 != data->dpm_level_enable_mask.mclk_dpm_enable_mask) { | ||
4798 | result = smum_send_msg_to_smc_with_parameter( | ||
4799 | hwmgr->smumgr, | ||
4800 | (PPSMC_Msg)PPSMC_MSG_MCLKDPM_SetEnabledMask, | ||
4801 | data->dpm_level_enable_mask.mclk_dpm_enable_mask); | ||
4802 | PP_ASSERT_WITH_CODE((0 == result), | ||
4803 | "Set Mclk Dpm enable Mask failed", return -1); | ||
4804 | } | ||
4805 | } | ||
4806 | |||
4807 | return 0; | ||
4808 | } | ||
4809 | |||
4810 | static int iceland_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input) | ||
4811 | { | ||
4812 | int tmp_result, result = 0; | ||
4813 | |||
4814 | tmp_result = iceland_find_dpm_states_clocks_in_dpm_table(hwmgr, input); | ||
4815 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to find DPM states clocks in DPM table!", result = tmp_result); | ||
4816 | |||
4817 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) { | ||
4818 | tmp_result = iceland_request_link_speed_change_before_state_change(hwmgr, input); | ||
4819 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to request link speed change before state change!", result = tmp_result); | ||
4820 | } | ||
4821 | |||
4822 | tmp_result = iceland_freeze_sclk_mclk_dpm(hwmgr); | ||
4823 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to freeze SCLK MCLK DPM!", result = tmp_result); | ||
4824 | |||
4825 | tmp_result = iceland_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input); | ||
4826 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to populate and upload SCLK MCLK DPM levels!", result = tmp_result); | ||
4827 | |||
4828 | tmp_result = iceland_generate_dpm_level_enable_mask(hwmgr, input); | ||
4829 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to generate DPM level enabled mask!", result = tmp_result); | ||
4830 | |||
4831 | tmp_result = iceland_update_vce_dpm(hwmgr, input); | ||
4832 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update VCE DPM!", result = tmp_result); | ||
4833 | |||
4834 | tmp_result = iceland_update_sclk_threshold(hwmgr); | ||
4835 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update SCLK threshold!", result = tmp_result); | ||
4836 | |||
4837 | tmp_result = iceland_update_and_upload_mc_reg_table(hwmgr); | ||
4838 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload MC reg table!", result = tmp_result); | ||
4839 | |||
4840 | tmp_result = iceland_program_memory_timing_parameters_conditionally(hwmgr); | ||
4841 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to program memory timing parameters!", result = tmp_result); | ||
4842 | |||
4843 | tmp_result = iceland_unfreeze_sclk_mclk_dpm(hwmgr); | ||
4844 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to unfreeze SCLK MCLK DPM!", result = tmp_result); | ||
4845 | |||
4846 | tmp_result = iceland_upload_dpm_level_enable_mask(hwmgr); | ||
4847 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload DPM level enabled mask!", result = tmp_result); | ||
4848 | |||
4849 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) { | ||
4850 | tmp_result = iceland_notify_link_speed_change_after_state_change(hwmgr, input); | ||
4851 | PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to notify link speed change after state change!", result = tmp_result); | ||
4852 | } | ||
4853 | |||
4854 | return result; | ||
4855 | } | ||
4856 | |||
4857 | static int iceland_get_power_state_size(struct pp_hwmgr *hwmgr) | ||
4858 | { | ||
4859 | return sizeof(struct iceland_power_state); | ||
4860 | } | ||
4861 | |||
4862 | static int iceland_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) | ||
4863 | { | ||
4864 | struct pp_power_state *ps; | ||
4865 | struct iceland_power_state *iceland_ps; | ||
4866 | |||
4867 | if (hwmgr == NULL) | ||
4868 | return -EINVAL; | ||
4869 | |||
4870 | ps = hwmgr->request_ps; | ||
4871 | |||
4872 | if (ps == NULL) | ||
4873 | return -EINVAL; | ||
4874 | |||
4875 | iceland_ps = cast_phw_iceland_power_state(&ps->hardware); | ||
4876 | |||
4877 | if (low) | ||
4878 | return iceland_ps->performance_levels[0].memory_clock; | ||
4879 | else | ||
4880 | return iceland_ps->performance_levels[iceland_ps->performance_level_count-1].memory_clock; | ||
4881 | } | ||
4882 | |||
4883 | static int iceland_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) | ||
4884 | { | ||
4885 | struct pp_power_state *ps; | ||
4886 | struct iceland_power_state *iceland_ps; | ||
4887 | |||
4888 | if (hwmgr == NULL) | ||
4889 | return -EINVAL; | ||
4890 | |||
4891 | ps = hwmgr->request_ps; | ||
4892 | |||
4893 | if (ps == NULL) | ||
4894 | return -EINVAL; | ||
4895 | |||
4896 | iceland_ps = cast_phw_iceland_power_state(&ps->hardware); | ||
4897 | |||
4898 | if (low) | ||
4899 | return iceland_ps->performance_levels[0].engine_clock; | ||
4900 | else | ||
4901 | return iceland_ps->performance_levels[iceland_ps->performance_level_count-1].engine_clock; | ||
4902 | } | ||
4903 | |||
4904 | static int iceland_get_current_pcie_lane_number( | ||
4905 | struct pp_hwmgr *hwmgr) | ||
4906 | { | ||
4907 | uint32_t link_width; | ||
4908 | |||
4909 | link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, | ||
4910 | CGS_IND_REG__PCIE, | ||
4911 | PCIE_LC_LINK_WIDTH_CNTL, | ||
4912 | LC_LINK_WIDTH_RD); | ||
4913 | |||
4914 | PP_ASSERT_WITH_CODE((7 >= link_width), | ||
4915 | "Invalid PCIe lane width!", return 0); | ||
4916 | |||
4917 | return decode_pcie_lane_width(link_width); | ||
4918 | } | ||
4919 | |||
4920 | static int iceland_dpm_patch_boot_state(struct pp_hwmgr *hwmgr, | ||
4921 | struct pp_hw_power_state *hw_ps) | ||
4922 | { | ||
4923 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4924 | struct iceland_power_state *ps = (struct iceland_power_state *)hw_ps; | ||
4925 | ATOM_FIRMWARE_INFO_V2_2 *fw_info; | ||
4926 | uint16_t size; | ||
4927 | uint8_t frev, crev; | ||
4928 | int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); | ||
4929 | |||
4930 | /* First retrieve the Boot clocks and VDDC from the firmware info table. | ||
4931 | * We assume here that fw_info is unchanged if this call fails. | ||
4932 | */ | ||
4933 | fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table( | ||
4934 | hwmgr->device, index, | ||
4935 | &size, &frev, &crev); | ||
4936 | if (!fw_info) | ||
4937 | /* During a test, there is no firmware info table. */ | ||
4938 | return 0; | ||
4939 | |||
4940 | /* Patch the state. */ | ||
4941 | data->vbios_boot_state.sclk_bootup_value = le32_to_cpu(fw_info->ulDefaultEngineClock); | ||
4942 | data->vbios_boot_state.mclk_bootup_value = le32_to_cpu(fw_info->ulDefaultMemoryClock); | ||
4943 | data->vbios_boot_state.mvdd_bootup_value = le16_to_cpu(fw_info->usBootUpMVDDCVoltage); | ||
4944 | data->vbios_boot_state.vddc_bootup_value = le16_to_cpu(fw_info->usBootUpVDDCVoltage); | ||
4945 | data->vbios_boot_state.vddci_bootup_value = le16_to_cpu(fw_info->usBootUpVDDCIVoltage); | ||
4946 | data->vbios_boot_state.pcie_gen_bootup_value = iceland_get_current_pcie_speed(hwmgr); | ||
4947 | data->vbios_boot_state.pcie_lane_bootup_value = | ||
4948 | (uint16_t)iceland_get_current_pcie_lane_number(hwmgr); | ||
4949 | |||
4950 | /* set boot power state */ | ||
4951 | ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value; | ||
4952 | ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value; | ||
4953 | ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value; | ||
4954 | ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value; | ||
4955 | |||
4956 | return 0; | ||
4957 | } | ||
4958 | |||
4959 | static int iceland_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr, | ||
4960 | struct pp_hw_power_state *power_state, | ||
4961 | unsigned int index, const void *clock_info) | ||
4962 | { | ||
4963 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
4964 | struct iceland_power_state *iceland_power_state = cast_phw_iceland_power_state(power_state); | ||
4965 | const ATOM_PPLIB_CI_CLOCK_INFO *visland_clk_info = clock_info; | ||
4966 | struct iceland_performance_level *performance_level; | ||
4967 | uint32_t engine_clock, memory_clock; | ||
4968 | uint16_t pcie_gen_from_bios; | ||
4969 | |||
4970 | engine_clock = visland_clk_info->ucEngineClockHigh << 16 | visland_clk_info->usEngineClockLow; | ||
4971 | memory_clock = visland_clk_info->ucMemoryClockHigh << 16 | visland_clk_info->usMemoryClockLow; | ||
4972 | |||
4973 | if (!(data->mc_micro_code_feature & DISABLE_MC_LOADMICROCODE) && memory_clock > data->highest_mclk) | ||
4974 | data->highest_mclk = memory_clock; | ||
4975 | |||
4976 | performance_level = &(iceland_power_state->performance_levels | ||
4977 | [iceland_power_state->performance_level_count++]); | ||
4978 | |||
4979 | PP_ASSERT_WITH_CODE( | ||
4980 | (iceland_power_state->performance_level_count < SMU71_MAX_LEVELS_GRAPHICS), | ||
4981 | "Performance levels exceeds SMC limit!", | ||
4982 | return -1); | ||
4983 | |||
4984 | PP_ASSERT_WITH_CODE( | ||
4985 | (iceland_power_state->performance_level_count <= | ||
4986 | hwmgr->platform_descriptor.hardwareActivityPerformanceLevels), | ||
4987 | "Performance levels exceeds Driver limit!", | ||
4988 | return -1); | ||
4989 | |||
4990 | /* Performance levels are arranged from low to high. */ | ||
4991 | performance_level->memory_clock = memory_clock; | ||
4992 | performance_level->engine_clock = engine_clock; | ||
4993 | |||
4994 | pcie_gen_from_bios = visland_clk_info->ucPCIEGen; | ||
4995 | |||
4996 | performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap, pcie_gen_from_bios); | ||
4997 | performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap, visland_clk_info->usPCIELane); | ||
4998 | |||
4999 | return 0; | ||
5000 | } | ||
5001 | |||
5002 | static int iceland_get_pp_table_entry(struct pp_hwmgr *hwmgr, | ||
5003 | unsigned long entry_index, struct pp_power_state *state) | ||
5004 | { | ||
5005 | int result; | ||
5006 | struct iceland_power_state *ps; | ||
5007 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
5008 | struct phm_clock_voltage_dependency_table *dep_mclk_table = | ||
5009 | hwmgr->dyn_state.vddci_dependency_on_mclk; | ||
5010 | |||
5011 | memset(&state->hardware, 0x00, sizeof(struct pp_hw_power_state)); | ||
5012 | |||
5013 | state->hardware.magic = PHM_VIslands_Magic; | ||
5014 | |||
5015 | ps = (struct iceland_power_state *)(&state->hardware); | ||
5016 | |||
5017 | result = pp_tables_get_entry(hwmgr, entry_index, state, | ||
5018 | iceland_get_pp_table_entry_callback_func); | ||
5019 | |||
5020 | /* | ||
5021 | * This is the earliest time we have all the dependency table | ||
5022 | * and the VBIOS boot state as | ||
5023 | * PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot | ||
5024 | * state if there is only one VDDCI/MCLK level, check if it's | ||
5025 | * the same as VBIOS boot state | ||
5026 | */ | ||
5027 | if (dep_mclk_table != NULL && dep_mclk_table->count == 1) { | ||
5028 | if (dep_mclk_table->entries[0].clk != | ||
5029 | data->vbios_boot_state.mclk_bootup_value) | ||
5030 | printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table " | ||
5031 | "does not match VBIOS boot MCLK level"); | ||
5032 | if (dep_mclk_table->entries[0].v != | ||
5033 | data->vbios_boot_state.vddci_bootup_value) | ||
5034 | printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table " | ||
5035 | "does not match VBIOS boot VDDCI level"); | ||
5036 | } | ||
5037 | |||
5038 | /* set DC compatible flag if this state supports DC */ | ||
5039 | if (!state->validation.disallowOnDC) | ||
5040 | ps->dc_compatible = true; | ||
5041 | |||
5042 | if (state->classification.flags & PP_StateClassificationFlag_ACPI) | ||
5043 | data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen; | ||
5044 | else if (0 != (state->classification.flags & PP_StateClassificationFlag_Boot)) { | ||
5045 | if (data->bacos.best_match == 0xffff) { | ||
5046 | /* For C.I. use boot state as base BACO state */ | ||
5047 | data->bacos.best_match = PP_StateClassificationFlag_Boot; | ||
5048 | data->bacos.performance_level = ps->performance_levels[0]; | ||
5049 | } | ||
5050 | } | ||
5051 | |||
5052 | |||
5053 | ps->uvd_clocks.VCLK = state->uvd_clocks.VCLK; | ||
5054 | ps->uvd_clocks.DCLK = state->uvd_clocks.DCLK; | ||
5055 | |||
5056 | if (!result) { | ||
5057 | uint32_t i; | ||
5058 | |||
5059 | switch (state->classification.ui_label) { | ||
5060 | case PP_StateUILabel_Performance: | ||
5061 | data->use_pcie_performance_levels = true; | ||
5062 | |||
5063 | for (i = 0; i < ps->performance_level_count; i++) { | ||
5064 | if (data->pcie_gen_performance.max < | ||
5065 | ps->performance_levels[i].pcie_gen) | ||
5066 | data->pcie_gen_performance.max = | ||
5067 | ps->performance_levels[i].pcie_gen; | ||
5068 | |||
5069 | if (data->pcie_gen_performance.min > | ||
5070 | ps->performance_levels[i].pcie_gen) | ||
5071 | data->pcie_gen_performance.min = | ||
5072 | ps->performance_levels[i].pcie_gen; | ||
5073 | |||
5074 | if (data->pcie_lane_performance.max < | ||
5075 | ps->performance_levels[i].pcie_lane) | ||
5076 | data->pcie_lane_performance.max = | ||
5077 | ps->performance_levels[i].pcie_lane; | ||
5078 | |||
5079 | if (data->pcie_lane_performance.min > | ||
5080 | ps->performance_levels[i].pcie_lane) | ||
5081 | data->pcie_lane_performance.min = | ||
5082 | ps->performance_levels[i].pcie_lane; | ||
5083 | } | ||
5084 | break; | ||
5085 | case PP_StateUILabel_Battery: | ||
5086 | data->use_pcie_power_saving_levels = true; | ||
5087 | |||
5088 | for (i = 0; i < ps->performance_level_count; i++) { | ||
5089 | if (data->pcie_gen_power_saving.max < | ||
5090 | ps->performance_levels[i].pcie_gen) | ||
5091 | data->pcie_gen_power_saving.max = | ||
5092 | ps->performance_levels[i].pcie_gen; | ||
5093 | |||
5094 | if (data->pcie_gen_power_saving.min > | ||
5095 | ps->performance_levels[i].pcie_gen) | ||
5096 | data->pcie_gen_power_saving.min = | ||
5097 | ps->performance_levels[i].pcie_gen; | ||
5098 | |||
5099 | if (data->pcie_lane_power_saving.max < | ||
5100 | ps->performance_levels[i].pcie_lane) | ||
5101 | data->pcie_lane_power_saving.max = | ||
5102 | ps->performance_levels[i].pcie_lane; | ||
5103 | |||
5104 | if (data->pcie_lane_power_saving.min > | ||
5105 | ps->performance_levels[i].pcie_lane) | ||
5106 | data->pcie_lane_power_saving.min = | ||
5107 | ps->performance_levels[i].pcie_lane; | ||
5108 | } | ||
5109 | break; | ||
5110 | default: | ||
5111 | break; | ||
5112 | } | ||
5113 | } | ||
5114 | return 0; | ||
5115 | } | ||
5116 | |||
5117 | static void | ||
5118 | iceland_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m) | ||
5119 | { | ||
5120 | uint32_t sclk, mclk, activity_percent; | ||
5121 | uint32_t offset; | ||
5122 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
5123 | |||
5124 | smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetSclkFrequency)); | ||
5125 | |||
5126 | sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); | ||
5127 | |||
5128 | smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetMclkFrequency)); | ||
5129 | |||
5130 | mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); | ||
5131 | seq_printf(m, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n", mclk/100, sclk/100); | ||
5132 | |||
5133 | offset = data->soft_regs_start + offsetof(SMU71_SoftRegisters, AverageGraphicsActivity); | ||
5134 | activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset); | ||
5135 | activity_percent += 0x80; | ||
5136 | activity_percent >>= 8; | ||
5137 | |||
5138 | seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent); | ||
5139 | |||
5140 | seq_printf(m, "uvd %sabled\n", data->uvd_power_gated ? "dis" : "en"); | ||
5141 | |||
5142 | seq_printf(m, "vce %sabled\n", data->vce_power_gated ? "dis" : "en"); | ||
5143 | } | ||
5144 | |||
5145 | int iceland_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr) | ||
5146 | { | ||
5147 | uint32_t num_active_displays = 0; | ||
5148 | struct cgs_display_info info = {0}; | ||
5149 | info.mode_info = NULL; | ||
5150 | |||
5151 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
5152 | |||
5153 | num_active_displays = info.display_count; | ||
5154 | |||
5155 | if (num_active_displays > 1) /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */ | ||
5156 | iceland_notify_smc_display_change(hwmgr, false); | ||
5157 | else | ||
5158 | iceland_notify_smc_display_change(hwmgr, true); | ||
5159 | |||
5160 | return 0; | ||
5161 | } | ||
5162 | |||
5163 | /** | ||
5164 | * Programs the display gap | ||
5165 | * | ||
5166 | * @param hwmgr the address of the powerplay hardware manager. | ||
5167 | * @return always OK | ||
5168 | */ | ||
5169 | int iceland_program_display_gap(struct pp_hwmgr *hwmgr) | ||
5170 | { | ||
5171 | uint32_t num_active_displays = 0; | ||
5172 | uint32_t display_gap = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL); | ||
5173 | uint32_t display_gap2; | ||
5174 | uint32_t pre_vbi_time_in_us; | ||
5175 | uint32_t frame_time_in_us; | ||
5176 | uint32_t ref_clock; | ||
5177 | uint32_t refresh_rate = 0; | ||
5178 | struct cgs_display_info info = {0}; | ||
5179 | struct cgs_mode_info mode_info; | ||
5180 | |||
5181 | info.mode_info = &mode_info; | ||
5182 | |||
5183 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
5184 | num_active_displays = info.display_count; | ||
5185 | |||
5186 | 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); | ||
5187 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL, display_gap); | ||
5188 | |||
5189 | ref_clock = mode_info.ref_clock; | ||
5190 | refresh_rate = mode_info.refresh_rate; | ||
5191 | |||
5192 | if(0 == refresh_rate) | ||
5193 | refresh_rate = 60; | ||
5194 | |||
5195 | frame_time_in_us = 1000000 / refresh_rate; | ||
5196 | |||
5197 | pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us; | ||
5198 | display_gap2 = pre_vbi_time_in_us * (ref_clock / 100); | ||
5199 | |||
5200 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2); | ||
5201 | |||
5202 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SOFT_REGISTERS_TABLE_4, PreVBlankGap, 0x64); | ||
5203 | |||
5204 | PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SOFT_REGISTERS_TABLE_5, VBlankTimeout, (frame_time_in_us - pre_vbi_time_in_us)); | ||
5205 | |||
5206 | if (num_active_displays == 1) | ||
5207 | iceland_notify_smc_display_change(hwmgr, true); | ||
5208 | |||
5209 | return 0; | ||
5210 | } | ||
5211 | |||
5212 | int iceland_display_configuration_changed_task(struct pp_hwmgr *hwmgr) | ||
5213 | { | ||
5214 | iceland_program_display_gap(hwmgr); | ||
5215 | |||
5216 | return 0; | ||
5217 | } | ||
5218 | |||
5219 | /** | ||
5220 | * Set maximum target operating fan output PWM | ||
5221 | * | ||
5222 | * @param pHwMgr: the address of the powerplay hardware manager. | ||
5223 | * @param usMaxFanPwm: max operating fan PWM in percents | ||
5224 | * @return The response that came from the SMC. | ||
5225 | */ | ||
5226 | static int iceland_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm) | ||
5227 | { | ||
5228 | hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm; | ||
5229 | |||
5230 | if (phm_is_hw_access_blocked(hwmgr)) | ||
5231 | return 0; | ||
5232 | |||
5233 | return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm) ? 0 : -1); | ||
5234 | } | ||
5235 | |||
5236 | /** | ||
5237 | * Set maximum target operating fan output RPM | ||
5238 | * | ||
5239 | * @param pHwMgr: the address of the powerplay hardware manager. | ||
5240 | * @param usMaxFanRpm: max operating fan RPM value. | ||
5241 | * @return The response that came from the SMC. | ||
5242 | */ | ||
5243 | static int iceland_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm) | ||
5244 | { | ||
5245 | hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM = us_max_fan_pwm; | ||
5246 | |||
5247 | if (phm_is_hw_access_blocked(hwmgr)) | ||
5248 | return 0; | ||
5249 | |||
5250 | return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanRpmMax, us_max_fan_pwm) ? 0 : -1); | ||
5251 | } | ||
5252 | |||
5253 | static int iceland_dpm_set_interrupt_state(void *private_data, | ||
5254 | unsigned src_id, unsigned type, | ||
5255 | int enabled) | ||
5256 | { | ||
5257 | uint32_t cg_thermal_int; | ||
5258 | struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr; | ||
5259 | |||
5260 | if (hwmgr == NULL) | ||
5261 | return -EINVAL; | ||
5262 | |||
5263 | switch (type) { | ||
5264 | case AMD_THERMAL_IRQ_LOW_TO_HIGH: | ||
5265 | if (enabled) { | ||
5266 | cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT); | ||
5267 | cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK; | ||
5268 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int); | ||
5269 | } else { | ||
5270 | cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT); | ||
5271 | cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK; | ||
5272 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int); | ||
5273 | } | ||
5274 | break; | ||
5275 | |||
5276 | case AMD_THERMAL_IRQ_HIGH_TO_LOW: | ||
5277 | if (enabled) { | ||
5278 | cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT); | ||
5279 | cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK; | ||
5280 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int); | ||
5281 | } else { | ||
5282 | cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT); | ||
5283 | cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK; | ||
5284 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int); | ||
5285 | } | ||
5286 | break; | ||
5287 | default: | ||
5288 | break; | ||
5289 | } | ||
5290 | return 0; | ||
5291 | } | ||
5292 | |||
5293 | static int iceland_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr, | ||
5294 | const void *thermal_interrupt_info) | ||
5295 | { | ||
5296 | int result; | ||
5297 | const struct pp_interrupt_registration_info *info = | ||
5298 | (const struct pp_interrupt_registration_info *)thermal_interrupt_info; | ||
5299 | |||
5300 | if (info == NULL) | ||
5301 | return -EINVAL; | ||
5302 | |||
5303 | result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST, | ||
5304 | iceland_dpm_set_interrupt_state, | ||
5305 | info->call_back, info->context); | ||
5306 | |||
5307 | if (result) | ||
5308 | return -EINVAL; | ||
5309 | |||
5310 | result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST, | ||
5311 | iceland_dpm_set_interrupt_state, | ||
5312 | info->call_back, info->context); | ||
5313 | |||
5314 | if (result) | ||
5315 | return -EINVAL; | ||
5316 | |||
5317 | return 0; | ||
5318 | } | ||
5319 | |||
5320 | |||
5321 | static bool iceland_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr) | ||
5322 | { | ||
5323 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
5324 | bool is_update_required = false; | ||
5325 | struct cgs_display_info info = {0,0,NULL}; | ||
5326 | |||
5327 | cgs_get_active_displays_info(hwmgr->device, &info); | ||
5328 | |||
5329 | if (data->display_timing.num_existing_displays != info.display_count) | ||
5330 | is_update_required = true; | ||
5331 | /* TO DO NEED TO GET DEEP SLEEP CLOCK FROM DAL | ||
5332 | if (phm_cap_enabled(hwmgr->hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) { | ||
5333 | cgs_get_min_clock_settings(hwmgr->device, &min_clocks); | ||
5334 | if(min_clocks.engineClockInSR != data->display_timing.minClockInSR) | ||
5335 | is_update_required = true; | ||
5336 | */ | ||
5337 | return is_update_required; | ||
5338 | } | ||
5339 | |||
5340 | |||
5341 | static inline bool iceland_are_power_levels_equal(const struct iceland_performance_level *pl1, | ||
5342 | const struct iceland_performance_level *pl2) | ||
5343 | { | ||
5344 | return ((pl1->memory_clock == pl2->memory_clock) && | ||
5345 | (pl1->engine_clock == pl2->engine_clock) && | ||
5346 | (pl1->pcie_gen == pl2->pcie_gen) && | ||
5347 | (pl1->pcie_lane == pl2->pcie_lane)); | ||
5348 | } | ||
5349 | |||
5350 | int iceland_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, | ||
5351 | const struct pp_hw_power_state *pstate2, bool *equal) | ||
5352 | { | ||
5353 | const struct iceland_power_state *psa = cast_const_phw_iceland_power_state(pstate1); | ||
5354 | const struct iceland_power_state *psb = cast_const_phw_iceland_power_state(pstate2); | ||
5355 | int i; | ||
5356 | |||
5357 | if (equal == NULL || psa == NULL || psb == NULL) | ||
5358 | return -EINVAL; | ||
5359 | |||
5360 | /* If the two states don't even have the same number of performance levels they cannot be the same state. */ | ||
5361 | if (psa->performance_level_count != psb->performance_level_count) { | ||
5362 | *equal = false; | ||
5363 | return 0; | ||
5364 | } | ||
5365 | |||
5366 | for (i = 0; i < psa->performance_level_count; i++) { | ||
5367 | if (!iceland_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) { | ||
5368 | /* If we have found even one performance level pair that is different the states are different. */ | ||
5369 | *equal = false; | ||
5370 | return 0; | ||
5371 | } | ||
5372 | } | ||
5373 | |||
5374 | /* If all performance levels are the same try to use the UVD clocks to break the tie.*/ | ||
5375 | *equal = ((psa->uvd_clocks.VCLK == psb->uvd_clocks.VCLK) && (psa->uvd_clocks.DCLK == psb->uvd_clocks.DCLK)); | ||
5376 | *equal &= ((psa->vce_clocks.EVCLK == psb->vce_clocks.EVCLK) && (psa->vce_clocks.ECCLK == psb->vce_clocks.ECCLK)); | ||
5377 | *equal &= (psa->sclk_threshold == psb->sclk_threshold); | ||
5378 | *equal &= (psa->acp_clk == psb->acp_clk); | ||
5379 | |||
5380 | return 0; | ||
5381 | } | ||
5382 | |||
5383 | static int iceland_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode) | ||
5384 | { | ||
5385 | if (mode) { | ||
5386 | /* stop auto-manage */ | ||
5387 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
5388 | PHM_PlatformCaps_MicrocodeFanControl)) | ||
5389 | iceland_fan_ctrl_stop_smc_fan_control(hwmgr); | ||
5390 | iceland_fan_ctrl_set_static_mode(hwmgr, mode); | ||
5391 | } else | ||
5392 | /* restart auto-manage */ | ||
5393 | iceland_fan_ctrl_reset_fan_speed_to_default(hwmgr); | ||
5394 | |||
5395 | return 0; | ||
5396 | } | ||
5397 | |||
5398 | static int iceland_get_fan_control_mode(struct pp_hwmgr *hwmgr) | ||
5399 | { | ||
5400 | if (hwmgr->fan_ctrl_is_in_default_mode) | ||
5401 | return hwmgr->fan_ctrl_default_mode; | ||
5402 | else | ||
5403 | return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, | ||
5404 | CG_FDO_CTRL2, FDO_PWM_MODE); | ||
5405 | } | ||
5406 | |||
5407 | static int iceland_force_clock_level(struct pp_hwmgr *hwmgr, | ||
5408 | enum pp_clock_type type, uint32_t mask) | ||
5409 | { | ||
5410 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
5411 | |||
5412 | if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) | ||
5413 | return -EINVAL; | ||
5414 | |||
5415 | switch (type) { | ||
5416 | case PP_SCLK: | ||
5417 | if (!data->sclk_dpm_key_disabled) | ||
5418 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
5419 | PPSMC_MSG_SCLKDPM_SetEnabledMask, | ||
5420 | data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask); | ||
5421 | break; | ||
5422 | case PP_MCLK: | ||
5423 | if (!data->mclk_dpm_key_disabled) | ||
5424 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
5425 | PPSMC_MSG_MCLKDPM_SetEnabledMask, | ||
5426 | data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask); | ||
5427 | break; | ||
5428 | case PP_PCIE: | ||
5429 | { | ||
5430 | uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask; | ||
5431 | uint32_t level = 0; | ||
5432 | |||
5433 | while (tmp >>= 1) | ||
5434 | level++; | ||
5435 | |||
5436 | if (!data->pcie_dpm_key_disabled) | ||
5437 | smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
5438 | PPSMC_MSG_PCIeDPM_ForceLevel, | ||
5439 | level); | ||
5440 | break; | ||
5441 | } | ||
5442 | default: | ||
5443 | break; | ||
5444 | } | ||
5445 | |||
5446 | return 0; | ||
5447 | } | ||
5448 | |||
5449 | static int iceland_print_clock_levels(struct pp_hwmgr *hwmgr, | ||
5450 | enum pp_clock_type type, char *buf) | ||
5451 | { | ||
5452 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
5453 | struct iceland_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table); | ||
5454 | struct iceland_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table); | ||
5455 | struct iceland_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table); | ||
5456 | int i, now, size = 0; | ||
5457 | uint32_t clock, pcie_speed; | ||
5458 | |||
5459 | switch (type) { | ||
5460 | case PP_SCLK: | ||
5461 | smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency); | ||
5462 | clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); | ||
5463 | |||
5464 | for (i = 0; i < sclk_table->count; i++) { | ||
5465 | if (clock > sclk_table->dpm_levels[i].value) | ||
5466 | continue; | ||
5467 | break; | ||
5468 | } | ||
5469 | now = i; | ||
5470 | |||
5471 | for (i = 0; i < sclk_table->count; i++) | ||
5472 | size += sprintf(buf + size, "%d: %uMhz %s\n", | ||
5473 | i, sclk_table->dpm_levels[i].value / 100, | ||
5474 | (i == now) ? "*" : ""); | ||
5475 | break; | ||
5476 | case PP_MCLK: | ||
5477 | smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency); | ||
5478 | clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); | ||
5479 | |||
5480 | for (i = 0; i < mclk_table->count; i++) { | ||
5481 | if (clock > mclk_table->dpm_levels[i].value) | ||
5482 | continue; | ||
5483 | break; | ||
5484 | } | ||
5485 | now = i; | ||
5486 | |||
5487 | for (i = 0; i < mclk_table->count; i++) | ||
5488 | size += sprintf(buf + size, "%d: %uMhz %s\n", | ||
5489 | i, mclk_table->dpm_levels[i].value / 100, | ||
5490 | (i == now) ? "*" : ""); | ||
5491 | break; | ||
5492 | case PP_PCIE: | ||
5493 | pcie_speed = iceland_get_current_pcie_speed(hwmgr); | ||
5494 | for (i = 0; i < pcie_table->count; i++) { | ||
5495 | if (pcie_speed != pcie_table->dpm_levels[i].value) | ||
5496 | continue; | ||
5497 | break; | ||
5498 | } | ||
5499 | now = i; | ||
5500 | |||
5501 | for (i = 0; i < pcie_table->count; i++) | ||
5502 | size += sprintf(buf + size, "%d: %s %s\n", i, | ||
5503 | (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x8" : | ||
5504 | (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" : | ||
5505 | (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "", | ||
5506 | (i == now) ? "*" : ""); | ||
5507 | break; | ||
5508 | default: | ||
5509 | break; | ||
5510 | } | ||
5511 | return size; | ||
5512 | } | ||
5513 | |||
5514 | static int iceland_get_sclk_od(struct pp_hwmgr *hwmgr) | ||
5515 | { | ||
5516 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
5517 | struct iceland_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table); | ||
5518 | struct iceland_single_dpm_table *golden_sclk_table = | ||
5519 | &(data->golden_dpm_table.sclk_table); | ||
5520 | int value; | ||
5521 | |||
5522 | value = (sclk_table->dpm_levels[sclk_table->count - 1].value - | ||
5523 | golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * | ||
5524 | 100 / | ||
5525 | golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value; | ||
5526 | |||
5527 | return value; | ||
5528 | } | ||
5529 | |||
5530 | static int iceland_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value) | ||
5531 | { | ||
5532 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
5533 | struct iceland_single_dpm_table *golden_sclk_table = | ||
5534 | &(data->golden_dpm_table.sclk_table); | ||
5535 | struct pp_power_state *ps; | ||
5536 | struct iceland_power_state *iceland_ps; | ||
5537 | |||
5538 | if (value > 20) | ||
5539 | value = 20; | ||
5540 | |||
5541 | ps = hwmgr->request_ps; | ||
5542 | |||
5543 | if (ps == NULL) | ||
5544 | return -EINVAL; | ||
5545 | |||
5546 | iceland_ps = cast_phw_iceland_power_state(&ps->hardware); | ||
5547 | |||
5548 | iceland_ps->performance_levels[iceland_ps->performance_level_count - 1].engine_clock = | ||
5549 | golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value * | ||
5550 | value / 100 + | ||
5551 | golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value; | ||
5552 | |||
5553 | return 0; | ||
5554 | } | ||
5555 | |||
5556 | static int iceland_get_mclk_od(struct pp_hwmgr *hwmgr) | ||
5557 | { | ||
5558 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
5559 | struct iceland_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table); | ||
5560 | struct iceland_single_dpm_table *golden_mclk_table = | ||
5561 | &(data->golden_dpm_table.mclk_table); | ||
5562 | int value; | ||
5563 | |||
5564 | value = (mclk_table->dpm_levels[mclk_table->count - 1].value - | ||
5565 | golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) * | ||
5566 | 100 / | ||
5567 | golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value; | ||
5568 | |||
5569 | return value; | ||
5570 | } | ||
5571 | |||
5572 | uint32_t iceland_get_xclk(struct pp_hwmgr *hwmgr) | ||
5573 | { | ||
5574 | uint32_t reference_clock; | ||
5575 | uint32_t tc; | ||
5576 | uint32_t divide; | ||
5577 | |||
5578 | ATOM_FIRMWARE_INFO *fw_info; | ||
5579 | uint16_t size; | ||
5580 | uint8_t frev, crev; | ||
5581 | int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); | ||
5582 | |||
5583 | tc = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK); | ||
5584 | |||
5585 | if (tc) | ||
5586 | return TCLK; | ||
5587 | |||
5588 | fw_info = (ATOM_FIRMWARE_INFO *)cgs_atom_get_data_table(hwmgr->device, index, | ||
5589 | &size, &frev, &crev); | ||
5590 | |||
5591 | if (!fw_info) | ||
5592 | return 0; | ||
5593 | |||
5594 | reference_clock = le16_to_cpu(fw_info->usReferenceClock); | ||
5595 | |||
5596 | divide = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL, XTALIN_DIVIDE); | ||
5597 | |||
5598 | if (0 != divide) | ||
5599 | return reference_clock / 4; | ||
5600 | |||
5601 | return reference_clock; | ||
5602 | } | ||
5603 | |||
5604 | static int iceland_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value) | ||
5605 | { | ||
5606 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
5607 | struct iceland_single_dpm_table *golden_mclk_table = | ||
5608 | &(data->golden_dpm_table.mclk_table); | ||
5609 | struct pp_power_state *ps; | ||
5610 | struct iceland_power_state *iceland_ps; | ||
5611 | |||
5612 | if (value > 20) | ||
5613 | value = 20; | ||
5614 | |||
5615 | ps = hwmgr->request_ps; | ||
5616 | |||
5617 | if (ps == NULL) | ||
5618 | return -EINVAL; | ||
5619 | |||
5620 | iceland_ps = cast_phw_iceland_power_state(&ps->hardware); | ||
5621 | |||
5622 | iceland_ps->performance_levels[iceland_ps->performance_level_count - 1].memory_clock = | ||
5623 | golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value * | ||
5624 | value / 100 + | ||
5625 | golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value; | ||
5626 | |||
5627 | return 0; | ||
5628 | } | ||
5629 | |||
5630 | static const struct pp_hwmgr_func iceland_hwmgr_funcs = { | ||
5631 | .backend_init = &iceland_hwmgr_backend_init, | ||
5632 | .backend_fini = &iceland_hwmgr_backend_fini, | ||
5633 | .asic_setup = &iceland_setup_asic_task, | ||
5634 | .dynamic_state_management_enable = &iceland_enable_dpm_tasks, | ||
5635 | .apply_state_adjust_rules = iceland_apply_state_adjust_rules, | ||
5636 | .force_dpm_level = &iceland_force_dpm_level, | ||
5637 | .power_state_set = iceland_set_power_state_tasks, | ||
5638 | .get_power_state_size = iceland_get_power_state_size, | ||
5639 | .get_mclk = iceland_dpm_get_mclk, | ||
5640 | .get_sclk = iceland_dpm_get_sclk, | ||
5641 | .patch_boot_state = iceland_dpm_patch_boot_state, | ||
5642 | .get_pp_table_entry = iceland_get_pp_table_entry, | ||
5643 | .get_num_of_pp_table_entries = iceland_get_num_of_entries, | ||
5644 | .print_current_perforce_level = iceland_print_current_perforce_level, | ||
5645 | .powerdown_uvd = iceland_phm_powerdown_uvd, | ||
5646 | .powergate_uvd = iceland_phm_powergate_uvd, | ||
5647 | .powergate_vce = iceland_phm_powergate_vce, | ||
5648 | .disable_clock_power_gating = iceland_phm_disable_clock_power_gating, | ||
5649 | .update_clock_gatings = iceland_phm_update_clock_gatings, | ||
5650 | .notify_smc_display_config_after_ps_adjustment = iceland_notify_smc_display_config_after_ps_adjustment, | ||
5651 | .display_config_changed = iceland_display_configuration_changed_task, | ||
5652 | .set_max_fan_pwm_output = iceland_set_max_fan_pwm_output, | ||
5653 | .set_max_fan_rpm_output = iceland_set_max_fan_rpm_output, | ||
5654 | .get_temperature = iceland_thermal_get_temperature, | ||
5655 | .stop_thermal_controller = iceland_thermal_stop_thermal_controller, | ||
5656 | .get_fan_speed_info = iceland_fan_ctrl_get_fan_speed_info, | ||
5657 | .get_fan_speed_percent = iceland_fan_ctrl_get_fan_speed_percent, | ||
5658 | .set_fan_speed_percent = iceland_fan_ctrl_set_fan_speed_percent, | ||
5659 | .reset_fan_speed_to_default = iceland_fan_ctrl_reset_fan_speed_to_default, | ||
5660 | .get_fan_speed_rpm = iceland_fan_ctrl_get_fan_speed_rpm, | ||
5661 | .set_fan_speed_rpm = iceland_fan_ctrl_set_fan_speed_rpm, | ||
5662 | .uninitialize_thermal_controller = iceland_thermal_ctrl_uninitialize_thermal_controller, | ||
5663 | .register_internal_thermal_interrupt = iceland_register_internal_thermal_interrupt, | ||
5664 | .check_smc_update_required_for_display_configuration = iceland_check_smc_update_required_for_display_configuration, | ||
5665 | .check_states_equal = iceland_check_states_equal, | ||
5666 | .set_fan_control_mode = iceland_set_fan_control_mode, | ||
5667 | .get_fan_control_mode = iceland_get_fan_control_mode, | ||
5668 | .force_clock_level = iceland_force_clock_level, | ||
5669 | .print_clock_levels = iceland_print_clock_levels, | ||
5670 | .get_sclk_od = iceland_get_sclk_od, | ||
5671 | .set_sclk_od = iceland_set_sclk_od, | ||
5672 | .get_mclk_od = iceland_get_mclk_od, | ||
5673 | .set_mclk_od = iceland_set_mclk_od, | ||
5674 | }; | ||
5675 | |||
5676 | int iceland_hwmgr_init(struct pp_hwmgr *hwmgr) | ||
5677 | { | ||
5678 | iceland_hwmgr *data; | ||
5679 | |||
5680 | data = kzalloc (sizeof(iceland_hwmgr), GFP_KERNEL); | ||
5681 | if (data == NULL) | ||
5682 | return -ENOMEM; | ||
5683 | memset(data, 0x00, sizeof(iceland_hwmgr)); | ||
5684 | |||
5685 | hwmgr->backend = data; | ||
5686 | hwmgr->hwmgr_func = &iceland_hwmgr_funcs; | ||
5687 | hwmgr->pptable_func = &pptable_funcs; | ||
5688 | |||
5689 | /* thermal */ | ||
5690 | pp_iceland_thermal_initialize(hwmgr); | ||
5691 | return 0; | ||
5692 | } | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.h new file mode 100644 index 000000000000..f253988de2d2 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.h | |||
@@ -0,0 +1,424 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | #ifndef ICELAND_HWMGR_H | ||
26 | #define ICELAND_HWMGR_H | ||
27 | |||
28 | #include "hwmgr.h" | ||
29 | #include "ppatomctrl.h" | ||
30 | #include "ppinterrupt.h" | ||
31 | #include "ppsmc.h" | ||
32 | #include "iceland_powertune.h" | ||
33 | #include "pp_endian.h" | ||
34 | #include "smu71_discrete.h" | ||
35 | |||
36 | #define ICELAND_MAX_HARDWARE_POWERLEVELS 2 | ||
37 | #define ICELAND_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15 | ||
38 | |||
39 | struct iceland_performance_level { | ||
40 | uint32_t memory_clock; | ||
41 | uint32_t engine_clock; | ||
42 | uint16_t pcie_gen; | ||
43 | uint16_t pcie_lane; | ||
44 | }; | ||
45 | |||
46 | struct _phw_iceland_bacos { | ||
47 | uint32_t best_match; | ||
48 | uint32_t baco_flags; | ||
49 | struct iceland_performance_level performance_level; | ||
50 | }; | ||
51 | typedef struct _phw_iceland_bacos phw_iceland_bacos; | ||
52 | |||
53 | struct _phw_iceland_uvd_clocks { | ||
54 | uint32_t VCLK; | ||
55 | uint32_t DCLK; | ||
56 | }; | ||
57 | |||
58 | typedef struct _phw_iceland_uvd_clocks phw_iceland_uvd_clocks; | ||
59 | |||
60 | struct _phw_iceland_vce_clocks { | ||
61 | uint32_t EVCLK; | ||
62 | uint32_t ECCLK; | ||
63 | }; | ||
64 | |||
65 | typedef struct _phw_iceland_vce_clocks phw_iceland_vce_clocks; | ||
66 | |||
67 | struct iceland_power_state { | ||
68 | uint32_t magic; | ||
69 | phw_iceland_uvd_clocks uvd_clocks; | ||
70 | phw_iceland_vce_clocks vce_clocks; | ||
71 | uint32_t sam_clk; | ||
72 | uint32_t acp_clk; | ||
73 | uint16_t performance_level_count; | ||
74 | bool dc_compatible; | ||
75 | uint32_t sclk_threshold; | ||
76 | struct iceland_performance_level performance_levels[ICELAND_MAX_HARDWARE_POWERLEVELS]; | ||
77 | }; | ||
78 | |||
79 | struct _phw_iceland_dpm_level { | ||
80 | bool enabled; | ||
81 | uint32_t value; | ||
82 | uint32_t param1; | ||
83 | }; | ||
84 | typedef struct _phw_iceland_dpm_level phw_iceland_dpm_level; | ||
85 | |||
86 | #define ICELAND_MAX_DEEPSLEEP_DIVIDER_ID 5 | ||
87 | #define MAX_REGULAR_DPM_NUMBER 8 | ||
88 | #define ICELAND_MINIMUM_ENGINE_CLOCK 5000 | ||
89 | |||
90 | struct iceland_single_dpm_table { | ||
91 | uint32_t count; | ||
92 | phw_iceland_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER]; | ||
93 | }; | ||
94 | |||
95 | struct iceland_dpm_table { | ||
96 | struct iceland_single_dpm_table sclk_table; | ||
97 | struct iceland_single_dpm_table mclk_table; | ||
98 | struct iceland_single_dpm_table pcie_speed_table; | ||
99 | struct iceland_single_dpm_table vddc_table; | ||
100 | struct iceland_single_dpm_table vdd_gfx_table; | ||
101 | struct iceland_single_dpm_table vdd_ci_table; | ||
102 | struct iceland_single_dpm_table mvdd_table; | ||
103 | }; | ||
104 | typedef struct _phw_iceland_dpm_table phw_iceland_dpm_table; | ||
105 | |||
106 | |||
107 | struct _phw_iceland_clock_regisiters { | ||
108 | uint32_t vCG_SPLL_FUNC_CNTL; | ||
109 | uint32_t vCG_SPLL_FUNC_CNTL_2; | ||
110 | uint32_t vCG_SPLL_FUNC_CNTL_3; | ||
111 | uint32_t vCG_SPLL_FUNC_CNTL_4; | ||
112 | uint32_t vCG_SPLL_SPREAD_SPECTRUM; | ||
113 | uint32_t vCG_SPLL_SPREAD_SPECTRUM_2; | ||
114 | uint32_t vDLL_CNTL; | ||
115 | uint32_t vMCLK_PWRMGT_CNTL; | ||
116 | uint32_t vMPLL_AD_FUNC_CNTL; | ||
117 | uint32_t vMPLL_DQ_FUNC_CNTL; | ||
118 | uint32_t vMPLL_FUNC_CNTL; | ||
119 | uint32_t vMPLL_FUNC_CNTL_1; | ||
120 | uint32_t vMPLL_FUNC_CNTL_2; | ||
121 | uint32_t vMPLL_SS1; | ||
122 | uint32_t vMPLL_SS2; | ||
123 | }; | ||
124 | typedef struct _phw_iceland_clock_regisiters phw_iceland_clock_registers; | ||
125 | |||
126 | struct _phw_iceland_voltage_smio_registers { | ||
127 | uint32_t vs0_vid_lower_smio_cntl; | ||
128 | }; | ||
129 | typedef struct _phw_iceland_voltage_smio_registers phw_iceland_voltage_smio_registers; | ||
130 | |||
131 | |||
132 | struct _phw_iceland_mc_reg_entry { | ||
133 | uint32_t mclk_max; | ||
134 | uint32_t mc_data[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE]; | ||
135 | }; | ||
136 | typedef struct _phw_iceland_mc_reg_entry phw_iceland_mc_reg_entry; | ||
137 | |||
138 | struct _phw_iceland_mc_reg_table { | ||
139 | uint8_t last; /* number of registers*/ | ||
140 | uint8_t num_entries; /* number of entries in mc_reg_table_entry used*/ | ||
141 | uint16_t validflag; /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/ | ||
142 | phw_iceland_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES]; | ||
143 | SMU71_Discrete_MCRegisterAddress mc_reg_address[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE]; | ||
144 | }; | ||
145 | typedef struct _phw_iceland_mc_reg_table phw_iceland_mc_reg_table; | ||
146 | |||
147 | #define DISABLE_MC_LOADMICROCODE 1 | ||
148 | #define DISABLE_MC_CFGPROGRAMMING 2 | ||
149 | |||
150 | |||
151 | /*Ultra Low Voltage parameter structure */ | ||
152 | struct phw_iceland_ulv_parm{ | ||
153 | bool ulv_supported; | ||
154 | uint32_t ch_ulv_parameter; | ||
155 | uint32_t ulv_volt_change_delay; | ||
156 | struct iceland_performance_level ulv_power_level; | ||
157 | }; | ||
158 | |||
159 | #define ICELAND_MAX_LEAKAGE_COUNT 8 | ||
160 | |||
161 | struct phw_iceland_leakage_voltage { | ||
162 | uint16_t count; | ||
163 | uint16_t leakage_id[ICELAND_MAX_LEAKAGE_COUNT]; | ||
164 | uint16_t actual_voltage[ICELAND_MAX_LEAKAGE_COUNT]; | ||
165 | }; | ||
166 | |||
167 | struct _phw_iceland_display_timing { | ||
168 | uint32_t min_clock_insr; | ||
169 | uint32_t num_existing_displays; | ||
170 | }; | ||
171 | typedef struct _phw_iceland_display_timing phw_iceland_display_timing; | ||
172 | |||
173 | |||
174 | struct phw_iceland_thermal_temperature_setting | ||
175 | { | ||
176 | long temperature_low; | ||
177 | long temperature_high; | ||
178 | long temperature_shutdown; | ||
179 | }; | ||
180 | |||
181 | struct _phw_iceland_dpmlevel_enable_mask { | ||
182 | uint32_t uvd_dpm_enable_mask; | ||
183 | uint32_t vce_dpm_enable_mask; | ||
184 | uint32_t acp_dpm_enable_mask; | ||
185 | uint32_t samu_dpm_enable_mask; | ||
186 | uint32_t sclk_dpm_enable_mask; | ||
187 | uint32_t mclk_dpm_enable_mask; | ||
188 | uint32_t pcie_dpm_enable_mask; | ||
189 | }; | ||
190 | typedef struct _phw_iceland_dpmlevel_enable_mask phw_iceland_dpmlevel_enable_mask; | ||
191 | |||
192 | struct _phw_iceland_pcie_perf_range { | ||
193 | uint16_t max; | ||
194 | uint16_t min; | ||
195 | }; | ||
196 | typedef struct _phw_iceland_pcie_perf_range phw_iceland_pcie_perf_range; | ||
197 | |||
198 | struct _phw_iceland_vbios_boot_state { | ||
199 | uint16_t mvdd_bootup_value; | ||
200 | uint16_t vddc_bootup_value; | ||
201 | uint16_t vddci_bootup_value; | ||
202 | uint16_t vddgfx_bootup_value; | ||
203 | uint32_t sclk_bootup_value; | ||
204 | uint32_t mclk_bootup_value; | ||
205 | uint16_t pcie_gen_bootup_value; | ||
206 | uint16_t pcie_lane_bootup_value; | ||
207 | }; | ||
208 | typedef struct _phw_iceland_vbios_boot_state phw_iceland_vbios_boot_state; | ||
209 | |||
210 | #define DPMTABLE_OD_UPDATE_SCLK 0x00000001 | ||
211 | #define DPMTABLE_OD_UPDATE_MCLK 0x00000002 | ||
212 | #define DPMTABLE_UPDATE_SCLK 0x00000004 | ||
213 | #define DPMTABLE_UPDATE_MCLK 0x00000008 | ||
214 | |||
215 | /* We need to review which fields are needed. */ | ||
216 | /* This is mostly a copy of the RV7xx/Evergreen structure which is close, but not identical to the N.Islands one. */ | ||
217 | struct iceland_hwmgr { | ||
218 | struct iceland_dpm_table dpm_table; | ||
219 | struct iceland_dpm_table golden_dpm_table; | ||
220 | |||
221 | uint32_t voting_rights_clients0; | ||
222 | uint32_t voting_rights_clients1; | ||
223 | uint32_t voting_rights_clients2; | ||
224 | uint32_t voting_rights_clients3; | ||
225 | uint32_t voting_rights_clients4; | ||
226 | uint32_t voting_rights_clients5; | ||
227 | uint32_t voting_rights_clients6; | ||
228 | uint32_t voting_rights_clients7; | ||
229 | uint32_t static_screen_threshold_unit; | ||
230 | uint32_t static_screen_threshold; | ||
231 | uint32_t voltage_control; | ||
232 | uint32_t vdd_gfx_control; | ||
233 | |||
234 | uint32_t vddc_vddci_delta; | ||
235 | uint32_t vddc_vddgfx_delta; | ||
236 | |||
237 | struct pp_interrupt_registration_info internal_high_thermal_interrupt_info; | ||
238 | struct pp_interrupt_registration_info internal_low_thermal_interrupt_info; | ||
239 | struct pp_interrupt_registration_info smc_to_host_interrupt_info; | ||
240 | uint32_t active_auto_throttle_sources; | ||
241 | |||
242 | struct pp_interrupt_registration_info external_throttle_interrupt; | ||
243 | irq_handler_func_t external_throttle_callback; | ||
244 | void *external_throttle_context; | ||
245 | |||
246 | struct pp_interrupt_registration_info ctf_interrupt_info; | ||
247 | irq_handler_func_t ctf_callback; | ||
248 | void *ctf_context; | ||
249 | |||
250 | phw_iceland_clock_registers clock_registers; | ||
251 | phw_iceland_voltage_smio_registers voltage_smio_registers; | ||
252 | |||
253 | bool is_memory_GDDR5; | ||
254 | uint16_t acpi_vddc; | ||
255 | bool pspp_notify_required; /* Flag to indicate if PSPP notification to SBIOS is required */ | ||
256 | uint16_t force_pcie_gen; /* The forced PCI-E speed if not 0xffff */ | ||
257 | uint16_t acpi_pcie_gen; /* The PCI-E speed at ACPI time */ | ||
258 | uint32_t pcie_gen_cap; /* The PCI-E speed capabilities bitmap from CAIL */ | ||
259 | uint32_t pcie_lane_cap; /* The PCI-E lane capabilities bitmap from CAIL */ | ||
260 | uint32_t pcie_spc_cap; /* Symbol Per Clock Capabilities from registry */ | ||
261 | struct phw_iceland_leakage_voltage vddc_leakage; /* The Leakage VDDC supported (based on leakage ID).*/ | ||
262 | struct phw_iceland_leakage_voltage vddcgfx_leakage; /* The Leakage VDDC supported (based on leakage ID). */ | ||
263 | struct phw_iceland_leakage_voltage vddci_leakage; /* The Leakage VDDCI supported (based on leakage ID). */ | ||
264 | |||
265 | uint32_t mvdd_control; | ||
266 | uint32_t vddc_mask_low; | ||
267 | uint32_t mvdd_mask_low; | ||
268 | uint16_t max_vddc_in_pp_table; /* the maximum VDDC value in the powerplay table*/ | ||
269 | uint16_t min_vddc_in_pp_table; | ||
270 | uint16_t max_vddci_in_pp_table; /* the maximum VDDCI value in the powerplay table */ | ||
271 | uint16_t min_vddci_in_pp_table; | ||
272 | uint32_t mclk_strobe_mode_threshold; | ||
273 | uint32_t mclk_stutter_mode_threshold; | ||
274 | uint32_t mclk_edc_enable_threshold; | ||
275 | uint32_t mclk_edc_wr_enable_threshold; | ||
276 | bool is_uvd_enabled; | ||
277 | bool is_xdma_enabled; | ||
278 | phw_iceland_vbios_boot_state vbios_boot_state; | ||
279 | |||
280 | bool battery_state; | ||
281 | bool is_tlu_enabled; | ||
282 | bool pcie_performance_request; | ||
283 | |||
284 | /* -------------- SMC SRAM Address of firmware header tables ----------------*/ | ||
285 | uint32_t sram_end; /* The first address after the SMC SRAM. */ | ||
286 | uint32_t dpm_table_start; /* The start of the dpm table in the SMC SRAM. */ | ||
287 | uint32_t soft_regs_start; /* The start of the soft registers in the SMC SRAM. */ | ||
288 | uint32_t mc_reg_table_start; /* The start of the mc register table in the SMC SRAM. */ | ||
289 | uint32_t fan_table_start; /* The start of the fan table in the SMC SRAM. */ | ||
290 | uint32_t arb_table_start; /* The start of the ARB setting table in the SMC SRAM. */ | ||
291 | uint32_t ulv_settings_start; | ||
292 | SMU71_Discrete_DpmTable smc_state_table; /* The carbon copy of the SMC state table. */ | ||
293 | SMU71_Discrete_MCRegisters mc_reg_table; | ||
294 | SMU71_Discrete_Ulv ulv_setting; /* The carbon copy of ULV setting. */ | ||
295 | |||
296 | /* -------------- Stuff originally coming from Evergreen --------------------*/ | ||
297 | phw_iceland_mc_reg_table iceland_mc_reg_table; | ||
298 | uint32_t vdd_ci_control; | ||
299 | pp_atomctrl_voltage_table vddc_voltage_table; | ||
300 | pp_atomctrl_voltage_table vddci_voltage_table; | ||
301 | pp_atomctrl_voltage_table vddgfx_voltage_table; | ||
302 | pp_atomctrl_voltage_table mvdd_voltage_table; | ||
303 | |||
304 | uint32_t mgcg_cgtt_local2; | ||
305 | uint32_t mgcg_cgtt_local3; | ||
306 | uint32_t gpio_debug; | ||
307 | uint32_t mc_micro_code_feature; | ||
308 | uint32_t highest_mclk; | ||
309 | uint16_t acpi_vdd_ci; | ||
310 | uint8_t mvdd_high_index; | ||
311 | uint8_t mvdd_low_index; | ||
312 | bool dll_defaule_on; | ||
313 | bool performance_request_registered; | ||
314 | |||
315 | /* ----------------- Low Power Features ---------------------*/ | ||
316 | phw_iceland_bacos bacos; | ||
317 | struct phw_iceland_ulv_parm ulv; | ||
318 | |||
319 | /* ----------------- CAC Stuff ---------------------*/ | ||
320 | uint32_t cac_table_start; | ||
321 | bool cac_configuration_required; /* TRUE if PP_CACConfigurationRequired == 1 */ | ||
322 | bool driver_calculate_cac_leakage; /* TRUE if PP_DriverCalculateCACLeakage == 1 */ | ||
323 | bool cac_enabled; | ||
324 | |||
325 | /* ----------------- DPM2 Parameters ---------------------*/ | ||
326 | uint32_t power_containment_features; | ||
327 | bool enable_bapm_feature; | ||
328 | bool enable_dte_feature; | ||
329 | bool enable_tdc_limit_feature; | ||
330 | bool enable_pkg_pwr_tracking_feature; | ||
331 | bool disable_uvd_power_tune_feature; | ||
332 | struct iceland_pt_defaults *power_tune_defaults; | ||
333 | SMU71_Discrete_PmFuses power_tune_table; | ||
334 | uint32_t ul_dte_tj_offset; /* Fudge factor in DPM table to correct HW DTE errors */ | ||
335 | uint32_t fast_watermark_threshold; /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */ | ||
336 | |||
337 | /* ----------------- Phase Shedding ---------------------*/ | ||
338 | bool vddc_phase_shed_control; | ||
339 | |||
340 | /* --------------------- DI/DT --------------------------*/ | ||
341 | phw_iceland_display_timing display_timing; | ||
342 | |||
343 | /* --------- ReadRegistry data for memory and engine clock margins ---- */ | ||
344 | uint32_t engine_clock_data; | ||
345 | uint32_t memory_clock_data; | ||
346 | |||
347 | /* -------- Thermal Temperature Setting --------------*/ | ||
348 | struct phw_iceland_thermal_temperature_setting thermal_temp_setting; | ||
349 | phw_iceland_dpmlevel_enable_mask dpm_level_enable_mask; | ||
350 | |||
351 | uint32_t need_update_smu7_dpm_table; | ||
352 | uint32_t sclk_dpm_key_disabled; | ||
353 | uint32_t mclk_dpm_key_disabled; | ||
354 | uint32_t pcie_dpm_key_disabled; | ||
355 | /* used to store the previous dal min sclock */ | ||
356 | uint32_t min_engine_clocks; | ||
357 | phw_iceland_pcie_perf_range pcie_gen_performance; | ||
358 | phw_iceland_pcie_perf_range pcie_lane_performance; | ||
359 | phw_iceland_pcie_perf_range pcie_gen_power_saving; | ||
360 | phw_iceland_pcie_perf_range pcie_lane_power_saving; | ||
361 | bool use_pcie_performance_levels; | ||
362 | bool use_pcie_power_saving_levels; | ||
363 | /* percentage value from 0-100, default 50 */ | ||
364 | uint32_t activity_target[SMU71_MAX_LEVELS_GRAPHICS]; | ||
365 | uint32_t mclk_activity_target; | ||
366 | uint32_t low_sclk_interrupt_threshold; | ||
367 | uint32_t last_mclk_dpm_enable_mask; | ||
368 | bool uvd_enabled; | ||
369 | uint32_t pcc_monitor_enabled; | ||
370 | |||
371 | /* --------- Power Gating States ------------*/ | ||
372 | bool uvd_power_gated; /* 1: gated, 0:not gated */ | ||
373 | bool vce_power_gated; /* 1: gated, 0:not gated */ | ||
374 | bool samu_power_gated; /* 1: gated, 0:not gated */ | ||
375 | bool acp_power_gated; /* 1: gated, 0:not gated */ | ||
376 | bool pg_acp_init; | ||
377 | |||
378 | /* soft pptable for re-uploading into smu */ | ||
379 | void *soft_pp_table; | ||
380 | }; | ||
381 | |||
382 | typedef struct iceland_hwmgr iceland_hwmgr; | ||
383 | |||
384 | int iceland_hwmgr_init(struct pp_hwmgr *hwmgr); | ||
385 | int iceland_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate); | ||
386 | uint32_t iceland_get_xclk(struct pp_hwmgr *hwmgr); | ||
387 | int iceland_populate_bapm_vddc_vid_sidd(struct pp_hwmgr *hwmgr); | ||
388 | int iceland_populate_vddc_vid(struct pp_hwmgr *hwmgr); | ||
389 | |||
390 | #define ICELAND_DPM2_NEAR_TDP_DEC 10 | ||
391 | #define ICELAND_DPM2_ABOVE_SAFE_INC 5 | ||
392 | #define ICELAND_DPM2_BELOW_SAFE_INC 20 | ||
393 | |||
394 | /* | ||
395 | * Log2 of the LTA window size (l2numWin_TDP). Eg. If LTA windows size | ||
396 | * is 128, then this value should be Log2(128) = 7. | ||
397 | */ | ||
398 | #define ICELAND_DPM2_LTA_WINDOW_SIZE 7 | ||
399 | |||
400 | #define ICELAND_DPM2_LTS_TRUNCATE 0 | ||
401 | |||
402 | #define ICELAND_DPM2_TDP_SAFE_LIMIT_PERCENT 80 // Maximum 100 | ||
403 | |||
404 | #define ICELAND_DPM2_MAXPS_PERCENT_H 90 // Maximum 0xFF | ||
405 | #define ICELAND_DPM2_MAXPS_PERCENT_M 90 // Maximum 0xFF | ||
406 | |||
407 | #define ICELAND_DPM2_PWREFFICIENCYRATIO_MARGIN 50 | ||
408 | |||
409 | #define ICELAND_DPM2_SQ_RAMP_MAX_POWER 0x3FFF | ||
410 | #define ICELAND_DPM2_SQ_RAMP_MIN_POWER 0x12 | ||
411 | #define ICELAND_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15 | ||
412 | #define ICELAND_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE 0x1E | ||
413 | #define ICELAND_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO 0xF | ||
414 | |||
415 | #define ICELAND_VOLTAGE_CONTROL_NONE 0x0 | ||
416 | #define ICELAND_VOLTAGE_CONTROL_BY_GPIO 0x1 | ||
417 | #define ICELAND_VOLTAGE_CONTROL_BY_SVID2 0x2 | ||
418 | |||
419 | /* convert to Q8.8 format for firmware */ | ||
420 | #define ICELAND_Q88_FORMAT_CONVERSION_UNIT 256 | ||
421 | |||
422 | #define ICELAND_UNUSED_GPIO_PIN 0x7F | ||
423 | |||
424 | #endif | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_powertune.c new file mode 100644 index 000000000000..041e9648e592 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_powertune.c | |||
@@ -0,0 +1,490 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include "amdgpu.h" | ||
27 | #include "hwmgr.h" | ||
28 | #include "smumgr.h" | ||
29 | #include "iceland_hwmgr.h" | ||
30 | #include "iceland_powertune.h" | ||
31 | #include "iceland_smumgr.h" | ||
32 | #include "smu71_discrete.h" | ||
33 | #include "smu71.h" | ||
34 | #include "pp_debug.h" | ||
35 | #include "cgs_common.h" | ||
36 | #include "pp_endian.h" | ||
37 | |||
38 | #include "bif/bif_5_0_d.h" | ||
39 | #include "bif/bif_5_0_sh_mask.h" | ||
40 | |||
41 | #define VOLTAGE_SCALE 4 | ||
42 | #define POWERTUNE_DEFAULT_SET_MAX 1 | ||
43 | |||
44 | #define DEVICE_ID_VI_ICELAND_M_6900 0x6900 | ||
45 | #define DEVICE_ID_VI_ICELAND_M_6901 0x6901 | ||
46 | #define DEVICE_ID_VI_ICELAND_M_6902 0x6902 | ||
47 | #define DEVICE_ID_VI_ICELAND_M_6903 0x6903 | ||
48 | |||
49 | |||
50 | struct iceland_pt_defaults defaults_iceland = | ||
51 | { | ||
52 | /* | ||
53 | * sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc, | ||
54 | * TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT | ||
55 | */ | ||
56 | 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000, | ||
57 | { 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61 }, | ||
58 | { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 } | ||
59 | }; | ||
60 | |||
61 | /* 35W - XT, XTL */ | ||
62 | struct iceland_pt_defaults defaults_icelandxt = | ||
63 | { | ||
64 | /* | ||
65 | * sviLoadLIneEn, SviLoadLineVddC, | ||
66 | * TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt, | ||
67 | * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, | ||
68 | * BAPM_TEMP_GRADIENT | ||
69 | */ | ||
70 | 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0, | ||
71 | { 0xA7, 0x0, 0x0, 0xB5, 0x0, 0x0, 0x9F, 0x0, 0x0, 0xD6, 0x0, 0x0, 0xD7, 0x0, 0x0}, | ||
72 | { 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0} | ||
73 | }; | ||
74 | |||
75 | /* 25W - PRO, LE */ | ||
76 | struct iceland_pt_defaults defaults_icelandpro = | ||
77 | { | ||
78 | /* | ||
79 | * sviLoadLIneEn, SviLoadLineVddC, | ||
80 | * TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt, | ||
81 | * TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, | ||
82 | * BAPM_TEMP_GRADIENT | ||
83 | */ | ||
84 | 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0, | ||
85 | { 0xB7, 0x0, 0x0, 0xC3, 0x0, 0x0, 0xB5, 0x0, 0x0, 0xEA, 0x0, 0x0, 0xE6, 0x0, 0x0}, | ||
86 | { 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0} | ||
87 | }; | ||
88 | |||
89 | void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) | ||
90 | { | ||
91 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
92 | uint32_t tmp = 0; | ||
93 | struct cgs_system_info sys_info = {0}; | ||
94 | uint32_t pdev_id; | ||
95 | |||
96 | sys_info.size = sizeof(struct cgs_system_info); | ||
97 | sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; | ||
98 | cgs_query_system_info(hwmgr->device, &sys_info); | ||
99 | pdev_id = (uint32_t)sys_info.value; | ||
100 | |||
101 | switch (pdev_id) { | ||
102 | case DEVICE_ID_VI_ICELAND_M_6900: | ||
103 | case DEVICE_ID_VI_ICELAND_M_6903: | ||
104 | data->power_tune_defaults = &defaults_icelandxt; | ||
105 | break; | ||
106 | |||
107 | case DEVICE_ID_VI_ICELAND_M_6901: | ||
108 | case DEVICE_ID_VI_ICELAND_M_6902: | ||
109 | data->power_tune_defaults = &defaults_icelandpro; | ||
110 | break; | ||
111 | default: | ||
112 | /* TODO: need to assign valid defaults */ | ||
113 | data->power_tune_defaults = &defaults_iceland; | ||
114 | pr_warning("Unknown V.I. Device ID.\n"); | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | /* Assume disabled */ | ||
119 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
120 | PHM_PlatformCaps_PowerContainment); | ||
121 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
122 | PHM_PlatformCaps_CAC); | ||
123 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
124 | PHM_PlatformCaps_SQRamping); | ||
125 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
126 | PHM_PlatformCaps_DBRamping); | ||
127 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
128 | PHM_PlatformCaps_TDRamping); | ||
129 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
130 | PHM_PlatformCaps_TCPRamping); | ||
131 | |||
132 | data->ul_dte_tj_offset = tmp; | ||
133 | |||
134 | if (!tmp) { | ||
135 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
136 | PHM_PlatformCaps_CAC); | ||
137 | |||
138 | data->fast_watermark_threshold = 100; | ||
139 | |||
140 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
141 | PHM_PlatformCaps_PowerContainment)) { | ||
142 | tmp = 1; | ||
143 | data->enable_dte_feature = tmp ? false : true; | ||
144 | data->enable_tdc_limit_feature = tmp ? true : false; | ||
145 | data->enable_pkg_pwr_tracking_feature = tmp ? true : false; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | int iceland_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr) | ||
151 | { | ||
152 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
153 | struct iceland_pt_defaults *defaults = data->power_tune_defaults; | ||
154 | SMU71_Discrete_DpmTable *dpm_table = &(data->smc_state_table); | ||
155 | struct phm_cac_tdp_table *cac_dtp_table = hwmgr->dyn_state.cac_dtp_table; | ||
156 | struct phm_ppm_table *ppm = hwmgr->dyn_state.ppm_parameter_table; | ||
157 | uint16_t *def1, *def2; | ||
158 | int i, j, k; | ||
159 | |||
160 | /* | ||
161 | * TDP number of fraction bits are changed from 8 to 7 for Iceland | ||
162 | * as requested by SMC team | ||
163 | */ | ||
164 | dpm_table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 256)); | ||
165 | dpm_table->TargetTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usConfigurableTDP * 256)); | ||
166 | |||
167 | dpm_table->DTETjOffset = (uint8_t)data->ul_dte_tj_offset; | ||
168 | |||
169 | dpm_table->GpuTjMax = (uint8_t)(data->thermal_temp_setting.temperature_high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES); | ||
170 | dpm_table->GpuTjHyst = 8; | ||
171 | |||
172 | dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base; | ||
173 | |||
174 | /* The following are for new Iceland Multi-input fan/thermal control */ | ||
175 | if(NULL != ppm) { | ||
176 | dpm_table->PPM_PkgPwrLimit = (uint16_t)ppm->dgpu_tdp * 256 / 1000; | ||
177 | dpm_table->PPM_TemperatureLimit = (uint16_t)ppm->tj_max * 256; | ||
178 | } else { | ||
179 | dpm_table->PPM_PkgPwrLimit = 0; | ||
180 | dpm_table->PPM_TemperatureLimit = 0; | ||
181 | } | ||
182 | |||
183 | CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_PkgPwrLimit); | ||
184 | CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_TemperatureLimit); | ||
185 | |||
186 | dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bamp_temp_gradient); | ||
187 | def1 = defaults->bapmti_r; | ||
188 | def2 = defaults->bapmti_rc; | ||
189 | |||
190 | for (i = 0; i < SMU71_DTE_ITERATIONS; i++) { | ||
191 | for (j = 0; j < SMU71_DTE_SOURCES; j++) { | ||
192 | for (k = 0; k < SMU71_DTE_SINKS; k++) { | ||
193 | dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*def1); | ||
194 | dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*def2); | ||
195 | def1++; | ||
196 | def2++; | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int iceland_populate_svi_load_line(struct pp_hwmgr *hwmgr) | ||
205 | { | ||
206 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
207 | const struct iceland_pt_defaults *defaults = data->power_tune_defaults; | ||
208 | |||
209 | data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en; | ||
210 | data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddc; | ||
211 | data->power_tune_table.SviLoadLineTrimVddC = 3; | ||
212 | data->power_tune_table.SviLoadLineOffsetVddC = 0; | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int iceland_populate_tdc_limit(struct pp_hwmgr *hwmgr) | ||
218 | { | ||
219 | uint16_t tdc_limit; | ||
220 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
221 | const struct iceland_pt_defaults *defaults = data->power_tune_defaults; | ||
222 | |||
223 | /* TDC number of fraction bits are changed from 8 to 7 | ||
224 | * for Iceland as requested by SMC team | ||
225 | */ | ||
226 | tdc_limit = (uint16_t)(hwmgr->dyn_state.cac_dtp_table->usTDC * 256); | ||
227 | data->power_tune_table.TDC_VDDC_PkgLimit = | ||
228 | CONVERT_FROM_HOST_TO_SMC_US(tdc_limit); | ||
229 | data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc = | ||
230 | defaults->tdc_vddc_throttle_release_limit_perc; | ||
231 | data->power_tune_table.TDC_MAWt = defaults->tdc_mawt; | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int iceland_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) | ||
237 | { | ||
238 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
239 | const struct iceland_pt_defaults *defaults = data->power_tune_defaults; | ||
240 | uint32_t temp; | ||
241 | |||
242 | if (iceland_read_smc_sram_dword(hwmgr->smumgr, | ||
243 | fuse_table_offset + | ||
244 | offsetof(SMU71_Discrete_PmFuses, TdcWaterfallCtl), | ||
245 | (uint32_t *)&temp, data->sram_end)) | ||
246 | PP_ASSERT_WITH_CODE(false, | ||
247 | "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", | ||
248 | return -EINVAL); | ||
249 | else | ||
250 | data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int iceland_populate_temperature_scaler(struct pp_hwmgr *hwmgr) | ||
256 | { | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int iceland_populate_gnb_lpml(struct pp_hwmgr *hwmgr) | ||
261 | { | ||
262 | int i; | ||
263 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
264 | |||
265 | /* Currently not used. Set all to zero. */ | ||
266 | for (i = 0; i < 8; i++) | ||
267 | data->power_tune_table.GnbLPML[i] = 0; | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int iceland_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr) | ||
273 | { | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int iceland_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr) | ||
278 | { | ||
279 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
280 | uint16_t HiSidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd; | ||
281 | uint16_t LoSidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd; | ||
282 | struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table; | ||
283 | |||
284 | HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256); | ||
285 | LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256); | ||
286 | |||
287 | data->power_tune_table.BapmVddCBaseLeakageHiSidd = | ||
288 | CONVERT_FROM_HOST_TO_SMC_US(HiSidd); | ||
289 | data->power_tune_table.BapmVddCBaseLeakageLoSidd = | ||
290 | CONVERT_FROM_HOST_TO_SMC_US(LoSidd); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | int iceland_populate_pm_fuses(struct pp_hwmgr *hwmgr) | ||
296 | { | ||
297 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
298 | uint32_t pm_fuse_table_offset; | ||
299 | |||
300 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
301 | PHM_PlatformCaps_PowerContainment)) { | ||
302 | if (iceland_read_smc_sram_dword(hwmgr->smumgr, | ||
303 | SMU71_FIRMWARE_HEADER_LOCATION + | ||
304 | offsetof(SMU71_Firmware_Header, PmFuseTable), | ||
305 | &pm_fuse_table_offset, data->sram_end)) | ||
306 | PP_ASSERT_WITH_CODE(false, | ||
307 | "Attempt to get pm_fuse_table_offset Failed!", | ||
308 | return -EINVAL); | ||
309 | |||
310 | /* DW0 - DW3 */ | ||
311 | if (iceland_populate_bapm_vddc_vid_sidd(hwmgr)) | ||
312 | PP_ASSERT_WITH_CODE(false, | ||
313 | "Attempt to populate bapm vddc vid Failed!", | ||
314 | return -EINVAL); | ||
315 | |||
316 | /* DW4 - DW5 */ | ||
317 | if (iceland_populate_vddc_vid(hwmgr)) | ||
318 | PP_ASSERT_WITH_CODE(false, | ||
319 | "Attempt to populate vddc vid Failed!", | ||
320 | return -EINVAL); | ||
321 | |||
322 | /* DW6 */ | ||
323 | if (iceland_populate_svi_load_line(hwmgr)) | ||
324 | PP_ASSERT_WITH_CODE(false, | ||
325 | "Attempt to populate SviLoadLine Failed!", | ||
326 | return -EINVAL); | ||
327 | /* DW7 */ | ||
328 | if (iceland_populate_tdc_limit(hwmgr)) | ||
329 | PP_ASSERT_WITH_CODE(false, | ||
330 | "Attempt to populate TDCLimit Failed!", return -EINVAL); | ||
331 | /* DW8 */ | ||
332 | if (iceland_populate_dw8(hwmgr, pm_fuse_table_offset)) | ||
333 | PP_ASSERT_WITH_CODE(false, | ||
334 | "Attempt to populate TdcWaterfallCtl, " | ||
335 | "LPMLTemperature Min and Max Failed!", | ||
336 | return -EINVAL); | ||
337 | |||
338 | /* DW9-DW12 */ | ||
339 | if (0 != iceland_populate_temperature_scaler(hwmgr)) | ||
340 | PP_ASSERT_WITH_CODE(false, | ||
341 | "Attempt to populate LPMLTemperatureScaler Failed!", | ||
342 | return -EINVAL); | ||
343 | |||
344 | /* DW13-DW16 */ | ||
345 | if (iceland_populate_gnb_lpml(hwmgr)) | ||
346 | PP_ASSERT_WITH_CODE(false, | ||
347 | "Attempt to populate GnbLPML Failed!", | ||
348 | return -EINVAL); | ||
349 | |||
350 | /* DW17 */ | ||
351 | if (iceland_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr)) | ||
352 | PP_ASSERT_WITH_CODE(false, | ||
353 | "Attempt to populate GnbLPML Min and Max Vid Failed!", | ||
354 | return -EINVAL); | ||
355 | |||
356 | /* DW18 */ | ||
357 | if (iceland_populate_bapm_vddc_base_leakage_sidd(hwmgr)) | ||
358 | PP_ASSERT_WITH_CODE(false, | ||
359 | "Attempt to populate BapmVddCBaseLeakage Hi and Lo Sidd Failed!", | ||
360 | return -EINVAL); | ||
361 | |||
362 | if (iceland_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset, | ||
363 | (uint8_t *)&data->power_tune_table, | ||
364 | sizeof(struct SMU71_Discrete_PmFuses), data->sram_end)) | ||
365 | PP_ASSERT_WITH_CODE(false, | ||
366 | "Attempt to download PmFuseTable Failed!", | ||
367 | return -EINVAL); | ||
368 | } | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | int iceland_enable_smc_cac(struct pp_hwmgr *hwmgr) | ||
373 | { | ||
374 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
375 | int result = 0; | ||
376 | |||
377 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
378 | PHM_PlatformCaps_CAC)) { | ||
379 | int smc_result; | ||
380 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
381 | (uint16_t)(PPSMC_MSG_EnableCac)); | ||
382 | PP_ASSERT_WITH_CODE((0 == smc_result), | ||
383 | "Failed to enable CAC in SMC.", result = -1); | ||
384 | |||
385 | data->cac_enabled = (0 == smc_result) ? true : false; | ||
386 | } | ||
387 | return result; | ||
388 | } | ||
389 | |||
390 | static int iceland_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n) | ||
391 | { | ||
392 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
393 | |||
394 | if(data->power_containment_features & | ||
395 | POWERCONTAINMENT_FEATURE_PkgPwrLimit) | ||
396 | return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
397 | PPSMC_MSG_PkgPwrSetLimit, n); | ||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int iceland_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp) | ||
402 | { | ||
403 | return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr, | ||
404 | PPSMC_MSG_OverDriveSetTargetTdp, target_tdp); | ||
405 | } | ||
406 | |||
407 | int iceland_enable_power_containment(struct pp_hwmgr *hwmgr) | ||
408 | { | ||
409 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
410 | SMU71_Discrete_DpmTable *dpm_table = &data->smc_state_table; | ||
411 | int smc_result; | ||
412 | int result = 0; | ||
413 | uint32_t is_asic_kicker; | ||
414 | |||
415 | data->power_containment_features = 0; | ||
416 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
417 | PHM_PlatformCaps_PowerContainment)) { | ||
418 | is_asic_kicker = cgs_read_register(hwmgr->device, mmCC_BIF_BX_STRAP2); | ||
419 | is_asic_kicker = (is_asic_kicker >> 12) & 0x01; | ||
420 | |||
421 | if (data->enable_bapm_feature && | ||
422 | (!is_asic_kicker || | ||
423 | phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
424 | PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc))) { | ||
425 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
426 | (uint16_t)(PPSMC_MSG_EnableDTE)); | ||
427 | PP_ASSERT_WITH_CODE((0 == smc_result), | ||
428 | "Failed to enable BAPM in SMC.", result = -1;); | ||
429 | if (0 == smc_result) | ||
430 | data->power_containment_features |= POWERCONTAINMENT_FEATURE_BAPM; | ||
431 | } | ||
432 | |||
433 | if (is_asic_kicker && !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
434 | PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc)) | ||
435 | dpm_table->DTEMode = 2; | ||
436 | |||
437 | if (data->enable_tdc_limit_feature) { | ||
438 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
439 | (uint16_t)(PPSMC_MSG_TDCLimitEnable)); | ||
440 | PP_ASSERT_WITH_CODE((0 == smc_result), | ||
441 | "Failed to enable TDCLimit in SMC.", result = -1;); | ||
442 | if (0 == smc_result) | ||
443 | data->power_containment_features |= | ||
444 | POWERCONTAINMENT_FEATURE_TDCLimit; | ||
445 | } | ||
446 | |||
447 | if (data->enable_pkg_pwr_tracking_feature) { | ||
448 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
449 | (uint16_t)(PPSMC_MSG_PkgPwrLimitEnable)); | ||
450 | PP_ASSERT_WITH_CODE((0 == smc_result), | ||
451 | "Failed to enable PkgPwrTracking in SMC.", result = -1;); | ||
452 | if (0 == smc_result) { | ||
453 | struct phm_cac_tdp_table *cac_table = | ||
454 | hwmgr->dyn_state.cac_dtp_table; | ||
455 | uint32_t default_limit = | ||
456 | (uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256); | ||
457 | |||
458 | data->power_containment_features |= | ||
459 | POWERCONTAINMENT_FEATURE_PkgPwrLimit; | ||
460 | |||
461 | if (iceland_set_power_limit(hwmgr, default_limit)) | ||
462 | printk(KERN_ERR "Failed to set Default Power Limit in SMC!"); | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | return result; | ||
467 | } | ||
468 | |||
469 | int iceland_power_control_set_level(struct pp_hwmgr *hwmgr) | ||
470 | { | ||
471 | struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table; | ||
472 | int adjust_percent, target_tdp; | ||
473 | int result = 0; | ||
474 | |||
475 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
476 | PHM_PlatformCaps_PowerContainment)) { | ||
477 | /* adjustment percentage has already been validated */ | ||
478 | adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ? | ||
479 | hwmgr->platform_descriptor.TDPAdjustment : | ||
480 | (-1 * hwmgr->platform_descriptor.TDPAdjustment); | ||
481 | /* | ||
482 | * SMC requested that target_tdp to be 7 bit fraction in DPM table | ||
483 | * but message to be 8 bit fraction for messages | ||
484 | */ | ||
485 | target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100; | ||
486 | result = iceland_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp); | ||
487 | } | ||
488 | |||
489 | return result; | ||
490 | } | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_powertune.h b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_powertune.h new file mode 100644 index 000000000000..6c25ee139ca3 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_powertune.h | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | #ifndef ICELAND_POWERTUNE_H | ||
26 | #define ICELAND_POWERTUNE_H | ||
27 | |||
28 | #include "smu71.h" | ||
29 | |||
30 | enum iceland_pt_config_reg_type { | ||
31 | ICELAND_CONFIGREG_MMR = 0, | ||
32 | ICELAND_CONFIGREG_SMC_IND, | ||
33 | ICELAND_CONFIGREG_DIDT_IND, | ||
34 | ICELAND_CONFIGREG_CACHE, | ||
35 | ICELAND_CONFIGREG_MAX | ||
36 | }; | ||
37 | |||
38 | /* PowerContainment Features */ | ||
39 | #define POWERCONTAINMENT_FEATURE_DTE 0x00000001 | ||
40 | #define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002 | ||
41 | #define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004 | ||
42 | #define POWERCONTAINMENT_FEATURE_BAPM 0x00000001 | ||
43 | |||
44 | struct iceland_pt_config_reg { | ||
45 | uint32_t offset; | ||
46 | uint32_t mask; | ||
47 | uint32_t shift; | ||
48 | uint32_t value; | ||
49 | enum iceland_pt_config_reg_type type; | ||
50 | }; | ||
51 | |||
52 | struct iceland_pt_defaults | ||
53 | { | ||
54 | uint8_t svi_load_line_en; | ||
55 | uint8_t svi_load_line_vddc; | ||
56 | uint8_t tdc_vddc_throttle_release_limit_perc; | ||
57 | uint8_t tdc_mawt; | ||
58 | uint8_t tdc_waterfall_ctl; | ||
59 | uint8_t dte_ambient_temp_base; | ||
60 | uint32_t display_cac; | ||
61 | uint32_t bamp_temp_gradient; | ||
62 | uint16_t bapmti_r[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS]; | ||
63 | uint16_t bapmti_rc[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS]; | ||
64 | }; | ||
65 | |||
66 | void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr); | ||
67 | int iceland_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr); | ||
68 | int iceland_populate_pm_fuses(struct pp_hwmgr *hwmgr); | ||
69 | int iceland_enable_smc_cac(struct pp_hwmgr *hwmgr); | ||
70 | int iceland_enable_power_containment(struct pp_hwmgr *hwmgr); | ||
71 | int iceland_power_control_set_level(struct pp_hwmgr *hwmgr); | ||
72 | |||
73 | #endif /* ICELAND_POWERTUNE_H */ | ||
74 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_thermal.c new file mode 100644 index 000000000000..527f37022424 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_thermal.c | |||
@@ -0,0 +1,595 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | #include <asm/div64.h> | ||
26 | #include "iceland_thermal.h" | ||
27 | #include "iceland_hwmgr.h" | ||
28 | #include "iceland_smumgr.h" | ||
29 | #include "atombios.h" | ||
30 | #include "ppsmc.h" | ||
31 | |||
32 | #include "gmc/gmc_8_1_d.h" | ||
33 | #include "gmc/gmc_8_1_sh_mask.h" | ||
34 | |||
35 | #include "bif/bif_5_0_d.h" | ||
36 | #include "bif/bif_5_0_sh_mask.h" | ||
37 | |||
38 | #include "smu/smu_7_1_1_d.h" | ||
39 | #include "smu/smu_7_1_1_sh_mask.h" | ||
40 | |||
41 | |||
42 | /** | ||
43 | * Get Fan Speed Control Parameters. | ||
44 | * @param hwmgr the address of the powerplay hardware manager. | ||
45 | * @param pSpeed is the address of the structure where the result is to be placed. | ||
46 | * @exception Always succeeds except if we cannot zero out the output structure. | ||
47 | */ | ||
48 | int iceland_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, | ||
49 | struct phm_fan_speed_info *fan_speed_info) | ||
50 | { | ||
51 | |||
52 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
53 | return 0; | ||
54 | |||
55 | fan_speed_info->supports_percent_read = true; | ||
56 | fan_speed_info->supports_percent_write = true; | ||
57 | fan_speed_info->min_percent = 0; | ||
58 | fan_speed_info->max_percent = 100; | ||
59 | |||
60 | if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) { | ||
61 | fan_speed_info->supports_rpm_read = true; | ||
62 | fan_speed_info->supports_rpm_write = true; | ||
63 | fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM; | ||
64 | fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM; | ||
65 | } else { | ||
66 | fan_speed_info->min_rpm = 0; | ||
67 | fan_speed_info->max_rpm = 0; | ||
68 | } | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * Get Fan Speed in percent. | ||
75 | * @param hwmgr the address of the powerplay hardware manager. | ||
76 | * @param pSpeed is the address of the structure where the result is to be placed. | ||
77 | * @exception Fails is the 100% setting appears to be 0. | ||
78 | */ | ||
79 | int iceland_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed) | ||
80 | { | ||
81 | uint32_t duty100; | ||
82 | uint32_t duty; | ||
83 | uint64_t tmp64; | ||
84 | |||
85 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
86 | return 0; | ||
87 | |||
88 | duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100); | ||
89 | duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY); | ||
90 | |||
91 | if (0 == duty100) | ||
92 | return -EINVAL; | ||
93 | |||
94 | |||
95 | tmp64 = (uint64_t)duty * 100; | ||
96 | do_div(tmp64, duty100); | ||
97 | *speed = (uint32_t)tmp64; | ||
98 | |||
99 | if (*speed > 100) | ||
100 | *speed = 100; | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * Get Fan Speed in RPM. | ||
107 | * @param hwmgr the address of the powerplay hardware manager. | ||
108 | * @param speed is the address of the structure where the result is to be placed. | ||
109 | * @exception Returns not supported if no fan is found or if pulses per revolution are not set | ||
110 | */ | ||
111 | int iceland_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed) | ||
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | /** | ||
117 | * Set Fan Speed Control to static mode, so that the user can decide what speed to use. | ||
118 | * @param hwmgr the address of the powerplay hardware manager. | ||
119 | * mode the fan control mode, 0 default, 1 by percent, 5, by RPM | ||
120 | * @exception Should always succeed. | ||
121 | */ | ||
122 | int iceland_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode) | ||
123 | { | ||
124 | |||
125 | if (hwmgr->fan_ctrl_is_in_default_mode) { | ||
126 | hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE); | ||
127 | hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN); | ||
128 | hwmgr->fan_ctrl_is_in_default_mode = false; | ||
129 | } | ||
130 | |||
131 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0); | ||
132 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * Reset Fan Speed Control to default mode. | ||
139 | * @param hwmgr the address of the powerplay hardware manager. | ||
140 | * @exception Should always succeed. | ||
141 | */ | ||
142 | static int iceland_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr) | ||
143 | { | ||
144 | if (!hwmgr->fan_ctrl_is_in_default_mode) { | ||
145 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode); | ||
146 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin); | ||
147 | hwmgr->fan_ctrl_is_in_default_mode = true; | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | int iceland_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr) | ||
154 | { | ||
155 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL; | ||
156 | } | ||
157 | |||
158 | |||
159 | int iceland_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr) | ||
160 | { | ||
161 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ? 0 : -EINVAL; | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * Set Fan Speed in percent. | ||
166 | * @param hwmgr the address of the powerplay hardware manager. | ||
167 | * @param speed is the percentage value (0% - 100%) to be set. | ||
168 | * @exception Fails is the 100% setting appears to be 0. | ||
169 | */ | ||
170 | int iceland_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed) | ||
171 | { | ||
172 | uint32_t duty100; | ||
173 | uint32_t duty; | ||
174 | uint64_t tmp64; | ||
175 | |||
176 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
177 | return -EINVAL; | ||
178 | |||
179 | if (speed > 100) { | ||
180 | pr_warning("Cannot set more than 100%% duty cycle. Set it to 100.\n"); | ||
181 | speed = 100; | ||
182 | } | ||
183 | |||
184 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) | ||
185 | iceland_fan_ctrl_stop_smc_fan_control(hwmgr); | ||
186 | |||
187 | duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100); | ||
188 | |||
189 | if (0 == duty100) | ||
190 | return -EINVAL; | ||
191 | |||
192 | tmp64 = (uint64_t)speed * duty100; | ||
193 | do_div(tmp64, 100); | ||
194 | duty = (uint32_t)tmp64; | ||
195 | |||
196 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty); | ||
197 | |||
198 | return iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | ||
199 | } | ||
200 | |||
201 | /** | ||
202 | * Reset Fan Speed to default. | ||
203 | * @param hwmgr the address of the powerplay hardware manager. | ||
204 | * @exception Always succeeds. | ||
205 | */ | ||
206 | int iceland_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr) | ||
207 | { | ||
208 | int result; | ||
209 | |||
210 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
211 | return 0; | ||
212 | |||
213 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) { | ||
214 | result = iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | ||
215 | if (0 == result) | ||
216 | result = iceland_fan_ctrl_start_smc_fan_control(hwmgr); | ||
217 | } else | ||
218 | result = iceland_fan_ctrl_set_default_mode(hwmgr); | ||
219 | |||
220 | return result; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * Set Fan Speed in RPM. | ||
225 | * @param hwmgr the address of the powerplay hardware manager. | ||
226 | * @param speed is the percentage value (min - max) to be set. | ||
227 | * @exception Fails is the speed not lie between min and max. | ||
228 | */ | ||
229 | int iceland_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) | ||
230 | { | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | /** | ||
235 | * Reads the remote temperature from the SIslands thermal controller. | ||
236 | * | ||
237 | * @param hwmgr The address of the hardware manager. | ||
238 | */ | ||
239 | int iceland_thermal_get_temperature(struct pp_hwmgr *hwmgr) | ||
240 | { | ||
241 | int temp; | ||
242 | |||
243 | temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP); | ||
244 | |||
245 | /* | ||
246 | * Bit 9 means the reading is lower than the lowest usable | ||
247 | * value. | ||
248 | */ | ||
249 | if (0 != (0x200 & temp)) | ||
250 | temp = ICELAND_THERMAL_MAXIMUM_TEMP_READING; | ||
251 | else | ||
252 | temp = (temp & 0x1ff); | ||
253 | |||
254 | temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | ||
255 | |||
256 | return temp; | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * Set the requested temperature range for high and low alert signals | ||
261 | * | ||
262 | * @param hwmgr The address of the hardware manager. | ||
263 | * @param range Temperature range to be programmed for high and low alert signals | ||
264 | * @exception PP_Result_BadInput if the input data is not valid. | ||
265 | */ | ||
266 | static int iceland_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp) | ||
267 | { | ||
268 | uint32_t low = ICELAND_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | ||
269 | uint32_t high = ICELAND_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; | ||
270 | |||
271 | if (low < low_temp) | ||
272 | low = low_temp; | ||
273 | if (high > high_temp) | ||
274 | high = high_temp; | ||
275 | |||
276 | if (low > high) | ||
277 | return -EINVAL; | ||
278 | |||
279 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); | ||
280 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); | ||
281 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /** | ||
287 | * Programs thermal controller one-time setting registers | ||
288 | * | ||
289 | * @param hwmgr The address of the hardware manager. | ||
290 | */ | ||
291 | static int iceland_thermal_initialize(struct pp_hwmgr *hwmgr) | ||
292 | { | ||
293 | if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) | ||
294 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, | ||
295 | CG_TACH_CTRL, EDGE_PER_REV, | ||
296 | hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1); | ||
297 | |||
298 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /** | ||
304 | * Enable thermal alerts on the RV770 thermal controller. | ||
305 | * | ||
306 | * @param hwmgr The address of the hardware manager. | ||
307 | */ | ||
308 | static int iceland_thermal_enable_alert(struct pp_hwmgr *hwmgr) | ||
309 | { | ||
310 | uint32_t alert; | ||
311 | |||
312 | alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK); | ||
313 | alert &= ~(ICELAND_THERMAL_HIGH_ALERT_MASK | ICELAND_THERMAL_LOW_ALERT_MASK); | ||
314 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert); | ||
315 | |||
316 | /* send message to SMU to enable internal thermal interrupts */ | ||
317 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1; | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * Disable thermal alerts on the RV770 thermal controller. | ||
322 | * @param hwmgr The address of the hardware manager. | ||
323 | */ | ||
324 | static int iceland_thermal_disable_alert(struct pp_hwmgr *hwmgr) | ||
325 | { | ||
326 | uint32_t alert; | ||
327 | |||
328 | alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK); | ||
329 | alert |= (ICELAND_THERMAL_HIGH_ALERT_MASK | ICELAND_THERMAL_LOW_ALERT_MASK); | ||
330 | PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert); | ||
331 | |||
332 | /* send message to SMU to disable internal thermal interrupts */ | ||
333 | return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1; | ||
334 | } | ||
335 | |||
336 | /** | ||
337 | * Uninitialize the thermal controller. | ||
338 | * Currently just disables alerts. | ||
339 | * @param hwmgr The address of the hardware manager. | ||
340 | */ | ||
341 | int iceland_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr) | ||
342 | { | ||
343 | int result = iceland_thermal_disable_alert(hwmgr); | ||
344 | |||
345 | if (result) | ||
346 | pr_warning("Failed to disable thermal alerts!\n"); | ||
347 | |||
348 | if (hwmgr->thermal_controller.fanInfo.bNoFan) | ||
349 | iceland_fan_ctrl_set_default_mode(hwmgr); | ||
350 | |||
351 | return result; | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * Set up the fan table to control the fan using the SMC. | ||
356 | * @param hwmgr the address of the powerplay hardware manager. | ||
357 | * @param pInput the pointer to input data | ||
358 | * @param pOutput the pointer to output data | ||
359 | * @param pStorage the pointer to temporary storage | ||
360 | * @param Result the last failure code | ||
361 | * @return result from set temperature range routine | ||
362 | */ | ||
363 | int tf_iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | ||
364 | { | ||
365 | struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend); | ||
366 | SMU71_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE }; | ||
367 | uint32_t duty100; | ||
368 | uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2; | ||
369 | uint16_t fdo_min, slope1, slope2; | ||
370 | uint32_t reference_clock; | ||
371 | int res; | ||
372 | uint64_t tmp64; | ||
373 | |||
374 | if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) | ||
375 | return 0; | ||
376 | |||
377 | if (0 == data->fan_table_start) { | ||
378 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100); | ||
383 | |||
384 | if (0 == duty100) { | ||
385 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100; | ||
390 | do_div(tmp64, 10000); | ||
391 | fdo_min = (uint16_t)tmp64; | ||
392 | |||
393 | t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin; | ||
394 | t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed; | ||
395 | |||
396 | pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin; | ||
397 | pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed; | ||
398 | |||
399 | slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); | ||
400 | slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100); | ||
401 | |||
402 | fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100); | ||
403 | fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100); | ||
404 | fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100); | ||
405 | |||
406 | fan_table.Slope1 = cpu_to_be16(slope1); | ||
407 | fan_table.Slope2 = cpu_to_be16(slope2); | ||
408 | |||
409 | fan_table.FdoMin = cpu_to_be16(fdo_min); | ||
410 | |||
411 | fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst); | ||
412 | |||
413 | fan_table.HystUp = cpu_to_be16(1); | ||
414 | |||
415 | fan_table.HystSlope = cpu_to_be16(1); | ||
416 | |||
417 | fan_table.TempRespLim = cpu_to_be16(5); | ||
418 | |||
419 | reference_clock = iceland_get_xclk(hwmgr); | ||
420 | |||
421 | fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600); | ||
422 | |||
423 | fan_table.FdoMax = cpu_to_be16((uint16_t)duty100); | ||
424 | |||
425 | fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL); | ||
426 | |||
427 | //fan_table.FanControl_GL_Flag = 1; | ||
428 | |||
429 | res = iceland_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), data->sram_end); | ||
430 | /* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command. | ||
431 | if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit != 0) | ||
432 | res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanMinPwm, \ | ||
433 | hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit) ? 0 : -1); | ||
434 | |||
435 | if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit != 0) | ||
436 | res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanSclkTarget, \ | ||
437 | hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit) ? 0 : -1); | ||
438 | |||
439 | if (0 != res) | ||
440 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl); | ||
441 | */ | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * Start the fan control on the SMC. | ||
447 | * @param hwmgr the address of the powerplay hardware manager. | ||
448 | * @param pInput the pointer to input data | ||
449 | * @param pOutput the pointer to output data | ||
450 | * @param pStorage the pointer to temporary storage | ||
451 | * @param Result the last failure code | ||
452 | * @return result from set temperature range routine | ||
453 | */ | ||
454 | int tf_iceland_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | ||
455 | { | ||
456 | /* If the fantable setup has failed we could have disabled PHM_PlatformCaps_MicrocodeFanControl even after this function was included in the table. | ||
457 | * Make sure that we still think controlling the fan is OK. | ||
458 | */ | ||
459 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) { | ||
460 | iceland_fan_ctrl_start_smc_fan_control(hwmgr); | ||
461 | iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC); | ||
462 | } | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | /** | ||
468 | * Set temperature range for high and low alerts | ||
469 | * @param hwmgr the address of the powerplay hardware manager. | ||
470 | * @param pInput the pointer to input data | ||
471 | * @param pOutput the pointer to output data | ||
472 | * @param pStorage the pointer to temporary storage | ||
473 | * @param Result the last failure code | ||
474 | * @return result from set temperature range routine | ||
475 | */ | ||
476 | static int tf_iceland_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, | ||
477 | void *input, void *output, void *storage, int result) | ||
478 | { | ||
479 | struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input; | ||
480 | |||
481 | if (range == NULL) | ||
482 | return -EINVAL; | ||
483 | |||
484 | return iceland_thermal_set_temperature_range(hwmgr, range->min, range->max); | ||
485 | } | ||
486 | |||
487 | /** | ||
488 | * Programs one-time setting registers | ||
489 | * @param hwmgr the address of the powerplay hardware manager. | ||
490 | * @param pInput the pointer to input data | ||
491 | * @param pOutput the pointer to output data | ||
492 | * @param pStorage the pointer to temporary storage | ||
493 | * @param Result the last failure code | ||
494 | * @return result from initialize thermal controller routine | ||
495 | */ | ||
496 | static int tf_iceland_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, | ||
497 | void *output, void *storage, int result) | ||
498 | { | ||
499 | return iceland_thermal_initialize(hwmgr); | ||
500 | } | ||
501 | |||
502 | /** | ||
503 | * Enable high and low alerts | ||
504 | * @param hwmgr the address of the powerplay hardware manager. | ||
505 | * @param pInput the pointer to input data | ||
506 | * @param pOutput the pointer to output data | ||
507 | * @param pStorage the pointer to temporary storage | ||
508 | * @param Result the last failure code | ||
509 | * @return result from enable alert routine | ||
510 | */ | ||
511 | static int tf_iceland_thermal_enable_alert(struct pp_hwmgr *hwmgr, | ||
512 | void *input, void *output, void *storage, int result) | ||
513 | { | ||
514 | return iceland_thermal_enable_alert(hwmgr); | ||
515 | } | ||
516 | |||
517 | /** | ||
518 | * Disable high and low alerts | ||
519 | * @param hwmgr the address of the powerplay hardware manager. | ||
520 | * @param pInput the pointer to input data | ||
521 | * @param pOutput the pointer to output data | ||
522 | * @param pStorage the pointer to temporary storage | ||
523 | * @param Result the last failure code | ||
524 | * @return result from disable alert routine | ||
525 | */ | ||
526 | static int tf_iceland_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result) | ||
527 | { | ||
528 | return iceland_thermal_disable_alert(hwmgr); | ||
529 | } | ||
530 | |||
531 | static const struct phm_master_table_item iceland_thermal_start_thermal_controller_master_list[] = { | ||
532 | { NULL, tf_iceland_thermal_initialize }, | ||
533 | { NULL, tf_iceland_thermal_set_temperature_range }, | ||
534 | { NULL, tf_iceland_thermal_enable_alert }, | ||
535 | /* | ||
536 | * We should restrict performance levels to low before we halt | ||
537 | * the SMC. On the other hand we are still in boot state when | ||
538 | * we do this so it would be pointless. If this assumption | ||
539 | * changes we have to revisit this table. | ||
540 | */ | ||
541 | { NULL, tf_iceland_thermal_setup_fan_table}, | ||
542 | { NULL, tf_iceland_thermal_start_smc_fan_control}, | ||
543 | { NULL, NULL } | ||
544 | }; | ||
545 | |||
546 | static const struct phm_master_table_header iceland_thermal_start_thermal_controller_master = { | ||
547 | 0, | ||
548 | PHM_MasterTableFlag_None, | ||
549 | iceland_thermal_start_thermal_controller_master_list | ||
550 | }; | ||
551 | |||
552 | static const struct phm_master_table_item iceland_thermal_set_temperature_range_master_list[] = { | ||
553 | { NULL, tf_iceland_thermal_disable_alert}, | ||
554 | { NULL, tf_iceland_thermal_set_temperature_range}, | ||
555 | { NULL, tf_iceland_thermal_enable_alert}, | ||
556 | { NULL, NULL } | ||
557 | }; | ||
558 | |||
559 | static const struct phm_master_table_header iceland_thermal_set_temperature_range_master = { | ||
560 | 0, | ||
561 | PHM_MasterTableFlag_None, | ||
562 | iceland_thermal_set_temperature_range_master_list | ||
563 | }; | ||
564 | |||
565 | int iceland_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr) | ||
566 | { | ||
567 | if (!hwmgr->thermal_controller.fanInfo.bNoFan) | ||
568 | iceland_fan_ctrl_set_default_mode(hwmgr); | ||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * Initializes the thermal controller related functions in the Hardware Manager structure. | ||
574 | * @param hwmgr The address of the hardware manager. | ||
575 | * @exception Any error code from the low-level communication. | ||
576 | */ | ||
577 | int pp_iceland_thermal_initialize(struct pp_hwmgr *hwmgr) | ||
578 | { | ||
579 | int result; | ||
580 | |||
581 | result = phm_construct_table(hwmgr, &iceland_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range)); | ||
582 | |||
583 | if (0 == result) { | ||
584 | result = phm_construct_table(hwmgr, | ||
585 | &iceland_thermal_start_thermal_controller_master, | ||
586 | &(hwmgr->start_thermal_controller)); | ||
587 | if (0 != result) | ||
588 | phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range)); | ||
589 | } | ||
590 | |||
591 | if (0 == result) | ||
592 | hwmgr->fan_ctrl_is_in_default_mode = true; | ||
593 | return result; | ||
594 | } | ||
595 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_thermal.h new file mode 100644 index 000000000000..267945f4df71 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_thermal.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #ifndef ICELAND_THERMAL_H | ||
27 | #define ICELAND_THERMAL_H | ||
28 | |||
29 | #include "hwmgr.h" | ||
30 | |||
31 | #define ICELAND_THERMAL_HIGH_ALERT_MASK 0x1 | ||
32 | #define ICELAND_THERMAL_LOW_ALERT_MASK 0x2 | ||
33 | |||
34 | #define ICELAND_THERMAL_MINIMUM_TEMP_READING -256 | ||
35 | #define ICELAND_THERMAL_MAXIMUM_TEMP_READING 255 | ||
36 | |||
37 | #define ICELAND_THERMAL_MINIMUM_ALERT_TEMP 0 | ||
38 | #define ICELAND_THERMAL_MAXIMUM_ALERT_TEMP 255 | ||
39 | |||
40 | #define FDO_PWM_MODE_STATIC 1 | ||
41 | #define FDO_PWM_MODE_STATIC_RPM 5 | ||
42 | |||
43 | |||
44 | extern int iceland_thermal_get_temperature(struct pp_hwmgr *hwmgr); | ||
45 | extern int iceland_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr); | ||
46 | extern int iceland_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info); | ||
47 | extern int iceland_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed); | ||
48 | extern int iceland_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode); | ||
49 | extern int iceland_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed); | ||
50 | extern int iceland_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr); | ||
51 | extern int pp_iceland_thermal_initialize(struct pp_hwmgr *hwmgr); | ||
52 | extern int iceland_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr); | ||
53 | extern int iceland_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed); | ||
54 | extern int iceland_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed); | ||
55 | extern int iceland_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr); | ||
56 | |||
57 | #endif | ||
58 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c index 783dcc3384f1..b69132296672 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c | |||
@@ -97,19 +97,6 @@ | |||
97 | #define PCIE_BUS_CLK 10000 | 97 | #define PCIE_BUS_CLK 10000 |
98 | #define TCLK (PCIE_BUS_CLK / 10) | 98 | #define TCLK (PCIE_BUS_CLK / 10) |
99 | 99 | ||
100 | |||
101 | static const uint16_t polaris10_clock_stretcher_lookup_table[2][4] = | ||
102 | { {600, 1050, 3, 0}, {600, 1050, 6, 1} }; | ||
103 | |||
104 | /* [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */ | ||
105 | static const uint32_t polaris10_clock_stretcher_ddt_table[2][4][4] = | ||
106 | { { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} }, | ||
107 | { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } }; | ||
108 | |||
109 | /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */ | ||
110 | static const uint8_t polaris10_clock_stretch_amount_conversion[2][6] = | ||
111 | { {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} }; | ||
112 | |||
113 | /** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */ | 100 | /** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */ |
114 | enum DPM_EVENT_SRC { | 101 | enum DPM_EVENT_SRC { |
115 | DPM_EVENT_SRC_ANALOG = 0, | 102 | DPM_EVENT_SRC_ANALOG = 0, |
@@ -2772,9 +2759,6 @@ int polaris10_set_features_platform_caps(struct pp_hwmgr *hwmgr) | |||
2772 | struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend); | 2759 | struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend); |
2773 | 2760 | ||
2774 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 2761 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
2775 | PHM_PlatformCaps_SclkDeepSleep); | ||
2776 | |||
2777 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
2778 | PHM_PlatformCaps_DynamicPatchPowerState); | 2762 | PHM_PlatformCaps_DynamicPatchPowerState); |
2779 | 2763 | ||
2780 | if (data->mvdd_control == POLARIS10_VOLTAGE_CONTROL_NONE) | 2764 | if (data->mvdd_control == POLARIS10_VOLTAGE_CONTROL_NONE) |
@@ -2819,13 +2803,6 @@ int polaris10_set_features_platform_caps(struct pp_hwmgr *hwmgr) | |||
2819 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 2803 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
2820 | PHM_PlatformCaps_TCPRamping); | 2804 | PHM_PlatformCaps_TCPRamping); |
2821 | 2805 | ||
2822 | if (hwmgr->powercontainment_enabled) | ||
2823 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
2824 | PHM_PlatformCaps_PowerContainment); | ||
2825 | else | ||
2826 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
2827 | PHM_PlatformCaps_PowerContainment); | ||
2828 | |||
2829 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 2806 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
2830 | PHM_PlatformCaps_CAC); | 2807 | PHM_PlatformCaps_CAC); |
2831 | 2808 | ||
@@ -2904,8 +2881,8 @@ static int polaris10_get_evv_voltages(struct pp_hwmgr *hwmgr) | |||
2904 | continue; | 2881 | continue; |
2905 | } | 2882 | } |
2906 | 2883 | ||
2907 | /* need to make sure vddc is less than 2v or else, it could burn the ASIC. | 2884 | /* need to make sure vddc is less than 2V or else, it could burn the ASIC. |
2908 | * real voltage level in unit of 0.01mv */ | 2885 | * real voltage level in unit of 0.01mV */ |
2909 | PP_ASSERT_WITH_CODE((vddc < 200000 && vddc != 0), | 2886 | PP_ASSERT_WITH_CODE((vddc < 200000 && vddc != 0), |
2910 | "Invalid VDDC value", result = -EINVAL;); | 2887 | "Invalid VDDC value", result = -EINVAL;); |
2911 | 2888 | ||
@@ -3142,7 +3119,10 @@ int polaris10_patch_voltage_workaround(struct pp_hwmgr *hwmgr) | |||
3142 | table_info->vddc_lookup_table; | 3119 | table_info->vddc_lookup_table; |
3143 | uint32_t i; | 3120 | uint32_t i; |
3144 | 3121 | ||
3145 | if (hwmgr->chip_id == CHIP_POLARIS10 && hwmgr->hw_revision == 0xC7) { | 3122 | if (hwmgr->chip_id == CHIP_POLARIS10 && hwmgr->hw_revision == 0xC7 && |
3123 | ((hwmgr->sub_sys_id == 0xb37 && hwmgr->sub_vendor_id == 0x1002) || | ||
3124 | (hwmgr->sub_sys_id == 0x4a8 && hwmgr->sub_vendor_id == 0x1043) || | ||
3125 | (hwmgr->sub_sys_id == 0x9480 && hwmgr->sub_vendor_id == 0x1682))) { | ||
3146 | if (lookup_table->entries[dep_mclk_table->entries[dep_mclk_table->count-1].vddInd].us_vdd >= 1000) | 3126 | if (lookup_table->entries[dep_mclk_table->entries[dep_mclk_table->count-1].vddInd].us_vdd >= 1000) |
3147 | return 0; | 3127 | return 0; |
3148 | 3128 | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c index 7dc4afd19d26..7f9ba7f15e19 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c | |||
@@ -301,6 +301,8 @@ void tonga_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) | |||
301 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 301 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
302 | PHM_PlatformCaps_DisableMemoryTransition); | 302 | PHM_PlatformCaps_DisableMemoryTransition); |
303 | 303 | ||
304 | tonga_initialize_power_tune_defaults(hwmgr); | ||
305 | |||
304 | data->mclk_strobe_mode_threshold = 40000; | 306 | data->mclk_strobe_mode_threshold = 40000; |
305 | data->mclk_stutter_mode_threshold = 30000; | 307 | data->mclk_stutter_mode_threshold = 30000; |
306 | data->mclk_edc_enable_threshold = 40000; | 308 | data->mclk_edc_enable_threshold = 40000; |
@@ -2478,7 +2480,7 @@ static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, uint32_t | |||
2478 | graphic_level->VoltageDownHyst = 0; | 2480 | graphic_level->VoltageDownHyst = 0; |
2479 | graphic_level->PowerThrottle = 0; | 2481 | graphic_level->PowerThrottle = 0; |
2480 | 2482 | ||
2481 | threshold = engine_clock * data->fast_watemark_threshold / 100; | 2483 | threshold = engine_clock * data->fast_watermark_threshold / 100; |
2482 | /* | 2484 | /* |
2483 | *get the DAL clock. do it in funture. | 2485 | *get the DAL clock. do it in funture. |
2484 | PECI_GetMinClockSettings(hwmgr->peci, &minClocks); | 2486 | PECI_GetMinClockSettings(hwmgr->peci, &minClocks); |
@@ -2981,6 +2983,10 @@ int tonga_init_smc_table(struct pp_hwmgr *hwmgr) | |||
2981 | PP_ASSERT_WITH_CODE(0 == result, | 2983 | PP_ASSERT_WITH_CODE(0 == result, |
2982 | "Failed to initialize Boot Level!", return result;); | 2984 | "Failed to initialize Boot Level!", return result;); |
2983 | 2985 | ||
2986 | result = tonga_populate_bapm_parameters_in_dpm_table(hwmgr); | ||
2987 | PP_ASSERT_WITH_CODE(result == 0, | ||
2988 | "Failed to populate BAPM Parameters!", return result); | ||
2989 | |||
2984 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | 2990 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, |
2985 | PHM_PlatformCaps_ClockStretcher)) { | 2991 | PHM_PlatformCaps_ClockStretcher)) { |
2986 | result = tonga_populate_clock_stretcher_data_table(hwmgr); | 2992 | result = tonga_populate_clock_stretcher_data_table(hwmgr); |
@@ -4369,6 +4375,10 @@ int tonga_enable_dpm_tasks(struct pp_hwmgr *hwmgr) | |||
4369 | PP_ASSERT_WITH_CODE((0 == tmp_result), | 4375 | PP_ASSERT_WITH_CODE((0 == tmp_result), |
4370 | "Failed to initialize ARB table index!", result = tmp_result); | 4376 | "Failed to initialize ARB table index!", result = tmp_result); |
4371 | 4377 | ||
4378 | tmp_result = tonga_populate_pm_fuses(hwmgr); | ||
4379 | PP_ASSERT_WITH_CODE((tmp_result == 0), | ||
4380 | "Failed to populate PM fuses!", result = tmp_result); | ||
4381 | |||
4372 | tmp_result = tonga_populate_initial_mc_reg_table(hwmgr); | 4382 | tmp_result = tonga_populate_initial_mc_reg_table(hwmgr); |
4373 | PP_ASSERT_WITH_CODE((0 == tmp_result), | 4383 | PP_ASSERT_WITH_CODE((0 == tmp_result), |
4374 | "Failed to populate initialize MC Reg table!", result = tmp_result); | 4384 | "Failed to populate initialize MC Reg table!", result = tmp_result); |
@@ -4387,6 +4397,18 @@ int tonga_enable_dpm_tasks(struct pp_hwmgr *hwmgr) | |||
4387 | PP_ASSERT_WITH_CODE((0 == tmp_result), | 4397 | PP_ASSERT_WITH_CODE((0 == tmp_result), |
4388 | "Failed to start DPM!", result = tmp_result); | 4398 | "Failed to start DPM!", result = tmp_result); |
4389 | 4399 | ||
4400 | tmp_result = tonga_enable_smc_cac(hwmgr); | ||
4401 | PP_ASSERT_WITH_CODE((tmp_result == 0), | ||
4402 | "Failed to enable SMC CAC!", result = tmp_result); | ||
4403 | |||
4404 | tmp_result = tonga_enable_power_containment(hwmgr); | ||
4405 | PP_ASSERT_WITH_CODE((tmp_result == 0), | ||
4406 | "Failed to enable power containment!", result = tmp_result); | ||
4407 | |||
4408 | tmp_result = tonga_power_control_set_level(hwmgr); | ||
4409 | PP_ASSERT_WITH_CODE((tmp_result == 0), | ||
4410 | "Failed to power control set level!", result = tmp_result); | ||
4411 | |||
4390 | return result; | 4412 | return result; |
4391 | } | 4413 | } |
4392 | 4414 | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h index 3961884bfa9b..fcad9426d3c1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h | |||
@@ -300,6 +300,7 @@ struct tonga_hwmgr { | |||
300 | bool dll_defaule_on; | 300 | bool dll_defaule_on; |
301 | bool performance_request_registered; | 301 | bool performance_request_registered; |
302 | 302 | ||
303 | |||
303 | /* ----------------- Low Power Features ---------------------*/ | 304 | /* ----------------- Low Power Features ---------------------*/ |
304 | phw_tonga_bacos bacos; | 305 | phw_tonga_bacos bacos; |
305 | phw_tonga_ulv_parm ulv; | 306 | phw_tonga_ulv_parm ulv; |
@@ -314,10 +315,14 @@ struct tonga_hwmgr { | |||
314 | bool enable_tdc_limit_feature; | 315 | bool enable_tdc_limit_feature; |
315 | bool enable_pkg_pwr_tracking_feature; | 316 | bool enable_pkg_pwr_tracking_feature; |
316 | bool disable_uvd_power_tune_feature; | 317 | bool disable_uvd_power_tune_feature; |
317 | phw_tonga_pt_defaults *power_tune_defaults; | 318 | struct tonga_pt_defaults *power_tune_defaults; |
318 | SMU72_Discrete_PmFuses power_tune_table; | 319 | SMU72_Discrete_PmFuses power_tune_table; |
319 | uint32_t ul_dte_tj_offset; /* Fudge factor in DPM table to correct HW DTE errors */ | 320 | uint32_t dte_tj_offset; /* Fudge factor in DPM table to correct HW DTE errors */ |
320 | uint32_t fast_watemark_threshold; /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */ | 321 | uint32_t fast_watermark_threshold; /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */ |
322 | |||
323 | |||
324 | bool enable_dte_feature; | ||
325 | |||
321 | 326 | ||
322 | /* ----------------- Phase Shedding ---------------------*/ | 327 | /* ----------------- Phase Shedding ---------------------*/ |
323 | bool vddc_phase_shed_control; | 328 | bool vddc_phase_shed_control; |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.c new file mode 100644 index 000000000000..9496ade3247e --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.c | |||
@@ -0,0 +1,498 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "hwmgr.h" | ||
25 | #include "smumgr.h" | ||
26 | #include "tonga_hwmgr.h" | ||
27 | #include "tonga_powertune.h" | ||
28 | #include "tonga_smumgr.h" | ||
29 | #include "smu72_discrete.h" | ||
30 | #include "pp_debug.h" | ||
31 | #include "tonga_ppsmc.h" | ||
32 | |||
33 | #define VOLTAGE_SCALE 4 | ||
34 | #define POWERTUNE_DEFAULT_SET_MAX 1 | ||
35 | |||
36 | struct tonga_pt_defaults tonga_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = { | ||
37 | /* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT */ | ||
38 | {1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000, | ||
39 | {0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61}, | ||
40 | {0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 } }, | ||
41 | }; | ||
42 | |||
43 | void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) | ||
44 | { | ||
45 | struct tonga_hwmgr *tonga_hwmgr = (struct tonga_hwmgr *)(hwmgr->backend); | ||
46 | struct phm_ppt_v1_information *table_info = | ||
47 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
48 | uint32_t tmp = 0; | ||
49 | |||
50 | if (table_info && | ||
51 | table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX && | ||
52 | table_info->cac_dtp_table->usPowerTuneDataSetID) | ||
53 | tonga_hwmgr->power_tune_defaults = | ||
54 | &tonga_power_tune_data_set_array | ||
55 | [table_info->cac_dtp_table->usPowerTuneDataSetID - 1]; | ||
56 | else | ||
57 | tonga_hwmgr->power_tune_defaults = &tonga_power_tune_data_set_array[0]; | ||
58 | |||
59 | /* Assume disabled */ | ||
60 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
61 | PHM_PlatformCaps_PowerContainment); | ||
62 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
63 | PHM_PlatformCaps_CAC); | ||
64 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
65 | PHM_PlatformCaps_SQRamping); | ||
66 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
67 | PHM_PlatformCaps_DBRamping); | ||
68 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
69 | PHM_PlatformCaps_TDRamping); | ||
70 | phm_cap_unset(hwmgr->platform_descriptor.platformCaps, | ||
71 | PHM_PlatformCaps_TCPRamping); | ||
72 | |||
73 | tonga_hwmgr->dte_tj_offset = tmp; | ||
74 | |||
75 | if (!tmp) { | ||
76 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | ||
77 | PHM_PlatformCaps_CAC); | ||
78 | |||
79 | tonga_hwmgr->fast_watermark_threshold = 100; | ||
80 | |||
81 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
82 | PHM_PlatformCaps_PowerContainment)) { | ||
83 | tmp = 1; | ||
84 | tonga_hwmgr->enable_dte_feature = tmp ? false : true; | ||
85 | tonga_hwmgr->enable_tdc_limit_feature = tmp ? true : false; | ||
86 | tonga_hwmgr->enable_pkg_pwr_tracking_feature = tmp ? true : false; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | |||
92 | int tonga_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr) | ||
93 | { | ||
94 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
95 | struct tonga_pt_defaults *defaults = data->power_tune_defaults; | ||
96 | SMU72_Discrete_DpmTable *dpm_table = &(data->smc_state_table); | ||
97 | struct phm_ppt_v1_information *table_info = | ||
98 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
99 | struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table; | ||
100 | int i, j, k; | ||
101 | uint16_t *pdef1; | ||
102 | uint16_t *pdef2; | ||
103 | |||
104 | |||
105 | /* TDP number of fraction bits are changed from 8 to 7 for Fiji | ||
106 | * as requested by SMC team | ||
107 | */ | ||
108 | dpm_table->DefaultTdp = PP_HOST_TO_SMC_US( | ||
109 | (uint16_t)(cac_dtp_table->usTDP * 256)); | ||
110 | dpm_table->TargetTdp = PP_HOST_TO_SMC_US( | ||
111 | (uint16_t)(cac_dtp_table->usConfigurableTDP * 256)); | ||
112 | |||
113 | PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255, | ||
114 | "Target Operating Temp is out of Range!", | ||
115 | ); | ||
116 | |||
117 | dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp); | ||
118 | dpm_table->GpuTjHyst = 8; | ||
119 | |||
120 | dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base; | ||
121 | |||
122 | dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bamp_temp_gradient); | ||
123 | pdef1 = defaults->bapmti_r; | ||
124 | pdef2 = defaults->bapmti_rc; | ||
125 | |||
126 | for (i = 0; i < SMU72_DTE_ITERATIONS; i++) { | ||
127 | for (j = 0; j < SMU72_DTE_SOURCES; j++) { | ||
128 | for (k = 0; k < SMU72_DTE_SINKS; k++) { | ||
129 | dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*pdef1); | ||
130 | dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*pdef2); | ||
131 | pdef1++; | ||
132 | pdef2++; | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int tonga_populate_svi_load_line(struct pp_hwmgr *hwmgr) | ||
141 | { | ||
142 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
143 | const struct tonga_pt_defaults *defaults = data->power_tune_defaults; | ||
144 | |||
145 | data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en; | ||
146 | data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddC; | ||
147 | data->power_tune_table.SviLoadLineTrimVddC = 3; | ||
148 | data->power_tune_table.SviLoadLineOffsetVddC = 0; | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int tonga_populate_tdc_limit(struct pp_hwmgr *hwmgr) | ||
154 | { | ||
155 | uint16_t tdc_limit; | ||
156 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
157 | struct phm_ppt_v1_information *table_info = | ||
158 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
159 | const struct tonga_pt_defaults *defaults = data->power_tune_defaults; | ||
160 | |||
161 | /* TDC number of fraction bits are changed from 8 to 7 | ||
162 | * for Fiji as requested by SMC team | ||
163 | */ | ||
164 | tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 256); | ||
165 | data->power_tune_table.TDC_VDDC_PkgLimit = | ||
166 | CONVERT_FROM_HOST_TO_SMC_US(tdc_limit); | ||
167 | data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc = | ||
168 | defaults->tdc_vddc_throttle_release_limit_perc; | ||
169 | data->power_tune_table.TDC_MAWt = defaults->tdc_mawt; | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int tonga_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) | ||
175 | { | ||
176 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
177 | const struct tonga_pt_defaults *defaults = data->power_tune_defaults; | ||
178 | uint32_t temp; | ||
179 | |||
180 | if (tonga_read_smc_sram_dword(hwmgr->smumgr, | ||
181 | fuse_table_offset + | ||
182 | offsetof(SMU72_Discrete_PmFuses, TdcWaterfallCtl), | ||
183 | (uint32_t *)&temp, data->sram_end)) | ||
184 | PP_ASSERT_WITH_CODE(false, | ||
185 | "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", | ||
186 | return -EINVAL); | ||
187 | else | ||
188 | data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl; | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int tonga_populate_temperature_scaler(struct pp_hwmgr *hwmgr) | ||
194 | { | ||
195 | int i; | ||
196 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
197 | |||
198 | /* Currently not used. Set all to zero. */ | ||
199 | for (i = 0; i < 16; i++) | ||
200 | data->power_tune_table.LPMLTemperatureScaler[i] = 0; | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int tonga_populate_fuzzy_fan(struct pp_hwmgr *hwmgr) | ||
206 | { | ||
207 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
208 | |||
209 | if ((hwmgr->thermal_controller.advanceFanControlParameters. | ||
210 | usFanOutputSensitivity & (1 << 15)) || | ||
211 | (hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity == 0)) | ||
212 | hwmgr->thermal_controller.advanceFanControlParameters. | ||
213 | usFanOutputSensitivity = hwmgr->thermal_controller. | ||
214 | advanceFanControlParameters.usDefaultFanOutputSensitivity; | ||
215 | |||
216 | data->power_tune_table.FuzzyFan_PwmSetDelta = | ||
217 | PP_HOST_TO_SMC_US(hwmgr->thermal_controller. | ||
218 | advanceFanControlParameters.usFanOutputSensitivity); | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int tonga_populate_gnb_lpml(struct pp_hwmgr *hwmgr) | ||
223 | { | ||
224 | int i; | ||
225 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
226 | |||
227 | /* Currently not used. Set all to zero. */ | ||
228 | for (i = 0; i < 16; i++) | ||
229 | data->power_tune_table.GnbLPML[i] = 0; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int tonga_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr) | ||
235 | { | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int tonga_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr) | ||
240 | { | ||
241 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
242 | struct phm_ppt_v1_information *table_info = | ||
243 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
244 | uint16_t hi_sidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd; | ||
245 | uint16_t lo_sidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd; | ||
246 | struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table; | ||
247 | |||
248 | hi_sidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256); | ||
249 | lo_sidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256); | ||
250 | |||
251 | data->power_tune_table.BapmVddCBaseLeakageHiSidd = | ||
252 | CONVERT_FROM_HOST_TO_SMC_US(hi_sidd); | ||
253 | data->power_tune_table.BapmVddCBaseLeakageLoSidd = | ||
254 | CONVERT_FROM_HOST_TO_SMC_US(lo_sidd); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | int tonga_populate_pm_fuses(struct pp_hwmgr *hwmgr) | ||
260 | { | ||
261 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
262 | uint32_t pm_fuse_table_offset; | ||
263 | |||
264 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
265 | PHM_PlatformCaps_PowerContainment)) { | ||
266 | if (tonga_read_smc_sram_dword(hwmgr->smumgr, | ||
267 | SMU72_FIRMWARE_HEADER_LOCATION + | ||
268 | offsetof(SMU72_Firmware_Header, PmFuseTable), | ||
269 | &pm_fuse_table_offset, data->sram_end)) | ||
270 | PP_ASSERT_WITH_CODE(false, | ||
271 | "Attempt to get pm_fuse_table_offset Failed!", | ||
272 | return -EINVAL); | ||
273 | |||
274 | /* DW6 */ | ||
275 | if (tonga_populate_svi_load_line(hwmgr)) | ||
276 | PP_ASSERT_WITH_CODE(false, | ||
277 | "Attempt to populate SviLoadLine Failed!", | ||
278 | return -EINVAL); | ||
279 | /* DW7 */ | ||
280 | if (tonga_populate_tdc_limit(hwmgr)) | ||
281 | PP_ASSERT_WITH_CODE(false, | ||
282 | "Attempt to populate TDCLimit Failed!", return -EINVAL); | ||
283 | /* DW8 */ | ||
284 | if (tonga_populate_dw8(hwmgr, pm_fuse_table_offset)) | ||
285 | PP_ASSERT_WITH_CODE(false, | ||
286 | "Attempt to populate TdcWaterfallCtl Failed !", | ||
287 | return -EINVAL); | ||
288 | |||
289 | /* DW9-DW12 */ | ||
290 | if (tonga_populate_temperature_scaler(hwmgr) != 0) | ||
291 | PP_ASSERT_WITH_CODE(false, | ||
292 | "Attempt to populate LPMLTemperatureScaler Failed!", | ||
293 | return -EINVAL); | ||
294 | |||
295 | /* DW13-DW14 */ | ||
296 | if (tonga_populate_fuzzy_fan(hwmgr)) | ||
297 | PP_ASSERT_WITH_CODE(false, | ||
298 | "Attempt to populate Fuzzy Fan Control parameters Failed!", | ||
299 | return -EINVAL); | ||
300 | |||
301 | /* DW15-DW18 */ | ||
302 | if (tonga_populate_gnb_lpml(hwmgr)) | ||
303 | PP_ASSERT_WITH_CODE(false, | ||
304 | "Attempt to populate GnbLPML Failed!", | ||
305 | return -EINVAL); | ||
306 | |||
307 | /* DW19 */ | ||
308 | if (tonga_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr)) | ||
309 | PP_ASSERT_WITH_CODE(false, | ||
310 | "Attempt to populate GnbLPML Min and Max Vid Failed!", | ||
311 | return -EINVAL); | ||
312 | |||
313 | /* DW20 */ | ||
314 | if (tonga_populate_bapm_vddc_base_leakage_sidd(hwmgr)) | ||
315 | PP_ASSERT_WITH_CODE(false, | ||
316 | "Attempt to populate BapmVddCBaseLeakage Hi and Lo Sidd Failed!", | ||
317 | return -EINVAL); | ||
318 | |||
319 | if (tonga_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset, | ||
320 | (uint8_t *)&data->power_tune_table, | ||
321 | sizeof(struct SMU72_Discrete_PmFuses), data->sram_end)) | ||
322 | PP_ASSERT_WITH_CODE(false, | ||
323 | "Attempt to download PmFuseTable Failed!", | ||
324 | return -EINVAL); | ||
325 | } | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | int tonga_enable_smc_cac(struct pp_hwmgr *hwmgr) | ||
330 | { | ||
331 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
332 | int result = 0; | ||
333 | |||
334 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
335 | PHM_PlatformCaps_CAC)) { | ||
336 | int smc_result; | ||
337 | |||
338 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
339 | (uint16_t)(PPSMC_MSG_EnableCac)); | ||
340 | PP_ASSERT_WITH_CODE((smc_result == 0), | ||
341 | "Failed to enable CAC in SMC.", result = -1); | ||
342 | |||
343 | data->cac_enabled = (smc_result == 0) ? true : false; | ||
344 | } | ||
345 | return result; | ||
346 | } | ||
347 | |||
348 | int tonga_disable_smc_cac(struct pp_hwmgr *hwmgr) | ||
349 | { | ||
350 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
351 | int result = 0; | ||
352 | |||
353 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
354 | PHM_PlatformCaps_CAC) && data->cac_enabled) { | ||
355 | int smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
356 | (uint16_t)(PPSMC_MSG_DisableCac)); | ||
357 | PP_ASSERT_WITH_CODE((smc_result == 0), | ||
358 | "Failed to disable CAC in SMC.", result = -1); | ||
359 | |||
360 | data->cac_enabled = false; | ||
361 | } | ||
362 | return result; | ||
363 | } | ||
364 | |||
365 | int tonga_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n) | ||
366 | { | ||
367 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
368 | |||
369 | if (data->power_containment_features & | ||
370 | POWERCONTAINMENT_FEATURE_PkgPwrLimit) | ||
371 | return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, | ||
372 | PPSMC_MSG_PkgPwrSetLimit, n); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int tonga_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp) | ||
377 | { | ||
378 | return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr, | ||
379 | PPSMC_MSG_OverDriveSetTargetTdp, target_tdp); | ||
380 | } | ||
381 | |||
382 | int tonga_enable_power_containment(struct pp_hwmgr *hwmgr) | ||
383 | { | ||
384 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
385 | struct phm_ppt_v1_information *table_info = | ||
386 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
387 | int smc_result; | ||
388 | int result = 0; | ||
389 | |||
390 | data->power_containment_features = 0; | ||
391 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
392 | PHM_PlatformCaps_PowerContainment)) { | ||
393 | if (data->enable_dte_feature) { | ||
394 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
395 | (uint16_t)(PPSMC_MSG_EnableDTE)); | ||
396 | PP_ASSERT_WITH_CODE((smc_result == 0), | ||
397 | "Failed to enable DTE in SMC.", result = -1;); | ||
398 | if (smc_result == 0) | ||
399 | data->power_containment_features |= POWERCONTAINMENT_FEATURE_DTE; | ||
400 | } | ||
401 | |||
402 | if (data->enable_tdc_limit_feature) { | ||
403 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
404 | (uint16_t)(PPSMC_MSG_TDCLimitEnable)); | ||
405 | PP_ASSERT_WITH_CODE((smc_result == 0), | ||
406 | "Failed to enable TDCLimit in SMC.", result = -1;); | ||
407 | if (smc_result == 0) | ||
408 | data->power_containment_features |= | ||
409 | POWERCONTAINMENT_FEATURE_TDCLimit; | ||
410 | } | ||
411 | |||
412 | if (data->enable_pkg_pwr_tracking_feature) { | ||
413 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
414 | (uint16_t)(PPSMC_MSG_PkgPwrLimitEnable)); | ||
415 | PP_ASSERT_WITH_CODE((smc_result == 0), | ||
416 | "Failed to enable PkgPwrTracking in SMC.", result = -1;); | ||
417 | if (smc_result == 0) { | ||
418 | struct phm_cac_tdp_table *cac_table = | ||
419 | table_info->cac_dtp_table; | ||
420 | uint32_t default_limit = | ||
421 | (uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256); | ||
422 | |||
423 | data->power_containment_features |= | ||
424 | POWERCONTAINMENT_FEATURE_PkgPwrLimit; | ||
425 | |||
426 | if (tonga_set_power_limit(hwmgr, default_limit)) | ||
427 | printk(KERN_ERR "Failed to set Default Power Limit in SMC!"); | ||
428 | } | ||
429 | } | ||
430 | } | ||
431 | return result; | ||
432 | } | ||
433 | |||
434 | int tonga_disable_power_containment(struct pp_hwmgr *hwmgr) | ||
435 | { | ||
436 | struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); | ||
437 | int result = 0; | ||
438 | |||
439 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
440 | PHM_PlatformCaps_PowerContainment) && | ||
441 | data->power_containment_features) { | ||
442 | int smc_result; | ||
443 | |||
444 | if (data->power_containment_features & | ||
445 | POWERCONTAINMENT_FEATURE_TDCLimit) { | ||
446 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
447 | (uint16_t)(PPSMC_MSG_TDCLimitDisable)); | ||
448 | PP_ASSERT_WITH_CODE((smc_result == 0), | ||
449 | "Failed to disable TDCLimit in SMC.", | ||
450 | result = smc_result); | ||
451 | } | ||
452 | |||
453 | if (data->power_containment_features & | ||
454 | POWERCONTAINMENT_FEATURE_DTE) { | ||
455 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
456 | (uint16_t)(PPSMC_MSG_DisableDTE)); | ||
457 | PP_ASSERT_WITH_CODE((smc_result == 0), | ||
458 | "Failed to disable DTE in SMC.", | ||
459 | result = smc_result); | ||
460 | } | ||
461 | |||
462 | if (data->power_containment_features & | ||
463 | POWERCONTAINMENT_FEATURE_PkgPwrLimit) { | ||
464 | smc_result = smum_send_msg_to_smc(hwmgr->smumgr, | ||
465 | (uint16_t)(PPSMC_MSG_PkgPwrLimitDisable)); | ||
466 | PP_ASSERT_WITH_CODE((smc_result == 0), | ||
467 | "Failed to disable PkgPwrTracking in SMC.", | ||
468 | result = smc_result); | ||
469 | } | ||
470 | data->power_containment_features = 0; | ||
471 | } | ||
472 | |||
473 | return result; | ||
474 | } | ||
475 | |||
476 | int tonga_power_control_set_level(struct pp_hwmgr *hwmgr) | ||
477 | { | ||
478 | struct phm_ppt_v1_information *table_info = | ||
479 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
480 | struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table; | ||
481 | int adjust_percent, target_tdp; | ||
482 | int result = 0; | ||
483 | |||
484 | if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, | ||
485 | PHM_PlatformCaps_PowerContainment)) { | ||
486 | /* adjustment percentage has already been validated */ | ||
487 | adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ? | ||
488 | hwmgr->platform_descriptor.TDPAdjustment : | ||
489 | (-1 * hwmgr->platform_descriptor.TDPAdjustment); | ||
490 | /* SMC requested that target_tdp to be 7 bit fraction in DPM table | ||
491 | * but message to be 8 bit fraction for messages | ||
492 | */ | ||
493 | target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100; | ||
494 | result = tonga_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp); | ||
495 | } | ||
496 | |||
497 | return result; | ||
498 | } | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h index 8e6670b3cb67..c8bdb92d81f4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h | |||
@@ -35,20 +35,23 @@ enum _phw_tonga_ptc_config_reg_type { | |||
35 | typedef enum _phw_tonga_ptc_config_reg_type phw_tonga_ptc_config_reg_type; | 35 | typedef enum _phw_tonga_ptc_config_reg_type phw_tonga_ptc_config_reg_type; |
36 | 36 | ||
37 | /* PowerContainment Features */ | 37 | /* PowerContainment Features */ |
38 | #define POWERCONTAINMENT_FEATURE_DTE 0x00000001 | ||
39 | |||
40 | |||
41 | /* PowerContainment Features */ | ||
38 | #define POWERCONTAINMENT_FEATURE_BAPM 0x00000001 | 42 | #define POWERCONTAINMENT_FEATURE_BAPM 0x00000001 |
39 | #define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002 | 43 | #define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002 |
40 | #define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004 | 44 | #define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004 |
41 | 45 | ||
42 | struct _phw_tonga_pt_config_reg { | 46 | struct tonga_pt_config_reg { |
43 | uint32_t Offset; | 47 | uint32_t Offset; |
44 | uint32_t Mask; | 48 | uint32_t Mask; |
45 | uint32_t Shift; | 49 | uint32_t Shift; |
46 | uint32_t Value; | 50 | uint32_t Value; |
47 | phw_tonga_ptc_config_reg_type Type; | 51 | phw_tonga_ptc_config_reg_type Type; |
48 | }; | 52 | }; |
49 | typedef struct _phw_tonga_pt_config_reg phw_tonga_pt_config_reg; | ||
50 | 53 | ||
51 | struct _phw_tonga_pt_defaults { | 54 | struct tonga_pt_defaults { |
52 | uint8_t svi_load_line_en; | 55 | uint8_t svi_load_line_en; |
53 | uint8_t svi_load_line_vddC; | 56 | uint8_t svi_load_line_vddC; |
54 | uint8_t tdc_vddc_throttle_release_limit_perc; | 57 | uint8_t tdc_vddc_throttle_release_limit_perc; |
@@ -60,7 +63,18 @@ struct _phw_tonga_pt_defaults { | |||
60 | uint16_t bapmti_r[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS]; | 63 | uint16_t bapmti_r[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS]; |
61 | uint16_t bapmti_rc[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS]; | 64 | uint16_t bapmti_rc[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS]; |
62 | }; | 65 | }; |
63 | typedef struct _phw_tonga_pt_defaults phw_tonga_pt_defaults; | 66 | |
67 | |||
68 | |||
69 | void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr); | ||
70 | int tonga_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr); | ||
71 | int tonga_populate_pm_fuses(struct pp_hwmgr *hwmgr); | ||
72 | int tonga_enable_smc_cac(struct pp_hwmgr *hwmgr); | ||
73 | int tonga_disable_smc_cac(struct pp_hwmgr *hwmgr); | ||
74 | int tonga_enable_power_containment(struct pp_hwmgr *hwmgr); | ||
75 | int tonga_disable_power_containment(struct pp_hwmgr *hwmgr); | ||
76 | int tonga_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n); | ||
77 | int tonga_power_control_set_level(struct pp_hwmgr *hwmgr); | ||
64 | 78 | ||
65 | #endif | 79 | #endif |
66 | 80 | ||
diff --git a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h index b764c8c05ec8..3f8172f545b0 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h +++ b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h | |||
@@ -132,8 +132,10 @@ struct amd_pp_init { | |||
132 | uint32_t chip_family; | 132 | uint32_t chip_family; |
133 | uint32_t chip_id; | 133 | uint32_t chip_id; |
134 | uint32_t rev_id; | 134 | uint32_t rev_id; |
135 | bool powercontainment_enabled; | 135 | uint16_t sub_sys_id; |
136 | uint16_t sub_vendor_id; | ||
136 | }; | 137 | }; |
138 | |||
137 | enum amd_pp_display_config_type{ | 139 | enum amd_pp_display_config_type{ |
138 | AMD_PP_DisplayConfigType_None = 0, | 140 | AMD_PP_DisplayConfigType_None = 0, |
139 | AMD_PP_DisplayConfigType_DP54 , | 141 | AMD_PP_DisplayConfigType_DP54 , |
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index bf0d2accf7bf..36b4ec9c9cb1 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | |||
@@ -41,6 +41,9 @@ struct phm_fan_speed_info; | |||
41 | struct pp_atomctrl_voltage_table; | 41 | struct pp_atomctrl_voltage_table; |
42 | 42 | ||
43 | 43 | ||
44 | extern int amdgpu_powercontainment; | ||
45 | extern int amdgpu_sclk_deep_sleep_en; | ||
46 | |||
44 | enum DISPLAY_GAP { | 47 | enum DISPLAY_GAP { |
45 | DISPLAY_GAP_VBLANK_OR_WM = 0, /* Wait for vblank or MCHG watermark. */ | 48 | DISPLAY_GAP_VBLANK_OR_WM = 0, /* Wait for vblank or MCHG watermark. */ |
46 | DISPLAY_GAP_VBLANK = 1, /* Wait for vblank. */ | 49 | DISPLAY_GAP_VBLANK = 1, /* Wait for vblank. */ |
@@ -614,7 +617,6 @@ struct pp_hwmgr { | |||
614 | uint32_t num_ps; | 617 | uint32_t num_ps; |
615 | struct pp_thermal_controller_info thermal_controller; | 618 | struct pp_thermal_controller_info thermal_controller; |
616 | bool fan_ctrl_is_in_default_mode; | 619 | bool fan_ctrl_is_in_default_mode; |
617 | bool powercontainment_enabled; | ||
618 | uint32_t fan_ctrl_default_mode; | 620 | uint32_t fan_ctrl_default_mode; |
619 | uint32_t tmin; | 621 | uint32_t tmin; |
620 | struct phm_microcode_version_info microcode_version_info; | 622 | struct phm_microcode_version_info microcode_version_info; |
@@ -637,16 +639,7 @@ extern int hw_init_power_state_table(struct pp_hwmgr *hwmgr); | |||
637 | extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, | 639 | extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, |
638 | uint32_t value, uint32_t mask); | 640 | uint32_t value, uint32_t mask); |
639 | 641 | ||
640 | extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, | ||
641 | uint32_t index, uint32_t value, uint32_t mask); | ||
642 | |||
643 | extern uint32_t phm_read_indirect_register(struct pp_hwmgr *hwmgr, | ||
644 | uint32_t indirect_port, uint32_t index); | ||
645 | 642 | ||
646 | extern void phm_write_indirect_register(struct pp_hwmgr *hwmgr, | ||
647 | uint32_t indirect_port, | ||
648 | uint32_t index, | ||
649 | uint32_t value); | ||
650 | 643 | ||
651 | extern void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, | 644 | extern void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, |
652 | uint32_t indirect_port, | 645 | uint32_t indirect_port, |
@@ -654,12 +647,7 @@ extern void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, | |||
654 | uint32_t value, | 647 | uint32_t value, |
655 | uint32_t mask); | 648 | uint32_t mask); |
656 | 649 | ||
657 | extern void phm_wait_for_indirect_register_unequal( | 650 | |
658 | struct pp_hwmgr *hwmgr, | ||
659 | uint32_t indirect_port, | ||
660 | uint32_t index, | ||
661 | uint32_t value, | ||
662 | uint32_t mask); | ||
663 | 651 | ||
664 | extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr); | 652 | extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr); |
665 | extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr); | 653 | extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr); |
@@ -697,43 +685,7 @@ extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); | |||
697 | PHM_FIELD_SHIFT(reg, field)) | 685 | PHM_FIELD_SHIFT(reg, field)) |
698 | 686 | ||
699 | 687 | ||
700 | #define PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, index, value, mask) \ | ||
701 | phm_wait_on_register(hwmgr, index, value, mask) | ||
702 | |||
703 | #define PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, index, value, mask) \ | ||
704 | phm_wait_for_register_unequal(hwmgr, index, value, mask) | ||
705 | |||
706 | #define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask) \ | ||
707 | phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask) | ||
708 | |||
709 | #define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask) \ | ||
710 | phm_wait_for_indirect_register_unequal(hwmgr, mm##port##_INDEX, index, value, mask) | ||
711 | 688 | ||
712 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask) \ | ||
713 | phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX_0, index, value, mask) | ||
714 | |||
715 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask) \ | ||
716 | phm_wait_for_indirect_register_unequal(hwmgr, mm##port##_INDEX_0, index, value, mask) | ||
717 | |||
718 | /* Operations on named registers. */ | ||
719 | |||
720 | #define PHM_WAIT_REGISTER(hwmgr, reg, value, mask) \ | ||
721 | PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg, value, mask) | ||
722 | |||
723 | #define PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, value, mask) \ | ||
724 | PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg, value, mask) | ||
725 | |||
726 | #define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ | ||
727 | PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
728 | |||
729 | #define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ | ||
730 | PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
731 | |||
732 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ | ||
733 | PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
734 | |||
735 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ | ||
736 | PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
737 | 689 | ||
738 | /* Operations on named fields. */ | 690 | /* Operations on named fields. */ |
739 | 691 | ||
@@ -762,60 +714,16 @@ extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); | |||
762 | PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ | 714 | PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ |
763 | reg, field, fieldval)) | 715 | reg, field, fieldval)) |
764 | 716 | ||
765 | #define PHM_WAIT_FIELD(hwmgr, reg, field, fieldval) \ | 717 | #define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask) \ |
766 | PHM_WAIT_REGISTER(hwmgr, reg, (fieldval) \ | 718 | phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask) |
767 | << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) | ||
768 | 719 | ||
769 | #define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ | ||
770 | PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \ | ||
771 | << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) | ||
772 | 720 | ||
773 | #define PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ | 721 | #define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ |
774 | PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \ | 722 | PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) |
775 | << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) | ||
776 | 723 | ||
777 | #define PHM_WAIT_FIELD_UNEQUAL(hwmgr, reg, field, fieldval) \ | 724 | #define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ |
778 | PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, (fieldval) \ | 725 | PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \ |
779 | << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) | ||
780 | |||
781 | #define PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ | ||
782 | PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, (fieldval) \ | ||
783 | << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) | ||
784 | |||
785 | #define PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ | ||
786 | PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, (fieldval) \ | ||
787 | << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) | 726 | << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) |
788 | 727 | ||
789 | /* Operations on arrays of registers & fields. */ | ||
790 | |||
791 | #define PHM_READ_ARRAY_REGISTER(device, reg, offset) \ | ||
792 | cgs_read_register(device, mm##reg + (offset)) | ||
793 | |||
794 | #define PHM_WRITE_ARRAY_REGISTER(device, reg, offset, value) \ | ||
795 | cgs_write_register(device, mm##reg + (offset), value) | ||
796 | |||
797 | #define PHM_WAIT_ARRAY_REGISTER(hwmgr, reg, offset, value, mask) \ | ||
798 | PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg + (offset), value, mask) | ||
799 | |||
800 | #define PHM_WAIT_ARRAY_REGISTER_UNEQUAL(hwmgr, reg, offset, value, mask) \ | ||
801 | PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg + (offset), value, mask) | ||
802 | |||
803 | #define PHM_READ_ARRAY_FIELD(hwmgr, reg, offset, field) \ | ||
804 | PHM_GET_FIELD(PHM_READ_ARRAY_REGISTER(hwmgr->device, reg, offset), reg, field) | ||
805 | |||
806 | #define PHM_WRITE_ARRAY_FIELD(hwmgr, reg, offset, field, fieldvalue) \ | ||
807 | PHM_WRITE_ARRAY_REGISTER(hwmgr->device, reg, offset, \ | ||
808 | PHM_SET_FIELD(PHM_READ_ARRAY_REGISTER(hwmgr->device, reg, offset), \ | ||
809 | reg, field, fieldvalue)) | ||
810 | |||
811 | #define PHM_WAIT_ARRAY_FIELD(hwmgr, reg, offset, field, fieldvalue) \ | ||
812 | PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg + (offset), \ | ||
813 | (fieldvalue) << PHM_FIELD_SHIFT(reg, field), \ | ||
814 | PHM_FIELD_MASK(reg, field)) | ||
815 | |||
816 | #define PHM_WAIT_ARRAY_FIELD_UNEQUAL(hwmgr, reg, offset, field, fieldvalue) \ | ||
817 | PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg + (offset), \ | ||
818 | (fieldvalue) << PHM_FIELD_SHIFT(reg, field), \ | ||
819 | PHM_FIELD_MASK(reg, field)) | ||
820 | 728 | ||
821 | #endif /* _HWMGR_H_ */ | 729 | #endif /* _HWMGR_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 index 000000000000..71c9b2d28640 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu71.h | |||
@@ -0,0 +1,510 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef SMU71_H | ||
24 | #define SMU71_H | ||
25 | |||
26 | #if !defined(SMC_MICROCODE) | ||
27 | #pragma pack(push, 1) | ||
28 | #endif | ||
29 | |||
30 | #define SMU__NUM_PCIE_DPM_LEVELS 8 | ||
31 | #define SMU__NUM_SCLK_DPM_STATE 8 | ||
32 | #define SMU__NUM_MCLK_DPM_LEVELS 4 | ||
33 | #define SMU__VARIANT__ICELAND 1 | ||
34 | #define SMU__DGPU_ONLY 1 | ||
35 | #define SMU__DYNAMIC_MCARB_SETTINGS 1 | ||
36 | |||
37 | enum SID_OPTION { | ||
38 | SID_OPTION_HI, | ||
39 | SID_OPTION_LO, | ||
40 | SID_OPTION_COUNT | ||
41 | }; | ||
42 | |||
43 | typedef struct { | ||
44 | uint32_t high; | ||
45 | uint32_t low; | ||
46 | } data_64_t; | ||
47 | |||
48 | typedef struct { | ||
49 | data_64_t high; | ||
50 | data_64_t low; | ||
51 | } data_128_t; | ||
52 | |||
53 | #define SMU7_CONTEXT_ID_SMC 1 | ||
54 | #define SMU7_CONTEXT_ID_VBIOS 2 | ||
55 | |||
56 | #define SMU71_MAX_LEVELS_VDDC 8 | ||
57 | #define SMU71_MAX_LEVELS_VDDCI 4 | ||
58 | #define SMU71_MAX_LEVELS_MVDD 4 | ||
59 | #define SMU71_MAX_LEVELS_VDDNB 8 | ||
60 | |||
61 | #define SMU71_MAX_LEVELS_GRAPHICS SMU__NUM_SCLK_DPM_STATE | ||
62 | #define SMU71_MAX_LEVELS_MEMORY SMU__NUM_MCLK_DPM_LEVELS | ||
63 | #define SMU71_MAX_LEVELS_GIO SMU__NUM_LCLK_DPM_LEVELS | ||
64 | #define SMU71_MAX_LEVELS_LINK SMU__NUM_PCIE_DPM_LEVELS | ||
65 | #define SMU71_MAX_ENTRIES_SMIO 32 | ||
66 | |||
67 | #define DPM_NO_LIMIT 0 | ||
68 | #define DPM_NO_UP 1 | ||
69 | #define DPM_GO_DOWN 2 | ||
70 | #define DPM_GO_UP 3 | ||
71 | |||
72 | #define SMU7_FIRST_DPM_GRAPHICS_LEVEL 0 | ||
73 | #define SMU7_FIRST_DPM_MEMORY_LEVEL 0 | ||
74 | |||
75 | #define GPIO_CLAMP_MODE_VRHOT 1 | ||
76 | #define GPIO_CLAMP_MODE_THERM 2 | ||
77 | #define GPIO_CLAMP_MODE_DC 4 | ||
78 | |||
79 | #define SCRATCH_B_TARG_PCIE_INDEX_SHIFT 0 | ||
80 | #define SCRATCH_B_TARG_PCIE_INDEX_MASK (0x7<<SCRATCH_B_TARG_PCIE_INDEX_SHIFT) | ||
81 | #define SCRATCH_B_CURR_PCIE_INDEX_SHIFT 3 | ||
82 | #define SCRATCH_B_CURR_PCIE_INDEX_MASK (0x7<<SCRATCH_B_CURR_PCIE_INDEX_SHIFT) | ||
83 | #define SCRATCH_B_TARG_UVD_INDEX_SHIFT 6 | ||
84 | #define SCRATCH_B_TARG_UVD_INDEX_MASK (0x7<<SCRATCH_B_TARG_UVD_INDEX_SHIFT) | ||
85 | #define SCRATCH_B_CURR_UVD_INDEX_SHIFT 9 | ||
86 | #define SCRATCH_B_CURR_UVD_INDEX_MASK (0x7<<SCRATCH_B_CURR_UVD_INDEX_SHIFT) | ||
87 | #define SCRATCH_B_TARG_VCE_INDEX_SHIFT 12 | ||
88 | #define SCRATCH_B_TARG_VCE_INDEX_MASK (0x7<<SCRATCH_B_TARG_VCE_INDEX_SHIFT) | ||
89 | #define SCRATCH_B_CURR_VCE_INDEX_SHIFT 15 | ||
90 | #define SCRATCH_B_CURR_VCE_INDEX_MASK (0x7<<SCRATCH_B_CURR_VCE_INDEX_SHIFT) | ||
91 | #define SCRATCH_B_TARG_ACP_INDEX_SHIFT 18 | ||
92 | #define SCRATCH_B_TARG_ACP_INDEX_MASK (0x7<<SCRATCH_B_TARG_ACP_INDEX_SHIFT) | ||
93 | #define SCRATCH_B_CURR_ACP_INDEX_SHIFT 21 | ||
94 | #define SCRATCH_B_CURR_ACP_INDEX_MASK (0x7<<SCRATCH_B_CURR_ACP_INDEX_SHIFT) | ||
95 | #define SCRATCH_B_TARG_SAMU_INDEX_SHIFT 24 | ||
96 | #define SCRATCH_B_TARG_SAMU_INDEX_MASK (0x7<<SCRATCH_B_TARG_SAMU_INDEX_SHIFT) | ||
97 | #define SCRATCH_B_CURR_SAMU_INDEX_SHIFT 27 | ||
98 | #define SCRATCH_B_CURR_SAMU_INDEX_MASK (0x7<<SCRATCH_B_CURR_SAMU_INDEX_SHIFT) | ||
99 | |||
100 | |||
101 | #if defined SMU__DGPU_ONLY | ||
102 | #define SMU71_DTE_ITERATIONS 5 | ||
103 | #define SMU71_DTE_SOURCES 3 | ||
104 | #define SMU71_DTE_SINKS 1 | ||
105 | #define SMU71_NUM_CPU_TES 0 | ||
106 | #define SMU71_NUM_GPU_TES 1 | ||
107 | #define SMU71_NUM_NON_TES 2 | ||
108 | |||
109 | #endif | ||
110 | |||
111 | #if defined SMU__FUSION_ONLY | ||
112 | #define SMU7_DTE_ITERATIONS 5 | ||
113 | #define SMU7_DTE_SOURCES 5 | ||
114 | #define SMU7_DTE_SINKS 3 | ||
115 | #define SMU7_NUM_CPU_TES 2 | ||
116 | #define SMU7_NUM_GPU_TES 1 | ||
117 | #define SMU7_NUM_NON_TES 2 | ||
118 | |||
119 | #endif | ||
120 | |||
121 | struct SMU71_PIDController | ||
122 | { | ||
123 | uint32_t Ki; | ||
124 | int32_t LFWindupUpperLim; | ||
125 | int32_t LFWindupLowerLim; | ||
126 | uint32_t StatePrecision; | ||
127 | uint32_t LfPrecision; | ||
128 | uint32_t LfOffset; | ||
129 | uint32_t MaxState; | ||
130 | uint32_t MaxLfFraction; | ||
131 | uint32_t StateShift; | ||
132 | }; | ||
133 | |||
134 | typedef struct SMU71_PIDController SMU71_PIDController; | ||
135 | |||
136 | struct SMU7_LocalDpmScoreboard | ||
137 | { | ||
138 | uint32_t PercentageBusy; | ||
139 | |||
140 | int32_t PIDError; | ||
141 | int32_t PIDIntegral; | ||
142 | int32_t PIDOutput; | ||
143 | |||
144 | uint32_t SigmaDeltaAccum; | ||
145 | uint32_t SigmaDeltaOutput; | ||
146 | uint32_t SigmaDeltaLevel; | ||
147 | |||
148 | uint32_t UtilizationSetpoint; | ||
149 | |||
150 | uint8_t TdpClampMode; | ||
151 | uint8_t TdcClampMode; | ||
152 | uint8_t ThermClampMode; | ||
153 | uint8_t VoltageBusy; | ||
154 | |||
155 | int8_t CurrLevel; | ||
156 | int8_t TargLevel; | ||
157 | uint8_t LevelChangeInProgress; | ||
158 | uint8_t UpHyst; | ||
159 | |||
160 | uint8_t DownHyst; | ||
161 | uint8_t VoltageDownHyst; | ||
162 | uint8_t DpmEnable; | ||
163 | uint8_t DpmRunning; | ||
164 | |||
165 | uint8_t DpmForce; | ||
166 | uint8_t DpmForceLevel; | ||
167 | uint8_t DisplayWatermark; | ||
168 | uint8_t McArbIndex; | ||
169 | |||
170 | uint32_t MinimumPerfSclk; | ||
171 | |||
172 | uint8_t AcpiReq; | ||
173 | uint8_t AcpiAck; | ||
174 | uint8_t GfxClkSlow; | ||
175 | uint8_t GpioClampMode; | ||
176 | |||
177 | uint8_t FpsFilterWeight; | ||
178 | uint8_t EnabledLevelsChange; | ||
179 | uint8_t DteClampMode; | ||
180 | uint8_t FpsClampMode; | ||
181 | |||
182 | uint16_t LevelResidencyCounters [SMU71_MAX_LEVELS_GRAPHICS]; | ||
183 | uint16_t LevelSwitchCounters [SMU71_MAX_LEVELS_GRAPHICS]; | ||
184 | |||
185 | void (*TargetStateCalculator)(uint8_t); | ||
186 | void (*SavedTargetStateCalculator)(uint8_t); | ||
187 | |||
188 | uint16_t AutoDpmInterval; | ||
189 | uint16_t AutoDpmRange; | ||
190 | |||
191 | uint8_t FpsEnabled; | ||
192 | uint8_t MaxPerfLevel; | ||
193 | uint8_t AllowLowClkInterruptToHost; | ||
194 | uint8_t FpsRunning; | ||
195 | |||
196 | uint32_t MaxAllowedFrequency; | ||
197 | }; | ||
198 | |||
199 | typedef struct SMU7_LocalDpmScoreboard SMU7_LocalDpmScoreboard; | ||
200 | |||
201 | #define SMU7_MAX_VOLTAGE_CLIENTS 12 | ||
202 | |||
203 | struct SMU7_VoltageScoreboard | ||
204 | { | ||
205 | uint16_t CurrentVoltage; | ||
206 | uint16_t HighestVoltage; | ||
207 | uint16_t MaxVid; | ||
208 | uint8_t HighestVidOffset; | ||
209 | uint8_t CurrentVidOffset; | ||
210 | #if defined (SMU__DGPU_ONLY) | ||
211 | uint8_t CurrentPhases; | ||
212 | uint8_t HighestPhases; | ||
213 | #else | ||
214 | uint8_t AvsOffset; | ||
215 | uint8_t AvsOffsetApplied; | ||
216 | #endif | ||
217 | uint8_t ControllerBusy; | ||
218 | uint8_t CurrentVid; | ||
219 | uint16_t RequestedVoltage[SMU7_MAX_VOLTAGE_CLIENTS]; | ||
220 | #if defined (SMU__DGPU_ONLY) | ||
221 | uint8_t RequestedPhases[SMU7_MAX_VOLTAGE_CLIENTS]; | ||
222 | #endif | ||
223 | uint8_t EnabledRequest[SMU7_MAX_VOLTAGE_CLIENTS]; | ||
224 | uint8_t TargetIndex; | ||
225 | uint8_t Delay; | ||
226 | uint8_t ControllerEnable; | ||
227 | uint8_t ControllerRunning; | ||
228 | uint16_t CurrentStdVoltageHiSidd; | ||
229 | uint16_t CurrentStdVoltageLoSidd; | ||
230 | #if defined (SMU__DGPU_ONLY) | ||
231 | uint16_t RequestedVddci; | ||
232 | uint16_t CurrentVddci; | ||
233 | uint16_t HighestVddci; | ||
234 | uint8_t CurrentVddciVid; | ||
235 | uint8_t TargetVddciIndex; | ||
236 | #endif | ||
237 | }; | ||
238 | |||
239 | typedef struct SMU7_VoltageScoreboard SMU7_VoltageScoreboard; | ||
240 | |||
241 | // ------------------------------------------------------------------------------------------------------------------------- | ||
242 | #define SMU7_MAX_PCIE_LINK_SPEEDS 3 /* 0:Gen1 1:Gen2 2:Gen3 */ | ||
243 | |||
244 | struct SMU7_PCIeLinkSpeedScoreboard | ||
245 | { | ||
246 | uint8_t DpmEnable; | ||
247 | uint8_t DpmRunning; | ||
248 | uint8_t DpmForce; | ||
249 | uint8_t DpmForceLevel; | ||
250 | |||
251 | uint8_t CurrentLinkSpeed; | ||
252 | uint8_t EnabledLevelsChange; | ||
253 | uint16_t AutoDpmInterval; | ||
254 | |||
255 | uint16_t AutoDpmRange; | ||
256 | uint16_t AutoDpmCount; | ||
257 | |||
258 | uint8_t DpmMode; | ||
259 | uint8_t AcpiReq; | ||
260 | uint8_t AcpiAck; | ||
261 | uint8_t CurrentLinkLevel; | ||
262 | |||
263 | }; | ||
264 | |||
265 | typedef struct SMU7_PCIeLinkSpeedScoreboard SMU7_PCIeLinkSpeedScoreboard; | ||
266 | |||
267 | // -------------------------------------------------------- CAC table ------------------------------------------------------ | ||
268 | #define SMU7_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16 | ||
269 | #define SMU7_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16 | ||
270 | |||
271 | #define SMU7_SCALE_I 7 | ||
272 | #define SMU7_SCALE_R 12 | ||
273 | |||
274 | struct SMU7_PowerScoreboard | ||
275 | { | ||
276 | uint16_t MinVoltage; | ||
277 | uint16_t MaxVoltage; | ||
278 | |||
279 | uint32_t AvgGpuPower; | ||
280 | |||
281 | uint16_t VddcLeakagePower[SID_OPTION_COUNT]; | ||
282 | uint16_t VddcSclkConstantPower[SID_OPTION_COUNT]; | ||
283 | uint16_t VddcSclkDynamicPower[SID_OPTION_COUNT]; | ||
284 | uint16_t VddcNonSclkDynamicPower[SID_OPTION_COUNT]; | ||
285 | uint16_t VddcTotalPower[SID_OPTION_COUNT]; | ||
286 | uint16_t VddcTotalCurrent[SID_OPTION_COUNT]; | ||
287 | uint16_t VddcLoadVoltage[SID_OPTION_COUNT]; | ||
288 | uint16_t VddcNoLoadVoltage[SID_OPTION_COUNT]; | ||
289 | |||
290 | uint16_t DisplayPhyPower; | ||
291 | uint16_t PciePhyPower; | ||
292 | |||
293 | uint16_t VddciTotalPower; | ||
294 | uint16_t Vddr1TotalPower; | ||
295 | |||
296 | uint32_t RocPower; | ||
297 | |||
298 | uint32_t last_power; | ||
299 | uint32_t enableWinAvg; | ||
300 | |||
301 | uint32_t lkg_acc; | ||
302 | uint16_t VoltLkgeScaler; | ||
303 | uint16_t TempLkgeScaler; | ||
304 | |||
305 | uint32_t uvd_cac_dclk; | ||
306 | uint32_t uvd_cac_vclk; | ||
307 | uint32_t vce_cac_eclk; | ||
308 | uint32_t samu_cac_samclk; | ||
309 | uint32_t display_cac_dispclk; | ||
310 | uint32_t acp_cac_aclk; | ||
311 | uint32_t unb_cac; | ||
312 | |||
313 | uint32_t WinTime; | ||
314 | |||
315 | uint16_t GpuPwr_MAWt; | ||
316 | uint16_t FilteredVddcTotalPower; | ||
317 | |||
318 | uint8_t CalculationRepeats; | ||
319 | uint8_t WaterfallUp; | ||
320 | uint8_t WaterfallDown; | ||
321 | uint8_t WaterfallLimit; | ||
322 | }; | ||
323 | |||
324 | typedef struct SMU7_PowerScoreboard SMU7_PowerScoreboard; | ||
325 | |||
326 | // -------------------------------------------------------------------------------------------------- | ||
327 | |||
328 | struct SMU7_ThermalScoreboard | ||
329 | { | ||
330 | int16_t GpuLimit; | ||
331 | int16_t GpuHyst; | ||
332 | uint16_t CurrGnbTemp; | ||
333 | uint16_t FilteredGnbTemp; | ||
334 | uint8_t ControllerEnable; | ||
335 | uint8_t ControllerRunning; | ||
336 | uint8_t WaterfallUp; | ||
337 | uint8_t WaterfallDown; | ||
338 | uint8_t WaterfallLimit; | ||
339 | uint8_t padding[3]; | ||
340 | }; | ||
341 | |||
342 | typedef struct SMU7_ThermalScoreboard SMU7_ThermalScoreboard; | ||
343 | |||
344 | // For FeatureEnables: | ||
345 | #define SMU7_SCLK_DPM_CONFIG_MASK 0x01 | ||
346 | #define SMU7_VOLTAGE_CONTROLLER_CONFIG_MASK 0x02 | ||
347 | #define SMU7_THERMAL_CONTROLLER_CONFIG_MASK 0x04 | ||
348 | #define SMU7_MCLK_DPM_CONFIG_MASK 0x08 | ||
349 | #define SMU7_UVD_DPM_CONFIG_MASK 0x10 | ||
350 | #define SMU7_VCE_DPM_CONFIG_MASK 0x20 | ||
351 | #define SMU7_ACP_DPM_CONFIG_MASK 0x40 | ||
352 | #define SMU7_SAMU_DPM_CONFIG_MASK 0x80 | ||
353 | #define SMU7_PCIEGEN_DPM_CONFIG_MASK 0x100 | ||
354 | |||
355 | #define SMU7_ACP_MCLK_HANDSHAKE_DISABLE 0x00000001 | ||
356 | #define SMU7_ACP_SCLK_HANDSHAKE_DISABLE 0x00000002 | ||
357 | #define SMU7_UVD_MCLK_HANDSHAKE_DISABLE 0x00000100 | ||
358 | #define SMU7_UVD_SCLK_HANDSHAKE_DISABLE 0x00000200 | ||
359 | #define SMU7_VCE_MCLK_HANDSHAKE_DISABLE 0x00010000 | ||
360 | #define SMU7_VCE_SCLK_HANDSHAKE_DISABLE 0x00020000 | ||
361 | |||
362 | // All 'soft registers' should be uint32_t. | ||
363 | struct SMU71_SoftRegisters | ||
364 | { | ||
365 | uint32_t RefClockFrequency; | ||
366 | uint32_t PmTimerPeriod; | ||
367 | uint32_t FeatureEnables; | ||
368 | #if defined (SMU__DGPU_ONLY) | ||
369 | uint32_t PreVBlankGap; | ||
370 | uint32_t VBlankTimeout; | ||
371 | uint32_t TrainTimeGap; | ||
372 | uint32_t MvddSwitchTime; | ||
373 | uint32_t LongestAcpiTrainTime; | ||
374 | uint32_t AcpiDelay; | ||
375 | uint32_t G5TrainTime; | ||
376 | uint32_t DelayMpllPwron; | ||
377 | uint32_t VoltageChangeTimeout; | ||
378 | #endif | ||
379 | uint32_t HandshakeDisables; | ||
380 | |||
381 | uint8_t DisplayPhy1Config; | ||
382 | uint8_t DisplayPhy2Config; | ||
383 | uint8_t DisplayPhy3Config; | ||
384 | uint8_t DisplayPhy4Config; | ||
385 | |||
386 | uint8_t DisplayPhy5Config; | ||
387 | uint8_t DisplayPhy6Config; | ||
388 | uint8_t DisplayPhy7Config; | ||
389 | uint8_t DisplayPhy8Config; | ||
390 | |||
391 | uint32_t AverageGraphicsActivity; | ||
392 | uint32_t AverageMemoryActivity; | ||
393 | uint32_t AverageGioActivity; | ||
394 | |||
395 | uint8_t SClkDpmEnabledLevels; | ||
396 | uint8_t MClkDpmEnabledLevels; | ||
397 | uint8_t LClkDpmEnabledLevels; | ||
398 | uint8_t PCIeDpmEnabledLevels; | ||
399 | |||
400 | uint32_t DRAM_LOG_ADDR_H; | ||
401 | uint32_t DRAM_LOG_ADDR_L; | ||
402 | uint32_t DRAM_LOG_PHY_ADDR_H; | ||
403 | uint32_t DRAM_LOG_PHY_ADDR_L; | ||
404 | uint32_t DRAM_LOG_BUFF_SIZE; | ||
405 | uint32_t UlvEnterCount; | ||
406 | uint32_t UlvTime; | ||
407 | uint32_t UcodeLoadStatus; | ||
408 | uint8_t DPMFreezeAndForced; | ||
409 | uint8_t Activity_Weight; | ||
410 | uint8_t Reserved8[2]; | ||
411 | uint32_t Reserved; | ||
412 | }; | ||
413 | |||
414 | typedef struct SMU71_SoftRegisters SMU71_SoftRegisters; | ||
415 | |||
416 | struct SMU71_Firmware_Header | ||
417 | { | ||
418 | uint32_t Digest[5]; | ||
419 | uint32_t Version; | ||
420 | uint32_t HeaderSize; | ||
421 | uint32_t Flags; | ||
422 | uint32_t EntryPoint; | ||
423 | uint32_t CodeSize; | ||
424 | uint32_t ImageSize; | ||
425 | |||
426 | uint32_t Rtos; | ||
427 | uint32_t SoftRegisters; | ||
428 | uint32_t DpmTable; | ||
429 | uint32_t FanTable; | ||
430 | uint32_t CacConfigTable; | ||
431 | uint32_t CacStatusTable; | ||
432 | |||
433 | uint32_t mcRegisterTable; | ||
434 | |||
435 | uint32_t mcArbDramTimingTable; | ||
436 | |||
437 | uint32_t PmFuseTable; | ||
438 | uint32_t Globals; | ||
439 | uint32_t UvdDpmTable; | ||
440 | uint32_t AcpDpmTable; | ||
441 | uint32_t VceDpmTable; | ||
442 | uint32_t SamuDpmTable; | ||
443 | uint32_t UlvSettings; | ||
444 | uint32_t Reserved[37]; | ||
445 | uint32_t Signature; | ||
446 | }; | ||
447 | |||
448 | typedef struct SMU71_Firmware_Header SMU71_Firmware_Header; | ||
449 | |||
450 | struct SMU7_HystController_Data | ||
451 | { | ||
452 | uint8_t waterfall_up; | ||
453 | uint8_t waterfall_down; | ||
454 | uint8_t pstate; | ||
455 | uint8_t clamp_mode; | ||
456 | }; | ||
457 | |||
458 | typedef struct SMU7_HystController_Data SMU7_HystController_Data; | ||
459 | |||
460 | #define SMU71_FIRMWARE_HEADER_LOCATION 0x20000 | ||
461 | |||
462 | enum DisplayConfig { | ||
463 | PowerDown = 1, | ||
464 | DP54x4, | ||
465 | DP54x2, | ||
466 | DP54x1, | ||
467 | DP27x4, | ||
468 | DP27x2, | ||
469 | DP27x1, | ||
470 | HDMI297, | ||
471 | HDMI162, | ||
472 | LVDS, | ||
473 | DP324x4, | ||
474 | DP324x2, | ||
475 | DP324x1 | ||
476 | }; | ||
477 | |||
478 | //#define SX_BLOCK_COUNT 8 | ||
479 | //#define MC_BLOCK_COUNT 1 | ||
480 | //#define CPL_BLOCK_COUNT 27 | ||
481 | |||
482 | #if defined SMU__VARIANT__ICELAND | ||
483 | #define SX_BLOCK_COUNT 8 | ||
484 | #define MC_BLOCK_COUNT 1 | ||
485 | #define CPL_BLOCK_COUNT 29 | ||
486 | #endif | ||
487 | |||
488 | struct SMU7_Local_Cac { | ||
489 | uint8_t BlockId; | ||
490 | uint8_t SignalId; | ||
491 | uint8_t Threshold; | ||
492 | uint8_t Padding; | ||
493 | }; | ||
494 | |||
495 | typedef struct SMU7_Local_Cac SMU7_Local_Cac; | ||
496 | |||
497 | struct SMU7_Local_Cac_Table { | ||
498 | SMU7_Local_Cac SxLocalCac[SX_BLOCK_COUNT]; | ||
499 | SMU7_Local_Cac CplLocalCac[CPL_BLOCK_COUNT]; | ||
500 | SMU7_Local_Cac McLocalCac[MC_BLOCK_COUNT]; | ||
501 | }; | ||
502 | |||
503 | typedef struct SMU7_Local_Cac_Table SMU7_Local_Cac_Table; | ||
504 | |||
505 | #if !defined(SMC_MICROCODE) | ||
506 | #pragma pack(pop) | ||
507 | #endif | ||
508 | |||
509 | #endif | ||
510 | |||
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 index 000000000000..c0e3936d5c2e --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu71_discrete.h | |||
@@ -0,0 +1,631 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef SMU71_DISCRETE_H | ||
24 | #define SMU71_DISCRETE_H | ||
25 | |||
26 | #include "smu71.h" | ||
27 | |||
28 | #if !defined(SMC_MICROCODE) | ||
29 | #pragma pack(push, 1) | ||
30 | #endif | ||
31 | |||
32 | #define VDDC_ON_SVI2 0x1 | ||
33 | #define VDDCI_ON_SVI2 0x2 | ||
34 | #define MVDD_ON_SVI2 0x4 | ||
35 | |||
36 | struct SMU71_Discrete_VoltageLevel | ||
37 | { | ||
38 | uint16_t Voltage; | ||
39 | uint16_t StdVoltageHiSidd; | ||
40 | uint16_t StdVoltageLoSidd; | ||
41 | uint8_t Smio; | ||
42 | uint8_t padding; | ||
43 | }; | ||
44 | |||
45 | typedef struct SMU71_Discrete_VoltageLevel SMU71_Discrete_VoltageLevel; | ||
46 | |||
47 | struct SMU71_Discrete_GraphicsLevel | ||
48 | { | ||
49 | uint32_t MinVddc; | ||
50 | uint32_t MinVddcPhases; | ||
51 | |||
52 | uint32_t SclkFrequency; | ||
53 | |||
54 | uint8_t pcieDpmLevel; | ||
55 | uint8_t DeepSleepDivId; | ||
56 | uint16_t ActivityLevel; | ||
57 | |||
58 | uint32_t CgSpllFuncCntl3; | ||
59 | uint32_t CgSpllFuncCntl4; | ||
60 | uint32_t SpllSpreadSpectrum; | ||
61 | uint32_t SpllSpreadSpectrum2; | ||
62 | uint32_t CcPwrDynRm; | ||
63 | uint32_t CcPwrDynRm1; | ||
64 | uint8_t SclkDid; | ||
65 | uint8_t DisplayWatermark; | ||
66 | uint8_t EnabledForActivity; | ||
67 | uint8_t EnabledForThrottle; | ||
68 | uint8_t UpHyst; | ||
69 | uint8_t DownHyst; | ||
70 | uint8_t VoltageDownHyst; | ||
71 | uint8_t PowerThrottle; | ||
72 | }; | ||
73 | |||
74 | typedef struct SMU71_Discrete_GraphicsLevel SMU71_Discrete_GraphicsLevel; | ||
75 | |||
76 | struct SMU71_Discrete_ACPILevel | ||
77 | { | ||
78 | uint32_t Flags; | ||
79 | uint32_t MinVddc; | ||
80 | uint32_t MinVddcPhases; | ||
81 | uint32_t SclkFrequency; | ||
82 | uint8_t SclkDid; | ||
83 | uint8_t DisplayWatermark; | ||
84 | uint8_t DeepSleepDivId; | ||
85 | uint8_t padding; | ||
86 | uint32_t CgSpllFuncCntl; | ||
87 | uint32_t CgSpllFuncCntl2; | ||
88 | uint32_t CgSpllFuncCntl3; | ||
89 | uint32_t CgSpllFuncCntl4; | ||
90 | uint32_t SpllSpreadSpectrum; | ||
91 | uint32_t SpllSpreadSpectrum2; | ||
92 | uint32_t CcPwrDynRm; | ||
93 | uint32_t CcPwrDynRm1; | ||
94 | }; | ||
95 | |||
96 | typedef struct SMU71_Discrete_ACPILevel SMU71_Discrete_ACPILevel; | ||
97 | |||
98 | struct SMU71_Discrete_Ulv | ||
99 | { | ||
100 | uint32_t CcPwrDynRm; | ||
101 | uint32_t CcPwrDynRm1; | ||
102 | uint16_t VddcOffset; | ||
103 | uint8_t VddcOffsetVid; | ||
104 | uint8_t VddcPhase; | ||
105 | uint32_t Reserved; | ||
106 | }; | ||
107 | |||
108 | typedef struct SMU71_Discrete_Ulv SMU71_Discrete_Ulv; | ||
109 | |||
110 | struct SMU71_Discrete_MemoryLevel | ||
111 | { | ||
112 | uint32_t MinVddc; | ||
113 | uint32_t MinVddcPhases; | ||
114 | uint32_t MinVddci; | ||
115 | uint32_t MinMvdd; | ||
116 | |||
117 | uint32_t MclkFrequency; | ||
118 | |||
119 | uint8_t EdcReadEnable; | ||
120 | uint8_t EdcWriteEnable; | ||
121 | uint8_t RttEnable; | ||
122 | uint8_t StutterEnable; | ||
123 | |||
124 | uint8_t StrobeEnable; | ||
125 | uint8_t StrobeRatio; | ||
126 | uint8_t EnabledForThrottle; | ||
127 | uint8_t EnabledForActivity; | ||
128 | |||
129 | uint8_t UpHyst; | ||
130 | uint8_t DownHyst; | ||
131 | uint8_t VoltageDownHyst; | ||
132 | uint8_t padding; | ||
133 | |||
134 | uint16_t ActivityLevel; | ||
135 | uint8_t DisplayWatermark; | ||
136 | uint8_t padding1; | ||
137 | |||
138 | uint32_t MpllFuncCntl; | ||
139 | uint32_t MpllFuncCntl_1; | ||
140 | uint32_t MpllFuncCntl_2; | ||
141 | uint32_t MpllAdFuncCntl; | ||
142 | uint32_t MpllDqFuncCntl; | ||
143 | uint32_t MclkPwrmgtCntl; | ||
144 | uint32_t DllCntl; | ||
145 | uint32_t MpllSs1; | ||
146 | uint32_t MpllSs2; | ||
147 | }; | ||
148 | |||
149 | typedef struct SMU71_Discrete_MemoryLevel SMU71_Discrete_MemoryLevel; | ||
150 | |||
151 | struct SMU71_Discrete_LinkLevel | ||
152 | { | ||
153 | uint8_t PcieGenSpeed; ///< 0:PciE-gen1 1:PciE-gen2 2:PciE-gen3 | ||
154 | uint8_t PcieLaneCount; ///< 1=x1, 2=x2, 3=x4, 4=x8, 5=x12, 6=x16 | ||
155 | uint8_t EnabledForActivity; | ||
156 | uint8_t SPC; | ||
157 | uint32_t DownThreshold; | ||
158 | uint32_t UpThreshold; | ||
159 | uint32_t Reserved; | ||
160 | }; | ||
161 | |||
162 | typedef struct SMU71_Discrete_LinkLevel SMU71_Discrete_LinkLevel; | ||
163 | |||
164 | |||
165 | #ifdef SMU__DYNAMIC_MCARB_SETTINGS | ||
166 | // MC ARB DRAM Timing registers. | ||
167 | struct SMU71_Discrete_MCArbDramTimingTableEntry | ||
168 | { | ||
169 | uint32_t McArbDramTiming; | ||
170 | uint32_t McArbDramTiming2; | ||
171 | uint8_t McArbBurstTime; | ||
172 | uint8_t padding[3]; | ||
173 | }; | ||
174 | |||
175 | typedef struct SMU71_Discrete_MCArbDramTimingTableEntry SMU71_Discrete_MCArbDramTimingTableEntry; | ||
176 | |||
177 | struct SMU71_Discrete_MCArbDramTimingTable | ||
178 | { | ||
179 | SMU71_Discrete_MCArbDramTimingTableEntry entries[SMU__NUM_SCLK_DPM_STATE][SMU__NUM_MCLK_DPM_LEVELS]; | ||
180 | }; | ||
181 | |||
182 | typedef struct SMU71_Discrete_MCArbDramTimingTable SMU71_Discrete_MCArbDramTimingTable; | ||
183 | #endif | ||
184 | |||
185 | // UVD VCLK/DCLK state (level) definition. | ||
186 | struct SMU71_Discrete_UvdLevel | ||
187 | { | ||
188 | uint32_t VclkFrequency; | ||
189 | uint32_t DclkFrequency; | ||
190 | uint16_t MinVddc; | ||
191 | uint8_t MinVddcPhases; | ||
192 | uint8_t VclkDivider; | ||
193 | uint8_t DclkDivider; | ||
194 | uint8_t padding[3]; | ||
195 | }; | ||
196 | |||
197 | typedef struct SMU71_Discrete_UvdLevel SMU71_Discrete_UvdLevel; | ||
198 | |||
199 | // Clocks for other external blocks (VCE, ACP, SAMU). | ||
200 | struct SMU71_Discrete_ExtClkLevel | ||
201 | { | ||
202 | uint32_t Frequency; | ||
203 | uint16_t MinVoltage; | ||
204 | uint8_t MinPhases; | ||
205 | uint8_t Divider; | ||
206 | }; | ||
207 | |||
208 | typedef struct SMU71_Discrete_ExtClkLevel SMU71_Discrete_ExtClkLevel; | ||
209 | |||
210 | // Everything that we need to keep track of about the current state. | ||
211 | // Use this instead of copies of the GraphicsLevel and MemoryLevel structures to keep track of state parameters | ||
212 | // that need to be checked later. | ||
213 | // We don't need to cache everything about a state, just a few parameters. | ||
214 | struct SMU71_Discrete_StateInfo | ||
215 | { | ||
216 | uint32_t SclkFrequency; | ||
217 | uint32_t MclkFrequency; | ||
218 | uint32_t VclkFrequency; | ||
219 | uint32_t DclkFrequency; | ||
220 | uint32_t SamclkFrequency; | ||
221 | uint32_t AclkFrequency; | ||
222 | uint32_t EclkFrequency; | ||
223 | uint16_t MvddVoltage; | ||
224 | uint16_t padding16; | ||
225 | uint8_t DisplayWatermark; | ||
226 | uint8_t McArbIndex; | ||
227 | uint8_t McRegIndex; | ||
228 | uint8_t SeqIndex; | ||
229 | uint8_t SclkDid; | ||
230 | int8_t SclkIndex; | ||
231 | int8_t MclkIndex; | ||
232 | uint8_t PCIeGen; | ||
233 | |||
234 | }; | ||
235 | |||
236 | typedef struct SMU71_Discrete_StateInfo SMU71_Discrete_StateInfo; | ||
237 | |||
238 | |||
239 | struct SMU71_Discrete_DpmTable | ||
240 | { | ||
241 | // Multi-DPM controller settings | ||
242 | SMU71_PIDController GraphicsPIDController; | ||
243 | SMU71_PIDController MemoryPIDController; | ||
244 | SMU71_PIDController LinkPIDController; | ||
245 | |||
246 | uint32_t SystemFlags; | ||
247 | |||
248 | // SMIO masks for voltage and phase controls | ||
249 | uint32_t SmioMaskVddcVid; | ||
250 | uint32_t SmioMaskVddcPhase; | ||
251 | uint32_t SmioMaskVddciVid; | ||
252 | uint32_t SmioMaskMvddVid; | ||
253 | |||
254 | uint32_t VddcLevelCount; | ||
255 | uint32_t VddciLevelCount; | ||
256 | uint32_t MvddLevelCount; | ||
257 | |||
258 | SMU71_Discrete_VoltageLevel VddcLevel [SMU71_MAX_LEVELS_VDDC]; | ||
259 | SMU71_Discrete_VoltageLevel VddciLevel [SMU71_MAX_LEVELS_VDDCI]; | ||
260 | SMU71_Discrete_VoltageLevel MvddLevel [SMU71_MAX_LEVELS_MVDD]; | ||
261 | |||
262 | uint8_t GraphicsDpmLevelCount; | ||
263 | uint8_t MemoryDpmLevelCount; | ||
264 | uint8_t LinkLevelCount; | ||
265 | uint8_t MasterDeepSleepControl; | ||
266 | |||
267 | uint32_t Reserved[5]; | ||
268 | |||
269 | // State table entries for each DPM state | ||
270 | SMU71_Discrete_GraphicsLevel GraphicsLevel [SMU71_MAX_LEVELS_GRAPHICS]; | ||
271 | SMU71_Discrete_MemoryLevel MemoryACPILevel; | ||
272 | SMU71_Discrete_MemoryLevel MemoryLevel [SMU71_MAX_LEVELS_MEMORY]; | ||
273 | SMU71_Discrete_LinkLevel LinkLevel [SMU71_MAX_LEVELS_LINK]; | ||
274 | SMU71_Discrete_ACPILevel ACPILevel; | ||
275 | |||
276 | uint32_t SclkStepSize; | ||
277 | uint32_t Smio [SMU71_MAX_ENTRIES_SMIO]; | ||
278 | |||
279 | uint8_t GraphicsBootLevel; | ||
280 | uint8_t GraphicsVoltageChangeEnable; | ||
281 | uint8_t GraphicsThermThrottleEnable; | ||
282 | uint8_t GraphicsInterval; | ||
283 | |||
284 | uint8_t VoltageInterval; | ||
285 | uint8_t ThermalInterval; | ||
286 | uint16_t TemperatureLimitHigh; | ||
287 | |||
288 | uint16_t TemperatureLimitLow; | ||
289 | uint8_t MemoryBootLevel; | ||
290 | uint8_t MemoryVoltageChangeEnable; | ||
291 | |||
292 | uint8_t MemoryInterval; | ||
293 | uint8_t MemoryThermThrottleEnable; | ||
294 | uint8_t MergedVddci; | ||
295 | uint8_t padding2; | ||
296 | |||
297 | uint16_t VoltageResponseTime; | ||
298 | uint16_t PhaseResponseTime; | ||
299 | |||
300 | uint8_t PCIeBootLinkLevel; | ||
301 | uint8_t PCIeGenInterval; | ||
302 | uint8_t DTEInterval; | ||
303 | uint8_t DTEMode; | ||
304 | |||
305 | uint8_t SVI2Enable; | ||
306 | uint8_t VRHotGpio; | ||
307 | uint8_t AcDcGpio; | ||
308 | uint8_t ThermGpio; | ||
309 | |||
310 | uint32_t DisplayCac; | ||
311 | |||
312 | uint16_t MaxPwr; | ||
313 | uint16_t NomPwr; | ||
314 | |||
315 | uint16_t FpsHighThreshold; | ||
316 | uint16_t FpsLowThreshold; | ||
317 | |||
318 | uint16_t BAPMTI_R [SMU71_DTE_ITERATIONS][SMU71_DTE_SOURCES][SMU71_DTE_SINKS]; | ||
319 | uint16_t BAPMTI_RC [SMU71_DTE_ITERATIONS][SMU71_DTE_SOURCES][SMU71_DTE_SINKS]; | ||
320 | |||
321 | uint8_t DTEAmbientTempBase; | ||
322 | uint8_t DTETjOffset; | ||
323 | uint8_t GpuTjMax; | ||
324 | uint8_t GpuTjHyst; | ||
325 | |||
326 | uint16_t BootVddc; | ||
327 | uint16_t BootVddci; | ||
328 | |||
329 | uint16_t BootMVdd; | ||
330 | uint16_t padding; | ||
331 | |||
332 | uint32_t BAPM_TEMP_GRADIENT; | ||
333 | |||
334 | uint32_t LowSclkInterruptThreshold; | ||
335 | uint32_t VddGfxReChkWait; | ||
336 | |||
337 | uint16_t PPM_PkgPwrLimit; | ||
338 | uint16_t PPM_TemperatureLimit; | ||
339 | |||
340 | uint16_t DefaultTdp; | ||
341 | uint16_t TargetTdp; | ||
342 | }; | ||
343 | |||
344 | typedef struct SMU71_Discrete_DpmTable SMU71_Discrete_DpmTable; | ||
345 | |||
346 | // --------------------------------------------------- AC Timing Parameters ------------------------------------------------ | ||
347 | #define SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE 16 | ||
348 | #define SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT SMU71_MAX_LEVELS_MEMORY | ||
349 | |||
350 | struct SMU71_Discrete_MCRegisterAddress | ||
351 | { | ||
352 | uint16_t s0; | ||
353 | uint16_t s1; | ||
354 | }; | ||
355 | |||
356 | typedef struct SMU71_Discrete_MCRegisterAddress SMU71_Discrete_MCRegisterAddress; | ||
357 | |||
358 | struct SMU71_Discrete_MCRegisterSet | ||
359 | { | ||
360 | uint32_t value[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE]; | ||
361 | }; | ||
362 | |||
363 | typedef struct SMU71_Discrete_MCRegisterSet SMU71_Discrete_MCRegisterSet; | ||
364 | |||
365 | struct SMU71_Discrete_MCRegisters | ||
366 | { | ||
367 | uint8_t last; | ||
368 | uint8_t reserved[3]; | ||
369 | SMU71_Discrete_MCRegisterAddress address[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE]; | ||
370 | SMU71_Discrete_MCRegisterSet data[SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT]; | ||
371 | }; | ||
372 | |||
373 | typedef struct SMU71_Discrete_MCRegisters SMU71_Discrete_MCRegisters; | ||
374 | |||
375 | |||
376 | // --------------------------------------------------- Fan Table ----------------------------------------------------------- | ||
377 | struct SMU71_Discrete_FanTable | ||
378 | { | ||
379 | uint16_t FdoMode; | ||
380 | int16_t TempMin; | ||
381 | int16_t TempMed; | ||
382 | int16_t TempMax; | ||
383 | int16_t Slope1; | ||
384 | int16_t Slope2; | ||
385 | int16_t FdoMin; | ||
386 | int16_t HystUp; | ||
387 | int16_t HystDown; | ||
388 | int16_t HystSlope; | ||
389 | int16_t TempRespLim; | ||
390 | int16_t TempCurr; | ||
391 | int16_t SlopeCurr; | ||
392 | int16_t PwmCurr; | ||
393 | uint32_t RefreshPeriod; | ||
394 | int16_t FdoMax; | ||
395 | uint8_t TempSrc; | ||
396 | int8_t Padding; | ||
397 | }; | ||
398 | |||
399 | typedef struct SMU71_Discrete_FanTable SMU71_Discrete_FanTable; | ||
400 | |||
401 | #define SMU7_DISCRETE_GPIO_SCLK_DEBUG 4 | ||
402 | #define SMU7_DISCRETE_GPIO_SCLK_DEBUG_BIT (0x1 << SMU7_DISCRETE_GPIO_SCLK_DEBUG) | ||
403 | |||
404 | struct SMU71_MclkDpmScoreboard | ||
405 | { | ||
406 | |||
407 | uint32_t PercentageBusy; | ||
408 | |||
409 | int32_t PIDError; | ||
410 | int32_t PIDIntegral; | ||
411 | int32_t PIDOutput; | ||
412 | |||
413 | uint32_t SigmaDeltaAccum; | ||
414 | uint32_t SigmaDeltaOutput; | ||
415 | uint32_t SigmaDeltaLevel; | ||
416 | |||
417 | uint32_t UtilizationSetpoint; | ||
418 | |||
419 | uint8_t TdpClampMode; | ||
420 | uint8_t TdcClampMode; | ||
421 | uint8_t ThermClampMode; | ||
422 | uint8_t VoltageBusy; | ||
423 | |||
424 | int8_t CurrLevel; | ||
425 | int8_t TargLevel; | ||
426 | uint8_t LevelChangeInProgress; | ||
427 | uint8_t UpHyst; | ||
428 | |||
429 | uint8_t DownHyst; | ||
430 | uint8_t VoltageDownHyst; | ||
431 | uint8_t DpmEnable; | ||
432 | uint8_t DpmRunning; | ||
433 | |||
434 | uint8_t DpmForce; | ||
435 | uint8_t DpmForceLevel; | ||
436 | uint8_t DisplayWatermark; | ||
437 | uint8_t McArbIndex; | ||
438 | |||
439 | uint32_t MinimumPerfMclk; | ||
440 | |||
441 | uint8_t AcpiReq; | ||
442 | uint8_t AcpiAck; | ||
443 | uint8_t MclkSwitchInProgress; | ||
444 | uint8_t MclkSwitchCritical; | ||
445 | |||
446 | uint8_t TargetMclkIndex; | ||
447 | uint8_t TargetMvddIndex; | ||
448 | uint8_t MclkSwitchResult; | ||
449 | |||
450 | uint8_t EnabledLevelsChange; | ||
451 | |||
452 | uint16_t LevelResidencyCounters [SMU71_MAX_LEVELS_MEMORY]; | ||
453 | uint16_t LevelSwitchCounters [SMU71_MAX_LEVELS_MEMORY]; | ||
454 | |||
455 | void (*TargetStateCalculator)(uint8_t); | ||
456 | void (*SavedTargetStateCalculator)(uint8_t); | ||
457 | |||
458 | uint16_t AutoDpmInterval; | ||
459 | uint16_t AutoDpmRange; | ||
460 | |||
461 | uint16_t MclkSwitchingTime; | ||
462 | uint8_t padding[2]; | ||
463 | }; | ||
464 | |||
465 | typedef struct SMU71_MclkDpmScoreboard SMU71_MclkDpmScoreboard; | ||
466 | |||
467 | struct SMU71_UlvScoreboard | ||
468 | { | ||
469 | uint8_t EnterUlv; | ||
470 | uint8_t ExitUlv; | ||
471 | uint8_t UlvActive; | ||
472 | uint8_t WaitingForUlv; | ||
473 | uint8_t UlvEnable; | ||
474 | uint8_t UlvRunning; | ||
475 | uint8_t UlvMasterEnable; | ||
476 | uint8_t padding; | ||
477 | uint32_t UlvAbortedCount; | ||
478 | uint32_t UlvTimeStamp; | ||
479 | }; | ||
480 | |||
481 | typedef struct SMU71_UlvScoreboard SMU71_UlvScoreboard; | ||
482 | |||
483 | struct SMU71_VddGfxScoreboard | ||
484 | { | ||
485 | uint8_t VddGfxEnable; | ||
486 | uint8_t VddGfxActive; | ||
487 | uint8_t padding[2]; | ||
488 | |||
489 | uint32_t VddGfxEnteredCount; | ||
490 | uint32_t VddGfxAbortedCount; | ||
491 | }; | ||
492 | |||
493 | typedef struct SMU71_VddGfxScoreboard SMU71_VddGfxScoreboard; | ||
494 | |||
495 | struct SMU71_AcpiScoreboard { | ||
496 | uint32_t SavedInterruptMask[2]; | ||
497 | uint8_t LastACPIRequest; | ||
498 | uint8_t CgBifResp; | ||
499 | uint8_t RequestType; | ||
500 | uint8_t Padding; | ||
501 | SMU71_Discrete_ACPILevel D0Level; | ||
502 | }; | ||
503 | |||
504 | typedef struct SMU71_AcpiScoreboard SMU71_AcpiScoreboard; | ||
505 | |||
506 | |||
507 | struct SMU71_Discrete_PmFuses { | ||
508 | // dw0-dw1 | ||
509 | uint8_t BapmVddCVidHiSidd[8]; | ||
510 | |||
511 | // dw2-dw3 | ||
512 | uint8_t BapmVddCVidLoSidd[8]; | ||
513 | |||
514 | // dw4-dw5 | ||
515 | uint8_t VddCVid[8]; | ||
516 | |||
517 | // dw6 | ||
518 | uint8_t SviLoadLineEn; | ||
519 | uint8_t SviLoadLineVddC; | ||
520 | uint8_t SviLoadLineTrimVddC; | ||
521 | uint8_t SviLoadLineOffsetVddC; | ||
522 | |||
523 | // dw7 | ||
524 | uint16_t TDC_VDDC_PkgLimit; | ||
525 | uint8_t TDC_VDDC_ThrottleReleaseLimitPerc; | ||
526 | uint8_t TDC_MAWt; | ||
527 | |||
528 | // dw8 | ||
529 | uint8_t TdcWaterfallCtl; | ||
530 | uint8_t LPMLTemperatureMin; | ||
531 | uint8_t LPMLTemperatureMax; | ||
532 | uint8_t Reserved; | ||
533 | |||
534 | // dw9-dw12 | ||
535 | uint8_t LPMLTemperatureScaler[16]; | ||
536 | |||
537 | // dw13-dw14 | ||
538 | int16_t FuzzyFan_ErrorSetDelta; | ||
539 | int16_t FuzzyFan_ErrorRateSetDelta; | ||
540 | int16_t FuzzyFan_PwmSetDelta; | ||
541 | uint16_t Reserved6; | ||
542 | |||
543 | // dw15 | ||
544 | uint8_t GnbLPML[16]; | ||
545 | |||
546 | // dw15 | ||
547 | uint8_t GnbLPMLMaxVid; | ||
548 | uint8_t GnbLPMLMinVid; | ||
549 | uint8_t Reserved1[2]; | ||
550 | |||
551 | // dw16 | ||
552 | uint16_t BapmVddCBaseLeakageHiSidd; | ||
553 | uint16_t BapmVddCBaseLeakageLoSidd; | ||
554 | }; | ||
555 | |||
556 | typedef struct SMU71_Discrete_PmFuses SMU71_Discrete_PmFuses; | ||
557 | |||
558 | struct SMU71_Discrete_Log_Header_Table { | ||
559 | uint32_t version; | ||
560 | uint32_t asic_id; | ||
561 | uint16_t flags; | ||
562 | uint16_t entry_size; | ||
563 | uint32_t total_size; | ||
564 | uint32_t num_of_entries; | ||
565 | uint8_t type; | ||
566 | uint8_t mode; | ||
567 | uint8_t filler_0[2]; | ||
568 | uint32_t filler_1[2]; | ||
569 | }; | ||
570 | |||
571 | typedef struct SMU71_Discrete_Log_Header_Table SMU71_Discrete_Log_Header_Table; | ||
572 | |||
573 | struct SMU71_Discrete_Log_Cntl { | ||
574 | uint8_t Enabled; | ||
575 | uint8_t Type; | ||
576 | uint8_t padding[2]; | ||
577 | uint32_t BufferSize; | ||
578 | uint32_t SamplesLogged; | ||
579 | uint32_t SampleSize; | ||
580 | uint32_t AddrL; | ||
581 | uint32_t AddrH; | ||
582 | }; | ||
583 | |||
584 | typedef struct SMU71_Discrete_Log_Cntl SMU71_Discrete_Log_Cntl; | ||
585 | |||
586 | #if defined SMU__DGPU_ONLY | ||
587 | #define CAC_ACC_NW_NUM_OF_SIGNALS 83 | ||
588 | #endif | ||
589 | |||
590 | |||
591 | struct SMU71_Discrete_Cac_Collection_Table { | ||
592 | uint32_t temperature; | ||
593 | uint32_t cac_acc_nw[CAC_ACC_NW_NUM_OF_SIGNALS]; | ||
594 | uint32_t filler[4]; | ||
595 | }; | ||
596 | |||
597 | typedef struct SMU71_Discrete_Cac_Collection_Table SMU71_Discrete_Cac_Collection_Table; | ||
598 | |||
599 | struct SMU71_Discrete_Cac_Verification_Table { | ||
600 | uint32_t VddcTotalPower; | ||
601 | uint32_t VddcLeakagePower; | ||
602 | uint32_t VddcConstantPower; | ||
603 | uint32_t VddcGfxDynamicPower; | ||
604 | uint32_t VddcUvdDynamicPower; | ||
605 | uint32_t VddcVceDynamicPower; | ||
606 | uint32_t VddcAcpDynamicPower; | ||
607 | uint32_t VddcPcieDynamicPower; | ||
608 | uint32_t VddcDceDynamicPower; | ||
609 | uint32_t VddcCurrent; | ||
610 | uint32_t VddcVoltage; | ||
611 | uint32_t VddciTotalPower; | ||
612 | uint32_t VddciLeakagePower; | ||
613 | uint32_t VddciConstantPower; | ||
614 | uint32_t VddciDynamicPower; | ||
615 | uint32_t Vddr1TotalPower; | ||
616 | uint32_t Vddr1LeakagePower; | ||
617 | uint32_t Vddr1ConstantPower; | ||
618 | uint32_t Vddr1DynamicPower; | ||
619 | uint32_t spare[8]; | ||
620 | uint32_t temperature; | ||
621 | }; | ||
622 | |||
623 | typedef struct SMU71_Discrete_Cac_Verification_Table SMU71_Discrete_Cac_Verification_Table; | ||
624 | |||
625 | #if !defined(SMC_MICROCODE) | ||
626 | #pragma pack(pop) | ||
627 | #endif | ||
628 | |||
629 | |||
630 | #endif | ||
631 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile index f10fb64ef981..19e79469f6bc 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile | |||
@@ -2,7 +2,8 @@ | |||
2 | # Makefile for the 'smu manager' sub-component of powerplay. | 2 | # Makefile for the 'smu manager' sub-component of powerplay. |
3 | # It provides the smu management services for the driver. | 3 | # It provides the smu management services for the driver. |
4 | 4 | ||
5 | SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o polaris10_smumgr.o | 5 | SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o \ |
6 | polaris10_smumgr.o iceland_smumgr.o | ||
6 | 7 | ||
7 | AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) | 8 | AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) |
8 | 9 | ||
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 index 000000000000..f50658332d9d --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c | |||
@@ -0,0 +1,713 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/gfp.h> | ||
29 | |||
30 | #include "smumgr.h" | ||
31 | #include "iceland_smumgr.h" | ||
32 | #include "pp_debug.h" | ||
33 | #include "smu_ucode_xfer_vi.h" | ||
34 | #include "ppsmc.h" | ||
35 | #include "smu/smu_7_1_1_d.h" | ||
36 | #include "smu/smu_7_1_1_sh_mask.h" | ||
37 | #include "cgs_common.h" | ||
38 | |||
39 | #define ICELAND_SMC_SIZE 0x20000 | ||
40 | #define BUFFER_SIZE 80000 | ||
41 | #define MAX_STRING_SIZE 15 | ||
42 | #define BUFFER_SIZETWO 131072 /*128 *1024*/ | ||
43 | |||
44 | /** | ||
45 | * Set the address for reading/writing the SMC SRAM space. | ||
46 | * @param smumgr the address of the powerplay hardware manager. | ||
47 | * @param smcAddress the address in the SMC RAM to access. | ||
48 | */ | ||
49 | static int iceland_set_smc_sram_address(struct pp_smumgr *smumgr, | ||
50 | uint32_t smcAddress, uint32_t limit) | ||
51 | { | ||
52 | if (smumgr == NULL || smumgr->device == NULL) | ||
53 | return -EINVAL; | ||
54 | PP_ASSERT_WITH_CODE((0 == (3 & smcAddress)), | ||
55 | "SMC address must be 4 byte aligned.", | ||
56 | return -1;); | ||
57 | |||
58 | PP_ASSERT_WITH_CODE((limit > (smcAddress + 3)), | ||
59 | "SMC address is beyond the SMC RAM area.", | ||
60 | return -1;); | ||
61 | |||
62 | cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smcAddress); | ||
63 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * Copy bytes from an array into the SMC RAM space. | ||
70 | * | ||
71 | * @param smumgr the address of the powerplay SMU manager. | ||
72 | * @param smcStartAddress the start address in the SMC RAM to copy bytes to. | ||
73 | * @param src the byte array to copy the bytes from. | ||
74 | * @param byteCount the number of bytes to copy. | ||
75 | */ | ||
76 | int iceland_copy_bytes_to_smc(struct pp_smumgr *smumgr, | ||
77 | uint32_t smcStartAddress, const uint8_t *src, | ||
78 | uint32_t byteCount, uint32_t limit) | ||
79 | { | ||
80 | uint32_t addr; | ||
81 | uint32_t data, orig_data; | ||
82 | int result = 0; | ||
83 | uint32_t extra_shift; | ||
84 | |||
85 | if (smumgr == NULL || smumgr->device == NULL) | ||
86 | return -EINVAL; | ||
87 | PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)), | ||
88 | "SMC address must be 4 byte aligned.", | ||
89 | return 0;); | ||
90 | |||
91 | PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)), | ||
92 | "SMC address is beyond the SMC RAM area.", | ||
93 | return 0;); | ||
94 | |||
95 | addr = smcStartAddress; | ||
96 | |||
97 | while (byteCount >= 4) { | ||
98 | /* | ||
99 | * Bytes are written into the | ||
100 | * SMC address space with the MSB first | ||
101 | */ | ||
102 | data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; | ||
103 | |||
104 | result = iceland_set_smc_sram_address(smumgr, addr, limit); | ||
105 | |||
106 | if (result) | ||
107 | goto out; | ||
108 | |||
109 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data); | ||
110 | |||
111 | src += 4; | ||
112 | byteCount -= 4; | ||
113 | addr += 4; | ||
114 | } | ||
115 | |||
116 | if (0 != byteCount) { | ||
117 | /* Now write odd bytes left, do a read modify write cycle */ | ||
118 | data = 0; | ||
119 | |||
120 | result = iceland_set_smc_sram_address(smumgr, addr, limit); | ||
121 | if (result) | ||
122 | goto out; | ||
123 | |||
124 | orig_data = cgs_read_register(smumgr->device, | ||
125 | mmSMC_IND_DATA_0); | ||
126 | extra_shift = 8 * (4 - byteCount); | ||
127 | |||
128 | while (byteCount > 0) { | ||
129 | data = (data << 8) + *src++; | ||
130 | byteCount--; | ||
131 | } | ||
132 | |||
133 | data <<= extra_shift; | ||
134 | data |= (orig_data & ~((~0UL) << extra_shift)); | ||
135 | |||
136 | result = iceland_set_smc_sram_address(smumgr, addr, limit); | ||
137 | if (result) | ||
138 | goto out; | ||
139 | |||
140 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data); | ||
141 | } | ||
142 | |||
143 | out: | ||
144 | return result; | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * Deassert the reset'pin' (set it to high). | ||
149 | * | ||
150 | * @param smumgr the address of the powerplay hardware manager. | ||
151 | */ | ||
152 | static int iceland_start_smc(struct pp_smumgr *smumgr) | ||
153 | { | ||
154 | SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | ||
155 | SMC_SYSCON_RESET_CNTL, rst_reg, 0); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static void iceland_pp_reset_smc(struct pp_smumgr *smumgr) | ||
161 | { | ||
162 | SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | ||
163 | SMC_SYSCON_RESET_CNTL, | ||
164 | rst_reg, 1); | ||
165 | } | ||
166 | |||
167 | int iceland_program_jump_on_start(struct pp_smumgr *smumgr) | ||
168 | { | ||
169 | static const unsigned char pData[] = { 0xE0, 0x00, 0x80, 0x40 }; | ||
170 | |||
171 | iceland_copy_bytes_to_smc(smumgr, 0x0, pData, 4, sizeof(pData)+1); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * Return if the SMC is currently running. | ||
178 | * | ||
179 | * @param smumgr the address of the powerplay hardware manager. | ||
180 | */ | ||
181 | bool iceland_is_smc_ram_running(struct pp_smumgr *smumgr) | ||
182 | { | ||
183 | uint32_t val1, val2; | ||
184 | |||
185 | val1 = SMUM_READ_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | ||
186 | SMC_SYSCON_CLOCK_CNTL_0, ck_disable); | ||
187 | val2 = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, | ||
188 | ixSMC_PC_C); | ||
189 | |||
190 | return ((0 == val1) && (0x20100 <= val2)); | ||
191 | } | ||
192 | |||
193 | /** | ||
194 | * Send a message to the SMC, and wait for its response. | ||
195 | * | ||
196 | * @param smumgr the address of the powerplay hardware manager. | ||
197 | * @param msg the message to send. | ||
198 | * @return The response that came from the SMC. | ||
199 | */ | ||
200 | static int iceland_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg) | ||
201 | { | ||
202 | if (smumgr == NULL || smumgr->device == NULL) | ||
203 | return -EINVAL; | ||
204 | |||
205 | if (!iceland_is_smc_ram_running(smumgr)) | ||
206 | return -EINVAL; | ||
207 | |||
208 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | ||
209 | PP_ASSERT_WITH_CODE( | ||
210 | 1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP), | ||
211 | "Failed to send Previous Message.", | ||
212 | ); | ||
213 | |||
214 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); | ||
215 | |||
216 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | ||
217 | PP_ASSERT_WITH_CODE( | ||
218 | 1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP), | ||
219 | "Failed to send Message.", | ||
220 | ); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * Send a message to the SMC with parameter | ||
227 | * | ||
228 | * @param smumgr: the address of the powerplay hardware manager. | ||
229 | * @param msg: the message to send. | ||
230 | * @param parameter: the parameter to send | ||
231 | * @return The response that came from the SMC. | ||
232 | */ | ||
233 | static int iceland_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, | ||
234 | uint16_t msg, uint32_t parameter) | ||
235 | { | ||
236 | if (smumgr == NULL || smumgr->device == NULL) | ||
237 | return -EINVAL; | ||
238 | |||
239 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter); | ||
240 | |||
241 | return iceland_send_msg_to_smc(smumgr, msg); | ||
242 | } | ||
243 | |||
244 | /* | ||
245 | * Read a 32bit value from the SMC SRAM space. | ||
246 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | ||
247 | * @param smumgr the address of the powerplay hardware manager. | ||
248 | * @param smcAddress the address in the SMC RAM to access. | ||
249 | * @param value and output parameter for the data read from the SMC SRAM. | ||
250 | */ | ||
251 | int iceland_read_smc_sram_dword(struct pp_smumgr *smumgr, | ||
252 | uint32_t smcAddress, uint32_t *value, | ||
253 | uint32_t limit) | ||
254 | { | ||
255 | int result; | ||
256 | |||
257 | result = iceland_set_smc_sram_address(smumgr, smcAddress, limit); | ||
258 | |||
259 | if (0 != result) | ||
260 | return result; | ||
261 | |||
262 | *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * Write a 32bit value to the SMC SRAM space. | ||
269 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | ||
270 | * @param smumgr the address of the powerplay hardware manager. | ||
271 | * @param smcAddress the address in the SMC RAM to access. | ||
272 | * @param value to write to the SMC SRAM. | ||
273 | */ | ||
274 | int iceland_write_smc_sram_dword(struct pp_smumgr *smumgr, | ||
275 | uint32_t smcAddress, uint32_t value, | ||
276 | uint32_t limit) | ||
277 | { | ||
278 | int result; | ||
279 | |||
280 | result = iceland_set_smc_sram_address(smumgr, smcAddress, limit); | ||
281 | |||
282 | if (0 != result) | ||
283 | return result; | ||
284 | |||
285 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int iceland_smu_fini(struct pp_smumgr *smumgr) | ||
291 | { | ||
292 | struct iceland_smumgr *priv = (struct iceland_smumgr *)(smumgr->backend); | ||
293 | |||
294 | smu_free_memory(smumgr->device, (void *)priv->header_buffer.handle); | ||
295 | |||
296 | if (smumgr->backend != NULL) { | ||
297 | kfree(smumgr->backend); | ||
298 | smumgr->backend = NULL; | ||
299 | } | ||
300 | |||
301 | cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU); | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static enum cgs_ucode_id iceland_convert_fw_type_to_cgs(uint32_t fw_type) | ||
306 | { | ||
307 | enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; | ||
308 | |||
309 | switch (fw_type) { | ||
310 | case UCODE_ID_SMU: | ||
311 | result = CGS_UCODE_ID_SMU; | ||
312 | break; | ||
313 | case UCODE_ID_SDMA0: | ||
314 | result = CGS_UCODE_ID_SDMA0; | ||
315 | break; | ||
316 | case UCODE_ID_SDMA1: | ||
317 | result = CGS_UCODE_ID_SDMA1; | ||
318 | break; | ||
319 | case UCODE_ID_CP_CE: | ||
320 | result = CGS_UCODE_ID_CP_CE; | ||
321 | break; | ||
322 | case UCODE_ID_CP_PFP: | ||
323 | result = CGS_UCODE_ID_CP_PFP; | ||
324 | break; | ||
325 | case UCODE_ID_CP_ME: | ||
326 | result = CGS_UCODE_ID_CP_ME; | ||
327 | break; | ||
328 | case UCODE_ID_CP_MEC: | ||
329 | result = CGS_UCODE_ID_CP_MEC; | ||
330 | break; | ||
331 | case UCODE_ID_CP_MEC_JT1: | ||
332 | result = CGS_UCODE_ID_CP_MEC_JT1; | ||
333 | break; | ||
334 | case UCODE_ID_CP_MEC_JT2: | ||
335 | result = CGS_UCODE_ID_CP_MEC_JT2; | ||
336 | break; | ||
337 | case UCODE_ID_RLC_G: | ||
338 | result = CGS_UCODE_ID_RLC_G; | ||
339 | break; | ||
340 | default: | ||
341 | break; | ||
342 | } | ||
343 | |||
344 | return result; | ||
345 | } | ||
346 | |||
347 | /** | ||
348 | * Convert the PPIRI firmware type to SMU type mask. | ||
349 | * For MEC, we need to check all MEC related type | ||
350 | */ | ||
351 | static uint16_t iceland_get_mask_for_firmware_type(uint16_t firmwareType) | ||
352 | { | ||
353 | uint16_t result = 0; | ||
354 | |||
355 | switch (firmwareType) { | ||
356 | case UCODE_ID_SDMA0: | ||
357 | result = UCODE_ID_SDMA0_MASK; | ||
358 | break; | ||
359 | case UCODE_ID_SDMA1: | ||
360 | result = UCODE_ID_SDMA1_MASK; | ||
361 | break; | ||
362 | case UCODE_ID_CP_CE: | ||
363 | result = UCODE_ID_CP_CE_MASK; | ||
364 | break; | ||
365 | case UCODE_ID_CP_PFP: | ||
366 | result = UCODE_ID_CP_PFP_MASK; | ||
367 | break; | ||
368 | case UCODE_ID_CP_ME: | ||
369 | result = UCODE_ID_CP_ME_MASK; | ||
370 | break; | ||
371 | case UCODE_ID_CP_MEC: | ||
372 | case UCODE_ID_CP_MEC_JT1: | ||
373 | case UCODE_ID_CP_MEC_JT2: | ||
374 | result = UCODE_ID_CP_MEC_MASK; | ||
375 | break; | ||
376 | case UCODE_ID_RLC_G: | ||
377 | result = UCODE_ID_RLC_G_MASK; | ||
378 | break; | ||
379 | default: | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | return result; | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * Check if the FW has been loaded, | ||
388 | * SMU will not return if loading has not finished. | ||
389 | */ | ||
390 | static int iceland_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fwType) | ||
391 | { | ||
392 | uint16_t fwMask = iceland_get_mask_for_firmware_type(fwType); | ||
393 | |||
394 | if (0 != SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND, | ||
395 | SOFT_REGISTERS_TABLE_27, fwMask, fwMask)) { | ||
396 | pr_err("[ powerplay ] check firmware loading failed\n"); | ||
397 | return -EINVAL; | ||
398 | } | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | /* Populate one firmware image to the data structure */ | ||
404 | static int iceland_populate_single_firmware_entry(struct pp_smumgr *smumgr, | ||
405 | uint16_t firmware_type, | ||
406 | struct SMU_Entry *pentry) | ||
407 | { | ||
408 | int result; | ||
409 | struct cgs_firmware_info info = {0}; | ||
410 | |||
411 | result = cgs_get_firmware_info( | ||
412 | smumgr->device, | ||
413 | iceland_convert_fw_type_to_cgs(firmware_type), | ||
414 | &info); | ||
415 | |||
416 | if (result == 0) { | ||
417 | pentry->version = 0; | ||
418 | pentry->id = (uint16_t)firmware_type; | ||
419 | pentry->image_addr_high = smu_upper_32_bits(info.mc_addr); | ||
420 | pentry->image_addr_low = smu_lower_32_bits(info.mc_addr); | ||
421 | pentry->meta_data_addr_high = 0; | ||
422 | pentry->meta_data_addr_low = 0; | ||
423 | pentry->data_size_byte = info.image_size; | ||
424 | pentry->num_register_entries = 0; | ||
425 | |||
426 | if (firmware_type == UCODE_ID_RLC_G) | ||
427 | pentry->flags = 1; | ||
428 | else | ||
429 | pentry->flags = 0; | ||
430 | } else { | ||
431 | return result; | ||
432 | } | ||
433 | |||
434 | return result; | ||
435 | } | ||
436 | |||
437 | static void iceland_pp_stop_smc_clock(struct pp_smumgr *smumgr) | ||
438 | { | ||
439 | SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | ||
440 | SMC_SYSCON_CLOCK_CNTL_0, | ||
441 | ck_disable, 1); | ||
442 | } | ||
443 | |||
444 | static void iceland_start_smc_clock(struct pp_smumgr *smumgr) | ||
445 | { | ||
446 | SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | ||
447 | SMC_SYSCON_CLOCK_CNTL_0, | ||
448 | ck_disable, 0); | ||
449 | } | ||
450 | |||
451 | int iceland_smu_start_smc(struct pp_smumgr *smumgr) | ||
452 | { | ||
453 | /* set smc instruct start point at 0x0 */ | ||
454 | iceland_program_jump_on_start(smumgr); | ||
455 | |||
456 | /* enable smc clock */ | ||
457 | iceland_start_smc_clock(smumgr); | ||
458 | |||
459 | /* de-assert reset */ | ||
460 | iceland_start_smc(smumgr); | ||
461 | |||
462 | SMUM_WAIT_INDIRECT_FIELD(smumgr, SMC_IND, FIRMWARE_FLAGS, | ||
463 | INTERRUPTS_ENABLED, 1); | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | /** | ||
469 | * Upload the SMC firmware to the SMC microcontroller. | ||
470 | * | ||
471 | * @param smumgr the address of the powerplay hardware manager. | ||
472 | * @param pFirmware the data structure containing the various sections of the firmware. | ||
473 | */ | ||
474 | int iceland_smu_upload_firmware_image(struct pp_smumgr *smumgr) | ||
475 | { | ||
476 | const uint8_t *src; | ||
477 | uint32_t byte_count, val; | ||
478 | uint32_t data; | ||
479 | struct cgs_firmware_info info = {0}; | ||
480 | |||
481 | if (smumgr == NULL || smumgr->device == NULL) | ||
482 | return -EINVAL; | ||
483 | |||
484 | /* load SMC firmware */ | ||
485 | cgs_get_firmware_info(smumgr->device, | ||
486 | iceland_convert_fw_type_to_cgs(UCODE_ID_SMU), &info); | ||
487 | |||
488 | if (info.image_size & 3) { | ||
489 | pr_err("[ powerplay ] SMC ucode is not 4 bytes aligned\n"); | ||
490 | return -EINVAL; | ||
491 | } | ||
492 | |||
493 | if (info.image_size > ICELAND_SMC_SIZE) { | ||
494 | pr_err("[ powerplay ] SMC address is beyond the SMC RAM area\n"); | ||
495 | return -EINVAL; | ||
496 | } | ||
497 | |||
498 | /* wait for smc boot up */ | ||
499 | SMUM_WAIT_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, | ||
500 | RCU_UC_EVENTS, boot_seq_done, 0); | ||
501 | |||
502 | /* clear firmware interrupt enable flag */ | ||
503 | val = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC, | ||
504 | ixSMC_SYSCON_MISC_CNTL); | ||
505 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | ||
506 | ixSMC_SYSCON_MISC_CNTL, val | 1); | ||
507 | |||
508 | /* stop smc clock */ | ||
509 | iceland_pp_stop_smc_clock(smumgr); | ||
510 | |||
511 | /* reset smc */ | ||
512 | iceland_pp_reset_smc(smumgr); | ||
513 | |||
514 | cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, | ||
515 | info.ucode_start_address); | ||
516 | |||
517 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, | ||
518 | AUTO_INCREMENT_IND_0, 1); | ||
519 | |||
520 | byte_count = info.image_size; | ||
521 | src = (const uint8_t *)info.kptr; | ||
522 | |||
523 | while (byte_count >= 4) { | ||
524 | data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; | ||
525 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data); | ||
526 | src += 4; | ||
527 | byte_count -= 4; | ||
528 | } | ||
529 | |||
530 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, | ||
531 | AUTO_INCREMENT_IND_0, 0); | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static int iceland_request_smu_reload_fw(struct pp_smumgr *smumgr) | ||
537 | { | ||
538 | struct iceland_smumgr *iceland_smu = | ||
539 | (struct iceland_smumgr *)(smumgr->backend); | ||
540 | uint16_t fw_to_load; | ||
541 | int result = 0; | ||
542 | struct SMU_DRAMData_TOC *toc; | ||
543 | |||
544 | toc = (struct SMU_DRAMData_TOC *)iceland_smu->pHeader; | ||
545 | toc->num_entries = 0; | ||
546 | toc->structure_version = 1; | ||
547 | |||
548 | PP_ASSERT_WITH_CODE( | ||
549 | 0 == iceland_populate_single_firmware_entry(smumgr, | ||
550 | UCODE_ID_RLC_G, | ||
551 | &toc->entry[toc->num_entries++]), | ||
552 | "Failed to Get Firmware Entry.\n", | ||
553 | return -1); | ||
554 | PP_ASSERT_WITH_CODE( | ||
555 | 0 == iceland_populate_single_firmware_entry(smumgr, | ||
556 | UCODE_ID_CP_CE, | ||
557 | &toc->entry[toc->num_entries++]), | ||
558 | "Failed to Get Firmware Entry.\n", | ||
559 | return -1); | ||
560 | PP_ASSERT_WITH_CODE( | ||
561 | 0 == iceland_populate_single_firmware_entry | ||
562 | (smumgr, UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]), | ||
563 | "Failed to Get Firmware Entry.\n", return -1); | ||
564 | PP_ASSERT_WITH_CODE( | ||
565 | 0 == iceland_populate_single_firmware_entry | ||
566 | (smumgr, UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]), | ||
567 | "Failed to Get Firmware Entry.\n", return -1); | ||
568 | PP_ASSERT_WITH_CODE( | ||
569 | 0 == iceland_populate_single_firmware_entry | ||
570 | (smumgr, UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]), | ||
571 | "Failed to Get Firmware Entry.\n", return -1); | ||
572 | PP_ASSERT_WITH_CODE( | ||
573 | 0 == iceland_populate_single_firmware_entry | ||
574 | (smumgr, UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]), | ||
575 | "Failed to Get Firmware Entry.\n", return -1); | ||
576 | PP_ASSERT_WITH_CODE( | ||
577 | 0 == iceland_populate_single_firmware_entry | ||
578 | (smumgr, UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]), | ||
579 | "Failed to Get Firmware Entry.\n", return -1); | ||
580 | PP_ASSERT_WITH_CODE( | ||
581 | 0 == iceland_populate_single_firmware_entry | ||
582 | (smumgr, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]), | ||
583 | "Failed to Get Firmware Entry.\n", return -1); | ||
584 | PP_ASSERT_WITH_CODE( | ||
585 | 0 == iceland_populate_single_firmware_entry | ||
586 | (smumgr, UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]), | ||
587 | "Failed to Get Firmware Entry.\n", return -1); | ||
588 | |||
589 | if (!iceland_is_smc_ram_running(smumgr)) { | ||
590 | result = iceland_smu_upload_firmware_image(smumgr); | ||
591 | if (result) | ||
592 | return result; | ||
593 | |||
594 | result = iceland_smu_start_smc(smumgr); | ||
595 | if (result) | ||
596 | return result; | ||
597 | } | ||
598 | |||
599 | iceland_send_msg_to_smc_with_parameter(smumgr, | ||
600 | PPSMC_MSG_DRV_DRAM_ADDR_HI, | ||
601 | iceland_smu->header_buffer.mc_addr_high); | ||
602 | |||
603 | iceland_send_msg_to_smc_with_parameter(smumgr, | ||
604 | PPSMC_MSG_DRV_DRAM_ADDR_LO, | ||
605 | iceland_smu->header_buffer.mc_addr_low); | ||
606 | |||
607 | fw_to_load = UCODE_ID_RLC_G_MASK | ||
608 | + UCODE_ID_SDMA0_MASK | ||
609 | + UCODE_ID_SDMA1_MASK | ||
610 | + UCODE_ID_CP_CE_MASK | ||
611 | + UCODE_ID_CP_ME_MASK | ||
612 | + UCODE_ID_CP_PFP_MASK | ||
613 | + UCODE_ID_CP_MEC_MASK | ||
614 | + UCODE_ID_CP_MEC_JT1_MASK | ||
615 | + UCODE_ID_CP_MEC_JT2_MASK; | ||
616 | |||
617 | PP_ASSERT_WITH_CODE( | ||
618 | 0 == iceland_send_msg_to_smc_with_parameter( | ||
619 | smumgr, PPSMC_MSG_LoadUcodes, fw_to_load), | ||
620 | "Fail to Request SMU Load uCode", return 0); | ||
621 | |||
622 | return result; | ||
623 | } | ||
624 | |||
625 | static int iceland_request_smu_load_specific_fw(struct pp_smumgr *smumgr, | ||
626 | uint32_t firmwareType) | ||
627 | { | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static int iceland_start_smu(struct pp_smumgr *smumgr) | ||
632 | { | ||
633 | int result; | ||
634 | |||
635 | result = iceland_smu_upload_firmware_image(smumgr); | ||
636 | if (result) | ||
637 | return result; | ||
638 | |||
639 | result = iceland_smu_start_smc(smumgr); | ||
640 | if (result) | ||
641 | return result; | ||
642 | |||
643 | result = iceland_request_smu_reload_fw(smumgr); | ||
644 | |||
645 | return result; | ||
646 | } | ||
647 | |||
648 | /** | ||
649 | * Write a 32bit value to the SMC SRAM space. | ||
650 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | ||
651 | * @param smumgr the address of the powerplay hardware manager. | ||
652 | * @param smcAddress the address in the SMC RAM to access. | ||
653 | * @param value to write to the SMC SRAM. | ||
654 | */ | ||
655 | static int iceland_smu_init(struct pp_smumgr *smumgr) | ||
656 | { | ||
657 | struct iceland_smumgr *iceland_smu; | ||
658 | uint64_t mc_addr = 0; | ||
659 | |||
660 | /* Allocate memory for backend private data */ | ||
661 | iceland_smu = (struct iceland_smumgr *)(smumgr->backend); | ||
662 | iceland_smu->header_buffer.data_size = | ||
663 | ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; | ||
664 | |||
665 | smu_allocate_memory(smumgr->device, | ||
666 | iceland_smu->header_buffer.data_size, | ||
667 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | ||
668 | PAGE_SIZE, | ||
669 | &mc_addr, | ||
670 | &iceland_smu->header_buffer.kaddr, | ||
671 | &iceland_smu->header_buffer.handle); | ||
672 | |||
673 | iceland_smu->pHeader = iceland_smu->header_buffer.kaddr; | ||
674 | iceland_smu->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); | ||
675 | iceland_smu->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); | ||
676 | |||
677 | PP_ASSERT_WITH_CODE((NULL != iceland_smu->pHeader), | ||
678 | "Out of memory.", | ||
679 | kfree(smumgr->backend); | ||
680 | cgs_free_gpu_mem(smumgr->device, | ||
681 | (cgs_handle_t)iceland_smu->header_buffer.handle); | ||
682 | return -1); | ||
683 | |||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static const struct pp_smumgr_func iceland_smu_funcs = { | ||
688 | .smu_init = &iceland_smu_init, | ||
689 | .smu_fini = &iceland_smu_fini, | ||
690 | .start_smu = &iceland_start_smu, | ||
691 | .check_fw_load_finish = &iceland_check_fw_load_finish, | ||
692 | .request_smu_load_fw = &iceland_request_smu_reload_fw, | ||
693 | .request_smu_load_specific_fw = &iceland_request_smu_load_specific_fw, | ||
694 | .send_msg_to_smc = &iceland_send_msg_to_smc, | ||
695 | .send_msg_to_smc_with_parameter = &iceland_send_msg_to_smc_with_parameter, | ||
696 | .download_pptable_settings = NULL, | ||
697 | .upload_pptable_settings = NULL, | ||
698 | }; | ||
699 | |||
700 | int iceland_smum_init(struct pp_smumgr *smumgr) | ||
701 | { | ||
702 | struct iceland_smumgr *iceland_smu = NULL; | ||
703 | |||
704 | iceland_smu = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL); | ||
705 | |||
706 | if (iceland_smu == NULL) | ||
707 | return -ENOMEM; | ||
708 | |||
709 | smumgr->backend = iceland_smu; | ||
710 | smumgr->smumgr_funcs = &iceland_smu_funcs; | ||
711 | |||
712 | return 0; | ||
713 | } | ||
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 index 000000000000..62009a7ae827 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Author: Huang Rui <ray.huang@amd.com> | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #ifndef _ICELAND_SMUMGR_H_ | ||
27 | #define _ICELAND_SMUMGR_H_ | ||
28 | |||
29 | struct iceland_buffer_entry { | ||
30 | uint32_t data_size; | ||
31 | uint32_t mc_addr_low; | ||
32 | uint32_t mc_addr_high; | ||
33 | void *kaddr; | ||
34 | unsigned long handle; | ||
35 | }; | ||
36 | |||
37 | /* Iceland only has header_buffer, don't have smu buffer. */ | ||
38 | struct iceland_smumgr { | ||
39 | uint8_t *pHeader; | ||
40 | uint8_t *pMecImage; | ||
41 | uint32_t ulSoftRegsStart; | ||
42 | |||
43 | struct iceland_buffer_entry header_buffer; | ||
44 | }; | ||
45 | |||
46 | extern int iceland_smum_init(struct pp_smumgr *smumgr); | ||
47 | extern int iceland_copy_bytes_to_smc(struct pp_smumgr *smumgr, | ||
48 | uint32_t smcStartAddress, | ||
49 | const uint8_t *src, | ||
50 | uint32_t byteCount, uint32_t limit); | ||
51 | |||
52 | extern int iceland_smu_start_smc(struct pp_smumgr *smumgr); | ||
53 | |||
54 | extern int iceland_read_smc_sram_dword(struct pp_smumgr *smumgr, | ||
55 | uint32_t smcAddress, | ||
56 | uint32_t *value, uint32_t limit); | ||
57 | extern int iceland_write_smc_sram_dword(struct pp_smumgr *smumgr, | ||
58 | uint32_t smcAddress, | ||
59 | uint32_t value, uint32_t limit); | ||
60 | |||
61 | extern bool iceland_is_smc_ram_running(struct pp_smumgr *smumgr); | ||
62 | extern int iceland_smu_upload_firmware_image(struct pp_smumgr *smumgr); | ||
63 | |||
64 | #endif | ||
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index 5dba7c509710..704ff4cc0023 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c | |||
@@ -978,7 +978,7 @@ static int polaris10_smu_init(struct pp_smumgr *smumgr) | |||
978 | return 0; | 978 | return 0; |
979 | } | 979 | } |
980 | 980 | ||
981 | static const struct pp_smumgr_func ellsemere_smu_funcs = { | 981 | static const struct pp_smumgr_func polaris10_smu_funcs = { |
982 | .smu_init = polaris10_smu_init, | 982 | .smu_init = polaris10_smu_init, |
983 | .smu_fini = polaris10_smu_fini, | 983 | .smu_fini = polaris10_smu_fini, |
984 | .start_smu = polaris10_start_smu, | 984 | .start_smu = polaris10_start_smu, |
@@ -1001,7 +1001,7 @@ int polaris10_smum_init(struct pp_smumgr *smumgr) | |||
1001 | return -1; | 1001 | return -1; |
1002 | 1002 | ||
1003 | smumgr->backend = polaris10_smu; | 1003 | smumgr->backend = polaris10_smu; |
1004 | smumgr->smumgr_funcs = &ellsemere_smu_funcs; | 1004 | smumgr->smumgr_funcs = &polaris10_smu_funcs; |
1005 | 1005 | ||
1006 | return 0; | 1006 | return 0; |
1007 | } | 1007 | } |
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c index 7723473e51a0..cf3cabee8918 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "linux/delay.h" | 30 | #include "linux/delay.h" |
31 | #include "cz_smumgr.h" | 31 | #include "cz_smumgr.h" |
32 | #include "tonga_smumgr.h" | 32 | #include "tonga_smumgr.h" |
33 | #include "iceland_smumgr.h" | ||
33 | #include "fiji_smumgr.h" | 34 | #include "fiji_smumgr.h" |
34 | #include "polaris10_smumgr.h" | 35 | #include "polaris10_smumgr.h" |
35 | 36 | ||
@@ -58,6 +59,9 @@ int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle) | |||
58 | break; | 59 | break; |
59 | case AMDGPU_FAMILY_VI: | 60 | case AMDGPU_FAMILY_VI: |
60 | switch (smumgr->chip_id) { | 61 | switch (smumgr->chip_id) { |
62 | case CHIP_TOPAZ: | ||
63 | iceland_smum_init(smumgr); | ||
64 | break; | ||
61 | case CHIP_TONGA: | 65 | case CHIP_TONGA: |
62 | tonga_smum_init(smumgr); | 66 | tonga_smum_init(smumgr); |
63 | break; | 67 | break; |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7f2510524f09..7b21281c4b78 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -3480,14 +3480,23 @@ out: | |||
3480 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | 3480 | int drm_mode_page_flip_ioctl(struct drm_device *dev, |
3481 | void *data, struct drm_file *file_priv) | 3481 | void *data, struct drm_file *file_priv) |
3482 | { | 3482 | { |
3483 | struct drm_mode_crtc_page_flip *page_flip = data; | 3483 | struct drm_mode_crtc_page_flip_target *page_flip = data; |
3484 | struct drm_crtc *crtc; | 3484 | struct drm_crtc *crtc; |
3485 | struct drm_framebuffer *fb = NULL; | 3485 | struct drm_framebuffer *fb = NULL; |
3486 | struct drm_pending_vblank_event *e = NULL; | 3486 | struct drm_pending_vblank_event *e = NULL; |
3487 | u32 target_vblank = page_flip->sequence; | ||
3487 | int ret = -EINVAL; | 3488 | int ret = -EINVAL; |
3488 | 3489 | ||
3489 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || | 3490 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS) |
3490 | page_flip->reserved != 0) | 3491 | return -EINVAL; |
3492 | |||
3493 | if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) | ||
3494 | return -EINVAL; | ||
3495 | |||
3496 | /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags | ||
3497 | * can be specified | ||
3498 | */ | ||
3499 | if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET) | ||
3491 | return -EINVAL; | 3500 | return -EINVAL; |
3492 | 3501 | ||
3493 | if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) | 3502 | if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) |
@@ -3497,6 +3506,45 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3497 | if (!crtc) | 3506 | if (!crtc) |
3498 | return -ENOENT; | 3507 | return -ENOENT; |
3499 | 3508 | ||
3509 | if (crtc->funcs->page_flip_target) { | ||
3510 | u32 current_vblank; | ||
3511 | int r; | ||
3512 | |||
3513 | r = drm_crtc_vblank_get(crtc); | ||
3514 | if (r) | ||
3515 | return r; | ||
3516 | |||
3517 | current_vblank = drm_crtc_vblank_count(crtc); | ||
3518 | |||
3519 | switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) { | ||
3520 | case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE: | ||
3521 | if ((int)(target_vblank - current_vblank) > 1) { | ||
3522 | DRM_DEBUG("Invalid absolute flip target %u, " | ||
3523 | "must be <= %u\n", target_vblank, | ||
3524 | current_vblank + 1); | ||
3525 | drm_crtc_vblank_put(crtc); | ||
3526 | return -EINVAL; | ||
3527 | } | ||
3528 | break; | ||
3529 | case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE: | ||
3530 | if (target_vblank != 0 && target_vblank != 1) { | ||
3531 | DRM_DEBUG("Invalid relative flip target %u, " | ||
3532 | "must be 0 or 1\n", target_vblank); | ||
3533 | drm_crtc_vblank_put(crtc); | ||
3534 | return -EINVAL; | ||
3535 | } | ||
3536 | target_vblank += current_vblank; | ||
3537 | break; | ||
3538 | default: | ||
3539 | target_vblank = current_vblank + | ||
3540 | !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC); | ||
3541 | break; | ||
3542 | } | ||
3543 | } else if (crtc->funcs->page_flip == NULL || | ||
3544 | (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) { | ||
3545 | return -EINVAL; | ||
3546 | } | ||
3547 | |||
3500 | drm_modeset_lock_crtc(crtc, crtc->primary); | 3548 | drm_modeset_lock_crtc(crtc, crtc->primary); |
3501 | if (crtc->primary->fb == NULL) { | 3549 | if (crtc->primary->fb == NULL) { |
3502 | /* The framebuffer is currently unbound, presumably | 3550 | /* The framebuffer is currently unbound, presumably |
@@ -3507,9 +3555,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3507 | goto out; | 3555 | goto out; |
3508 | } | 3556 | } |
3509 | 3557 | ||
3510 | if (crtc->funcs->page_flip == NULL) | ||
3511 | goto out; | ||
3512 | |||
3513 | fb = drm_framebuffer_lookup(dev, page_flip->fb_id); | 3558 | fb = drm_framebuffer_lookup(dev, page_flip->fb_id); |
3514 | if (!fb) { | 3559 | if (!fb) { |
3515 | ret = -ENOENT; | 3560 | ret = -ENOENT; |
@@ -3550,7 +3595,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3550 | } | 3595 | } |
3551 | 3596 | ||
3552 | crtc->primary->old_fb = crtc->primary->fb; | 3597 | crtc->primary->old_fb = crtc->primary->fb; |
3553 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); | 3598 | if (crtc->funcs->page_flip_target) |
3599 | ret = crtc->funcs->page_flip_target(crtc, fb, e, | ||
3600 | page_flip->flags, | ||
3601 | target_vblank); | ||
3602 | else | ||
3603 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); | ||
3554 | if (ret) { | 3604 | if (ret) { |
3555 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) | 3605 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) |
3556 | drm_event_cancel_free(dev, &e->base); | 3606 | drm_event_cancel_free(dev, &e->base); |
@@ -3563,6 +3613,8 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3563 | } | 3613 | } |
3564 | 3614 | ||
3565 | out: | 3615 | out: |
3616 | if (ret) | ||
3617 | drm_crtc_vblank_put(crtc); | ||
3566 | if (fb) | 3618 | if (fb) |
3567 | drm_framebuffer_unreference(fb); | 3619 | drm_framebuffer_unreference(fb); |
3568 | if (crtc->primary->old_fb) | 3620 | if (crtc->primary->old_fb) |
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index bb51ee97956d..12b7753a0d27 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
@@ -228,6 +228,7 @@ static int drm_getstats(struct drm_device *dev, void *data, | |||
228 | static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) | 228 | static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) |
229 | { | 229 | { |
230 | struct drm_get_cap *req = data; | 230 | struct drm_get_cap *req = data; |
231 | struct drm_crtc *crtc; | ||
231 | 232 | ||
232 | req->value = 0; | 233 | req->value = 0; |
233 | switch (req->capability) { | 234 | switch (req->capability) { |
@@ -254,6 +255,13 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ | |||
254 | case DRM_CAP_ASYNC_PAGE_FLIP: | 255 | case DRM_CAP_ASYNC_PAGE_FLIP: |
255 | req->value = dev->mode_config.async_page_flip; | 256 | req->value = dev->mode_config.async_page_flip; |
256 | break; | 257 | break; |
258 | case DRM_CAP_PAGE_FLIP_TARGET: | ||
259 | req->value = 1; | ||
260 | drm_for_each_crtc(crtc, dev) { | ||
261 | if (!crtc->funcs->page_flip_target) | ||
262 | req->value = 0; | ||
263 | } | ||
264 | break; | ||
257 | case DRM_CAP_CURSOR_WIDTH: | 265 | case DRM_CAP_CURSOR_WIDTH: |
258 | if (dev->mode_config.cursor_width) | 266 | if (dev->mode_config.cursor_width) |
259 | req->value = dev->mode_config.cursor_width; | 267 | req->value = dev->mode_config.cursor_width; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 6190035edfea..8ab9ce5089fe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
@@ -1151,7 +1151,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, | |||
1151 | if (ret) | 1151 | if (ret) |
1152 | goto out; | 1152 | goto out; |
1153 | 1153 | ||
1154 | ret = ttm_bo_move_ttm(bo, true, intr, no_wait_gpu, new_mem); | 1154 | ret = ttm_bo_move_ttm(bo, intr, no_wait_gpu, new_mem); |
1155 | out: | 1155 | out: |
1156 | ttm_bo_mem_put(bo, &tmp_mem); | 1156 | ttm_bo_mem_put(bo, &tmp_mem); |
1157 | return ret; | 1157 | return ret; |
@@ -1179,7 +1179,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, | |||
1179 | if (ret) | 1179 | if (ret) |
1180 | return ret; | 1180 | return ret; |
1181 | 1181 | ||
1182 | ret = ttm_bo_move_ttm(bo, true, intr, no_wait_gpu, &tmp_mem); | 1182 | ret = ttm_bo_move_ttm(bo, intr, no_wait_gpu, &tmp_mem); |
1183 | if (ret) | 1183 | if (ret) |
1184 | goto out; | 1184 | goto out; |
1185 | 1185 | ||
@@ -1297,7 +1297,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, | |||
1297 | /* Fallback to software copy. */ | 1297 | /* Fallback to software copy. */ |
1298 | ret = ttm_bo_wait(bo, intr, no_wait_gpu); | 1298 | ret = ttm_bo_wait(bo, intr, no_wait_gpu); |
1299 | if (ret == 0) | 1299 | if (ret == 0) |
1300 | ret = ttm_bo_move_memcpy(bo, evict, intr, no_wait_gpu, new_mem); | 1300 | ret = ttm_bo_move_memcpy(bo, intr, no_wait_gpu, new_mem); |
1301 | 1301 | ||
1302 | out: | 1302 | out: |
1303 | if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { | 1303 | if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { |
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index d50c9679e631..6a22de045cb5 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c | |||
@@ -361,8 +361,8 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, | |||
361 | qxl_move_null(bo, new_mem); | 361 | qxl_move_null(bo, new_mem); |
362 | return 0; | 362 | return 0; |
363 | } | 363 | } |
364 | return ttm_bo_move_memcpy(bo, evict, interruptible, | 364 | return ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, |
365 | no_wait_gpu, new_mem); | 365 | new_mem); |
366 | } | 366 | } |
367 | 367 | ||
368 | static void qxl_bo_move_notify(struct ttm_buffer_object *bo, | 368 | static void qxl_bo_move_notify(struct ttm_buffer_object *bo, |
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index a89c4803aced..4824f70b0258 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -1435,8 +1435,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, | |||
1435 | WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, | 1435 | WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, |
1436 | (viewport_w << 16) | viewport_h); | 1436 | (viewport_w << 16) | viewport_h); |
1437 | 1437 | ||
1438 | /* set pageflip to happen only at start of vblank interval (front porch) */ | 1438 | /* set pageflip to happen anywhere in vblank interval */ |
1439 | WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); | 1439 | WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); |
1440 | 1440 | ||
1441 | if (!atomic && fb && fb != crtc->primary->fb) { | 1441 | if (!atomic && fb && fb != crtc->primary->fb) { |
1442 | radeon_fb = to_radeon_framebuffer(fb); | 1442 | radeon_fb = to_radeon_framebuffer(fb); |
@@ -1636,8 +1636,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, | |||
1636 | WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, | 1636 | WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, |
1637 | (viewport_w << 16) | viewport_h); | 1637 | (viewport_w << 16) | viewport_h); |
1638 | 1638 | ||
1639 | /* set pageflip to happen only at start of vblank interval (front porch) */ | 1639 | /* set pageflip to happen anywhere in vblank interval */ |
1640 | WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); | 1640 | WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); |
1641 | 1641 | ||
1642 | if (!atomic && fb && fb != crtc->primary->fb) { | 1642 | if (!atomic && fb && fb != crtc->primary->fb) { |
1643 | radeon_fb = to_radeon_framebuffer(fb); | 1643 | radeon_fb = to_radeon_framebuffer(fb); |
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index cead089a9e7d..432cb46f6a34 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c | |||
@@ -389,22 +389,21 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) | |||
389 | { | 389 | { |
390 | struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; | 390 | struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; |
391 | u8 msg[DP_DPCD_SIZE]; | 391 | u8 msg[DP_DPCD_SIZE]; |
392 | int ret, i; | 392 | int ret; |
393 | 393 | ||
394 | for (i = 0; i < 7; i++) { | 394 | ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg, |
395 | ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg, | 395 | DP_DPCD_SIZE); |
396 | DP_DPCD_SIZE); | 396 | if (ret == DP_DPCD_SIZE) { |
397 | if (ret == DP_DPCD_SIZE) { | 397 | memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); |
398 | memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); | ||
399 | 398 | ||
400 | DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd), | 399 | DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd), |
401 | dig_connector->dpcd); | 400 | dig_connector->dpcd); |
402 | 401 | ||
403 | radeon_dp_probe_oui(radeon_connector); | 402 | radeon_dp_probe_oui(radeon_connector); |
404 | 403 | ||
405 | return true; | 404 | return true; |
406 | } | ||
407 | } | 405 | } |
406 | |||
408 | dig_connector->dpcd[0] = 0; | 407 | dig_connector->dpcd[0] = 0; |
409 | return false; | 408 | return false; |
410 | } | 409 | } |
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 0c1b9ff433af..b1784a1b482a 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c | |||
@@ -1871,7 +1871,7 @@ int ci_mc_load_microcode(struct radeon_device *rdev) | |||
1871 | { | 1871 | { |
1872 | const __be32 *fw_data = NULL; | 1872 | const __be32 *fw_data = NULL; |
1873 | const __le32 *new_fw_data = NULL; | 1873 | const __le32 *new_fw_data = NULL; |
1874 | u32 running, blackout = 0, tmp; | 1874 | u32 running, tmp; |
1875 | u32 *io_mc_regs = NULL; | 1875 | u32 *io_mc_regs = NULL; |
1876 | const __le32 *new_io_mc_regs = NULL; | 1876 | const __le32 *new_io_mc_regs = NULL; |
1877 | int i, regs_size, ucode_size; | 1877 | int i, regs_size, ucode_size; |
@@ -1912,11 +1912,6 @@ int ci_mc_load_microcode(struct radeon_device *rdev) | |||
1912 | running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; | 1912 | running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; |
1913 | 1913 | ||
1914 | if (running == 0) { | 1914 | if (running == 0) { |
1915 | if (running) { | ||
1916 | blackout = RREG32(MC_SHARED_BLACKOUT_CNTL); | ||
1917 | WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1); | ||
1918 | } | ||
1919 | |||
1920 | /* reset the engine and set to writable */ | 1915 | /* reset the engine and set to writable */ |
1921 | WREG32(MC_SEQ_SUP_CNTL, 0x00000008); | 1916 | WREG32(MC_SEQ_SUP_CNTL, 0x00000008); |
1922 | WREG32(MC_SEQ_SUP_CNTL, 0x00000010); | 1917 | WREG32(MC_SEQ_SUP_CNTL, 0x00000010); |
@@ -1964,9 +1959,6 @@ int ci_mc_load_microcode(struct radeon_device *rdev) | |||
1964 | break; | 1959 | break; |
1965 | udelay(1); | 1960 | udelay(1); |
1966 | } | 1961 | } |
1967 | |||
1968 | if (running) | ||
1969 | WREG32(MC_SHARED_BLACKOUT_CNTL, blackout); | ||
1970 | } | 1962 | } |
1971 | 1963 | ||
1972 | return 0; | 1964 | return 0; |
@@ -8215,7 +8207,7 @@ static void cik_uvd_resume(struct radeon_device *rdev) | |||
8215 | return; | 8207 | return; |
8216 | 8208 | ||
8217 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | 8209 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
8218 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); | 8210 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0)); |
8219 | if (r) { | 8211 | if (r) { |
8220 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); | 8212 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); |
8221 | return; | 8213 | return; |
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index cead2284fd79..48db93577c1d 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h | |||
@@ -2069,6 +2069,7 @@ | |||
2069 | #define UVD_UDEC_ADDR_CONFIG 0xef4c | 2069 | #define UVD_UDEC_ADDR_CONFIG 0xef4c |
2070 | #define UVD_UDEC_DB_ADDR_CONFIG 0xef50 | 2070 | #define UVD_UDEC_DB_ADDR_CONFIG 0xef50 |
2071 | #define UVD_UDEC_DBW_ADDR_CONFIG 0xef54 | 2071 | #define UVD_UDEC_DBW_ADDR_CONFIG 0xef54 |
2072 | #define UVD_NO_OP 0xeffc | ||
2072 | 2073 | ||
2073 | #define UVD_LMI_EXT40_ADDR 0xf498 | 2074 | #define UVD_LMI_EXT40_ADDR 0xf498 |
2074 | #define UVD_GP_SCRATCH4 0xf4e0 | 2075 | #define UVD_GP_SCRATCH4 0xf4e0 |
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index db275b7ed34a..0b6b5766216f 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c | |||
@@ -2878,9 +2878,8 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s | |||
2878 | for (i = 0; i < rdev->num_crtc; i++) { | 2878 | for (i = 0; i < rdev->num_crtc; i++) { |
2879 | if (save->crtc_enabled[i]) { | 2879 | if (save->crtc_enabled[i]) { |
2880 | tmp = RREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i]); | 2880 | tmp = RREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i]); |
2881 | if ((tmp & 0x7) != 3) { | 2881 | if ((tmp & 0x7) != 0) { |
2882 | tmp &= ~0x7; | 2882 | tmp &= ~0x7; |
2883 | tmp |= 0x3; | ||
2884 | WREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i], tmp); | 2883 | WREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i], tmp); |
2885 | } | 2884 | } |
2886 | tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]); | 2885 | tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]); |
@@ -5580,7 +5579,7 @@ static void evergreen_uvd_resume(struct radeon_device *rdev) | |||
5580 | return; | 5579 | return; |
5581 | 5580 | ||
5582 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | 5581 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
5583 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); | 5582 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0)); |
5584 | if (r) { | 5583 | if (r) { |
5585 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); | 5584 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); |
5586 | return; | 5585 | return; |
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index c8e3d394cde7..f3d88ca2aa8f 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h | |||
@@ -1523,6 +1523,7 @@ | |||
1523 | #define UVD_UDEC_ADDR_CONFIG 0xef4c | 1523 | #define UVD_UDEC_ADDR_CONFIG 0xef4c |
1524 | #define UVD_UDEC_DB_ADDR_CONFIG 0xef50 | 1524 | #define UVD_UDEC_DB_ADDR_CONFIG 0xef50 |
1525 | #define UVD_UDEC_DBW_ADDR_CONFIG 0xef54 | 1525 | #define UVD_UDEC_DBW_ADDR_CONFIG 0xef54 |
1526 | #define UVD_NO_OP 0xeffc | ||
1526 | #define UVD_RBC_RB_RPTR 0xf690 | 1527 | #define UVD_RBC_RB_RPTR 0xf690 |
1527 | #define UVD_RBC_RB_WPTR 0xf694 | 1528 | #define UVD_RBC_RB_WPTR 0xf694 |
1528 | #define UVD_STATUS 0xf6bc | 1529 | #define UVD_STATUS 0xf6bc |
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 4a3d7cab83f7..103fc8650197 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c | |||
@@ -2062,7 +2062,7 @@ static void cayman_uvd_resume(struct radeon_device *rdev) | |||
2062 | return; | 2062 | return; |
2063 | 2063 | ||
2064 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | 2064 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
2065 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); | 2065 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0)); |
2066 | if (r) { | 2066 | if (r) { |
2067 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); | 2067 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); |
2068 | return; | 2068 | return; |
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index 47eb49b77d32..3c9fec88ea44 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h | |||
@@ -1137,6 +1137,7 @@ | |||
1137 | #define UVD_UDEC_ADDR_CONFIG 0xEF4C | 1137 | #define UVD_UDEC_ADDR_CONFIG 0xEF4C |
1138 | #define UVD_UDEC_DB_ADDR_CONFIG 0xEF50 | 1138 | #define UVD_UDEC_DB_ADDR_CONFIG 0xEF50 |
1139 | #define UVD_UDEC_DBW_ADDR_CONFIG 0xEF54 | 1139 | #define UVD_UDEC_DBW_ADDR_CONFIG 0xEF54 |
1140 | #define UVD_NO_OP 0xEFFC | ||
1140 | #define UVD_RBC_RB_RPTR 0xF690 | 1141 | #define UVD_RBC_RB_RPTR 0xF690 |
1141 | #define UVD_RBC_RB_WPTR 0xF694 | 1142 | #define UVD_RBC_RB_WPTR 0xF694 |
1142 | #define UVD_STATUS 0xf6bc | 1143 | #define UVD_STATUS 0xf6bc |
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 9247e7d207fe..640653606f86 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
@@ -3097,7 +3097,7 @@ static void r600_uvd_resume(struct radeon_device *rdev) | |||
3097 | return; | 3097 | return; |
3098 | 3098 | ||
3099 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | 3099 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
3100 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); | 3100 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0)); |
3101 | if (r) { | 3101 | if (r) { |
3102 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); | 3102 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); |
3103 | return; | 3103 | return; |
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 1e8495cca41e..2e00a5287bd2 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h | |||
@@ -1490,6 +1490,7 @@ | |||
1490 | #define UVD_GPCOM_VCPU_DATA0 0xef10 | 1490 | #define UVD_GPCOM_VCPU_DATA0 0xef10 |
1491 | #define UVD_GPCOM_VCPU_DATA1 0xef14 | 1491 | #define UVD_GPCOM_VCPU_DATA1 0xef14 |
1492 | #define UVD_ENGINE_CNTL 0xef18 | 1492 | #define UVD_ENGINE_CNTL 0xef18 |
1493 | #define UVD_NO_OP 0xeffc | ||
1493 | 1494 | ||
1494 | #define UVD_SEMA_CNTL 0xf400 | 1495 | #define UVD_SEMA_CNTL 0xf400 |
1495 | #define UVD_RB_ARB_CTRL 0xf480 | 1496 | #define UVD_RB_ARB_CTRL 0xf480 |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5633ee3eb46e..1b0dcad916b0 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -742,6 +742,7 @@ struct radeon_flip_work { | |||
742 | struct work_struct unpin_work; | 742 | struct work_struct unpin_work; |
743 | struct radeon_device *rdev; | 743 | struct radeon_device *rdev; |
744 | int crtc_id; | 744 | int crtc_id; |
745 | u32 target_vblank; | ||
745 | uint64_t base; | 746 | uint64_t base; |
746 | struct drm_pending_vblank_event *event; | 747 | struct drm_pending_vblank_event *event; |
747 | struct radeon_bo *old_rbo; | 748 | struct radeon_bo *old_rbo; |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index c3206fb8f4cf..890171f08987 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -400,14 +400,13 @@ static void radeon_flip_work_func(struct work_struct *__work) | |||
400 | struct radeon_flip_work *work = | 400 | struct radeon_flip_work *work = |
401 | container_of(__work, struct radeon_flip_work, flip_work); | 401 | container_of(__work, struct radeon_flip_work, flip_work); |
402 | struct radeon_device *rdev = work->rdev; | 402 | struct radeon_device *rdev = work->rdev; |
403 | struct drm_device *dev = rdev->ddev; | ||
403 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id]; | 404 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id]; |
404 | 405 | ||
405 | struct drm_crtc *crtc = &radeon_crtc->base; | 406 | struct drm_crtc *crtc = &radeon_crtc->base; |
406 | unsigned long flags; | 407 | unsigned long flags; |
407 | int r; | 408 | int r; |
408 | int vpos, hpos, stat, min_udelay = 0; | 409 | int vpos, hpos; |
409 | unsigned repcnt = 4; | ||
410 | struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; | ||
411 | 410 | ||
412 | down_read(&rdev->exclusive_lock); | 411 | down_read(&rdev->exclusive_lock); |
413 | if (work->fence) { | 412 | if (work->fence) { |
@@ -438,59 +437,25 @@ static void radeon_flip_work_func(struct work_struct *__work) | |||
438 | work->fence = NULL; | 437 | work->fence = NULL; |
439 | } | 438 | } |
440 | 439 | ||
440 | /* Wait until we're out of the vertical blank period before the one | ||
441 | * targeted by the flip | ||
442 | */ | ||
443 | while (radeon_crtc->enabled && | ||
444 | (radeon_get_crtc_scanoutpos(dev, work->crtc_id, 0, | ||
445 | &vpos, &hpos, NULL, NULL, | ||
446 | &crtc->hwmode) | ||
447 | & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == | ||
448 | (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) && | ||
449 | (int)(work->target_vblank - | ||
450 | dev->driver->get_vblank_counter(dev, work->crtc_id)) > 0) | ||
451 | usleep_range(1000, 2000); | ||
452 | |||
441 | /* We borrow the event spin lock for protecting flip_status */ | 453 | /* We borrow the event spin lock for protecting flip_status */ |
442 | spin_lock_irqsave(&crtc->dev->event_lock, flags); | 454 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
443 | 455 | ||
444 | /* set the proper interrupt */ | 456 | /* set the proper interrupt */ |
445 | radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); | 457 | radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); |
446 | 458 | ||
447 | /* If this happens to execute within the "virtually extended" vblank | ||
448 | * interval before the start of the real vblank interval then it needs | ||
449 | * to delay programming the mmio flip until the real vblank is entered. | ||
450 | * This prevents completing a flip too early due to the way we fudge | ||
451 | * our vblank counter and vblank timestamps in order to work around the | ||
452 | * problem that the hw fires vblank interrupts before actual start of | ||
453 | * vblank (when line buffer refilling is done for a frame). It | ||
454 | * complements the fudging logic in radeon_get_crtc_scanoutpos() for | ||
455 | * timestamping and radeon_get_vblank_counter_kms() for vblank counts. | ||
456 | * | ||
457 | * In practice this won't execute very often unless on very fast | ||
458 | * machines because the time window for this to happen is very small. | ||
459 | */ | ||
460 | while (radeon_crtc->enabled && --repcnt) { | ||
461 | /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank | ||
462 | * start in hpos, and to the "fudged earlier" vblank start in | ||
463 | * vpos. | ||
464 | */ | ||
465 | stat = radeon_get_crtc_scanoutpos(rdev->ddev, work->crtc_id, | ||
466 | GET_DISTANCE_TO_VBLANKSTART, | ||
467 | &vpos, &hpos, NULL, NULL, | ||
468 | &crtc->hwmode); | ||
469 | |||
470 | if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != | ||
471 | (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) || | ||
472 | !(vpos >= 0 && hpos <= 0)) | ||
473 | break; | ||
474 | |||
475 | /* Sleep at least until estimated real start of hw vblank */ | ||
476 | min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); | ||
477 | if (min_udelay > vblank->framedur_ns / 2000) { | ||
478 | /* Don't wait ridiculously long - something is wrong */ | ||
479 | repcnt = 0; | ||
480 | break; | ||
481 | } | ||
482 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | ||
483 | usleep_range(min_udelay, 2 * min_udelay); | ||
484 | spin_lock_irqsave(&crtc->dev->event_lock, flags); | ||
485 | }; | ||
486 | |||
487 | if (!repcnt) | ||
488 | DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, " | ||
489 | "framedur %d, linedur %d, stat %d, vpos %d, " | ||
490 | "hpos %d\n", work->crtc_id, min_udelay, | ||
491 | vblank->framedur_ns / 1000, | ||
492 | vblank->linedur_ns / 1000, stat, vpos, hpos); | ||
493 | |||
494 | /* do the flip (mmio) */ | 459 | /* do the flip (mmio) */ |
495 | radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base, work->async); | 460 | radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base, work->async); |
496 | 461 | ||
@@ -499,10 +464,11 @@ static void radeon_flip_work_func(struct work_struct *__work) | |||
499 | up_read(&rdev->exclusive_lock); | 464 | up_read(&rdev->exclusive_lock); |
500 | } | 465 | } |
501 | 466 | ||
502 | static int radeon_crtc_page_flip(struct drm_crtc *crtc, | 467 | static int radeon_crtc_page_flip_target(struct drm_crtc *crtc, |
503 | struct drm_framebuffer *fb, | 468 | struct drm_framebuffer *fb, |
504 | struct drm_pending_vblank_event *event, | 469 | struct drm_pending_vblank_event *event, |
505 | uint32_t page_flip_flags) | 470 | uint32_t page_flip_flags, |
471 | uint32_t target) | ||
506 | { | 472 | { |
507 | struct drm_device *dev = crtc->dev; | 473 | struct drm_device *dev = crtc->dev; |
508 | struct radeon_device *rdev = dev->dev_private; | 474 | struct radeon_device *rdev = dev->dev_private; |
@@ -599,12 +565,8 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, | |||
599 | base &= ~7; | 565 | base &= ~7; |
600 | } | 566 | } |
601 | work->base = base; | 567 | work->base = base; |
602 | 568 | work->target_vblank = target - drm_crtc_vblank_count(crtc) + | |
603 | r = drm_crtc_vblank_get(crtc); | 569 | dev->driver->get_vblank_counter(dev, work->crtc_id); |
604 | if (r) { | ||
605 | DRM_ERROR("failed to get vblank before flip\n"); | ||
606 | goto pflip_cleanup; | ||
607 | } | ||
608 | 570 | ||
609 | /* We borrow the event spin lock for protecting flip_work */ | 571 | /* We borrow the event spin lock for protecting flip_work */ |
610 | spin_lock_irqsave(&crtc->dev->event_lock, flags); | 572 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
@@ -613,7 +575,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, | |||
613 | DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); | 575 | DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); |
614 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | 576 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); |
615 | r = -EBUSY; | 577 | r = -EBUSY; |
616 | goto vblank_cleanup; | 578 | goto pflip_cleanup; |
617 | } | 579 | } |
618 | radeon_crtc->flip_status = RADEON_FLIP_PENDING; | 580 | radeon_crtc->flip_status = RADEON_FLIP_PENDING; |
619 | radeon_crtc->flip_work = work; | 581 | radeon_crtc->flip_work = work; |
@@ -626,9 +588,6 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, | |||
626 | queue_work(radeon_crtc->flip_queue, &work->flip_work); | 588 | queue_work(radeon_crtc->flip_queue, &work->flip_work); |
627 | return 0; | 589 | return 0; |
628 | 590 | ||
629 | vblank_cleanup: | ||
630 | drm_crtc_vblank_put(crtc); | ||
631 | |||
632 | pflip_cleanup: | 591 | pflip_cleanup: |
633 | if (unlikely(radeon_bo_reserve(new_rbo, false) != 0)) { | 592 | if (unlikely(radeon_bo_reserve(new_rbo, false) != 0)) { |
634 | DRM_ERROR("failed to reserve new rbo in error path\n"); | 593 | DRM_ERROR("failed to reserve new rbo in error path\n"); |
@@ -697,7 +656,7 @@ static const struct drm_crtc_funcs radeon_crtc_funcs = { | |||
697 | .gamma_set = radeon_crtc_gamma_set, | 656 | .gamma_set = radeon_crtc_gamma_set, |
698 | .set_config = radeon_crtc_set_config, | 657 | .set_config = radeon_crtc_set_config, |
699 | .destroy = radeon_crtc_destroy, | 658 | .destroy = radeon_crtc_destroy, |
700 | .page_flip = radeon_crtc_page_flip, | 659 | .page_flip_target = radeon_crtc_page_flip_target, |
701 | }; | 660 | }; |
702 | 661 | ||
703 | static void radeon_crtc_init(struct drm_device *dev, int index) | 662 | static void radeon_crtc_init(struct drm_device *dev, int index) |
diff --git a/drivers/gpu/drm/radeon/radeon_dp_auxch.c b/drivers/gpu/drm/radeon/radeon_dp_auxch.c index db64e0062689..2d465648856a 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_auxch.c +++ b/drivers/gpu/drm/radeon/radeon_dp_auxch.c | |||
@@ -164,7 +164,6 @@ radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg | |||
164 | } | 164 | } |
165 | 165 | ||
166 | if (tmp & AUX_SW_RX_TIMEOUT) { | 166 | if (tmp & AUX_SW_RX_TIMEOUT) { |
167 | DRM_DEBUG_KMS("dp_aux_ch timed out\n"); | ||
168 | ret = -ETIMEDOUT; | 167 | ret = -ETIMEDOUT; |
169 | goto done; | 168 | goto done; |
170 | } | 169 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 90f2ff217b31..07e44931f1f1 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c | |||
@@ -95,9 +95,10 @@ | |||
95 | * 2.44.0 - SET_APPEND_CNT packet3 support | 95 | * 2.44.0 - SET_APPEND_CNT packet3 support |
96 | * 2.45.0 - Allow setting shader registers using DMA/COPY packet3 on SI | 96 | * 2.45.0 - Allow setting shader registers using DMA/COPY packet3 on SI |
97 | * 2.46.0 - Add PFP_SYNC_ME support on evergreen | 97 | * 2.46.0 - Add PFP_SYNC_ME support on evergreen |
98 | * 2.47.0 - Add UVD_NO_OP register support | ||
98 | */ | 99 | */ |
99 | #define KMS_DRIVER_MAJOR 2 | 100 | #define KMS_DRIVER_MAJOR 2 |
100 | #define KMS_DRIVER_MINOR 46 | 101 | #define KMS_DRIVER_MINOR 47 |
101 | #define KMS_DRIVER_PATCHLEVEL 0 | 102 | #define KMS_DRIVER_PATCHLEVEL 0 |
102 | int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); | 103 | int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); |
103 | int radeon_driver_unload_kms(struct drm_device *dev); | 104 | int radeon_driver_unload_kms(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 9590bcd321c0..021aa005623f 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c | |||
@@ -938,10 +938,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, | |||
938 | "Radeon i2c hw bus %s", name); | 938 | "Radeon i2c hw bus %s", name); |
939 | i2c->adapter.algo = &radeon_i2c_algo; | 939 | i2c->adapter.algo = &radeon_i2c_algo; |
940 | ret = i2c_add_adapter(&i2c->adapter); | 940 | ret = i2c_add_adapter(&i2c->adapter); |
941 | if (ret) { | 941 | if (ret) |
942 | DRM_ERROR("Failed to register hw i2c %s\n", name); | ||
943 | goto out_free; | 942 | goto out_free; |
944 | } | ||
945 | } else if (rec->hw_capable && | 943 | } else if (rec->hw_capable && |
946 | radeon_hw_i2c && | 944 | radeon_hw_i2c && |
947 | ASIC_IS_DCE3(rdev)) { | 945 | ASIC_IS_DCE3(rdev)) { |
@@ -950,10 +948,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, | |||
950 | "Radeon i2c hw bus %s", name); | 948 | "Radeon i2c hw bus %s", name); |
951 | i2c->adapter.algo = &radeon_atom_i2c_algo; | 949 | i2c->adapter.algo = &radeon_atom_i2c_algo; |
952 | ret = i2c_add_adapter(&i2c->adapter); | 950 | ret = i2c_add_adapter(&i2c->adapter); |
953 | if (ret) { | 951 | if (ret) |
954 | DRM_ERROR("Failed to register hw i2c %s\n", name); | ||
955 | goto out_free; | 952 | goto out_free; |
956 | } | ||
957 | } else { | 953 | } else { |
958 | /* set the radeon bit adapter */ | 954 | /* set the radeon bit adapter */ |
959 | snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), | 955 | snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), |
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 0c00e192c845..93414aca60d6 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c | |||
@@ -346,7 +346,7 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo, | |||
346 | if (unlikely(r)) { | 346 | if (unlikely(r)) { |
347 | goto out_cleanup; | 347 | goto out_cleanup; |
348 | } | 348 | } |
349 | r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, new_mem); | 349 | r = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, new_mem); |
350 | out_cleanup: | 350 | out_cleanup: |
351 | ttm_bo_mem_put(bo, &tmp_mem); | 351 | ttm_bo_mem_put(bo, &tmp_mem); |
352 | return r; | 352 | return r; |
@@ -379,7 +379,7 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo, | |||
379 | if (unlikely(r)) { | 379 | if (unlikely(r)) { |
380 | return r; | 380 | return r; |
381 | } | 381 | } |
382 | r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, &tmp_mem); | 382 | r = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, &tmp_mem); |
383 | if (unlikely(r)) { | 383 | if (unlikely(r)) { |
384 | goto out_cleanup; | 384 | goto out_cleanup; |
385 | } | 385 | } |
@@ -444,8 +444,7 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, | |||
444 | 444 | ||
445 | if (r) { | 445 | if (r) { |
446 | memcpy: | 446 | memcpy: |
447 | r = ttm_bo_move_memcpy(bo, evict, interruptible, | 447 | r = ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, new_mem); |
448 | no_wait_gpu, new_mem); | ||
449 | if (r) { | 448 | if (r) { |
450 | return r; | 449 | return r; |
451 | } | 450 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 73dfe01435ea..0cd0e7bdee55 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c | |||
@@ -669,6 +669,7 @@ static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, | |||
669 | return r; | 669 | return r; |
670 | break; | 670 | break; |
671 | case UVD_ENGINE_CNTL: | 671 | case UVD_ENGINE_CNTL: |
672 | case UVD_NO_OP: | ||
672 | break; | 673 | break; |
673 | default: | 674 | default: |
674 | DRM_ERROR("Invalid reg 0x%X!\n", | 675 | DRM_ERROR("Invalid reg 0x%X!\n", |
@@ -753,8 +754,10 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev, | |||
753 | ib.ptr[3] = addr >> 32; | 754 | ib.ptr[3] = addr >> 32; |
754 | ib.ptr[4] = PACKET0(UVD_GPCOM_VCPU_CMD, 0); | 755 | ib.ptr[4] = PACKET0(UVD_GPCOM_VCPU_CMD, 0); |
755 | ib.ptr[5] = 0; | 756 | ib.ptr[5] = 0; |
756 | for (i = 6; i < 16; ++i) | 757 | for (i = 6; i < 16; i += 2) { |
757 | ib.ptr[i] = PACKET2(0); | 758 | ib.ptr[i] = PACKET0(UVD_NO_OP, 0); |
759 | ib.ptr[i+1] = 0; | ||
760 | } | ||
758 | ib.length_dw = 16; | 761 | ib.length_dw = 16; |
759 | 762 | ||
760 | r = radeon_ib_schedule(rdev, &ib, NULL, false); | 763 | r = radeon_ib_schedule(rdev, &ib, NULL, false); |
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index c55d653aaf5f..76c55c5d11ec 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c | |||
@@ -406,9 +406,8 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) | |||
406 | for (i = 0; i < rdev->num_crtc; i++) { | 406 | for (i = 0; i < rdev->num_crtc; i++) { |
407 | if (save->crtc_enabled[i]) { | 407 | if (save->crtc_enabled[i]) { |
408 | tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i]); | 408 | tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i]); |
409 | if ((tmp & 0x7) != 3) { | 409 | if ((tmp & 0x7) != 0) { |
410 | tmp &= ~0x7; | 410 | tmp &= ~0x7; |
411 | tmp |= 0x3; | ||
412 | WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i], tmp); | 411 | WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i], tmp); |
413 | } | 412 | } |
414 | tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); | 413 | tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); |
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 1c120a4c3c97..729ae588c970 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c | |||
@@ -1738,7 +1738,7 @@ static void rv770_uvd_resume(struct radeon_device *rdev) | |||
1738 | return; | 1738 | return; |
1739 | 1739 | ||
1740 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | 1740 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
1741 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); | 1741 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0)); |
1742 | if (r) { | 1742 | if (r) { |
1743 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); | 1743 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); |
1744 | return; | 1744 | return; |
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 9ef2064b1c9c..0271f4c559ae 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h | |||
@@ -387,6 +387,7 @@ | |||
387 | #define UVD_UDEC_TILING_CONFIG 0xef40 | 387 | #define UVD_UDEC_TILING_CONFIG 0xef40 |
388 | #define UVD_UDEC_DB_TILING_CONFIG 0xef44 | 388 | #define UVD_UDEC_DB_TILING_CONFIG 0xef44 |
389 | #define UVD_UDEC_DBW_TILING_CONFIG 0xef48 | 389 | #define UVD_UDEC_DBW_TILING_CONFIG 0xef48 |
390 | #define UVD_NO_OP 0xeffc | ||
390 | 391 | ||
391 | #define GC_USER_SHADER_PIPE_CONFIG 0x8954 | 392 | #define GC_USER_SHADER_PIPE_CONFIG 0x8954 |
392 | #define INACTIVE_QD_PIPES(x) ((x) << 8) | 393 | #define INACTIVE_QD_PIPES(x) ((x) << 8) |
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 2523ca96c6c7..7ee9aafbdf74 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c | |||
@@ -1547,7 +1547,7 @@ int si_mc_load_microcode(struct radeon_device *rdev) | |||
1547 | { | 1547 | { |
1548 | const __be32 *fw_data = NULL; | 1548 | const __be32 *fw_data = NULL; |
1549 | const __le32 *new_fw_data = NULL; | 1549 | const __le32 *new_fw_data = NULL; |
1550 | u32 running, blackout = 0; | 1550 | u32 running; |
1551 | u32 *io_mc_regs = NULL; | 1551 | u32 *io_mc_regs = NULL; |
1552 | const __le32 *new_io_mc_regs = NULL; | 1552 | const __le32 *new_io_mc_regs = NULL; |
1553 | int i, regs_size, ucode_size; | 1553 | int i, regs_size, ucode_size; |
@@ -1598,11 +1598,6 @@ int si_mc_load_microcode(struct radeon_device *rdev) | |||
1598 | running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; | 1598 | running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; |
1599 | 1599 | ||
1600 | if (running == 0) { | 1600 | if (running == 0) { |
1601 | if (running) { | ||
1602 | blackout = RREG32(MC_SHARED_BLACKOUT_CNTL); | ||
1603 | WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1); | ||
1604 | } | ||
1605 | |||
1606 | /* reset the engine and set to writable */ | 1601 | /* reset the engine and set to writable */ |
1607 | WREG32(MC_SEQ_SUP_CNTL, 0x00000008); | 1602 | WREG32(MC_SEQ_SUP_CNTL, 0x00000008); |
1608 | WREG32(MC_SEQ_SUP_CNTL, 0x00000010); | 1603 | WREG32(MC_SEQ_SUP_CNTL, 0x00000010); |
@@ -1641,9 +1636,6 @@ int si_mc_load_microcode(struct radeon_device *rdev) | |||
1641 | break; | 1636 | break; |
1642 | udelay(1); | 1637 | udelay(1); |
1643 | } | 1638 | } |
1644 | |||
1645 | if (running) | ||
1646 | WREG32(MC_SHARED_BLACKOUT_CNTL, blackout); | ||
1647 | } | 1639 | } |
1648 | 1640 | ||
1649 | return 0; | 1641 | return 0; |
@@ -6928,7 +6920,7 @@ static void si_uvd_resume(struct radeon_device *rdev) | |||
6928 | return; | 6920 | return; |
6929 | 6921 | ||
6930 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | 6922 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
6931 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); | 6923 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, PACKET0(UVD_NO_OP, 0)); |
6932 | if (r) { | 6924 | if (r) { |
6933 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); | 6925 | dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); |
6934 | return; | 6926 | return; |
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index d1a7b58dd291..eb220eecba78 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h | |||
@@ -1559,6 +1559,7 @@ | |||
1559 | #define UVD_UDEC_ADDR_CONFIG 0xEF4C | 1559 | #define UVD_UDEC_ADDR_CONFIG 0xEF4C |
1560 | #define UVD_UDEC_DB_ADDR_CONFIG 0xEF50 | 1560 | #define UVD_UDEC_DB_ADDR_CONFIG 0xEF50 |
1561 | #define UVD_UDEC_DBW_ADDR_CONFIG 0xEF54 | 1561 | #define UVD_UDEC_DBW_ADDR_CONFIG 0xEF54 |
1562 | #define UVD_NO_OP 0xEFFC | ||
1562 | #define UVD_RBC_RB_RPTR 0xF690 | 1563 | #define UVD_RBC_RB_RPTR 0xF690 |
1563 | #define UVD_RBC_RB_WPTR 0xF694 | 1564 | #define UVD_RBC_RB_WPTR 0xF694 |
1564 | #define UVD_STATUS 0xf6bc | 1565 | #define UVD_STATUS 0xf6bc |
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 42c074a9c955..c2a30bdc8a01 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c | |||
@@ -354,14 +354,12 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, | |||
354 | 354 | ||
355 | if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) && | 355 | if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) && |
356 | !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) | 356 | !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) |
357 | ret = ttm_bo_move_ttm(bo, evict, interruptible, no_wait_gpu, | 357 | ret = ttm_bo_move_ttm(bo, interruptible, no_wait_gpu, mem); |
358 | mem); | ||
359 | else if (bdev->driver->move) | 358 | else if (bdev->driver->move) |
360 | ret = bdev->driver->move(bo, evict, interruptible, | 359 | ret = bdev->driver->move(bo, evict, interruptible, |
361 | no_wait_gpu, mem); | 360 | no_wait_gpu, mem); |
362 | else | 361 | else |
363 | ret = ttm_bo_move_memcpy(bo, evict, interruptible, | 362 | ret = ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, mem); |
364 | no_wait_gpu, mem); | ||
365 | 363 | ||
366 | if (ret) { | 364 | if (ret) { |
367 | if (bdev->driver->move_notify) { | 365 | if (bdev->driver->move_notify) { |
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index f157a9efd220..bf6e21655c57 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c | |||
@@ -45,8 +45,8 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo) | |||
45 | } | 45 | } |
46 | 46 | ||
47 | int ttm_bo_move_ttm(struct ttm_buffer_object *bo, | 47 | int ttm_bo_move_ttm(struct ttm_buffer_object *bo, |
48 | bool evict, bool interruptible, | 48 | bool interruptible, bool no_wait_gpu, |
49 | bool no_wait_gpu, struct ttm_mem_reg *new_mem) | 49 | struct ttm_mem_reg *new_mem) |
50 | { | 50 | { |
51 | struct ttm_tt *ttm = bo->ttm; | 51 | struct ttm_tt *ttm = bo->ttm; |
52 | struct ttm_mem_reg *old_mem = &bo->mem; | 52 | 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, | |||
329 | } | 329 | } |
330 | 330 | ||
331 | int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, | 331 | int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, |
332 | bool evict, bool interruptible, | 332 | bool interruptible, bool no_wait_gpu, |
333 | bool no_wait_gpu, | ||
334 | struct ttm_mem_reg *new_mem) | 333 | struct ttm_mem_reg *new_mem) |
335 | { | 334 | { |
336 | struct ttm_bo_device *bdev = bo->bdev; | 335 | struct ttm_bo_device *bdev = bo->bdev; |
diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c index a1803fbcc898..29855be96be0 100644 --- a/drivers/gpu/drm/ttm/ttm_memory.c +++ b/drivers/gpu/drm/ttm/ttm_memory.c | |||
@@ -600,3 +600,9 @@ size_t ttm_round_pot(size_t size) | |||
600 | return 0; | 600 | return 0; |
601 | } | 601 | } |
602 | EXPORT_SYMBOL(ttm_round_pot); | 602 | EXPORT_SYMBOL(ttm_round_pot); |
603 | |||
604 | uint64_t ttm_get_kernel_zone_memory_size(struct ttm_mem_global *glob) | ||
605 | { | ||
606 | return glob->zone_kernel->max_mem; | ||
607 | } | ||
608 | EXPORT_SYMBOL(ttm_get_kernel_zone_memory_size); | ||
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 3fa0275e509f..7c8a77b181c2 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -391,6 +391,24 @@ struct drm_crtc_funcs { | |||
391 | uint32_t flags); | 391 | uint32_t flags); |
392 | 392 | ||
393 | /** | 393 | /** |
394 | * @page_flip_target: | ||
395 | * | ||
396 | * Same as @page_flip but with an additional parameter specifying the | ||
397 | * absolute target vertical blank period (as reported by | ||
398 | * drm_crtc_vblank_count()) when the flip should take effect. | ||
399 | * | ||
400 | * Note that the core code calls drm_crtc_vblank_get before this entry | ||
401 | * point, and will call drm_crtc_vblank_put if this entry point returns | ||
402 | * any non-0 error code. It's the driver's responsibility to call | ||
403 | * drm_crtc_vblank_put after this entry point returns 0, typically when | ||
404 | * the flip completes. | ||
405 | */ | ||
406 | int (*page_flip_target)(struct drm_crtc *crtc, | ||
407 | struct drm_framebuffer *fb, | ||
408 | struct drm_pending_vblank_event *event, | ||
409 | uint32_t flags, uint32_t target); | ||
410 | |||
411 | /** | ||
394 | * @set_property: | 412 | * @set_property: |
395 | * | 413 | * |
396 | * This is the legacy entry point to update a property attached to the | 414 | * This is the legacy entry point to update a property attached to the |
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 99c6d01d24f2..c986fa7effd2 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h | |||
@@ -961,7 +961,6 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev, | |||
961 | * ttm_bo_move_ttm | 961 | * ttm_bo_move_ttm |
962 | * | 962 | * |
963 | * @bo: A pointer to a struct ttm_buffer_object. | 963 | * @bo: A pointer to a struct ttm_buffer_object. |
964 | * @evict: 1: This is an eviction. Don't try to pipeline. | ||
965 | * @interruptible: Sleep interruptible if waiting. | 964 | * @interruptible: Sleep interruptible if waiting. |
966 | * @no_wait_gpu: Return immediately if the GPU is busy. | 965 | * @no_wait_gpu: Return immediately if the GPU is busy. |
967 | * @new_mem: struct ttm_mem_reg indicating where to move. | 966 | * @new_mem: struct ttm_mem_reg indicating where to move. |
@@ -977,14 +976,13 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev, | |||
977 | */ | 976 | */ |
978 | 977 | ||
979 | extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo, | 978 | extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo, |
980 | bool evict, bool interruptible, bool no_wait_gpu, | 979 | bool interruptible, bool no_wait_gpu, |
981 | struct ttm_mem_reg *new_mem); | 980 | struct ttm_mem_reg *new_mem); |
982 | 981 | ||
983 | /** | 982 | /** |
984 | * ttm_bo_move_memcpy | 983 | * ttm_bo_move_memcpy |
985 | * | 984 | * |
986 | * @bo: A pointer to a struct ttm_buffer_object. | 985 | * @bo: A pointer to a struct ttm_buffer_object. |
987 | * @evict: 1: This is an eviction. Don't try to pipeline. | ||
988 | * @interruptible: Sleep interruptible if waiting. | 986 | * @interruptible: Sleep interruptible if waiting. |
989 | * @no_wait_gpu: Return immediately if the GPU is busy. | 987 | * @no_wait_gpu: Return immediately if the GPU is busy. |
990 | * @new_mem: struct ttm_mem_reg indicating where to move. | 988 | * @new_mem: struct ttm_mem_reg indicating where to move. |
@@ -1000,8 +998,7 @@ extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo, | |||
1000 | */ | 998 | */ |
1001 | 999 | ||
1002 | extern int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, | 1000 | extern int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, |
1003 | bool evict, bool interruptible, | 1001 | bool interruptible, bool no_wait_gpu, |
1004 | bool no_wait_gpu, | ||
1005 | struct ttm_mem_reg *new_mem); | 1002 | struct ttm_mem_reg *new_mem); |
1006 | 1003 | ||
1007 | /** | 1004 | /** |
diff --git a/include/drm/ttm/ttm_memory.h b/include/drm/ttm/ttm_memory.h index 72dcbe81dd07..c4520890f267 100644 --- a/include/drm/ttm/ttm_memory.h +++ b/include/drm/ttm/ttm_memory.h | |||
@@ -155,4 +155,5 @@ extern int ttm_mem_global_alloc_page(struct ttm_mem_global *glob, | |||
155 | extern void ttm_mem_global_free_page(struct ttm_mem_global *glob, | 155 | extern void ttm_mem_global_free_page(struct ttm_mem_global *glob, |
156 | struct page *page); | 156 | struct page *page); |
157 | extern size_t ttm_round_pot(size_t size); | 157 | extern size_t ttm_round_pot(size_t size); |
158 | extern uint64_t ttm_get_kernel_zone_memory_size(struct ttm_mem_global *glob); | ||
158 | #endif | 159 | #endif |
diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 462246aa200e..ae2845fdcb5f 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h | |||
@@ -77,6 +77,10 @@ extern "C" { | |||
77 | #define AMDGPU_GEM_CREATE_NO_CPU_ACCESS (1 << 1) | 77 | #define AMDGPU_GEM_CREATE_NO_CPU_ACCESS (1 << 1) |
78 | /* Flag that USWC attributes should be used for GTT */ | 78 | /* Flag that USWC attributes should be used for GTT */ |
79 | #define AMDGPU_GEM_CREATE_CPU_GTT_USWC (1 << 2) | 79 | #define AMDGPU_GEM_CREATE_CPU_GTT_USWC (1 << 2) |
80 | /* Flag that the memory should be in VRAM and cleared */ | ||
81 | #define AMDGPU_GEM_CREATE_VRAM_CLEARED (1 << 3) | ||
82 | /* Flag that create shadow bo(GTT) while allocating vram bo */ | ||
83 | #define AMDGPU_GEM_CREATE_SHADOW (1 << 4) | ||
80 | 84 | ||
81 | struct drm_amdgpu_gem_create_in { | 85 | struct drm_amdgpu_gem_create_in { |
82 | /** the requested memory size */ | 86 | /** the requested memory size */ |
@@ -481,6 +485,8 @@ struct drm_amdgpu_cs_chunk_data { | |||
481 | #define AMDGPU_INFO_DEV_INFO 0x16 | 485 | #define AMDGPU_INFO_DEV_INFO 0x16 |
482 | /* visible vram usage */ | 486 | /* visible vram usage */ |
483 | #define AMDGPU_INFO_VIS_VRAM_USAGE 0x17 | 487 | #define AMDGPU_INFO_VIS_VRAM_USAGE 0x17 |
488 | /* number of TTM buffer evictions */ | ||
489 | #define AMDGPU_INFO_NUM_EVICTIONS 0x18 | ||
484 | 490 | ||
485 | #define AMDGPU_INFO_MMR_SE_INDEX_SHIFT 0 | 491 | #define AMDGPU_INFO_MMR_SE_INDEX_SHIFT 0 |
486 | #define AMDGPU_INFO_MMR_SE_INDEX_MASK 0xff | 492 | #define AMDGPU_INFO_MMR_SE_INDEX_MASK 0xff |
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 452675fb55d9..b2c52843bc70 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h | |||
@@ -646,6 +646,7 @@ struct drm_gem_open { | |||
646 | #define DRM_CAP_CURSOR_WIDTH 0x8 | 646 | #define DRM_CAP_CURSOR_WIDTH 0x8 |
647 | #define DRM_CAP_CURSOR_HEIGHT 0x9 | 647 | #define DRM_CAP_CURSOR_HEIGHT 0x9 |
648 | #define DRM_CAP_ADDFB2_MODIFIERS 0x10 | 648 | #define DRM_CAP_ADDFB2_MODIFIERS 0x10 |
649 | #define DRM_CAP_PAGE_FLIP_TARGET 0x11 | ||
649 | 650 | ||
650 | /** DRM_IOCTL_GET_CAP ioctl argument type */ | 651 | /** DRM_IOCTL_GET_CAP ioctl argument type */ |
651 | struct drm_get_cap { | 652 | struct drm_get_cap { |
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 49a72659b801..df0e3504c349 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h | |||
@@ -520,7 +520,13 @@ struct drm_color_lut { | |||
520 | 520 | ||
521 | #define DRM_MODE_PAGE_FLIP_EVENT 0x01 | 521 | #define DRM_MODE_PAGE_FLIP_EVENT 0x01 |
522 | #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 | 522 | #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 |
523 | #define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT|DRM_MODE_PAGE_FLIP_ASYNC) | 523 | #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 |
524 | #define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8 | ||
525 | #define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \ | ||
526 | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE) | ||
527 | #define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \ | ||
528 | DRM_MODE_PAGE_FLIP_ASYNC | \ | ||
529 | DRM_MODE_PAGE_FLIP_TARGET) | ||
524 | 530 | ||
525 | /* | 531 | /* |
526 | * Request a page flip on the specified crtc. | 532 | * Request a page flip on the specified crtc. |
@@ -543,8 +549,7 @@ struct drm_color_lut { | |||
543 | * 'as soon as possible', meaning that it not delay waiting for vblank. | 549 | * 'as soon as possible', meaning that it not delay waiting for vblank. |
544 | * This may cause tearing on the screen. | 550 | * This may cause tearing on the screen. |
545 | * | 551 | * |
546 | * The reserved field must be zero until we figure out something | 552 | * The reserved field must be zero. |
547 | * clever to use it for. | ||
548 | */ | 553 | */ |
549 | 554 | ||
550 | struct drm_mode_crtc_page_flip { | 555 | struct drm_mode_crtc_page_flip { |
@@ -555,6 +560,34 @@ struct drm_mode_crtc_page_flip { | |||
555 | __u64 user_data; | 560 | __u64 user_data; |
556 | }; | 561 | }; |
557 | 562 | ||
563 | /* | ||
564 | * Request a page flip on the specified crtc. | ||
565 | * | ||
566 | * Same as struct drm_mode_crtc_page_flip, but supports new flags and | ||
567 | * re-purposes the reserved field: | ||
568 | * | ||
569 | * The sequence field must be zero unless either of the | ||
570 | * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is specified. When | ||
571 | * the ABSOLUTE flag is specified, the sequence field denotes the absolute | ||
572 | * vblank sequence when the flip should take effect. When the RELATIVE | ||
573 | * flag is specified, the sequence field denotes the relative (to the | ||
574 | * current one when the ioctl is called) vblank sequence when the flip | ||
575 | * should take effect. NOTE: DRM_IOCTL_WAIT_VBLANK must still be used to | ||
576 | * make sure the vblank sequence before the target one has passed before | ||
577 | * calling this ioctl. The purpose of the | ||
578 | * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is merely to clarify | ||
579 | * the target for when code dealing with a page flip runs during a | ||
580 | * vertical blank period. | ||
581 | */ | ||
582 | |||
583 | struct drm_mode_crtc_page_flip_target { | ||
584 | __u32 crtc_id; | ||
585 | __u32 fb_id; | ||
586 | __u32 flags; | ||
587 | __u32 sequence; | ||
588 | __u64 user_data; | ||
589 | }; | ||
590 | |||
558 | /* create a dumb scanout buffer */ | 591 | /* create a dumb scanout buffer */ |
559 | struct drm_mode_create_dumb { | 592 | struct drm_mode_create_dumb { |
560 | __u32 height; | 593 | __u32 height; |