提交 565c17b5 编写于 作者: D Dave Airlie

Merge branch 'drm-next-4.19' of git://people.freedesktop.org/~agd5f/linux into drm-next

First feature request for 4.19.  Highlights:
- Add initial amdgpu documentation
- Add initial GPU scheduler documention
- GPU scheduler fixes for dying processes
- Add support for the JPEG engine on VCN
- Switch CI to use powerplay by default
- EDC support for CZ
- More powerplay cleanups
- Misc DC fixes
Signed-off-by: NDave Airlie <airlied@redhat.com>

Link: https://patchwork.freedesktop.org/patch/msgid/20180621161138.3008-1-alexander.deucher@amd.com
=========================
drm/amdgpu AMDgpu driver
=========================
The drm/amdgpu driver supports all AMD Radeon GPUs based on the Graphics Core
Next (GCN) architecture.
Core Driver Infrastructure
==========================
This section covers core driver infrastructure.
.. _amdgpu_memory_domains:
Memory Domains
--------------
.. kernel-doc:: include/uapi/drm/amdgpu_drm.h
:doc: memory domains
Buffer Objects
--------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
:doc: amdgpu_object
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
:internal:
PRIME Buffer Sharing
--------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
:doc: PRIME Buffer Sharing
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
:internal:
MMU Notifier
------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
:doc: MMU Notifier
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
:internal:
AMDGPU Virtual Memory
---------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
:doc: GPUVM
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
:internal:
Interrupt Handling
------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
:doc: Interrupt Handling
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
:internal:
GPU Power/Thermal Controls and Monitoring
=========================================
This section covers hwmon and power/thermal controls.
HWMON Interfaces
----------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: hwmon
GPU sysfs Power State Interfaces
--------------------------------
GPU power controls are exposed via sysfs files.
power_dpm_state
~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: power_dpm_state
power_dpm_force_performance_level
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: power_dpm_force_performance_level
pp_table
~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: pp_table
pp_od_clk_voltage
~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: pp_od_clk_voltage
pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie
pp_power_profile_mode
~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
:doc: pp_power_profile_mode
...@@ -4,6 +4,7 @@ GPU Driver Documentation ...@@ -4,6 +4,7 @@ GPU Driver Documentation
.. toctree:: .. toctree::
amdgpu
i915 i915
meson meson
pl111 pl111
......
...@@ -395,6 +395,8 @@ VMA Offset Manager ...@@ -395,6 +395,8 @@ VMA Offset Manager
.. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c .. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c
:export: :export:
.. _prime_buffer_sharing:
PRIME Buffer Sharing PRIME Buffer Sharing
==================== ====================
...@@ -496,3 +498,21 @@ DRM Sync Objects ...@@ -496,3 +498,21 @@ DRM Sync Objects
.. kernel-doc:: drivers/gpu/drm/drm_syncobj.c .. kernel-doc:: drivers/gpu/drm/drm_syncobj.c
:export: :export:
GPU Scheduler
=============
Overview
--------
.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler.c
:doc: Overview
Scheduler Function References
-----------------------------
.. kernel-doc:: include/drm/gpu_scheduler.h
:internal:
.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler.c
:export:
...@@ -136,6 +136,7 @@ ...@@ -136,6 +136,7 @@
#define GENERIC_OBJECT_ID_PX2_NON_DRIVABLE 0x02 #define GENERIC_OBJECT_ID_PX2_NON_DRIVABLE 0x02
#define GENERIC_OBJECT_ID_MXM_OPM 0x03 #define GENERIC_OBJECT_ID_MXM_OPM 0x03
#define GENERIC_OBJECT_ID_STEREO_PIN 0x04 //This object could show up from Misc Object table, it follows ATOM_OBJECT format, and contains one ATOM_OBJECT_GPIO_CNTL_RECORD for the stereo pin #define GENERIC_OBJECT_ID_STEREO_PIN 0x04 //This object could show up from Misc Object table, it follows ATOM_OBJECT format, and contains one ATOM_OBJECT_GPIO_CNTL_RECORD for the stereo pin
#define GENERIC_OBJECT_ID_BRACKET_LAYOUT 0x05
/****************************************************/ /****************************************************/
/* Graphics Object ENUM ID Definition */ /* Graphics Object ENUM ID Definition */
...@@ -714,6 +715,13 @@ ...@@ -714,6 +715,13 @@
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
GENERIC_OBJECT_ID_STEREO_PIN << OBJECT_ID_SHIFT) GENERIC_OBJECT_ID_STEREO_PIN << OBJECT_ID_SHIFT)
#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT)
#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT)
/****************************************************/ /****************************************************/
/* Object Cap definition - Shared with BIOS */ /* Object Cap definition - Shared with BIOS */
/****************************************************/ /****************************************************/
......
...@@ -968,6 +968,8 @@ struct amdgpu_gfx { ...@@ -968,6 +968,8 @@ struct amdgpu_gfx {
struct amdgpu_irq_src eop_irq; struct amdgpu_irq_src eop_irq;
struct amdgpu_irq_src priv_reg_irq; struct amdgpu_irq_src priv_reg_irq;
struct amdgpu_irq_src priv_inst_irq; struct amdgpu_irq_src priv_inst_irq;
struct amdgpu_irq_src cp_ecc_error_irq;
struct amdgpu_irq_src sq_irq;
/* gfx status */ /* gfx status */
uint32_t gfx_current_status; uint32_t gfx_current_status;
/* ce ram size*/ /* ce ram size*/
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <drm/drm_syncobj.h> #include <drm/drm_syncobj.h>
#include "amdgpu.h" #include "amdgpu.h"
#include "amdgpu_trace.h" #include "amdgpu_trace.h"
#include "amdgpu_gmc.h"
static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p, static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
struct drm_amdgpu_cs_chunk_fence *data, struct drm_amdgpu_cs_chunk_fence *data,
...@@ -302,7 +303,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, ...@@ -302,7 +303,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,
*max_bytes = us_to_bytes(adev, adev->mm_stats.accum_us); *max_bytes = us_to_bytes(adev, adev->mm_stats.accum_us);
/* Do the same for visible VRAM if half of it is free */ /* Do the same for visible VRAM if half of it is free */
if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size) { if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) {
u64 total_vis_vram = adev->gmc.visible_vram_size; u64 total_vis_vram = adev->gmc.visible_vram_size;
u64 used_vis_vram = u64 used_vis_vram =
amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
...@@ -359,7 +360,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, ...@@ -359,7 +360,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
* to move it. Don't move anything if the threshold is zero. * to move it. Don't move anything if the threshold is zero.
*/ */
if (p->bytes_moved < p->bytes_moved_threshold) { if (p->bytes_moved < p->bytes_moved_threshold) {
if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
(bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) { (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) {
/* And don't move a CPU_ACCESS_REQUIRED BO to limited /* And don't move a CPU_ACCESS_REQUIRED BO to limited
* visible VRAM if we've depleted our allowance to do * visible VRAM if we've depleted our allowance to do
...@@ -381,7 +382,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, ...@@ -381,7 +382,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
p->bytes_moved += ctx.bytes_moved; p->bytes_moved += ctx.bytes_moved;
if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
amdgpu_bo_in_cpu_visible_vram(bo)) amdgpu_bo_in_cpu_visible_vram(bo))
p->bytes_moved_vis += ctx.bytes_moved; p->bytes_moved_vis += ctx.bytes_moved;
...@@ -434,7 +435,7 @@ static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p, ...@@ -434,7 +435,7 @@ static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p,
/* Good we can try to move this BO somewhere else */ /* Good we can try to move this BO somewhere else */
update_bytes_moved_vis = update_bytes_moved_vis =
adev->gmc.visible_vram_size < adev->gmc.real_vram_size && !amdgpu_gmc_vram_full_visible(&adev->gmc) &&
amdgpu_bo_in_cpu_visible_vram(bo); amdgpu_bo_in_cpu_visible_vram(bo);
amdgpu_ttm_placement_from_domain(bo, other); amdgpu_ttm_placement_from_domain(bo, other);
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
......
...@@ -449,26 +449,28 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) ...@@ -449,26 +449,28 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
struct amdgpu_ctx *ctx; struct amdgpu_ctx *ctx;
struct idr *idp; struct idr *idp;
uint32_t id, i; uint32_t id, i;
long max_wait = MAX_WAIT_SCHED_ENTITY_Q_EMPTY;
idp = &mgr->ctx_handles; idp = &mgr->ctx_handles;
mutex_lock(&mgr->lock);
idr_for_each_entry(idp, ctx, id) { idr_for_each_entry(idp, ctx, id) {
if (!ctx->adev) if (!ctx->adev) {
mutex_unlock(&mgr->lock);
return; return;
}
for (i = 0; i < ctx->adev->num_rings; i++) { for (i = 0; i < ctx->adev->num_rings; i++) {
if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring) if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring)
continue; continue;
if (kref_read(&ctx->refcount) == 1) max_wait = drm_sched_entity_do_release(&ctx->adev->rings[i]->sched,
drm_sched_entity_do_release(&ctx->adev->rings[i]->sched, &ctx->rings[i].entity, max_wait);
&ctx->rings[i].entity);
else
DRM_ERROR("ctx %p is still alive\n", ctx);
} }
} }
mutex_unlock(&mgr->lock);
} }
void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr) void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr)
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* Alex Deucher * Alex Deucher
* Jerome Glisse * Jerome Glisse
*/ */
#include <linux/power_supply.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -675,17 +676,15 @@ void amdgpu_device_vram_location(struct amdgpu_device *adev, ...@@ -675,17 +676,15 @@ void amdgpu_device_vram_location(struct amdgpu_device *adev,
} }
/** /**
* amdgpu_device_gart_location - try to find GTT location * amdgpu_device_gart_location - try to find GART location
* *
* @adev: amdgpu device structure holding all necessary informations * @adev: amdgpu device structure holding all necessary informations
* @mc: memory controller structure holding memory informations * @mc: memory controller structure holding memory informations
* *
* Function will place try to place GTT before or after VRAM. * Function will place try to place GART before or after VRAM.
* *
* If GTT size is bigger than space left then we ajust GTT size. * If GART size is bigger than space left then we ajust GART size.
* Thus function will never fails. * Thus function will never fails.
*
* FIXME: when reducing GTT size align new size on power of 2.
*/ */
void amdgpu_device_gart_location(struct amdgpu_device *adev, void amdgpu_device_gart_location(struct amdgpu_device *adev,
struct amdgpu_gmc *mc) struct amdgpu_gmc *mc)
...@@ -698,13 +697,13 @@ void amdgpu_device_gart_location(struct amdgpu_device *adev, ...@@ -698,13 +697,13 @@ void amdgpu_device_gart_location(struct amdgpu_device *adev,
size_bf = mc->vram_start; size_bf = mc->vram_start;
if (size_bf > size_af) { if (size_bf > size_af) {
if (mc->gart_size > size_bf) { if (mc->gart_size > size_bf) {
dev_warn(adev->dev, "limiting GTT\n"); dev_warn(adev->dev, "limiting GART\n");
mc->gart_size = size_bf; mc->gart_size = size_bf;
} }
mc->gart_start = 0; mc->gart_start = 0;
} else { } else {
if (mc->gart_size > size_af) { if (mc->gart_size > size_af) {
dev_warn(adev->dev, "limiting GTT\n"); dev_warn(adev->dev, "limiting GART\n");
mc->gart_size = size_af; mc->gart_size = size_af;
} }
/* VCE doesn't like it when BOs cross a 4GB segment, so align /* VCE doesn't like it when BOs cross a 4GB segment, so align
...@@ -713,7 +712,7 @@ void amdgpu_device_gart_location(struct amdgpu_device *adev, ...@@ -713,7 +712,7 @@ void amdgpu_device_gart_location(struct amdgpu_device *adev,
mc->gart_start = ALIGN(mc->vram_end + 1, 0x100000000ULL); mc->gart_start = ALIGN(mc->vram_end + 1, 0x100000000ULL);
} }
mc->gart_end = mc->gart_start + mc->gart_size - 1; mc->gart_end = mc->gart_start + mc->gart_size - 1;
dev_info(adev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n", dev_info(adev->dev, "GART: %lluM 0x%016llX - 0x%016llX\n",
mc->gart_size >> 20, mc->gart_start, mc->gart_end); mc->gart_size >> 20, mc->gart_start, mc->gart_end);
} }
...@@ -1926,7 +1925,7 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev) ...@@ -1926,7 +1925,7 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev)
if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) if (adev->powerplay.pp_feature & PP_GFXOFF_MASK)
amdgpu_device_ip_set_powergating_state(adev, amdgpu_device_ip_set_powergating_state(adev,
AMD_IP_BLOCK_TYPE_SMC, AMD_IP_BLOCK_TYPE_SMC,
AMD_CG_STATE_UNGATE); AMD_PG_STATE_UNGATE);
/* ungate SMC block first */ /* ungate SMC block first */
r = amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_SMC, r = amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_SMC,
...@@ -2293,6 +2292,8 @@ int amdgpu_device_init(struct amdgpu_device *adev, ...@@ -2293,6 +2292,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
INIT_DELAYED_WORK(&adev->late_init_work, INIT_DELAYED_WORK(&adev->late_init_work,
amdgpu_device_ip_late_init_func_handler); amdgpu_device_ip_late_init_func_handler);
adev->pm.ac_power = power_supply_is_system_supplied() > 0 ? true : false;
/* Registers mapping */ /* Registers mapping */
/* TODO: block userspace mapping of io register */ /* TODO: block userspace mapping of io register */
if (adev->asic_type >= CHIP_BONAIRE) { if (adev->asic_type >= CHIP_BONAIRE) {
......
...@@ -402,7 +402,6 @@ struct amdgpu_dpm { ...@@ -402,7 +402,6 @@ struct amdgpu_dpm {
u32 tdp_adjustment; u32 tdp_adjustment;
u16 load_line_slope; u16 load_line_slope;
bool power_control; bool power_control;
bool ac_power;
/* special states active */ /* special states active */
bool thermal_active; bool thermal_active;
bool uvd_active; bool uvd_active;
...@@ -439,6 +438,7 @@ struct amdgpu_pm { ...@@ -439,6 +438,7 @@ struct amdgpu_pm {
struct amd_pp_display_configuration pm_display_cfg;/* set by dc */ struct amd_pp_display_configuration pm_display_cfg;/* set by dc */
uint32_t smu_prv_buffer_size; uint32_t smu_prv_buffer_size;
struct amdgpu_bo *smu_prv_buffer; struct amdgpu_bo *smu_prv_buffer;
bool ac_power;
}; };
#define R600_SSTU_DFLT 0 #define R600_SSTU_DFLT 0
......
...@@ -855,9 +855,21 @@ static const struct dev_pm_ops amdgpu_pm_ops = { ...@@ -855,9 +855,21 @@ static const struct dev_pm_ops amdgpu_pm_ops = {
.runtime_idle = amdgpu_pmops_runtime_idle, .runtime_idle = amdgpu_pmops_runtime_idle,
}; };
static int amdgpu_flush(struct file *f, fl_owner_t id)
{
struct drm_file *file_priv = f->private_data;
struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
amdgpu_ctx_mgr_entity_fini(&fpriv->ctx_mgr);
return 0;
}
static const struct file_operations amdgpu_driver_kms_fops = { static const struct file_operations amdgpu_driver_kms_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_open, .open = drm_open,
.flush = amdgpu_flush,
.release = drm_release, .release = drm_release,
.unlocked_ioctl = amdgpu_drm_ioctl, .unlocked_ioctl = amdgpu_drm_ioctl,
.mmap = amdgpu_mmap, .mmap = amdgpu_mmap,
......
...@@ -510,7 +510,6 @@ int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data, ...@@ -510,7 +510,6 @@ int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data,
* @adev: amdgpu_device pointer * @adev: amdgpu_device pointer
* @vm: vm to update * @vm: vm to update
* @bo_va: bo_va to update * @bo_va: bo_va to update
* @list: validation list
* @operation: map, unmap or clear * @operation: map, unmap or clear
* *
* Update the bo_va directly after setting its address. Errors are not * Update the bo_va directly after setting its address. Errors are not
...@@ -519,7 +518,6 @@ int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data, ...@@ -519,7 +518,6 @@ int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data,
static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev, static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
struct amdgpu_vm *vm, struct amdgpu_vm *vm,
struct amdgpu_bo_va *bo_va, struct amdgpu_bo_va *bo_va,
struct list_head *list,
uint32_t operation) uint32_t operation)
{ {
int r; int r;
...@@ -612,7 +610,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, ...@@ -612,7 +610,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
return -ENOENT; return -ENOENT;
abo = gem_to_amdgpu_bo(gobj); abo = gem_to_amdgpu_bo(gobj);
tv.bo = &abo->tbo; tv.bo = &abo->tbo;
tv.shared = false; tv.shared = !!(abo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID);
list_add(&tv.head, &list); list_add(&tv.head, &list);
} else { } else {
gobj = NULL; gobj = NULL;
...@@ -673,7 +671,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, ...@@ -673,7 +671,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
break; break;
} }
if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !amdgpu_vm_debug) if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !amdgpu_vm_debug)
amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, &list, amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va,
args->operation); args->operation);
error_backoff: error_backoff:
......
...@@ -109,4 +109,19 @@ struct amdgpu_gmc { ...@@ -109,4 +109,19 @@ struct amdgpu_gmc {
const struct amdgpu_gmc_funcs *gmc_funcs; const struct amdgpu_gmc_funcs *gmc_funcs;
}; };
/**
* amdgpu_gmc_vram_full_visible - Check if full VRAM is visible through the BAR
*
* @adev: amdgpu_device pointer
*
* Returns:
* True if full VRAM is visible through the BAR
*/
static inline bool amdgpu_gmc_vram_full_visible(struct amdgpu_gmc *gmc)
{
WARN_ON(gmc->real_vram_size < gmc->visible_vram_size);
return (gmc->real_vram_size == gmc->visible_vram_size);
}
#endif #endif
...@@ -353,7 +353,8 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev) ...@@ -353,7 +353,8 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
ring->funcs->type == AMDGPU_RING_TYPE_VCE || ring->funcs->type == AMDGPU_RING_TYPE_VCE ||
ring->funcs->type == AMDGPU_RING_TYPE_UVD_ENC || ring->funcs->type == AMDGPU_RING_TYPE_UVD_ENC ||
ring->funcs->type == AMDGPU_RING_TYPE_VCN_DEC || ring->funcs->type == AMDGPU_RING_TYPE_VCN_DEC ||
ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC ||
ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG)
tmo = tmo_mm; tmo = tmo_mm;
else else
tmo = tmo_gfx; tmo = tmo_gfx;
......
...@@ -25,6 +25,23 @@ ...@@ -25,6 +25,23 @@
* Alex Deucher * Alex Deucher
* Jerome Glisse * Jerome Glisse
*/ */
/**
* DOC: Interrupt Handling
*
* Interrupts generated within GPU hardware raise interrupt requests that are
* passed to amdgpu IRQ handler which is responsible for detecting source and
* type of the interrupt and dispatching matching handlers. If handling an
* interrupt requires calling kernel functions that may sleep processing is
* dispatched to work handlers.
*
* If MSI functionality is not disabled by module parameter then MSI
* support will be enabled.
*
* For GPU interrupt sources that may be driven by another driver, IRQ domain
* support is used (with mapping between virtual and hardware IRQs).
*/
#include <linux/irq.h> #include <linux/irq.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
...@@ -43,19 +60,21 @@ ...@@ -43,19 +60,21 @@
#define AMDGPU_WAIT_IDLE_TIMEOUT 200 #define AMDGPU_WAIT_IDLE_TIMEOUT 200
/*
* Handle hotplug events outside the interrupt handler proper.
*/
/** /**
* amdgpu_hotplug_work_func - display hotplug work handler * amdgpu_hotplug_work_func - work handler for display hotplug event
* *
* @work: work struct * @work: work struct pointer
* *
* This is the hot plug event work handler (all asics). * This is the hotplug event work handler (all ASICs).
* The work gets scheduled from the irq handler if there * The work gets scheduled from the IRQ handler if there
* was a hot plug interrupt. It walks the connector table * was a hotplug interrupt. It walks through the connector table
* and calls the hotplug handler for each one, then sends * and calls hotplug handler for each connector. After this, it sends
* a drm hotplug event to alert userspace. * a DRM hotplug event to alert userspace.
*
* This design approach is required in order to defer hotplug event handling
* from the IRQ handler to a work handler because hotplug handler has to use
* mutexes which cannot be locked in an IRQ handler (since &mutex_lock may
* sleep).
*/ */
static void amdgpu_hotplug_work_func(struct work_struct *work) static void amdgpu_hotplug_work_func(struct work_struct *work)
{ {
...@@ -74,13 +93,12 @@ static void amdgpu_hotplug_work_func(struct work_struct *work) ...@@ -74,13 +93,12 @@ static void amdgpu_hotplug_work_func(struct work_struct *work)
} }
/** /**
* amdgpu_irq_reset_work_func - execute gpu reset * amdgpu_irq_reset_work_func - execute GPU reset
* *
* @work: work struct * @work: work struct pointer
* *
* Execute scheduled gpu reset (cayman+). * Execute scheduled GPU reset (Cayman+).
* This function is called when the irq handler * This function is called when the IRQ handler thinks we need a GPU reset.
* thinks we need a gpu reset.
*/ */
static void amdgpu_irq_reset_work_func(struct work_struct *work) static void amdgpu_irq_reset_work_func(struct work_struct *work)
{ {
...@@ -91,7 +109,13 @@ static void amdgpu_irq_reset_work_func(struct work_struct *work) ...@@ -91,7 +109,13 @@ static void amdgpu_irq_reset_work_func(struct work_struct *work)
amdgpu_device_gpu_recover(adev, NULL, false); amdgpu_device_gpu_recover(adev, NULL, false);
} }
/* Disable *all* interrupts */ /**
* amdgpu_irq_disable_all - disable *all* interrupts
*
* @adev: amdgpu device pointer
*
* Disable all types of interrupts from all sources.
*/
void amdgpu_irq_disable_all(struct amdgpu_device *adev) void amdgpu_irq_disable_all(struct amdgpu_device *adev)
{ {
unsigned long irqflags; unsigned long irqflags;
...@@ -123,11 +147,15 @@ void amdgpu_irq_disable_all(struct amdgpu_device *adev) ...@@ -123,11 +147,15 @@ void amdgpu_irq_disable_all(struct amdgpu_device *adev)
} }
/** /**
* amdgpu_irq_handler - irq handler * amdgpu_irq_handler - IRQ handler
*
* @irq: IRQ number (unused)
* @arg: pointer to DRM device
* *
* @int irq, void *arg: args * IRQ handler for amdgpu driver (all ASICs).
* *
* This is the irq handler for the amdgpu driver (all asics). * Returns:
* result of handling the IRQ, as defined by &irqreturn_t
*/ */
irqreturn_t amdgpu_irq_handler(int irq, void *arg) irqreturn_t amdgpu_irq_handler(int irq, void *arg)
{ {
...@@ -142,18 +170,18 @@ irqreturn_t amdgpu_irq_handler(int irq, void *arg) ...@@ -142,18 +170,18 @@ irqreturn_t amdgpu_irq_handler(int irq, void *arg)
} }
/** /**
* amdgpu_msi_ok - asic specific msi checks * amdgpu_msi_ok - check whether MSI functionality is enabled
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer (unused)
*
* Checks whether MSI functionality has been disabled via module parameter
* (all ASICs).
* *
* Handles asic specific MSI checks to determine if * Returns:
* MSIs should be enabled on a particular chip (all asics). * *true* if MSIs are allowed to be enabled or *false* otherwise
* Returns true if MSIs should be enabled, false if MSIs
* should not be enabled.
*/ */
static bool amdgpu_msi_ok(struct amdgpu_device *adev) static bool amdgpu_msi_ok(struct amdgpu_device *adev)
{ {
/* force MSI on */
if (amdgpu_msi == 1) if (amdgpu_msi == 1)
return true; return true;
else if (amdgpu_msi == 0) else if (amdgpu_msi == 0)
...@@ -163,12 +191,15 @@ static bool amdgpu_msi_ok(struct amdgpu_device *adev) ...@@ -163,12 +191,15 @@ static bool amdgpu_msi_ok(struct amdgpu_device *adev)
} }
/** /**
* amdgpu_irq_init - init driver interrupt info * amdgpu_irq_init - initialize interrupt handling
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* *
* Sets up the work irq handlers, vblank init, MSIs, etc. (all asics). * Sets up work functions for hotplug and reset interrupts, enables MSI
* Returns 0 for success, error for failure. * functionality, initializes vblank, hotplug and reset interrupt handling.
*
* Returns:
* 0 on success or error code on failure
*/ */
int amdgpu_irq_init(struct amdgpu_device *adev) int amdgpu_irq_init(struct amdgpu_device *adev)
{ {
...@@ -176,7 +207,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev) ...@@ -176,7 +207,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
spin_lock_init(&adev->irq.lock); spin_lock_init(&adev->irq.lock);
/* enable msi */ /* Enable MSI if not disabled by module parameter */
adev->irq.msi_enabled = false; adev->irq.msi_enabled = false;
if (amdgpu_msi_ok(adev)) { if (amdgpu_msi_ok(adev)) {
...@@ -189,7 +220,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev) ...@@ -189,7 +220,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
if (!amdgpu_device_has_dc_support(adev)) { if (!amdgpu_device_has_dc_support(adev)) {
if (!adev->enable_virtual_display) if (!adev->enable_virtual_display)
/* Disable vblank irqs aggressively for power-saving */ /* Disable vblank IRQs aggressively for power-saving */
/* XXX: can this be enabled for DC? */ /* XXX: can this be enabled for DC? */
adev->ddev->vblank_disable_immediate = true; adev->ddev->vblank_disable_immediate = true;
...@@ -197,7 +228,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev) ...@@ -197,7 +228,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
if (r) if (r)
return r; return r;
/* pre DCE11 */ /* Pre-DCE11 */
INIT_WORK(&adev->hotplug_work, INIT_WORK(&adev->hotplug_work,
amdgpu_hotplug_work_func); amdgpu_hotplug_work_func);
} }
...@@ -220,11 +251,13 @@ int amdgpu_irq_init(struct amdgpu_device *adev) ...@@ -220,11 +251,13 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
} }
/** /**
* amdgpu_irq_fini - tear down driver interrupt info * amdgpu_irq_fini - shut down interrupt handling
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* *
* Tears down the work irq handlers, vblank handlers, MSIs, etc. (all asics). * Tears down work functions for hotplug and reset interrupts, disables MSI
* functionality, shuts down vblank, hotplug and reset interrupt handling,
* turns off interrupts from all sources (all ASICs).
*/ */
void amdgpu_irq_fini(struct amdgpu_device *adev) void amdgpu_irq_fini(struct amdgpu_device *adev)
{ {
...@@ -264,12 +297,17 @@ void amdgpu_irq_fini(struct amdgpu_device *adev) ...@@ -264,12 +297,17 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
} }
/** /**
* amdgpu_irq_add_id - register irq source * amdgpu_irq_add_id - register IRQ source
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* @src_id: source id for this source * @client_id: client id
* @source: irq source * @src_id: source id
* @source: IRQ source pointer
*
* Registers IRQ source on a client.
* *
* Returns:
* 0 on success or error code otherwise
*/ */
int amdgpu_irq_add_id(struct amdgpu_device *adev, int amdgpu_irq_add_id(struct amdgpu_device *adev,
unsigned client_id, unsigned src_id, unsigned client_id, unsigned src_id,
...@@ -312,12 +350,12 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, ...@@ -312,12 +350,12 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev,
} }
/** /**
* amdgpu_irq_dispatch - dispatch irq to IP blocks * amdgpu_irq_dispatch - dispatch IRQ to IP blocks
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* @entry: interrupt vector * @entry: interrupt vector pointer
* *
* Dispatches the irq to the different IP blocks * Dispatches IRQ to IP blocks.
*/ */
void amdgpu_irq_dispatch(struct amdgpu_device *adev, void amdgpu_irq_dispatch(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry) struct amdgpu_iv_entry *entry)
...@@ -361,13 +399,13 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev, ...@@ -361,13 +399,13 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
} }
/** /**
* amdgpu_irq_update - update hw interrupt state * amdgpu_irq_update - update hardware interrupt state
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* @src: interrupt src you want to enable * @src: interrupt source pointer
* @type: type of interrupt you want to update * @type: type of interrupt
* *
* Updates the interrupt state for a specific src (all asics). * Updates interrupt state for the specific source (all ASICs).
*/ */
int amdgpu_irq_update(struct amdgpu_device *adev, int amdgpu_irq_update(struct amdgpu_device *adev,
struct amdgpu_irq_src *src, unsigned type) struct amdgpu_irq_src *src, unsigned type)
...@@ -378,7 +416,7 @@ int amdgpu_irq_update(struct amdgpu_device *adev, ...@@ -378,7 +416,7 @@ int amdgpu_irq_update(struct amdgpu_device *adev,
spin_lock_irqsave(&adev->irq.lock, irqflags); spin_lock_irqsave(&adev->irq.lock, irqflags);
/* we need to determine after taking the lock, otherwise /* We need to determine after taking the lock, otherwise
we might disable just enabled interrupts again */ we might disable just enabled interrupts again */
if (amdgpu_irq_enabled(adev, src, type)) if (amdgpu_irq_enabled(adev, src, type))
state = AMDGPU_IRQ_STATE_ENABLE; state = AMDGPU_IRQ_STATE_ENABLE;
...@@ -390,6 +428,14 @@ int amdgpu_irq_update(struct amdgpu_device *adev, ...@@ -390,6 +428,14 @@ int amdgpu_irq_update(struct amdgpu_device *adev,
return r; return r;
} }
/**
* amdgpu_irq_gpu_reset_resume_helper - update interrupt states on all sources
*
* @adev: amdgpu device pointer
*
* Updates state of all types of interrupts on all sources on resume after
* reset.
*/
void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev) void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev)
{ {
int i, j, k; int i, j, k;
...@@ -413,10 +459,13 @@ void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev) ...@@ -413,10 +459,13 @@ void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev)
* amdgpu_irq_get - enable interrupt * amdgpu_irq_get - enable interrupt
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* @src: interrupt src you want to enable * @src: interrupt source pointer
* @type: type of interrupt you want to enable * @type: type of interrupt
* *
* Enables the interrupt type for a specific src (all asics). * Enables specified type of interrupt on the specified source (all ASICs).
*
* Returns:
* 0 on success or error code otherwise
*/ */
int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src, int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
unsigned type) unsigned type)
...@@ -440,10 +489,13 @@ int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src, ...@@ -440,10 +489,13 @@ int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
* amdgpu_irq_put - disable interrupt * amdgpu_irq_put - disable interrupt
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* @src: interrupt src you want to disable * @src: interrupt source pointer
* @type: type of interrupt you want to disable * @type: type of interrupt
*
* Enables specified type of interrupt on the specified source (all ASICs).
* *
* Disables the interrupt type for a specific src (all asics). * Returns:
* 0 on success or error code otherwise
*/ */
int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src, int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
unsigned type) unsigned type)
...@@ -464,12 +516,17 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src, ...@@ -464,12 +516,17 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
} }
/** /**
* amdgpu_irq_enabled - test if irq is enabled or not * amdgpu_irq_enabled - check whether interrupt is enabled or not
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* @idx: interrupt src you want to test * @src: interrupt source pointer
* @type: type of interrupt
* *
* Tests if the given interrupt source is enabled or not * Checks whether the given type of interrupt is enabled on the given source.
*
* Returns:
* *true* if interrupt is enabled, *false* if interrupt is disabled or on
* invalid parameters
*/ */
bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src, bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
unsigned type) unsigned type)
...@@ -486,7 +543,7 @@ bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src, ...@@ -486,7 +543,7 @@ bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
return !!atomic_read(&src->enabled_types[type]); return !!atomic_read(&src->enabled_types[type]);
} }
/* gen irq */ /* XXX: Generic IRQ handling */
static void amdgpu_irq_mask(struct irq_data *irqd) static void amdgpu_irq_mask(struct irq_data *irqd)
{ {
/* XXX */ /* XXX */
...@@ -497,12 +554,26 @@ static void amdgpu_irq_unmask(struct irq_data *irqd) ...@@ -497,12 +554,26 @@ static void amdgpu_irq_unmask(struct irq_data *irqd)
/* XXX */ /* XXX */
} }
/* amdgpu hardware interrupt chip descriptor */
static struct irq_chip amdgpu_irq_chip = { static struct irq_chip amdgpu_irq_chip = {
.name = "amdgpu-ih", .name = "amdgpu-ih",
.irq_mask = amdgpu_irq_mask, .irq_mask = amdgpu_irq_mask,
.irq_unmask = amdgpu_irq_unmask, .irq_unmask = amdgpu_irq_unmask,
}; };
/**
* amdgpu_irqdomain_map - create mapping between virtual and hardware IRQ numbers
*
* @d: amdgpu IRQ domain pointer (unused)
* @irq: virtual IRQ number
* @hwirq: hardware irq number
*
* Current implementation assigns simple interrupt handler to the given virtual
* IRQ.
*
* Returns:
* 0 on success or error code otherwise
*/
static int amdgpu_irqdomain_map(struct irq_domain *d, static int amdgpu_irqdomain_map(struct irq_domain *d,
unsigned int irq, irq_hw_number_t hwirq) unsigned int irq, irq_hw_number_t hwirq)
{ {
...@@ -514,17 +585,21 @@ static int amdgpu_irqdomain_map(struct irq_domain *d, ...@@ -514,17 +585,21 @@ static int amdgpu_irqdomain_map(struct irq_domain *d,
return 0; return 0;
} }
/* Implementation of methods for amdgpu IRQ domain */
static const struct irq_domain_ops amdgpu_hw_irqdomain_ops = { static const struct irq_domain_ops amdgpu_hw_irqdomain_ops = {
.map = amdgpu_irqdomain_map, .map = amdgpu_irqdomain_map,
}; };
/** /**
* amdgpu_irq_add_domain - create a linear irq domain * amdgpu_irq_add_domain - create a linear IRQ domain
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* *
* Create an irq domain for GPU interrupt sources * Creates an IRQ domain for GPU interrupt sources
* that may be driven by another driver (e.g., ACP). * that may be driven by another driver (e.g., ACP).
*
* Returns:
* 0 on success or error code otherwise
*/ */
int amdgpu_irq_add_domain(struct amdgpu_device *adev) int amdgpu_irq_add_domain(struct amdgpu_device *adev)
{ {
...@@ -539,11 +614,11 @@ int amdgpu_irq_add_domain(struct amdgpu_device *adev) ...@@ -539,11 +614,11 @@ int amdgpu_irq_add_domain(struct amdgpu_device *adev)
} }
/** /**
* amdgpu_irq_remove_domain - remove the irq domain * amdgpu_irq_remove_domain - remove the IRQ domain
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* *
* Remove the irq domain for GPU interrupt sources * Removes the IRQ domain for GPU interrupt sources
* that may be driven by another driver (e.g., ACP). * that may be driven by another driver (e.g., ACP).
*/ */
void amdgpu_irq_remove_domain(struct amdgpu_device *adev) void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
...@@ -555,16 +630,17 @@ void amdgpu_irq_remove_domain(struct amdgpu_device *adev) ...@@ -555,16 +630,17 @@ void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
} }
/** /**
* amdgpu_irq_create_mapping - create a mapping between a domain irq and a * amdgpu_irq_create_mapping - create mapping between domain Linux IRQs
* Linux irq
* *
* @adev: amdgpu device pointer * @adev: amdgpu device pointer
* @src_id: IH source id * @src_id: IH source id
* *
* Create a mapping between a domain irq (GPU IH src id) and a Linux irq * Creates mapping between a domain IRQ (GPU IH src id) and a Linux IRQ
* Use this for components that generate a GPU interrupt, but are driven * Use this for components that generate a GPU interrupt, but are driven
* by a different driver (e.g., ACP). * by a different driver (e.g., ACP).
* Returns the Linux irq. *
* Returns:
* Linux IRQ
*/ */
unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id) unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id)
{ {
......
...@@ -329,35 +329,35 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file ...@@ -329,35 +329,35 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
type = AMD_IP_BLOCK_TYPE_GFX; type = AMD_IP_BLOCK_TYPE_GFX;
for (i = 0; i < adev->gfx.num_gfx_rings; i++) for (i = 0; i < adev->gfx.num_gfx_rings; i++)
ring_mask |= ((adev->gfx.gfx_ring[i].ready ? 1 : 0) << i); ring_mask |= ((adev->gfx.gfx_ring[i].ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_start_alignment = 32;
ib_size_alignment = 8; ib_size_alignment = 32;
break; break;
case AMDGPU_HW_IP_COMPUTE: case AMDGPU_HW_IP_COMPUTE:
type = AMD_IP_BLOCK_TYPE_GFX; type = AMD_IP_BLOCK_TYPE_GFX;
for (i = 0; i < adev->gfx.num_compute_rings; i++) for (i = 0; i < adev->gfx.num_compute_rings; i++)
ring_mask |= ((adev->gfx.compute_ring[i].ready ? 1 : 0) << i); ring_mask |= ((adev->gfx.compute_ring[i].ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_start_alignment = 32;
ib_size_alignment = 8; ib_size_alignment = 32;
break; break;
case AMDGPU_HW_IP_DMA: case AMDGPU_HW_IP_DMA:
type = AMD_IP_BLOCK_TYPE_SDMA; type = AMD_IP_BLOCK_TYPE_SDMA;
for (i = 0; i < adev->sdma.num_instances; i++) for (i = 0; i < adev->sdma.num_instances; i++)
ring_mask |= ((adev->sdma.instance[i].ring.ready ? 1 : 0) << i); ring_mask |= ((adev->sdma.instance[i].ring.ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_start_alignment = 256;
ib_size_alignment = 1; ib_size_alignment = 4;
break; break;
case AMDGPU_HW_IP_UVD: case AMDGPU_HW_IP_UVD:
type = AMD_IP_BLOCK_TYPE_UVD; type = AMD_IP_BLOCK_TYPE_UVD;
for (i = 0; i < adev->uvd.num_uvd_inst; i++) for (i = 0; i < adev->uvd.num_uvd_inst; i++)
ring_mask |= ((adev->uvd.inst[i].ring.ready ? 1 : 0) << i); ring_mask |= ((adev->uvd.inst[i].ring.ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_start_alignment = 64;
ib_size_alignment = 16; ib_size_alignment = 64;
break; break;
case AMDGPU_HW_IP_VCE: case AMDGPU_HW_IP_VCE:
type = AMD_IP_BLOCK_TYPE_VCE; type = AMD_IP_BLOCK_TYPE_VCE;
for (i = 0; i < adev->vce.num_rings; i++) for (i = 0; i < adev->vce.num_rings; i++)
ring_mask |= ((adev->vce.ring[i].ready ? 1 : 0) << i); ring_mask |= ((adev->vce.ring[i].ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_start_alignment = 4;
ib_size_alignment = 1; ib_size_alignment = 1;
break; break;
case AMDGPU_HW_IP_UVD_ENC: case AMDGPU_HW_IP_UVD_ENC:
...@@ -367,22 +367,28 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file ...@@ -367,22 +367,28 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
ring_mask |= ring_mask |=
((adev->uvd.inst[i].ring_enc[j].ready ? 1 : 0) << ((adev->uvd.inst[i].ring_enc[j].ready ? 1 : 0) <<
(j + i * adev->uvd.num_enc_rings)); (j + i * adev->uvd.num_enc_rings));
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_start_alignment = 64;
ib_size_alignment = 1; ib_size_alignment = 64;
break; break;
case AMDGPU_HW_IP_VCN_DEC: case AMDGPU_HW_IP_VCN_DEC:
type = AMD_IP_BLOCK_TYPE_VCN; type = AMD_IP_BLOCK_TYPE_VCN;
ring_mask = adev->vcn.ring_dec.ready ? 1 : 0; ring_mask = adev->vcn.ring_dec.ready ? 1 : 0;
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_start_alignment = 16;
ib_size_alignment = 16; ib_size_alignment = 16;
break; break;
case AMDGPU_HW_IP_VCN_ENC: case AMDGPU_HW_IP_VCN_ENC:
type = AMD_IP_BLOCK_TYPE_VCN; type = AMD_IP_BLOCK_TYPE_VCN;
for (i = 0; i < adev->vcn.num_enc_rings; i++) for (i = 0; i < adev->vcn.num_enc_rings; i++)
ring_mask |= ((adev->vcn.ring_enc[i].ready ? 1 : 0) << i); ring_mask |= ((adev->vcn.ring_enc[i].ready ? 1 : 0) << i);
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_start_alignment = 64;
ib_size_alignment = 1; ib_size_alignment = 1;
break; break;
case AMDGPU_HW_IP_VCN_JPEG:
type = AMD_IP_BLOCK_TYPE_VCN;
ring_mask = adev->vcn.ring_jpeg.ready ? 1 : 0;
ib_start_alignment = 16;
ib_size_alignment = 16;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -427,6 +433,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file ...@@ -427,6 +433,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
break; break;
case AMDGPU_HW_IP_VCN_DEC: case AMDGPU_HW_IP_VCN_DEC:
case AMDGPU_HW_IP_VCN_ENC: case AMDGPU_HW_IP_VCN_ENC:
case AMDGPU_HW_IP_VCN_JPEG:
type = AMD_IP_BLOCK_TYPE_VCN; type = AMD_IP_BLOCK_TYPE_VCN;
break; break;
default: default:
...@@ -930,7 +937,6 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, ...@@ -930,7 +937,6 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
return; return;
pm_runtime_get_sync(dev->dev); pm_runtime_get_sync(dev->dev);
amdgpu_ctx_mgr_entity_fini(&fpriv->ctx_mgr);
if (adev->asic_type != CHIP_RAVEN) { if (adev->asic_type != CHIP_RAVEN) {
amdgpu_uvd_free_handles(adev, file_priv); amdgpu_uvd_free_handles(adev, file_priv);
......
...@@ -28,6 +28,21 @@ ...@@ -28,6 +28,21 @@
* Christian König <christian.koenig@amd.com> * Christian König <christian.koenig@amd.com>
*/ */
/**
* DOC: MMU Notifier
*
* For coherent userptr handling registers an MMU notifier to inform the driver
* about updates on the page tables of a process.
*
* When somebody tries to invalidate the page tables we block the update until
* all operations on the pages in question are completed, then those pages are
* marked as accessed and also dirty if it wasn't a read only access.
*
* New command submissions using the userptrs in question are delayed until all
* page table invalidation are completed and we once more see a coherent process
* address space.
*/
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
...@@ -38,6 +53,21 @@ ...@@ -38,6 +53,21 @@
#include "amdgpu.h" #include "amdgpu.h"
#include "amdgpu_amdkfd.h" #include "amdgpu_amdkfd.h"
/**
* struct amdgpu_mn
*
* @adev: amdgpu device pointer
* @mm: process address space
* @mn: MMU notifier structur
* @work: destruction work item
* @node: hash table node to find structure by adev and mn
* @lock: rw semaphore protecting the notifier nodes
* @objects: interval tree containing amdgpu_mn_nodes
* @read_lock: mutex for recursive locking of @lock
* @recursion: depth of recursion
*
* Data for each amdgpu device and process address space.
*/
struct amdgpu_mn { struct amdgpu_mn {
/* constant after initialisation */ /* constant after initialisation */
struct amdgpu_device *adev; struct amdgpu_device *adev;
...@@ -58,13 +88,21 @@ struct amdgpu_mn { ...@@ -58,13 +88,21 @@ struct amdgpu_mn {
atomic_t recursion; atomic_t recursion;
}; };
/**
* struct amdgpu_mn_node
*
* @it: interval node defining start-last of the affected address range
* @bos: list of all BOs in the affected address range
*
* Manages all BOs which are affected of a certain range of address space.
*/
struct amdgpu_mn_node { struct amdgpu_mn_node {
struct interval_tree_node it; struct interval_tree_node it;
struct list_head bos; struct list_head bos;
}; };
/** /**
* amdgpu_mn_destroy - destroy the rmn * amdgpu_mn_destroy - destroy the MMU notifier
* *
* @work: previously sheduled work item * @work: previously sheduled work item
* *
...@@ -72,47 +110,50 @@ struct amdgpu_mn_node { ...@@ -72,47 +110,50 @@ struct amdgpu_mn_node {
*/ */
static void amdgpu_mn_destroy(struct work_struct *work) static void amdgpu_mn_destroy(struct work_struct *work)
{ {
struct amdgpu_mn *rmn = container_of(work, struct amdgpu_mn, work); struct amdgpu_mn *amn = container_of(work, struct amdgpu_mn, work);
struct amdgpu_device *adev = rmn->adev; struct amdgpu_device *adev = amn->adev;
struct amdgpu_mn_node *node, *next_node; struct amdgpu_mn_node *node, *next_node;
struct amdgpu_bo *bo, *next_bo; struct amdgpu_bo *bo, *next_bo;
mutex_lock(&adev->mn_lock); mutex_lock(&adev->mn_lock);
down_write(&rmn->lock); down_write(&amn->lock);
hash_del(&rmn->node); hash_del(&amn->node);
rbtree_postorder_for_each_entry_safe(node, next_node, rbtree_postorder_for_each_entry_safe(node, next_node,
&rmn->objects.rb_root, it.rb) { &amn->objects.rb_root, it.rb) {
list_for_each_entry_safe(bo, next_bo, &node->bos, mn_list) { list_for_each_entry_safe(bo, next_bo, &node->bos, mn_list) {
bo->mn = NULL; bo->mn = NULL;
list_del_init(&bo->mn_list); list_del_init(&bo->mn_list);
} }
kfree(node); kfree(node);
} }
up_write(&rmn->lock); up_write(&amn->lock);
mutex_unlock(&adev->mn_lock); mutex_unlock(&adev->mn_lock);
mmu_notifier_unregister_no_release(&rmn->mn, rmn->mm); mmu_notifier_unregister_no_release(&amn->mn, amn->mm);
kfree(rmn); kfree(amn);
} }
/** /**
* amdgpu_mn_release - callback to notify about mm destruction * amdgpu_mn_release - callback to notify about mm destruction
* *
* @mn: our notifier * @mn: our notifier
* @mn: the mm this callback is about * @mm: the mm this callback is about
* *
* Shedule a work item to lazy destroy our notifier. * Shedule a work item to lazy destroy our notifier.
*/ */
static void amdgpu_mn_release(struct mmu_notifier *mn, static void amdgpu_mn_release(struct mmu_notifier *mn,
struct mm_struct *mm) struct mm_struct *mm)
{ {
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
INIT_WORK(&rmn->work, amdgpu_mn_destroy);
schedule_work(&rmn->work); INIT_WORK(&amn->work, amdgpu_mn_destroy);
schedule_work(&amn->work);
} }
/** /**
* amdgpu_mn_lock - take the write side lock for this mn * amdgpu_mn_lock - take the write side lock for this notifier
*
* @mn: our notifier
*/ */
void amdgpu_mn_lock(struct amdgpu_mn *mn) void amdgpu_mn_lock(struct amdgpu_mn *mn)
{ {
...@@ -121,7 +162,9 @@ void amdgpu_mn_lock(struct amdgpu_mn *mn) ...@@ -121,7 +162,9 @@ void amdgpu_mn_lock(struct amdgpu_mn *mn)
} }
/** /**
* amdgpu_mn_unlock - drop the write side lock for this mn * amdgpu_mn_unlock - drop the write side lock for this notifier
*
* @mn: our notifier
*/ */
void amdgpu_mn_unlock(struct amdgpu_mn *mn) void amdgpu_mn_unlock(struct amdgpu_mn *mn)
{ {
...@@ -130,40 +173,38 @@ void amdgpu_mn_unlock(struct amdgpu_mn *mn) ...@@ -130,40 +173,38 @@ void amdgpu_mn_unlock(struct amdgpu_mn *mn)
} }
/** /**
* amdgpu_mn_read_lock - take the rmn read lock * amdgpu_mn_read_lock - take the read side lock for this notifier
*
* @rmn: our notifier
* *
* Take the rmn read side lock. * @amn: our notifier
*/ */
static void amdgpu_mn_read_lock(struct amdgpu_mn *rmn) static void amdgpu_mn_read_lock(struct amdgpu_mn *amn)
{ {
mutex_lock(&rmn->read_lock); mutex_lock(&amn->read_lock);
if (atomic_inc_return(&rmn->recursion) == 1) if (atomic_inc_return(&amn->recursion) == 1)
down_read_non_owner(&rmn->lock); down_read_non_owner(&amn->lock);
mutex_unlock(&rmn->read_lock); mutex_unlock(&amn->read_lock);
} }
/** /**
* amdgpu_mn_read_unlock - drop the rmn read lock * amdgpu_mn_read_unlock - drop the read side lock for this notifier
*
* @rmn: our notifier
* *
* Drop the rmn read side lock. * @amn: our notifier
*/ */
static void amdgpu_mn_read_unlock(struct amdgpu_mn *rmn) static void amdgpu_mn_read_unlock(struct amdgpu_mn *amn)
{ {
if (atomic_dec_return(&rmn->recursion) == 0) if (atomic_dec_return(&amn->recursion) == 0)
up_read_non_owner(&rmn->lock); up_read_non_owner(&amn->lock);
} }
/** /**
* amdgpu_mn_invalidate_node - unmap all BOs of a node * amdgpu_mn_invalidate_node - unmap all BOs of a node
* *
* @node: the node with the BOs to unmap * @node: the node with the BOs to unmap
* @start: start of address range affected
* @end: end of address range affected
* *
* We block for all BOs and unmap them by move them * Block for operations on BOs to finish and mark pages as accessed and
* into system domain again. * potentially dirty.
*/ */
static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node, static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node,
unsigned long start, unsigned long start,
...@@ -190,27 +231,27 @@ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node, ...@@ -190,27 +231,27 @@ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node,
* amdgpu_mn_invalidate_range_start_gfx - callback to notify about mm change * amdgpu_mn_invalidate_range_start_gfx - callback to notify about mm change
* *
* @mn: our notifier * @mn: our notifier
* @mn: the mm this callback is about * @mm: the mm this callback is about
* @start: start of updated range * @start: start of updated range
* @end: end of updated range * @end: end of updated range
* *
* We block for all BOs between start and end to be idle and * Block for operations on BOs to finish and mark pages as accessed and
* unmap them by move them into system domain again. * potentially dirty.
*/ */
static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn,
struct mm_struct *mm, struct mm_struct *mm,
unsigned long start, unsigned long start,
unsigned long end) unsigned long end)
{ {
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
struct interval_tree_node *it; struct interval_tree_node *it;
/* notification is exclusive, but interval is inclusive */ /* notification is exclusive, but interval is inclusive */
end -= 1; end -= 1;
amdgpu_mn_read_lock(rmn); amdgpu_mn_read_lock(amn);
it = interval_tree_iter_first(&rmn->objects, start, end); it = interval_tree_iter_first(&amn->objects, start, end);
while (it) { while (it) {
struct amdgpu_mn_node *node; struct amdgpu_mn_node *node;
...@@ -238,15 +279,15 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn, ...@@ -238,15 +279,15 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
unsigned long start, unsigned long start,
unsigned long end) unsigned long end)
{ {
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
struct interval_tree_node *it; struct interval_tree_node *it;
/* notification is exclusive, but interval is inclusive */ /* notification is exclusive, but interval is inclusive */
end -= 1; end -= 1;
amdgpu_mn_read_lock(rmn); amdgpu_mn_read_lock(amn);
it = interval_tree_iter_first(&rmn->objects, start, end); it = interval_tree_iter_first(&amn->objects, start, end);
while (it) { while (it) {
struct amdgpu_mn_node *node; struct amdgpu_mn_node *node;
struct amdgpu_bo *bo; struct amdgpu_bo *bo;
...@@ -268,7 +309,7 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn, ...@@ -268,7 +309,7 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
* amdgpu_mn_invalidate_range_end - callback to notify about mm change * amdgpu_mn_invalidate_range_end - callback to notify about mm change
* *
* @mn: our notifier * @mn: our notifier
* @mn: the mm this callback is about * @mm: the mm this callback is about
* @start: start of updated range * @start: start of updated range
* @end: end of updated range * @end: end of updated range
* *
...@@ -279,9 +320,9 @@ static void amdgpu_mn_invalidate_range_end(struct mmu_notifier *mn, ...@@ -279,9 +320,9 @@ static void amdgpu_mn_invalidate_range_end(struct mmu_notifier *mn,
unsigned long start, unsigned long start,
unsigned long end) unsigned long end)
{ {
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
amdgpu_mn_read_unlock(rmn); amdgpu_mn_read_unlock(amn);
} }
static const struct mmu_notifier_ops amdgpu_mn_ops[] = { static const struct mmu_notifier_ops amdgpu_mn_ops[] = {
...@@ -315,7 +356,7 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev, ...@@ -315,7 +356,7 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev,
enum amdgpu_mn_type type) enum amdgpu_mn_type type)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
struct amdgpu_mn *rmn; struct amdgpu_mn *amn;
unsigned long key = AMDGPU_MN_KEY(mm, type); unsigned long key = AMDGPU_MN_KEY(mm, type);
int r; int r;
...@@ -325,41 +366,41 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev, ...@@ -325,41 +366,41 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev,
return ERR_PTR(-EINTR); return ERR_PTR(-EINTR);
} }
hash_for_each_possible(adev->mn_hash, rmn, node, key) hash_for_each_possible(adev->mn_hash, amn, node, key)
if (AMDGPU_MN_KEY(rmn->mm, rmn->type) == key) if (AMDGPU_MN_KEY(amn->mm, amn->type) == key)
goto release_locks; goto release_locks;
rmn = kzalloc(sizeof(*rmn), GFP_KERNEL); amn = kzalloc(sizeof(*amn), GFP_KERNEL);
if (!rmn) { if (!amn) {
rmn = ERR_PTR(-ENOMEM); amn = ERR_PTR(-ENOMEM);
goto release_locks; goto release_locks;
} }
rmn->adev = adev; amn->adev = adev;
rmn->mm = mm; amn->mm = mm;
init_rwsem(&rmn->lock); init_rwsem(&amn->lock);
rmn->type = type; amn->type = type;
rmn->mn.ops = &amdgpu_mn_ops[type]; amn->mn.ops = &amdgpu_mn_ops[type];
rmn->objects = RB_ROOT_CACHED; amn->objects = RB_ROOT_CACHED;
mutex_init(&rmn->read_lock); mutex_init(&amn->read_lock);
atomic_set(&rmn->recursion, 0); atomic_set(&amn->recursion, 0);
r = __mmu_notifier_register(&rmn->mn, mm); r = __mmu_notifier_register(&amn->mn, mm);
if (r) if (r)
goto free_rmn; goto free_amn;
hash_add(adev->mn_hash, &rmn->node, AMDGPU_MN_KEY(mm, type)); hash_add(adev->mn_hash, &amn->node, AMDGPU_MN_KEY(mm, type));
release_locks: release_locks:
up_write(&mm->mmap_sem); up_write(&mm->mmap_sem);
mutex_unlock(&adev->mn_lock); mutex_unlock(&adev->mn_lock);
return rmn; return amn;
free_rmn: free_amn:
up_write(&mm->mmap_sem); up_write(&mm->mmap_sem);
mutex_unlock(&adev->mn_lock); mutex_unlock(&adev->mn_lock);
kfree(rmn); kfree(amn);
return ERR_PTR(r); return ERR_PTR(r);
} }
...@@ -379,14 +420,14 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) ...@@ -379,14 +420,14 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
enum amdgpu_mn_type type = enum amdgpu_mn_type type =
bo->kfd_bo ? AMDGPU_MN_TYPE_HSA : AMDGPU_MN_TYPE_GFX; bo->kfd_bo ? AMDGPU_MN_TYPE_HSA : AMDGPU_MN_TYPE_GFX;
struct amdgpu_mn *rmn; struct amdgpu_mn *amn;
struct amdgpu_mn_node *node = NULL, *new_node; struct amdgpu_mn_node *node = NULL, *new_node;
struct list_head bos; struct list_head bos;
struct interval_tree_node *it; struct interval_tree_node *it;
rmn = amdgpu_mn_get(adev, type); amn = amdgpu_mn_get(adev, type);
if (IS_ERR(rmn)) if (IS_ERR(amn))
return PTR_ERR(rmn); return PTR_ERR(amn);
new_node = kmalloc(sizeof(*new_node), GFP_KERNEL); new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
if (!new_node) if (!new_node)
...@@ -394,12 +435,12 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) ...@@ -394,12 +435,12 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
INIT_LIST_HEAD(&bos); INIT_LIST_HEAD(&bos);
down_write(&rmn->lock); down_write(&amn->lock);
while ((it = interval_tree_iter_first(&rmn->objects, addr, end))) { while ((it = interval_tree_iter_first(&amn->objects, addr, end))) {
kfree(node); kfree(node);
node = container_of(it, struct amdgpu_mn_node, it); node = container_of(it, struct amdgpu_mn_node, it);
interval_tree_remove(&node->it, &rmn->objects); interval_tree_remove(&node->it, &amn->objects);
addr = min(it->start, addr); addr = min(it->start, addr);
end = max(it->last, end); end = max(it->last, end);
list_splice(&node->bos, &bos); list_splice(&node->bos, &bos);
...@@ -410,7 +451,7 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) ...@@ -410,7 +451,7 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
else else
kfree(new_node); kfree(new_node);
bo->mn = rmn; bo->mn = amn;
node->it.start = addr; node->it.start = addr;
node->it.last = end; node->it.last = end;
...@@ -418,9 +459,9 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) ...@@ -418,9 +459,9 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
list_splice(&bos, &node->bos); list_splice(&bos, &node->bos);
list_add(&bo->mn_list, &node->bos); list_add(&bo->mn_list, &node->bos);
interval_tree_insert(&node->it, &rmn->objects); interval_tree_insert(&node->it, &amn->objects);
up_write(&rmn->lock); up_write(&amn->lock);
return 0; return 0;
} }
...@@ -435,18 +476,18 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) ...@@ -435,18 +476,18 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
void amdgpu_mn_unregister(struct amdgpu_bo *bo) void amdgpu_mn_unregister(struct amdgpu_bo *bo)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
struct amdgpu_mn *rmn; struct amdgpu_mn *amn;
struct list_head *head; struct list_head *head;
mutex_lock(&adev->mn_lock); mutex_lock(&adev->mn_lock);
rmn = bo->mn; amn = bo->mn;
if (rmn == NULL) { if (amn == NULL) {
mutex_unlock(&adev->mn_lock); mutex_unlock(&adev->mn_lock);
return; return;
} }
down_write(&rmn->lock); down_write(&amn->lock);
/* save the next list entry for later */ /* save the next list entry for later */
head = bo->mn_list.next; head = bo->mn_list.next;
...@@ -456,12 +497,13 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo) ...@@ -456,12 +497,13 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo)
if (list_empty(head)) { if (list_empty(head)) {
struct amdgpu_mn_node *node; struct amdgpu_mn_node *node;
node = container_of(head, struct amdgpu_mn_node, bos); node = container_of(head, struct amdgpu_mn_node, bos);
interval_tree_remove(&node->it, &rmn->objects); interval_tree_remove(&node->it, &amn->objects);
kfree(node); kfree(node);
} }
up_write(&rmn->lock); up_write(&amn->lock);
mutex_unlock(&adev->mn_lock); mutex_unlock(&adev->mn_lock);
} }
...@@ -38,6 +38,19 @@ ...@@ -38,6 +38,19 @@
#include "amdgpu_trace.h" #include "amdgpu_trace.h"
#include "amdgpu_amdkfd.h" #include "amdgpu_amdkfd.h"
/**
* DOC: amdgpu_object
*
* This defines the interfaces to operate on an &amdgpu_bo buffer object which
* represents memory used by driver (VRAM, system memory, etc.). The driver
* provides DRM/GEM APIs to userspace. DRM/GEM APIs then use these interfaces
* to create/destroy/set buffer object which are then managed by the kernel TTM
* memory manager.
* The interfaces are also used internally by kernel clients, including gfx,
* uvd, etc. for kernel managed allocations used by the GPU.
*
*/
static bool amdgpu_need_backup(struct amdgpu_device *adev) static bool amdgpu_need_backup(struct amdgpu_device *adev)
{ {
if (adev->flags & AMD_IS_APU) if (adev->flags & AMD_IS_APU)
...@@ -73,6 +86,16 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) ...@@ -73,6 +86,16 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
kfree(bo); kfree(bo);
} }
/**
* amdgpu_ttm_bo_is_amdgpu_bo - check if the buffer object is an &amdgpu_bo
* @bo: buffer object to be checked
*
* Uses destroy function associated with the object to determine if this is
* an &amdgpu_bo.
*
* Returns:
* true if the object belongs to &amdgpu_bo, false if not.
*/
bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
{ {
if (bo->destroy == &amdgpu_ttm_bo_destroy) if (bo->destroy == &amdgpu_ttm_bo_destroy)
...@@ -80,6 +103,14 @@ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) ...@@ -80,6 +103,14 @@ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
return false; return false;
} }
/**
* amdgpu_ttm_placement_from_domain - set buffer's placement
* @abo: &amdgpu_bo buffer object whose placement is to be set
* @domain: requested domain
*
* Sets buffer's placement according to requested domain and the buffer's
* flags.
*/
void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain) void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
...@@ -184,7 +215,8 @@ void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain) ...@@ -184,7 +215,8 @@ void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
* *
* Note: For bo_ptr new BO is only created if bo_ptr points to NULL. * Note: For bo_ptr new BO is only created if bo_ptr points to NULL.
* *
* Returns 0 on success, negative error code otherwise. * Returns:
* 0 on success, negative error code otherwise.
*/ */
int amdgpu_bo_create_reserved(struct amdgpu_device *adev, int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
unsigned long size, int align, unsigned long size, int align,
...@@ -261,7 +293,8 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, ...@@ -261,7 +293,8 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
* *
* Note: For bo_ptr new BO is only created if bo_ptr points to NULL. * Note: For bo_ptr new BO is only created if bo_ptr points to NULL.
* *
* Returns 0 on success, negative error code otherwise. * Returns:
* 0 on success, negative error code otherwise.
*/ */
int amdgpu_bo_create_kernel(struct amdgpu_device *adev, int amdgpu_bo_create_kernel(struct amdgpu_device *adev,
unsigned long size, int align, unsigned long size, int align,
...@@ -285,6 +318,8 @@ int amdgpu_bo_create_kernel(struct amdgpu_device *adev, ...@@ -285,6 +318,8 @@ int amdgpu_bo_create_kernel(struct amdgpu_device *adev,
* amdgpu_bo_free_kernel - free BO for kernel use * amdgpu_bo_free_kernel - free BO for kernel use
* *
* @bo: amdgpu BO to free * @bo: amdgpu BO to free
* @gpu_addr: pointer to where the BO's GPU memory space address was stored
* @cpu_addr: pointer to where the BO's CPU memory space address was stored
* *
* unmaps and unpin a BO for kernel internal use. * unmaps and unpin a BO for kernel internal use.
*/ */
...@@ -428,7 +463,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, ...@@ -428,7 +463,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
if (unlikely(r != 0)) if (unlikely(r != 0))
return r; return r;
if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
bo->tbo.mem.mem_type == TTM_PL_VRAM && bo->tbo.mem.mem_type == TTM_PL_VRAM &&
bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT) bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT)
amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved,
...@@ -498,6 +533,20 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, ...@@ -498,6 +533,20 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev,
return r; return r;
} }
/**
* amdgpu_bo_create - create an &amdgpu_bo buffer object
* @adev: amdgpu device object
* @bp: parameters to be used for the buffer object
* @bo_ptr: pointer to the buffer object pointer
*
* Creates an &amdgpu_bo buffer object; and if requested, also creates a
* shadow object.
* Shadow object is used to backup the original buffer object, and is always
* in GTT.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_create(struct amdgpu_device *adev, int amdgpu_bo_create(struct amdgpu_device *adev,
struct amdgpu_bo_param *bp, struct amdgpu_bo_param *bp,
struct amdgpu_bo **bo_ptr) struct amdgpu_bo **bo_ptr)
...@@ -527,6 +576,21 @@ int amdgpu_bo_create(struct amdgpu_device *adev, ...@@ -527,6 +576,21 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
return r; return r;
} }
/**
* amdgpu_bo_backup_to_shadow - Backs up an &amdgpu_bo buffer object
* @adev: amdgpu device object
* @ring: amdgpu_ring for the engine handling the buffer operations
* @bo: &amdgpu_bo buffer to be backed up
* @resv: reservation object with embedded fence
* @fence: dma_fence associated with the operation
* @direct: whether to submit the job directly
*
* Copies an &amdgpu_bo buffer object to its shadow object.
* Not used for now.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev, int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
struct amdgpu_ring *ring, struct amdgpu_ring *ring,
struct amdgpu_bo *bo, struct amdgpu_bo *bo,
...@@ -559,6 +623,18 @@ int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev, ...@@ -559,6 +623,18 @@ int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
return r; return r;
} }
/**
* amdgpu_bo_validate - validate an &amdgpu_bo buffer object
* @bo: pointer to the buffer object
*
* Sets placement according to domain; and changes placement and caching
* policy of the buffer object according to the placement.
* This is used for validating shadow bos. It calls ttm_bo_validate() to
* make sure the buffer is resident where it needs to be.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_validate(struct amdgpu_bo *bo) int amdgpu_bo_validate(struct amdgpu_bo *bo)
{ {
struct ttm_operation_ctx ctx = { false, false }; struct ttm_operation_ctx ctx = { false, false };
...@@ -581,6 +657,22 @@ int amdgpu_bo_validate(struct amdgpu_bo *bo) ...@@ -581,6 +657,22 @@ int amdgpu_bo_validate(struct amdgpu_bo *bo)
return r; return r;
} }
/**
* amdgpu_bo_restore_from_shadow - restore an &amdgpu_bo buffer object
* @adev: amdgpu device object
* @ring: amdgpu_ring for the engine handling the buffer operations
* @bo: &amdgpu_bo buffer to be restored
* @resv: reservation object with embedded fence
* @fence: dma_fence associated with the operation
* @direct: whether to submit the job directly
*
* Copies a buffer object's shadow content back to the object.
* This is used for recovering a buffer from its shadow in case of a gpu
* reset where vram context may be lost.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev, int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev,
struct amdgpu_ring *ring, struct amdgpu_ring *ring,
struct amdgpu_bo *bo, struct amdgpu_bo *bo,
...@@ -613,6 +705,17 @@ int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev, ...@@ -613,6 +705,17 @@ int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev,
return r; return r;
} }
/**
* amdgpu_bo_kmap - map an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be mapped
* @ptr: kernel virtual address to be returned
*
* Calls ttm_bo_kmap() to set up the kernel virtual mapping; calls
* amdgpu_bo_kptr() to get the kernel virtual address.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
{ {
void *kptr; void *kptr;
...@@ -643,6 +746,15 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) ...@@ -643,6 +746,15 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
return 0; return 0;
} }
/**
* amdgpu_bo_kptr - returns a kernel virtual address of the buffer object
* @bo: &amdgpu_bo buffer object
*
* Calls ttm_kmap_obj_virtual() to get the kernel virtual address
*
* Returns:
* the virtual address of a buffer object area.
*/
void *amdgpu_bo_kptr(struct amdgpu_bo *bo) void *amdgpu_bo_kptr(struct amdgpu_bo *bo)
{ {
bool is_iomem; bool is_iomem;
...@@ -650,12 +762,27 @@ void *amdgpu_bo_kptr(struct amdgpu_bo *bo) ...@@ -650,12 +762,27 @@ void *amdgpu_bo_kptr(struct amdgpu_bo *bo)
return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem); return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem);
} }
/**
* amdgpu_bo_kunmap - unmap an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be unmapped
*
* Unmaps a kernel map set up by amdgpu_bo_kmap().
*/
void amdgpu_bo_kunmap(struct amdgpu_bo *bo) void amdgpu_bo_kunmap(struct amdgpu_bo *bo)
{ {
if (bo->kmap.bo) if (bo->kmap.bo)
ttm_bo_kunmap(&bo->kmap); ttm_bo_kunmap(&bo->kmap);
} }
/**
* amdgpu_bo_ref - reference an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object
*
* References the contained &ttm_buffer_object.
*
* Returns:
* a refcounted pointer to the &amdgpu_bo buffer object.
*/
struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo) struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo)
{ {
if (bo == NULL) if (bo == NULL)
...@@ -665,6 +792,12 @@ struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo) ...@@ -665,6 +792,12 @@ struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo)
return bo; return bo;
} }
/**
* amdgpu_bo_unref - unreference an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object
*
* Unreferences the contained &ttm_buffer_object and clear the pointer
*/
void amdgpu_bo_unref(struct amdgpu_bo **bo) void amdgpu_bo_unref(struct amdgpu_bo **bo)
{ {
struct ttm_buffer_object *tbo; struct ttm_buffer_object *tbo;
...@@ -678,6 +811,29 @@ void amdgpu_bo_unref(struct amdgpu_bo **bo) ...@@ -678,6 +811,29 @@ void amdgpu_bo_unref(struct amdgpu_bo **bo)
*bo = NULL; *bo = NULL;
} }
/**
* amdgpu_bo_pin_restricted - pin an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be pinned
* @domain: domain to be pinned to
* @min_offset: the start of requested address range
* @max_offset: the end of requested address range
* @gpu_addr: GPU offset of the &amdgpu_bo buffer object
*
* Pins the buffer object according to requested domain and address range. If
* the memory is unbound gart memory, binds the pages into gart table. Adjusts
* pin_count and pin_size accordingly.
*
* Pinning means to lock pages in memory along with keeping them at a fixed
* offset. It is required when a buffer can not be moved, for example, when
* a display buffer is being scanned out.
*
* Compared with amdgpu_bo_pin(), this function gives more flexibility on
* where to pin a buffer if there are specific restrictions on where a buffer
* must be located.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
u64 min_offset, u64 max_offset, u64 min_offset, u64 max_offset,
u64 *gpu_addr) u64 *gpu_addr)
...@@ -772,11 +928,34 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, ...@@ -772,11 +928,34 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
return r; return r;
} }
/**
* amdgpu_bo_pin - pin an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be pinned
* @domain: domain to be pinned to
* @gpu_addr: GPU offset of the &amdgpu_bo buffer object
*
* A simple wrapper to amdgpu_bo_pin_restricted().
* Provides a simpler API for buffers that do not have any strict restrictions
* on where a buffer must be located.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr) int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr)
{ {
return amdgpu_bo_pin_restricted(bo, domain, 0, 0, gpu_addr); return amdgpu_bo_pin_restricted(bo, domain, 0, 0, gpu_addr);
} }
/**
* amdgpu_bo_unpin - unpin an &amdgpu_bo buffer object
* @bo: &amdgpu_bo buffer object to be unpinned
*
* Decreases the pin_count, and clears the flags if pin_count reaches 0.
* Changes placement and pin size accordingly.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_unpin(struct amdgpu_bo *bo) int amdgpu_bo_unpin(struct amdgpu_bo *bo)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
...@@ -812,6 +991,16 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo) ...@@ -812,6 +991,16 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo)
return r; return r;
} }
/**
* amdgpu_bo_evict_vram - evict VRAM buffers
* @adev: amdgpu device object
*
* Evicts all VRAM buffers on the lru list of the memory type.
* Mainly used for evicting vram at suspend time.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_evict_vram(struct amdgpu_device *adev) int amdgpu_bo_evict_vram(struct amdgpu_device *adev)
{ {
/* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */ /* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */
...@@ -834,6 +1023,15 @@ static const char *amdgpu_vram_names[] = { ...@@ -834,6 +1023,15 @@ static const char *amdgpu_vram_names[] = {
"DDR4", "DDR4",
}; };
/**
* amdgpu_bo_init - initialize memory manager
* @adev: amdgpu device object
*
* Calls amdgpu_ttm_init() to initialize amdgpu memory manager.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_init(struct amdgpu_device *adev) int amdgpu_bo_init(struct amdgpu_device *adev)
{ {
/* reserve PAT memory space to WC for VRAM */ /* reserve PAT memory space to WC for VRAM */
...@@ -851,6 +1049,16 @@ int amdgpu_bo_init(struct amdgpu_device *adev) ...@@ -851,6 +1049,16 @@ int amdgpu_bo_init(struct amdgpu_device *adev)
return amdgpu_ttm_init(adev); return amdgpu_ttm_init(adev);
} }
/**
* amdgpu_bo_late_init - late init
* @adev: amdgpu device object
*
* Calls amdgpu_ttm_late_init() to free resources used earlier during
* initialization.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_late_init(struct amdgpu_device *adev) int amdgpu_bo_late_init(struct amdgpu_device *adev)
{ {
amdgpu_ttm_late_init(adev); amdgpu_ttm_late_init(adev);
...@@ -858,6 +1066,12 @@ int amdgpu_bo_late_init(struct amdgpu_device *adev) ...@@ -858,6 +1066,12 @@ int amdgpu_bo_late_init(struct amdgpu_device *adev)
return 0; return 0;
} }
/**
* amdgpu_bo_fini - tear down memory manager
* @adev: amdgpu device object
*
* Reverses amdgpu_bo_init() to tear down memory manager.
*/
void amdgpu_bo_fini(struct amdgpu_device *adev) void amdgpu_bo_fini(struct amdgpu_device *adev)
{ {
amdgpu_ttm_fini(adev); amdgpu_ttm_fini(adev);
...@@ -865,12 +1079,33 @@ void amdgpu_bo_fini(struct amdgpu_device *adev) ...@@ -865,12 +1079,33 @@ void amdgpu_bo_fini(struct amdgpu_device *adev)
arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size); arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size);
} }
/**
* amdgpu_bo_fbdev_mmap - mmap fbdev memory
* @bo: &amdgpu_bo buffer object
* @vma: vma as input from the fbdev mmap method
*
* Calls ttm_fbdev_mmap() to mmap fbdev memory if it is backed by a bo.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo, int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
struct vm_area_struct *vma) struct vm_area_struct *vma)
{ {
return ttm_fbdev_mmap(vma, &bo->tbo); return ttm_fbdev_mmap(vma, &bo->tbo);
} }
/**
* amdgpu_bo_set_tiling_flags - set tiling flags
* @bo: &amdgpu_bo buffer object
* @tiling_flags: new flags
*
* Sets buffer object's tiling flags with the new one. Used by GEM ioctl or
* kernel driver to set the tiling flags on a buffer.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags) int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
...@@ -883,6 +1118,14 @@ int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags) ...@@ -883,6 +1118,14 @@ int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags)
return 0; return 0;
} }
/**
* amdgpu_bo_get_tiling_flags - get tiling flags
* @bo: &amdgpu_bo buffer object
* @tiling_flags: returned flags
*
* Gets buffer object's tiling flags. Used by GEM ioctl or kernel driver to
* set the tiling flags on a buffer.
*/
void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags) void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags)
{ {
lockdep_assert_held(&bo->tbo.resv->lock.base); lockdep_assert_held(&bo->tbo.resv->lock.base);
...@@ -891,6 +1134,19 @@ void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags) ...@@ -891,6 +1134,19 @@ void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags)
*tiling_flags = bo->tiling_flags; *tiling_flags = bo->tiling_flags;
} }
/**
* amdgpu_bo_set_metadata - set metadata
* @bo: &amdgpu_bo buffer object
* @metadata: new metadata
* @metadata_size: size of the new metadata
* @flags: flags of the new metadata
*
* Sets buffer object's metadata, its size and flags.
* Used via GEM ioctl.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
uint32_t metadata_size, uint64_t flags) uint32_t metadata_size, uint64_t flags)
{ {
...@@ -920,6 +1176,21 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, ...@@ -920,6 +1176,21 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
return 0; return 0;
} }
/**
* amdgpu_bo_get_metadata - get metadata
* @bo: &amdgpu_bo buffer object
* @buffer: returned metadata
* @buffer_size: size of the buffer
* @metadata_size: size of the returned metadata
* @flags: flags of the returned metadata
*
* Gets buffer object's metadata, its size and flags. buffer_size shall not be
* less than metadata_size.
* Used via GEM ioctl.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
size_t buffer_size, uint32_t *metadata_size, size_t buffer_size, uint32_t *metadata_size,
uint64_t *flags) uint64_t *flags)
...@@ -943,6 +1214,16 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, ...@@ -943,6 +1214,16 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
return 0; return 0;
} }
/**
* amdgpu_bo_move_notify - notification about a memory move
* @bo: pointer to a buffer object
* @evict: if this move is evicting the buffer from the graphics address space
* @new_mem: new information of the bufer object
*
* Marks the corresponding &amdgpu_bo buffer object as invalid, also performs
* bookkeeping.
* TTM driver callback which is called when ttm moves a buffer.
*/
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
bool evict, bool evict,
struct ttm_mem_reg *new_mem) struct ttm_mem_reg *new_mem)
...@@ -971,6 +1252,17 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, ...@@ -971,6 +1252,17 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
trace_amdgpu_ttm_bo_move(abo, new_mem->mem_type, old_mem->mem_type); trace_amdgpu_ttm_bo_move(abo, new_mem->mem_type, old_mem->mem_type);
} }
/**
* amdgpu_bo_fault_reserve_notify - notification about a memory fault
* @bo: pointer to a buffer object
*
* Notifies the driver we are taking a fault on this BO and have reserved it,
* also performs bookkeeping.
* TTM driver callback for dealing with vm faults.
*
* Returns:
* 0 for success or a negative error code on failure.
*/
int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
...@@ -1044,10 +1336,11 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence, ...@@ -1044,10 +1336,11 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
* amdgpu_bo_gpu_offset - return GPU offset of bo * amdgpu_bo_gpu_offset - return GPU offset of bo
* @bo: amdgpu object for which we query the offset * @bo: amdgpu object for which we query the offset
* *
* Returns current GPU offset of the object.
*
* Note: object should either be pinned or reserved when calling this * Note: object should either be pinned or reserved when calling this
* function, it might be useful to add check for this for debugging. * function, it might be useful to add check for this for debugging.
*
* Returns:
* current GPU offset of the object.
*/ */
u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
{ {
...@@ -1063,6 +1356,14 @@ u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) ...@@ -1063,6 +1356,14 @@ u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
return bo->tbo.offset; return bo->tbo.offset;
} }
/**
* amdgpu_bo_get_preferred_pin_domain - get preferred domain for scanout
* @adev: amdgpu device object
* @domain: allowed :ref:`memory domains <amdgpu_memory_domains>`
*
* Returns:
* Which of the allowed domains is preferred for pinning the BO for scanout.
*/
uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev, uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev,
uint32_t domain) uint32_t domain)
{ {
......
...@@ -68,11 +68,11 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev) ...@@ -68,11 +68,11 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
if (adev->pm.dpm_enabled) { if (adev->pm.dpm_enabled) {
mutex_lock(&adev->pm.mutex); mutex_lock(&adev->pm.mutex);
if (power_supply_is_system_supplied() > 0) if (power_supply_is_system_supplied() > 0)
adev->pm.dpm.ac_power = true; adev->pm.ac_power = true;
else else
adev->pm.dpm.ac_power = false; adev->pm.ac_power = false;
if (adev->powerplay.pp_funcs->enable_bapm) if (adev->powerplay.pp_funcs->enable_bapm)
amdgpu_dpm_enable_bapm(adev, adev->pm.dpm.ac_power); amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power);
mutex_unlock(&adev->pm.mutex); mutex_unlock(&adev->pm.mutex);
} }
} }
...@@ -80,12 +80,15 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev) ...@@ -80,12 +80,15 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
/** /**
* DOC: power_dpm_state * DOC: power_dpm_state
* *
* This is a legacy interface and is only provided for backwards compatibility. * The power_dpm_state file is a legacy interface and is only provided for
* The amdgpu driver provides a sysfs API for adjusting certain power * backwards compatibility. The amdgpu driver provides a sysfs API for adjusting
* related parameters. The file power_dpm_state is used for this. * certain power related parameters. The file power_dpm_state is used for this.
* It accepts the following arguments: * It accepts the following arguments:
*
* - battery * - battery
*
* - balanced * - balanced
*
* - performance * - performance
* *
* battery * battery
...@@ -169,14 +172,21 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev, ...@@ -169,14 +172,21 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev,
* The amdgpu driver provides a sysfs API for adjusting certain power * The amdgpu driver provides a sysfs API for adjusting certain power
* related parameters. The file power_dpm_force_performance_level is * related parameters. The file power_dpm_force_performance_level is
* used for this. It accepts the following arguments: * used for this. It accepts the following arguments:
*
* - auto * - auto
*
* - low * - low
*
* - high * - high
*
* - manual * - manual
* - GPU fan *
* - profile_standard * - profile_standard
*
* - profile_min_sclk * - profile_min_sclk
*
* - profile_min_mclk * - profile_min_mclk
*
* - profile_peak * - profile_peak
* *
* auto * auto
...@@ -463,8 +473,11 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, ...@@ -463,8 +473,11 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
* this. * this.
* *
* Reading the file will display: * Reading the file will display:
*
* - a list of engine clock levels and voltages labeled OD_SCLK * - a list of engine clock levels and voltages labeled OD_SCLK
*
* - a list of memory clock levels and voltages labeled OD_MCLK * - a list of memory clock levels and voltages labeled OD_MCLK
*
* - a list of valid ranges for sclk, mclk, and voltage labeled OD_RANGE * - a list of valid ranges for sclk, mclk, and voltage labeled OD_RANGE
* *
* To manually adjust these settings, first select manual using * To manually adjust these settings, first select manual using
...@@ -1285,35 +1298,51 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, ...@@ -1285,35 +1298,51 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,
* DOC: hwmon * DOC: hwmon
* *
* The amdgpu driver exposes the following sensor interfaces: * The amdgpu driver exposes the following sensor interfaces:
*
* - GPU temperature (via the on-die sensor) * - GPU temperature (via the on-die sensor)
*
* - GPU voltage * - GPU voltage
*
* - Northbridge voltage (APUs only) * - Northbridge voltage (APUs only)
*
* - GPU power * - GPU power
*
* - GPU fan * - GPU fan
* *
* hwmon interfaces for GPU temperature: * hwmon interfaces for GPU temperature:
*
* - temp1_input: the on die GPU temperature in millidegrees Celsius * - temp1_input: the on die GPU temperature in millidegrees Celsius
*
* - temp1_crit: temperature critical max value in millidegrees Celsius * - temp1_crit: temperature critical max value in millidegrees Celsius
*
* - temp1_crit_hyst: temperature hysteresis for critical limit in millidegrees Celsius * - temp1_crit_hyst: temperature hysteresis for critical limit in millidegrees Celsius
* *
* hwmon interfaces for GPU voltage: * hwmon interfaces for GPU voltage:
*
* - in0_input: the voltage on the GPU in millivolts * - in0_input: the voltage on the GPU in millivolts
*
* - in1_input: the voltage on the Northbridge in millivolts * - in1_input: the voltage on the Northbridge in millivolts
* *
* hwmon interfaces for GPU power: * hwmon interfaces for GPU power:
*
* - power1_average: average power used by the GPU in microWatts * - power1_average: average power used by the GPU in microWatts
*
* - power1_cap_min: minimum cap supported in microWatts * - power1_cap_min: minimum cap supported in microWatts
*
* - power1_cap_max: maximum cap supported in microWatts * - power1_cap_max: maximum cap supported in microWatts
*
* - power1_cap: selected power cap in microWatts * - power1_cap: selected power cap in microWatts
* *
* hwmon interfaces for GPU fan: * hwmon interfaces for GPU fan:
*
* - pwm1: pulse width modulation fan level (0-255) * - pwm1: pulse width modulation fan level (0-255)
* - pwm1_enable: pulse width modulation fan control method *
* 0: no fan speed control * - pwm1_enable: pulse width modulation fan control method (0: no fan speed control, 1: manual fan speed control using pwm interface, 2: automatic fan speed control)
* 1: manual fan speed control using pwm interface *
* 2: automatic fan speed control
* - pwm1_min: pulse width modulation fan control minimum level (0) * - pwm1_min: pulse width modulation fan control minimum level (0)
*
* - pwm1_max: pulse width modulation fan control maximum level (255) * - pwm1_max: pulse width modulation fan control maximum level (255)
*
* - fan1_input: fan speed in RPM * - fan1_input: fan speed in RPM
* *
* You can use hwmon tools like sensors to view this information on your system. * You can use hwmon tools like sensors to view this information on your system.
...@@ -1878,6 +1907,14 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) ...@@ -1878,6 +1907,14 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
amdgpu_fence_wait_empty(ring); amdgpu_fence_wait_empty(ring);
} }
mutex_lock(&adev->pm.mutex);
/* update battery/ac status */
if (power_supply_is_system_supplied() > 0)
adev->pm.ac_power = true;
else
adev->pm.ac_power = false;
mutex_unlock(&adev->pm.mutex);
if (adev->powerplay.pp_funcs->dispatch_tasks) { if (adev->powerplay.pp_funcs->dispatch_tasks) {
if (!amdgpu_device_has_dc_support(adev)) { if (!amdgpu_device_has_dc_support(adev)) {
mutex_lock(&adev->pm.mutex); mutex_lock(&adev->pm.mutex);
...@@ -1898,14 +1935,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) ...@@ -1898,14 +1935,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
} else { } else {
mutex_lock(&adev->pm.mutex); mutex_lock(&adev->pm.mutex);
amdgpu_dpm_get_active_displays(adev); amdgpu_dpm_get_active_displays(adev);
/* update battery/ac status */
if (power_supply_is_system_supplied() > 0)
adev->pm.dpm.ac_power = true;
else
adev->pm.dpm.ac_power = false;
amdgpu_dpm_change_power_state_locked(adev); amdgpu_dpm_change_power_state_locked(adev);
mutex_unlock(&adev->pm.mutex); mutex_unlock(&adev->pm.mutex);
} }
} }
......
...@@ -23,6 +23,14 @@ ...@@ -23,6 +23,14 @@
* *
* Authors: Alex Deucher * Authors: Alex Deucher
*/ */
/**
* DOC: PRIME Buffer Sharing
*
* The following callback implementations are used for :ref:`sharing GEM buffer
* objects between different devices via PRIME <prime_buffer_sharing>`.
*/
#include <drm/drmP.h> #include <drm/drmP.h>
#include "amdgpu.h" #include "amdgpu.h"
...@@ -32,6 +40,14 @@ ...@@ -32,6 +40,14 @@
static const struct dma_buf_ops amdgpu_dmabuf_ops; static const struct dma_buf_ops amdgpu_dmabuf_ops;
/**
* amdgpu_gem_prime_get_sg_table - &drm_driver.gem_prime_get_sg_table
* implementation
* @obj: GEM buffer object
*
* Returns:
* A scatter/gather table for the pinned pages of the buffer object's memory.
*/
struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj) struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj)
{ {
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
...@@ -40,6 +56,15 @@ struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj) ...@@ -40,6 +56,15 @@ struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj)
return drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages); return drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages);
} }
/**
* amdgpu_gem_prime_vmap - &dma_buf_ops.vmap implementation
* @obj: GEM buffer object
*
* Sets up an in-kernel virtual mapping of the buffer object's memory.
*
* Returns:
* The virtual address of the mapping or an error pointer.
*/
void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj) void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj)
{ {
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
...@@ -53,6 +78,13 @@ void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj) ...@@ -53,6 +78,13 @@ void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj)
return bo->dma_buf_vmap.virtual; return bo->dma_buf_vmap.virtual;
} }
/**
* amdgpu_gem_prime_vunmap - &dma_buf_ops.vunmap implementation
* @obj: GEM buffer object
* @vaddr: virtual address (unused)
*
* Tears down the in-kernel virtual mapping of the buffer object's memory.
*/
void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
{ {
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
...@@ -60,6 +92,17 @@ void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) ...@@ -60,6 +92,17 @@ void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
ttm_bo_kunmap(&bo->dma_buf_vmap); ttm_bo_kunmap(&bo->dma_buf_vmap);
} }
/**
* amdgpu_gem_prime_mmap - &drm_driver.gem_prime_mmap implementation
* @obj: GEM buffer object
* @vma: virtual memory area
*
* Sets up a userspace mapping of the buffer object's memory in the given
* virtual memory area.
*
* Returns:
* 0 on success or negative error code.
*/
int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
{ {
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
...@@ -94,6 +137,19 @@ int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma ...@@ -94,6 +137,19 @@ int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma
return ret; return ret;
} }
/**
* amdgpu_gem_prime_import_sg_table - &drm_driver.gem_prime_import_sg_table
* implementation
* @dev: DRM device
* @attach: DMA-buf attachment
* @sg: Scatter/gather table
*
* Import shared DMA buffer memory exported by another device.
*
* Returns:
* A new GEM buffer object of the given DRM device, representing the memory
* described by the given DMA-buf attachment and scatter/gather table.
*/
struct drm_gem_object * struct drm_gem_object *
amdgpu_gem_prime_import_sg_table(struct drm_device *dev, amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct dma_buf_attachment *attach,
...@@ -132,6 +188,19 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, ...@@ -132,6 +188,19 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
/**
* amdgpu_gem_map_attach - &dma_buf_ops.attach implementation
* @dma_buf: shared DMA buffer
* @target_dev: target device
* @attach: DMA-buf attachment
*
* Makes sure that the shared DMA buffer can be accessed by the target device.
* For now, simply pins it to the GTT domain, where it should be accessible by
* all DMA devices.
*
* Returns:
* 0 on success or negative error code.
*/
static int amdgpu_gem_map_attach(struct dma_buf *dma_buf, static int amdgpu_gem_map_attach(struct dma_buf *dma_buf,
struct dma_buf_attachment *attach) struct dma_buf_attachment *attach)
{ {
...@@ -180,6 +249,14 @@ static int amdgpu_gem_map_attach(struct dma_buf *dma_buf, ...@@ -180,6 +249,14 @@ static int amdgpu_gem_map_attach(struct dma_buf *dma_buf,
return r; return r;
} }
/**
* amdgpu_gem_map_detach - &dma_buf_ops.detach implementation
* @dma_buf: shared DMA buffer
* @attach: DMA-buf attachment
*
* This is called when a shared DMA buffer no longer needs to be accessible by
* the other device. For now, simply unpins the buffer from GTT.
*/
static void amdgpu_gem_map_detach(struct dma_buf *dma_buf, static void amdgpu_gem_map_detach(struct dma_buf *dma_buf,
struct dma_buf_attachment *attach) struct dma_buf_attachment *attach)
{ {
...@@ -201,6 +278,13 @@ static void amdgpu_gem_map_detach(struct dma_buf *dma_buf, ...@@ -201,6 +278,13 @@ static void amdgpu_gem_map_detach(struct dma_buf *dma_buf,
drm_gem_map_detach(dma_buf, attach); drm_gem_map_detach(dma_buf, attach);
} }
/**
* amdgpu_gem_prime_res_obj - &drm_driver.gem_prime_res_obj implementation
* @obj: GEM buffer object
*
* Returns:
* The buffer object's reservation object.
*/
struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj) struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj)
{ {
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
...@@ -208,6 +292,18 @@ struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj) ...@@ -208,6 +292,18 @@ struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj)
return bo->tbo.resv; return bo->tbo.resv;
} }
/**
* amdgpu_gem_begin_cpu_access - &dma_buf_ops.begin_cpu_access implementation
* @dma_buf: shared DMA buffer
* @direction: direction of DMA transfer
*
* This is called before CPU access to the shared DMA buffer's memory. If it's
* a read access, the buffer is moved to the GTT domain if possible, for optimal
* CPU read performance.
*
* Returns:
* 0 on success or negative error code.
*/
static int amdgpu_gem_begin_cpu_access(struct dma_buf *dma_buf, static int amdgpu_gem_begin_cpu_access(struct dma_buf *dma_buf,
enum dma_data_direction direction) enum dma_data_direction direction)
{ {
...@@ -250,6 +346,18 @@ static const struct dma_buf_ops amdgpu_dmabuf_ops = { ...@@ -250,6 +346,18 @@ static const struct dma_buf_ops amdgpu_dmabuf_ops = {
.vunmap = drm_gem_dmabuf_vunmap, .vunmap = drm_gem_dmabuf_vunmap,
}; };
/**
* amdgpu_gem_prime_export - &drm_driver.gem_prime_export implementation
* @dev: DRM device
* @gobj: GEM buffer object
* @flags: flags like DRM_CLOEXEC and DRM_RDWR
*
* The main work is done by the &drm_gem_prime_export helper, which in turn
* uses &amdgpu_gem_prime_res_obj.
*
* Returns:
* Shared DMA buffer representing the GEM buffer object from the given device.
*/
struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
struct drm_gem_object *gobj, struct drm_gem_object *gobj,
int flags) int flags)
...@@ -270,6 +378,17 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, ...@@ -270,6 +378,17 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
return buf; return buf;
} }
/**
* amdgpu_gem_prime_import - &drm_driver.gem_prime_import implementation
* @dev: DRM device
* @dma_buf: Shared DMA buffer
*
* The main work is done by the &drm_gem_prime_import helper, which in turn
* uses &amdgpu_gem_prime_import_sg_table.
*
* Returns:
* GEM buffer object representing the shared DMA buffer for the given device.
*/
struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev,
struct dma_buf *dma_buf) struct dma_buf *dma_buf)
{ {
......
...@@ -96,6 +96,9 @@ static int amdgpu_identity_map(struct amdgpu_device *adev, ...@@ -96,6 +96,9 @@ static int amdgpu_identity_map(struct amdgpu_device *adev,
case AMDGPU_HW_IP_VCN_ENC: case AMDGPU_HW_IP_VCN_ENC:
*out_ring = &adev->vcn.ring_enc[ring]; *out_ring = &adev->vcn.ring_enc[ring];
break; break;
case AMDGPU_HW_IP_VCN_JPEG:
*out_ring = &adev->vcn.ring_jpeg;
break;
default: default:
*out_ring = NULL; *out_ring = NULL;
DRM_ERROR("unknown HW IP type: %d\n", mapper->hw_ip); DRM_ERROR("unknown HW IP type: %d\n", mapper->hw_ip);
...@@ -260,6 +263,9 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev, ...@@ -260,6 +263,9 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev,
case AMDGPU_HW_IP_VCN_ENC: case AMDGPU_HW_IP_VCN_ENC:
ip_num_rings = adev->vcn.num_enc_rings; ip_num_rings = adev->vcn.num_enc_rings;
break; break;
case AMDGPU_HW_IP_VCN_JPEG:
ip_num_rings = 1;
break;
default: default:
DRM_DEBUG("unknown ip type: %d\n", hw_ip); DRM_DEBUG("unknown ip type: %d\n", hw_ip);
return -EINVAL; return -EINVAL;
...@@ -287,6 +293,7 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev, ...@@ -287,6 +293,7 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev,
case AMDGPU_HW_IP_UVD_ENC: case AMDGPU_HW_IP_UVD_ENC:
case AMDGPU_HW_IP_VCN_DEC: case AMDGPU_HW_IP_VCN_DEC:
case AMDGPU_HW_IP_VCN_ENC: case AMDGPU_HW_IP_VCN_ENC:
case AMDGPU_HW_IP_VCN_JPEG:
r = amdgpu_identity_map(adev, mapper, ring, out_ring); r = amdgpu_identity_map(adev, mapper, ring, out_ring);
break; break;
case AMDGPU_HW_IP_DMA: case AMDGPU_HW_IP_DMA:
......
...@@ -304,7 +304,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, ...@@ -304,7 +304,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
0xffffffffffffffff : ring->buf_mask; 0xffffffffffffffff : ring->buf_mask;
/* Allocate ring buffer */ /* Allocate ring buffer */
if (ring->ring_obj == NULL) { if (ring->ring_obj == NULL) {
r = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE, r = amdgpu_bo_create_kernel(adev, ring->ring_size + ring->funcs->extra_dw, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_GTT, AMDGPU_GEM_DOMAIN_GTT,
&ring->ring_obj, &ring->ring_obj,
&ring->gpu_addr, &ring->gpu_addr,
......
...@@ -53,7 +53,8 @@ enum amdgpu_ring_type { ...@@ -53,7 +53,8 @@ enum amdgpu_ring_type {
AMDGPU_RING_TYPE_KIQ, AMDGPU_RING_TYPE_KIQ,
AMDGPU_RING_TYPE_UVD_ENC, AMDGPU_RING_TYPE_UVD_ENC,
AMDGPU_RING_TYPE_VCN_DEC, AMDGPU_RING_TYPE_VCN_DEC,
AMDGPU_RING_TYPE_VCN_ENC AMDGPU_RING_TYPE_VCN_ENC,
AMDGPU_RING_TYPE_VCN_JPEG
}; };
struct amdgpu_device; struct amdgpu_device;
...@@ -112,6 +113,7 @@ struct amdgpu_ring_funcs { ...@@ -112,6 +113,7 @@ struct amdgpu_ring_funcs {
u32 nop; u32 nop;
bool support_64bit_ptrs; bool support_64bit_ptrs;
unsigned vmhub; unsigned vmhub;
unsigned extra_dw;
/* ring read/write ptr handling */ /* ring read/write ptr handling */
u64 (*get_rptr)(struct amdgpu_ring *ring); u64 (*get_rptr)(struct amdgpu_ring *ring);
......
...@@ -277,7 +277,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, ...@@ -277,7 +277,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo,
if (!adev->mman.buffer_funcs_enabled) { if (!adev->mman.buffer_funcs_enabled) {
/* Move to system memory */ /* Move to system memory */
amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU);
} else if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && } else if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
!(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) && !(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) &&
amdgpu_bo_in_cpu_visible_vram(abo)) { amdgpu_bo_in_cpu_visible_vram(abo)) {
......
...@@ -127,7 +127,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) ...@@ -127,7 +127,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
unsigned long bo_size; unsigned long bo_size;
const char *fw_name; const char *fw_name;
const struct common_firmware_header *hdr; const struct common_firmware_header *hdr;
unsigned version_major, version_minor, family_id; unsigned family_id;
int i, j, r; int i, j, r;
INIT_DELAYED_WORK(&adev->uvd.inst->idle_work, amdgpu_uvd_idle_work_handler); INIT_DELAYED_WORK(&adev->uvd.inst->idle_work, amdgpu_uvd_idle_work_handler);
...@@ -208,6 +208,10 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) ...@@ -208,6 +208,10 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
hdr = (const struct common_firmware_header *)adev->uvd.fw->data; hdr = (const struct common_firmware_header *)adev->uvd.fw->data;
family_id = le32_to_cpu(hdr->ucode_version) & 0xff; family_id = le32_to_cpu(hdr->ucode_version) & 0xff;
if (adev->asic_type < CHIP_VEGA20) {
unsigned version_major, version_minor;
version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff;
version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n", DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n",
...@@ -231,6 +235,19 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) ...@@ -231,6 +235,19 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
(adev->uvd.fw_version < FW_1_66_16)) (adev->uvd.fw_version < FW_1_66_16))
DRM_ERROR("POLARIS10/11 UVD firmware version %hu.%hu is too old.\n", DRM_ERROR("POLARIS10/11 UVD firmware version %hu.%hu is too old.\n",
version_major, version_minor); version_major, version_minor);
} else {
unsigned int enc_major, enc_minor, dec_minor;
dec_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
enc_minor = (le32_to_cpu(hdr->ucode_version) >> 24) & 0x3f;
enc_major = (le32_to_cpu(hdr->ucode_version) >> 30) & 0x3;
DRM_INFO("Found UVD firmware ENC: %hu.%hu DEC: .%hu Family ID: %hu\n",
enc_major, enc_minor, dec_minor, family_id);
adev->uvd.max_handles = AMDGPU_MAX_UVD_HANDLES;
adev->uvd.fw_version = le32_to_cpu(hdr->ucode_version);
}
bo_size = AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE bo_size = AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE
+ AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles; + AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles;
......
...@@ -119,6 +119,8 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev) ...@@ -119,6 +119,8 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev)
for (i = 0; i < adev->vcn.num_enc_rings; ++i) for (i = 0; i < adev->vcn.num_enc_rings; ++i)
amdgpu_ring_fini(&adev->vcn.ring_enc[i]); amdgpu_ring_fini(&adev->vcn.ring_enc[i]);
amdgpu_ring_fini(&adev->vcn.ring_jpeg);
release_firmware(adev->vcn.fw); release_firmware(adev->vcn.fw);
return 0; return 0;
...@@ -576,3 +578,129 @@ int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) ...@@ -576,3 +578,129 @@ int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
dma_fence_put(fence); dma_fence_put(fence);
return r; return r;
} }
int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
uint32_t tmp = 0;
unsigned i;
int r;
WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID), 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
if (r) {
DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
ring->idx, r);
return r;
}
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID), 0, 0, 0));
amdgpu_ring_write(ring, 0xDEADBEEF);
amdgpu_ring_commit(ring);
for (i = 0; i < adev->usec_timeout; i++) {
tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID));
if (tmp == 0xDEADBEEF)
break;
DRM_UDELAY(1);
}
if (i < adev->usec_timeout) {
DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
ring->idx, i);
} else {
DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
ring->idx, tmp);
r = -EINVAL;
}
return r;
}
static int amdgpu_vcn_jpeg_set_reg(struct amdgpu_ring *ring, uint32_t handle,
struct dma_fence **fence)
{
struct amdgpu_device *adev = ring->adev;
struct amdgpu_job *job;
struct amdgpu_ib *ib;
struct dma_fence *f = NULL;
const unsigned ib_size_dw = 16;
int i, r;
r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job);
if (r)
return r;
ib = &job->ibs[0];
ib->ptr[0] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH), 0, 0, PACKETJ_TYPE0);
ib->ptr[1] = 0xDEADBEEF;
for (i = 2; i < 16; i += 2) {
ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6);
ib->ptr[i+1] = 0;
}
ib->length_dw = 16;
r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f);
job->fence = dma_fence_get(f);
if (r)
goto err;
amdgpu_job_free(job);
if (fence)
*fence = dma_fence_get(f);
dma_fence_put(f);
return 0;
err:
amdgpu_job_free(job);
return r;
}
int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout)
{
struct amdgpu_device *adev = ring->adev;
uint32_t tmp = 0;
unsigned i;
struct dma_fence *fence = NULL;
long r = 0;
r = amdgpu_vcn_jpeg_set_reg(ring, 1, &fence);
if (r) {
DRM_ERROR("amdgpu: failed to set jpeg register (%ld).\n", r);
goto error;
}
r = dma_fence_wait_timeout(fence, false, timeout);
if (r == 0) {
DRM_ERROR("amdgpu: IB test timed out.\n");
r = -ETIMEDOUT;
goto error;
} else if (r < 0) {
DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto error;
} else
r = 0;
for (i = 0; i < adev->usec_timeout; i++) {
tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH));
if (tmp == 0xDEADBEEF)
break;
DRM_UDELAY(1);
}
if (i < adev->usec_timeout)
DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
else {
DRM_ERROR("ib test failed (0x%08X)\n", tmp);
r = -EINVAL;
}
dma_fence_put(fence);
error:
return r;
}
...@@ -66,6 +66,7 @@ struct amdgpu_vcn { ...@@ -66,6 +66,7 @@ struct amdgpu_vcn {
const struct firmware *fw; /* VCN firmware */ const struct firmware *fw; /* VCN firmware */
struct amdgpu_ring ring_dec; struct amdgpu_ring ring_dec;
struct amdgpu_ring ring_enc[AMDGPU_VCN_MAX_ENC_RINGS]; struct amdgpu_ring ring_enc[AMDGPU_VCN_MAX_ENC_RINGS];
struct amdgpu_ring ring_jpeg;
struct amdgpu_irq_src irq; struct amdgpu_irq_src irq;
unsigned num_enc_rings; unsigned num_enc_rings;
}; };
...@@ -83,4 +84,7 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout); ...@@ -83,4 +84,7 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout);
int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring); int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring);
int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout); int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout);
int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring);
int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout);
#endif #endif
...@@ -1221,7 +1221,7 @@ static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, ...@@ -1221,7 +1221,7 @@ static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index,
ectx.abort = false; ectx.abort = false;
ectx.last_jump = 0; ectx.last_jump = 0;
if (ws) if (ws)
ectx.ws = kcalloc(4, ws, GFP_KERNEL); ectx.ws = kcalloc(4, ws, GFP_ATOMIC);
else else
ectx.ws = NULL; ectx.ws = NULL;
......
...@@ -951,12 +951,12 @@ static void ci_apply_state_adjust_rules(struct amdgpu_device *adev, ...@@ -951,12 +951,12 @@ static void ci_apply_state_adjust_rules(struct amdgpu_device *adev,
else else
pi->battery_state = false; pi->battery_state = false;
if (adev->pm.dpm.ac_power) if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
if (adev->pm.dpm.ac_power == false) { if (adev->pm.ac_power == false) {
for (i = 0; i < ps->performance_level_count; i++) { for (i = 0; i < ps->performance_level_count; i++) {
if (ps->performance_levels[i].mclk > max_limits->mclk) if (ps->performance_levels[i].mclk > max_limits->mclk)
ps->performance_levels[i].mclk = max_limits->mclk; ps->performance_levels[i].mclk = max_limits->mclk;
...@@ -4078,7 +4078,7 @@ static int ci_enable_uvd_dpm(struct amdgpu_device *adev, bool enable) ...@@ -4078,7 +4078,7 @@ static int ci_enable_uvd_dpm(struct amdgpu_device *adev, bool enable)
const struct amdgpu_clock_and_voltage_limits *max_limits; const struct amdgpu_clock_and_voltage_limits *max_limits;
int i; int i;
if (adev->pm.dpm.ac_power) if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
...@@ -4127,7 +4127,7 @@ static int ci_enable_vce_dpm(struct amdgpu_device *adev, bool enable) ...@@ -4127,7 +4127,7 @@ static int ci_enable_vce_dpm(struct amdgpu_device *adev, bool enable)
const struct amdgpu_clock_and_voltage_limits *max_limits; const struct amdgpu_clock_and_voltage_limits *max_limits;
int i; int i;
if (adev->pm.dpm.ac_power) if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
...@@ -4160,7 +4160,7 @@ static int ci_enable_samu_dpm(struct amdgpu_device *adev, bool enable) ...@@ -4160,7 +4160,7 @@ static int ci_enable_samu_dpm(struct amdgpu_device *adev, bool enable)
const struct amdgpu_clock_and_voltage_limits *max_limits; const struct amdgpu_clock_and_voltage_limits *max_limits;
int i; int i;
if (adev->pm.dpm.ac_power) if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
...@@ -4191,7 +4191,7 @@ static int ci_enable_acp_dpm(struct amdgpu_device *adev, bool enable) ...@@ -4191,7 +4191,7 @@ static int ci_enable_acp_dpm(struct amdgpu_device *adev, bool enable)
const struct amdgpu_clock_and_voltage_limits *max_limits; const struct amdgpu_clock_and_voltage_limits *max_limits;
int i; int i;
if (adev->pm.dpm.ac_power) if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
......
...@@ -2003,9 +2003,9 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) ...@@ -2003,9 +2003,9 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block);
amdgpu_device_ip_block_add(adev, &cik_ih_ip_block); amdgpu_device_ip_block_add(adev, &cik_ih_ip_block);
if (amdgpu_dpm == -1) if (amdgpu_dpm == -1)
amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
else
amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
else
amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
if (adev->enable_virtual_display) if (adev->enable_virtual_display)
amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block);
#if defined(CONFIG_DRM_AMD_DC) #if defined(CONFIG_DRM_AMD_DC)
...@@ -2024,9 +2024,9 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) ...@@ -2024,9 +2024,9 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block); amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block);
amdgpu_device_ip_block_add(adev, &cik_ih_ip_block); amdgpu_device_ip_block_add(adev, &cik_ih_ip_block);
if (amdgpu_dpm == -1) if (amdgpu_dpm == -1)
amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
else
amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
else
amdgpu_device_ip_block_add(adev, &ci_smu_ip_block);
if (adev->enable_virtual_display) if (adev->enable_virtual_display)
amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block);
#if defined(CONFIG_DRM_AMD_DC) #if defined(CONFIG_DRM_AMD_DC)
......
...@@ -866,26 +866,32 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) ...@@ -866,26 +866,32 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
struct amdgpu_device *adev = ring->adev; struct amdgpu_device *adev = ring->adev;
struct amdgpu_ib ib; struct amdgpu_ib ib;
struct dma_fence *f = NULL; struct dma_fence *f = NULL;
uint32_t scratch;
uint32_t tmp = 0; unsigned int index;
uint64_t gpu_addr;
uint32_t tmp;
long r; long r;
r = amdgpu_gfx_scratch_get(adev, &scratch); r = amdgpu_device_wb_get(adev, &index);
if (r) { if (r) {
DRM_ERROR("amdgpu: failed to get scratch reg (%ld).\n", r); dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
return r; return r;
} }
WREG32(scratch, 0xCAFEDEAD);
gpu_addr = adev->wb.gpu_addr + (index * 4);
adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD);
memset(&ib, 0, sizeof(ib)); memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 256, &ib); r = amdgpu_ib_get(adev, NULL, 16, &ib);
if (r) { if (r) {
DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r); DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
goto err1; goto err1;
} }
ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); ib.ptr[0] = PACKET3(PACKET3_WRITE_DATA, 3);
ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START)); ib.ptr[1] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
ib.ptr[2] = 0xDEADBEEF; ib.ptr[2] = lower_32_bits(gpu_addr);
ib.length_dw = 3; ib.ptr[3] = upper_32_bits(gpu_addr);
ib.ptr[4] = 0xDEADBEEF;
ib.length_dw = 5;
r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f); r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f);
if (r) if (r)
...@@ -900,20 +906,21 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) ...@@ -900,20 +906,21 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r); DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err2; goto err2;
} }
tmp = RREG32(scratch);
tmp = adev->wb.wb[index];
if (tmp == 0xDEADBEEF) { if (tmp == 0xDEADBEEF) {
DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx); DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
r = 0; r = 0;
} else { } else {
DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n", DRM_ERROR("ib test on ring %d failed\n", ring->idx);
scratch, tmp);
r = -EINVAL; r = -EINVAL;
} }
err2: err2:
amdgpu_ib_free(adev, &ib, NULL); amdgpu_ib_free(adev, &ib, NULL);
dma_fence_put(f); dma_fence_put(f);
err1: err1:
amdgpu_gfx_scratch_free(adev, scratch); amdgpu_device_wb_free(adev, index);
return r; return r;
} }
...@@ -2048,6 +2055,20 @@ static int gfx_v8_0_sw_init(void *handle) ...@@ -2048,6 +2055,20 @@ static int gfx_v8_0_sw_init(void *handle)
if (r) if (r)
return r; return r;
/* Add CP EDC/ECC irq */
r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 197,
&adev->gfx.cp_ecc_error_irq);
if (r)
return r;
/* SQ interrupts. */
r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 239,
&adev->gfx.sq_irq);
if (r) {
DRM_ERROR("amdgpu_irq_add() for SQ failed: %d\n", r);
return r;
}
adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
gfx_v8_0_scratch_init(adev); gfx_v8_0_scratch_init(adev);
...@@ -5111,6 +5132,10 @@ static int gfx_v8_0_hw_fini(void *handle) ...@@ -5111,6 +5132,10 @@ static int gfx_v8_0_hw_fini(void *handle)
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.sq_irq, 0);
/* disable KCQ to avoid CPC touch memory not valid anymore */ /* disable KCQ to avoid CPC touch memory not valid anymore */
for (i = 0; i < adev->gfx.num_compute_rings; i++) for (i = 0; i < adev->gfx.num_compute_rings; i++)
gfx_v8_0_kcq_disable(&adev->gfx.kiq.ring, &adev->gfx.compute_ring[i]); gfx_v8_0_kcq_disable(&adev->gfx.kiq.ring, &adev->gfx.compute_ring[i]);
...@@ -5542,6 +5567,20 @@ static int gfx_v8_0_late_init(void *handle) ...@@ -5542,6 +5567,20 @@ static int gfx_v8_0_late_init(void *handle)
if (r) if (r)
return r; return r;
r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0);
if (r) {
DRM_ERROR("amdgpu_irq_get() failed to get IRQ for EDC, r: %d.\n", r);
return r;
}
r = amdgpu_irq_get(adev, &adev->gfx.sq_irq, 0);
if (r) {
DRM_ERROR(
"amdgpu_irq_get() failed to get IRQ for SQ, r: %d.\n",
r);
return r;
}
amdgpu_device_ip_set_powergating_state(adev, amdgpu_device_ip_set_powergating_state(adev,
AMD_IP_BLOCK_TYPE_GFX, AMD_IP_BLOCK_TYPE_GFX,
AMD_PG_STATE_GATE); AMD_PG_STATE_GATE);
...@@ -6787,6 +6826,77 @@ static int gfx_v8_0_set_eop_interrupt_state(struct amdgpu_device *adev, ...@@ -6787,6 +6826,77 @@ static int gfx_v8_0_set_eop_interrupt_state(struct amdgpu_device *adev,
return 0; return 0;
} }
static int gfx_v8_0_set_cp_ecc_int_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
unsigned int type,
enum amdgpu_interrupt_state state)
{
int enable_flag;
switch (state) {
case AMDGPU_IRQ_STATE_DISABLE:
enable_flag = 0;
break;
case AMDGPU_IRQ_STATE_ENABLE:
enable_flag = 1;
break;
default:
return -EINVAL;
}
WREG32_FIELD(CP_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CP_INT_CNTL_RING0, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CP_INT_CNTL_RING1, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CP_INT_CNTL_RING2, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CPC_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, enable_flag);
WREG32_FIELD(CP_ME1_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME1_PIPE1_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME1_PIPE2_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME1_PIPE3_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME2_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME2_PIPE1_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME2_PIPE2_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
WREG32_FIELD(CP_ME2_PIPE3_INT_CNTL, CP_ECC_ERROR_INT_ENABLE,
enable_flag);
return 0;
}
static int gfx_v8_0_set_sq_int_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
unsigned int type,
enum amdgpu_interrupt_state state)
{
int enable_flag;
switch (state) {
case AMDGPU_IRQ_STATE_DISABLE:
enable_flag = 1;
break;
case AMDGPU_IRQ_STATE_ENABLE:
enable_flag = 0;
break;
default:
return -EINVAL;
}
WREG32_FIELD(SQ_INTERRUPT_MSG_CTRL, STALL,
enable_flag);
return 0;
}
static int gfx_v8_0_eop_irq(struct amdgpu_device *adev, static int gfx_v8_0_eop_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source, struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry) struct amdgpu_iv_entry *entry)
...@@ -6837,6 +6947,69 @@ static int gfx_v8_0_priv_inst_irq(struct amdgpu_device *adev, ...@@ -6837,6 +6947,69 @@ static int gfx_v8_0_priv_inst_irq(struct amdgpu_device *adev,
return 0; return 0;
} }
static int gfx_v8_0_cp_ecc_error_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
DRM_ERROR("CP EDC/ECC error detected.");
return 0;
}
static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
u8 enc, se_id;
char type[20];
/* Parse all fields according to SQ_INTERRUPT* registers */
enc = (entry->src_data[0] >> 26) & 0x3;
se_id = (entry->src_data[0] >> 24) & 0x3;
switch (enc) {
case 0:
DRM_INFO("SQ general purpose intr detected:"
"se_id %d, immed_overflow %d, host_reg_overflow %d,"
"host_cmd_overflow %d, cmd_timestamp %d,"
"reg_timestamp %d, thread_trace_buff_full %d,"
"wlt %d, thread_trace %d.\n",
se_id,
(entry->src_data[0] >> 7) & 0x1,
(entry->src_data[0] >> 6) & 0x1,
(entry->src_data[0] >> 5) & 0x1,
(entry->src_data[0] >> 4) & 0x1,
(entry->src_data[0] >> 3) & 0x1,
(entry->src_data[0] >> 2) & 0x1,
(entry->src_data[0] >> 1) & 0x1,
entry->src_data[0] & 0x1
);
break;
case 1:
case 2:
if (enc == 1)
sprintf(type, "instruction intr");
else
sprintf(type, "EDC/ECC error");
DRM_INFO(
"SQ %s detected: "
"se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n",
type, se_id,
(entry->src_data[0] >> 20) & 0xf,
(entry->src_data[0] >> 18) & 0x3,
(entry->src_data[0] >> 14) & 0xf,
(entry->src_data[0] >> 10) & 0xf
);
break;
default:
DRM_ERROR("SQ invalid encoding type\n.");
return -EINVAL;
}
return 0;
}
static int gfx_v8_0_kiq_set_interrupt_state(struct amdgpu_device *adev, static int gfx_v8_0_kiq_set_interrupt_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *src, struct amdgpu_irq_src *src,
unsigned int type, unsigned int type,
...@@ -7037,6 +7210,16 @@ static const struct amdgpu_irq_src_funcs gfx_v8_0_kiq_irq_funcs = { ...@@ -7037,6 +7210,16 @@ static const struct amdgpu_irq_src_funcs gfx_v8_0_kiq_irq_funcs = {
.process = gfx_v8_0_kiq_irq, .process = gfx_v8_0_kiq_irq,
}; };
static const struct amdgpu_irq_src_funcs gfx_v8_0_cp_ecc_error_irq_funcs = {
.set = gfx_v8_0_set_cp_ecc_int_state,
.process = gfx_v8_0_cp_ecc_error_irq,
};
static const struct amdgpu_irq_src_funcs gfx_v8_0_sq_irq_funcs = {
.set = gfx_v8_0_set_sq_int_state,
.process = gfx_v8_0_sq_irq,
};
static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev) static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev)
{ {
adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST; adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST;
...@@ -7050,6 +7233,12 @@ static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev) ...@@ -7050,6 +7233,12 @@ static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev)
adev->gfx.kiq.irq.num_types = AMDGPU_CP_KIQ_IRQ_LAST; adev->gfx.kiq.irq.num_types = AMDGPU_CP_KIQ_IRQ_LAST;
adev->gfx.kiq.irq.funcs = &gfx_v8_0_kiq_irq_funcs; adev->gfx.kiq.irq.funcs = &gfx_v8_0_kiq_irq_funcs;
adev->gfx.cp_ecc_error_irq.num_types = 1;
adev->gfx.cp_ecc_error_irq.funcs = &gfx_v8_0_cp_ecc_error_irq_funcs;
adev->gfx.sq_irq.num_types = 1;
adev->gfx.sq_irq.funcs = &gfx_v8_0_sq_irq_funcs;
} }
static void gfx_v8_0_set_rlc_funcs(struct amdgpu_device *adev) static void gfx_v8_0_set_rlc_funcs(struct amdgpu_device *adev)
......
...@@ -1921,7 +1921,7 @@ static int kv_dpm_set_power_state(void *handle) ...@@ -1921,7 +1921,7 @@ static int kv_dpm_set_power_state(void *handle)
int ret; int ret;
if (pi->bapm_enable) { if (pi->bapm_enable) {
ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.dpm.ac_power); ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.ac_power);
if (ret) { if (ret) {
DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n"); DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n");
return ret; return ret;
......
...@@ -3480,7 +3480,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, ...@@ -3480,7 +3480,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
disable_sclk_switching = true; disable_sclk_switching = true;
} }
if (adev->pm.dpm.ac_power) if (adev->pm.ac_power)
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
else else
max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
...@@ -3489,7 +3489,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, ...@@ -3489,7 +3489,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
if (ps->performance_levels[i].vddc > ps->performance_levels[i+1].vddc) if (ps->performance_levels[i].vddc > ps->performance_levels[i+1].vddc)
ps->performance_levels[i].vddc = ps->performance_levels[i+1].vddc; ps->performance_levels[i].vddc = ps->performance_levels[i+1].vddc;
} }
if (adev->pm.dpm.ac_power == false) { if (adev->pm.ac_power == false) {
for (i = 0; i < ps->performance_level_count; i++) { for (i = 0; i < ps->performance_level_count; i++) {
if (ps->performance_levels[i].mclk > max_limits->mclk) if (ps->performance_levels[i].mclk > max_limits->mclk)
ps->performance_levels[i].mclk = max_limits->mclk; ps->performance_levels[i].mclk = max_limits->mclk;
......
...@@ -53,6 +53,29 @@ ...@@ -53,6 +53,29 @@
#define PACKET3_COMPUTE(op, n) (PACKET3(op, n) | 1 << 1) #define PACKET3_COMPUTE(op, n) (PACKET3(op, n) | 1 << 1)
#define PACKETJ_CONDITION_CHECK0 0
#define PACKETJ_CONDITION_CHECK1 1
#define PACKETJ_CONDITION_CHECK2 2
#define PACKETJ_CONDITION_CHECK3 3
#define PACKETJ_CONDITION_CHECK4 4
#define PACKETJ_CONDITION_CHECK5 5
#define PACKETJ_CONDITION_CHECK6 6
#define PACKETJ_CONDITION_CHECK7 7
#define PACKETJ_TYPE0 0
#define PACKETJ_TYPE1 1
#define PACKETJ_TYPE2 2
#define PACKETJ_TYPE3 3
#define PACKETJ_TYPE4 4
#define PACKETJ_TYPE5 5
#define PACKETJ_TYPE6 6
#define PACKETJ_TYPE7 7
#define PACKETJ(reg, r, cond, type) ((reg & 0x3FFFF) | \
((r & 0x3F) << 18) | \
((cond & 0xF) << 24) | \
((type & 0xF) << 28))
/* Packet 3 types */ /* Packet 3 types */
#define PACKET3_NOP 0x10 #define PACKET3_NOP 0x10
#define PACKET3_SET_BASE 0x11 #define PACKET3_SET_BASE 0x11
......
...@@ -38,7 +38,9 @@ ...@@ -38,7 +38,9 @@
static int vcn_v1_0_stop(struct amdgpu_device *adev); static int vcn_v1_0_stop(struct amdgpu_device *adev);
static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev);
static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev);
static void vcn_v1_0_set_jpeg_ring_funcs(struct amdgpu_device *adev);
static void vcn_v1_0_set_irq_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_irq_funcs(struct amdgpu_device *adev);
static void vcn_v1_0_jpeg_ring_set_patch_ring(struct amdgpu_ring *ring, uint32_t ptr);
/** /**
* vcn_v1_0_early_init - set function pointers * vcn_v1_0_early_init - set function pointers
...@@ -55,6 +57,7 @@ static int vcn_v1_0_early_init(void *handle) ...@@ -55,6 +57,7 @@ static int vcn_v1_0_early_init(void *handle)
vcn_v1_0_set_dec_ring_funcs(adev); vcn_v1_0_set_dec_ring_funcs(adev);
vcn_v1_0_set_enc_ring_funcs(adev); vcn_v1_0_set_enc_ring_funcs(adev);
vcn_v1_0_set_jpeg_ring_funcs(adev);
vcn_v1_0_set_irq_funcs(adev); vcn_v1_0_set_irq_funcs(adev);
return 0; return 0;
...@@ -86,6 +89,11 @@ static int vcn_v1_0_sw_init(void *handle) ...@@ -86,6 +89,11 @@ static int vcn_v1_0_sw_init(void *handle)
return r; return r;
} }
/* VCN JPEG TRAP */
r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, 126, &adev->vcn.irq);
if (r)
return r;
r = amdgpu_vcn_sw_init(adev); r = amdgpu_vcn_sw_init(adev);
if (r) if (r)
return r; return r;
...@@ -108,6 +116,12 @@ static int vcn_v1_0_sw_init(void *handle) ...@@ -108,6 +116,12 @@ static int vcn_v1_0_sw_init(void *handle)
return r; return r;
} }
ring = &adev->vcn.ring_jpeg;
sprintf(ring->name, "vcn_jpeg");
r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.irq, 0);
if (r)
return r;
return r; return r;
} }
...@@ -162,6 +176,14 @@ static int vcn_v1_0_hw_init(void *handle) ...@@ -162,6 +176,14 @@ static int vcn_v1_0_hw_init(void *handle)
} }
} }
ring = &adev->vcn.ring_jpeg;
ring->ready = true;
r = amdgpu_ring_test_ring(ring);
if (r) {
ring->ready = false;
goto done;
}
done: done:
if (!r) if (!r)
DRM_INFO("VCN decode and encode initialized successfully.\n"); DRM_INFO("VCN decode and encode initialized successfully.\n");
...@@ -729,6 +751,22 @@ static int vcn_v1_0_start(struct amdgpu_device *adev) ...@@ -729,6 +751,22 @@ static int vcn_v1_0_start(struct amdgpu_device *adev)
WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4); WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4);
ring = &adev->vcn.ring_jpeg;
WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_VMID, 0);
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, (0x00000001L | 0x00000002L));
WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW, lower_32_bits(ring->gpu_addr));
WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, upper_32_bits(ring->gpu_addr));
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR, 0);
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, 0);
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, 0x00000002L);
/* initialize wptr */
ring->wptr = RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR);
/* copy patch commands to the jpeg ring */
vcn_v1_0_jpeg_ring_set_patch_ring(ring,
(ring->wptr + ring->max_dw * amdgpu_sched_hw_submission));
return 0; return 0;
} }
...@@ -1126,6 +1164,383 @@ static void vcn_v1_0_enc_ring_emit_wreg(struct amdgpu_ring *ring, ...@@ -1126,6 +1164,383 @@ static void vcn_v1_0_enc_ring_emit_wreg(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, val); amdgpu_ring_write(ring, val);
} }
/**
* vcn_v1_0_jpeg_ring_get_rptr - get read pointer
*
* @ring: amdgpu_ring pointer
*
* Returns the current hardware read pointer
*/
static uint64_t vcn_v1_0_jpeg_ring_get_rptr(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR);
}
/**
* vcn_v1_0_jpeg_ring_get_wptr - get write pointer
*
* @ring: amdgpu_ring pointer
*
* Returns the current hardware write pointer
*/
static uint64_t vcn_v1_0_jpeg_ring_get_wptr(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR);
}
/**
* vcn_v1_0_jpeg_ring_set_wptr - set write pointer
*
* @ring: amdgpu_ring pointer
*
* Commits the write pointer to the hardware
*/
static void vcn_v1_0_jpeg_ring_set_wptr(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr));
}
/**
* vcn_v1_0_jpeg_ring_insert_start - insert a start command
*
* @ring: amdgpu_ring pointer
*
* Write a start command to the ring.
*/
static void vcn_v1_0_jpeg_ring_insert_start(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x68e04);
amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x80010000);
}
/**
* vcn_v1_0_jpeg_ring_insert_end - insert a end command
*
* @ring: amdgpu_ring pointer
*
* Write a end command to the ring.
*/
static void vcn_v1_0_jpeg_ring_insert_end(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x68e04);
amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x00010000);
}
/**
* vcn_v1_0_jpeg_ring_emit_fence - emit an fence & trap command
*
* @ring: amdgpu_ring pointer
* @fence: fence to emit
*
* Write a fence and a trap command to the ring.
*/
static void vcn_v1_0_jpeg_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
unsigned flags)
{
struct amdgpu_device *adev = ring->adev;
WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_DATA0), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, seq);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_DATA1), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, seq);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_CMD), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x8);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_CMD), 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE4));
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x01400200);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, seq);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring,
PACKETJ(0, 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE2));
amdgpu_ring_write(ring, 0xffffffff);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x3fbc);
amdgpu_ring_write(ring,
PACKETJ(0, 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x1);
}
/**
* vcn_v1_0_jpeg_ring_emit_ib - execute indirect buffer
*
* @ring: amdgpu_ring pointer
* @ib: indirect buffer to execute
*
* Write ring commands to execute the indirect buffer.
*/
static void vcn_v1_0_jpeg_ring_emit_ib(struct amdgpu_ring *ring,
struct amdgpu_ib *ib,
unsigned vmid, bool ctx_switch)
{
struct amdgpu_device *adev = ring->adev;
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_VMID), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, (vmid | (vmid << 4)));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JPEG_VMID), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, (vmid | (vmid << 4)));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_IB_SIZE), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, ib->length_dw);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, lower_32_bits(ring->gpu_addr));
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, upper_32_bits(ring->gpu_addr));
amdgpu_ring_write(ring,
PACKETJ(0, 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE2));
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x01400200);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x2);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_STATUS), 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE3));
amdgpu_ring_write(ring, 0x2);
}
static void vcn_v1_0_jpeg_ring_emit_reg_wait(struct amdgpu_ring *ring,
uint32_t reg, uint32_t val,
uint32_t mask)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reg_offset = (reg << 2);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, 0x01400200);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0));
amdgpu_ring_write(ring, val);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) ||
((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) {
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring,
PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3));
} else {
amdgpu_ring_write(ring, reg_offset);
amdgpu_ring_write(ring,
PACKETJ(0, 0, 0, PACKETJ_TYPE3));
}
amdgpu_ring_write(ring, mask);
}
static void vcn_v1_0_jpeg_ring_emit_vm_flush(struct amdgpu_ring *ring,
unsigned vmid, uint64_t pd_addr)
{
struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub];
uint32_t data0, data1, mask;
pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr);
/* wait for register write */
data0 = hub->ctx0_ptb_addr_lo32 + vmid * 2;
data1 = lower_32_bits(pd_addr);
mask = 0xffffffff;
vcn_v1_0_jpeg_ring_emit_reg_wait(ring, data0, data1, mask);
}
static void vcn_v1_0_jpeg_ring_emit_wreg(struct amdgpu_ring *ring,
uint32_t reg, uint32_t val)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reg_offset = (reg << 2);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0));
if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) ||
((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) {
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring,
PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0));
} else {
amdgpu_ring_write(ring, reg_offset);
amdgpu_ring_write(ring,
PACKETJ(0, 0, 0, PACKETJ_TYPE0));
}
amdgpu_ring_write(ring, val);
}
static void vcn_v1_0_jpeg_ring_nop(struct amdgpu_ring *ring, uint32_t count)
{
int i;
WARN_ON(ring->wptr % 2 || count % 2);
for (i = 0; i < count / 2; i++) {
amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE6));
amdgpu_ring_write(ring, 0);
}
}
static void vcn_v1_0_jpeg_ring_patch_wreg(struct amdgpu_ring *ring, uint32_t *ptr, uint32_t reg_offset, uint32_t val)
{
struct amdgpu_device *adev = ring->adev;
ring->ring[(*ptr)++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0);
if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) ||
((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) {
ring->ring[(*ptr)++] = 0;
ring->ring[(*ptr)++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0);
} else {
ring->ring[(*ptr)++] = reg_offset;
ring->ring[(*ptr)++] = PACKETJ(0, 0, 0, PACKETJ_TYPE0);
}
ring->ring[(*ptr)++] = val;
}
static void vcn_v1_0_jpeg_ring_set_patch_ring(struct amdgpu_ring *ring, uint32_t ptr)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reg, reg_offset, val, mask, i;
// 1st: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW);
reg_offset = (reg << 2);
val = lower_32_bits(ring->gpu_addr);
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
// 2nd: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH);
reg_offset = (reg << 2);
val = upper_32_bits(ring->gpu_addr);
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
// 3rd to 5th: issue MEM_READ commands
for (i = 0; i <= 2; i++) {
ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE2);
ring->ring[ptr++] = 0;
}
// 6th: program mmUVD_JRBC_RB_CNTL register to enable NO_FETCH and RPTR write ability
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL);
reg_offset = (reg << 2);
val = 0x13;
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
// 7th: program mmUVD_JRBC_RB_REF_DATA
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA);
reg_offset = (reg << 2);
val = 0x1;
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
// 8th: issue conditional register read mmUVD_JRBC_RB_CNTL
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL);
reg_offset = (reg << 2);
val = 0x1;
mask = 0x1;
ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0);
ring->ring[ptr++] = 0x01400200;
ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0);
ring->ring[ptr++] = val;
ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0);
if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) ||
((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) {
ring->ring[ptr++] = 0;
ring->ring[ptr++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3);
} else {
ring->ring[ptr++] = reg_offset;
ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE3);
}
ring->ring[ptr++] = mask;
//9th to 21st: insert no-op
for (i = 0; i <= 12; i++) {
ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE6);
ring->ring[ptr++] = 0;
}
//22nd: reset mmUVD_JRBC_RB_RPTR
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_RPTR);
reg_offset = (reg << 2);
val = 0;
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
//23rd: program mmUVD_JRBC_RB_CNTL to disable no_fetch
reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL);
reg_offset = (reg << 2);
val = 0x12;
vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val);
}
static int vcn_v1_0_set_interrupt_state(struct amdgpu_device *adev, static int vcn_v1_0_set_interrupt_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *source, struct amdgpu_irq_src *source,
unsigned type, unsigned type,
...@@ -1150,6 +1565,9 @@ static int vcn_v1_0_process_interrupt(struct amdgpu_device *adev, ...@@ -1150,6 +1565,9 @@ static int vcn_v1_0_process_interrupt(struct amdgpu_device *adev,
case 120: case 120:
amdgpu_fence_process(&adev->vcn.ring_enc[1]); amdgpu_fence_process(&adev->vcn.ring_enc[1]);
break; break;
case 126:
amdgpu_fence_process(&adev->vcn.ring_jpeg);
break;
default: default:
DRM_ERROR("Unhandled interrupt: %d %d\n", DRM_ERROR("Unhandled interrupt: %d %d\n",
entry->src_id, entry->src_data[0]); entry->src_id, entry->src_data[0]);
...@@ -1273,6 +1691,39 @@ static const struct amdgpu_ring_funcs vcn_v1_0_enc_ring_vm_funcs = { ...@@ -1273,6 +1691,39 @@ static const struct amdgpu_ring_funcs vcn_v1_0_enc_ring_vm_funcs = {
.emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
}; };
static const struct amdgpu_ring_funcs vcn_v1_0_jpeg_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.nop = PACKET0(0x81ff, 0),
.support_64bit_ptrs = false,
.vmhub = AMDGPU_MMHUB,
.extra_dw = 64,
.get_rptr = vcn_v1_0_jpeg_ring_get_rptr,
.get_wptr = vcn_v1_0_jpeg_ring_get_wptr,
.set_wptr = vcn_v1_0_jpeg_ring_set_wptr,
.emit_frame_size =
6 + 6 + /* hdp invalidate / flush */
SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 +
SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 +
8 + /* vcn_v1_0_dec_ring_emit_vm_flush */
14 + 14 + /* vcn_v1_0_dec_ring_emit_fence x2 vm fence */
6,
.emit_ib_size = 22, /* vcn_v1_0_dec_ring_emit_ib */
.emit_ib = vcn_v1_0_jpeg_ring_emit_ib,
.emit_fence = vcn_v1_0_jpeg_ring_emit_fence,
.emit_vm_flush = vcn_v1_0_jpeg_ring_emit_vm_flush,
.test_ring = amdgpu_vcn_jpeg_ring_test_ring,
.test_ib = amdgpu_vcn_jpeg_ring_test_ib,
.insert_nop = vcn_v1_0_jpeg_ring_nop,
.insert_start = vcn_v1_0_jpeg_ring_insert_start,
.insert_end = vcn_v1_0_jpeg_ring_insert_end,
.pad_ib = amdgpu_ring_generic_pad_ib,
.begin_use = amdgpu_vcn_ring_begin_use,
.end_use = amdgpu_vcn_ring_end_use,
.emit_wreg = vcn_v1_0_jpeg_ring_emit_wreg,
.emit_reg_wait = vcn_v1_0_jpeg_ring_emit_reg_wait,
};
static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev) static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev)
{ {
adev->vcn.ring_dec.funcs = &vcn_v1_0_dec_ring_vm_funcs; adev->vcn.ring_dec.funcs = &vcn_v1_0_dec_ring_vm_funcs;
...@@ -1289,6 +1740,12 @@ static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev) ...@@ -1289,6 +1740,12 @@ static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev)
DRM_INFO("VCN encode is enabled in VM mode\n"); DRM_INFO("VCN encode is enabled in VM mode\n");
} }
static void vcn_v1_0_set_jpeg_ring_funcs(struct amdgpu_device *adev)
{
adev->vcn.ring_jpeg.funcs = &vcn_v1_0_jpeg_ring_vm_funcs;
DRM_INFO("VCN jpeg decode is enabled in VM mode\n");
}
static const struct amdgpu_irq_src_funcs vcn_v1_0_irq_funcs = { static const struct amdgpu_irq_src_funcs vcn_v1_0_irq_funcs = {
.set = vcn_v1_0_set_interrupt_state, .set = vcn_v1_0_set_interrupt_state,
.process = vcn_v1_0_process_interrupt, .process = vcn_v1_0_process_interrupt,
......
...@@ -9,19 +9,10 @@ config DRM_AMD_DC ...@@ -9,19 +9,10 @@ config DRM_AMD_DC
support for AMDGPU. This adds required support for Vega and support for AMDGPU. This adds required support for Vega and
Raven ASICs. Raven ASICs.
config DRM_AMD_DC_FBC
bool "AMD FBC - Enable Frame Buffer Compression"
depends on DRM_AMD_DC
help
Choose this option if you want to use frame buffer compression
support.
This is a power optimisation feature, check its availability
on your hardware before enabling this option.
config DRM_AMD_DC_DCN1_0 config DRM_AMD_DC_DCN1_0
bool "DCN 1.0 Raven family" bool "DCN 1.0 Raven family"
depends on DRM_AMD_DC && X86 depends on DRM_AMD_DC && X86
default y
help help
Choose this option if you want to have Choose this option if you want to have
RV family for display engine RV family for display engine
......
...@@ -347,7 +347,6 @@ static void hotplug_notify_work_func(struct work_struct *work) ...@@ -347,7 +347,6 @@ static void hotplug_notify_work_func(struct work_struct *work)
drm_kms_helper_hotplug_event(dev); drm_kms_helper_hotplug_event(dev);
} }
#if defined(CONFIG_DRM_AMD_DC_FBC)
/* Allocate memory for FBC compressed data */ /* Allocate memory for FBC compressed data */
static void amdgpu_dm_fbc_init(struct drm_connector *connector) static void amdgpu_dm_fbc_init(struct drm_connector *connector)
{ {
...@@ -388,7 +387,6 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector) ...@@ -388,7 +387,6 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
} }
} }
#endif
/* Init display KMS /* Init display KMS
...@@ -3426,12 +3424,15 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) ...@@ -3426,12 +3424,15 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
struct edid *edid = amdgpu_dm_connector->edid; struct edid *edid = amdgpu_dm_connector->edid;
encoder = helper->best_encoder(connector); encoder = helper->best_encoder(connector);
if (!edid || !drm_edid_is_valid(edid)) {
drm_add_modes_noedid(connector, 640, 480);
} else {
amdgpu_dm_connector_ddc_get_modes(connector, edid); amdgpu_dm_connector_ddc_get_modes(connector, edid);
amdgpu_dm_connector_add_common_modes(encoder, connector); amdgpu_dm_connector_add_common_modes(encoder, connector);
}
#if defined(CONFIG_DRM_AMD_DC_FBC)
amdgpu_dm_fbc_init(connector); amdgpu_dm_fbc_init(connector);
#endif
return amdgpu_dm_connector->num_modes; return amdgpu_dm_connector->num_modes;
} }
......
...@@ -72,13 +72,11 @@ struct irq_list_head { ...@@ -72,13 +72,11 @@ struct irq_list_head {
struct work_struct work; struct work_struct work;
}; };
#if defined(CONFIG_DRM_AMD_DC_FBC)
struct dm_comressor_info { struct dm_comressor_info {
void *cpu_addr; void *cpu_addr;
struct amdgpu_bo *bo_ptr; struct amdgpu_bo *bo_ptr;
uint64_t gpu_addr; uint64_t gpu_addr;
}; };
#endif
struct amdgpu_display_manager { struct amdgpu_display_manager {
...@@ -129,9 +127,8 @@ struct amdgpu_display_manager { ...@@ -129,9 +127,8 @@ struct amdgpu_display_manager {
* Caches device atomic state for suspend/resume * Caches device atomic state for suspend/resume
*/ */
struct drm_atomic_state *cached_state; struct drm_atomic_state *cached_state;
#if defined(CONFIG_DRM_AMD_DC_FBC)
struct dm_comressor_info compressor; struct dm_comressor_info compressor;
#endif
}; };
struct amdgpu_dm_connector { struct amdgpu_dm_connector {
......
...@@ -497,6 +497,34 @@ enum dc_edid_status dm_helpers_read_local_edid( ...@@ -497,6 +497,34 @@ enum dc_edid_status dm_helpers_read_local_edid(
DRM_ERROR("EDID err: %d, on connector: %s", DRM_ERROR("EDID err: %d, on connector: %s",
edid_status, edid_status,
aconnector->base.name); aconnector->base.name);
if (link->aux_mode) {
union test_request test_request = {0};
union test_response test_response = {0};
dm_helpers_dp_read_dpcd(ctx,
link,
DP_TEST_REQUEST,
&test_request.raw,
sizeof(union test_request));
if (!test_request.bits.EDID_READ)
return edid_status;
test_response.bits.EDID_CHECKSUM_WRITE = 1;
dm_helpers_dp_write_dpcd(ctx,
link,
DP_TEST_EDID_CHECKSUM,
&sink->dc_edid.raw_edid[sink->dc_edid.length-1],
1);
dm_helpers_dp_write_dpcd(ctx,
link,
DP_TEST_RESPONSE,
&test_response.raw,
sizeof(test_response));
}
return edid_status; return edid_status;
} }
......
...@@ -35,14 +35,6 @@ ...@@ -35,14 +35,6 @@
#include "amdgpu_dm_irq.h" #include "amdgpu_dm_irq.h"
#include "amdgpu_pm.h" #include "amdgpu_pm.h"
unsigned long long dm_get_timestamp(struct dc_context *ctx)
{
struct timespec64 time;
getrawmonotonic64(&time);
return timespec64_to_ns(&time);
}
unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx,
unsigned long long current_time_stamp, unsigned long long current_time_stamp,
unsigned long long last_time_stamp) unsigned long long last_time_stamp)
......
...@@ -78,6 +78,8 @@ void dc_conn_log(struct dc_context *ctx, ...@@ -78,6 +78,8 @@ void dc_conn_log(struct dc_context *ctx,
if (i == NUM_ELEMENTS(signal_type_info_tbl)) if (i == NUM_ELEMENTS(signal_type_info_tbl))
goto fail; goto fail;
dm_logger_append_heading(&entry);
dm_logger_append(&entry, "[%s][ConnIdx:%d] ", dm_logger_append(&entry, "[%s][ConnIdx:%d] ",
signal_type_info_tbl[i].name, signal_type_info_tbl[i].name,
link->link_index); link->link_index);
......
...@@ -34,6 +34,7 @@ static const struct dc_log_type_info log_type_info_tbl[] = { ...@@ -34,6 +34,7 @@ static const struct dc_log_type_info log_type_info_tbl[] = {
{LOG_WARNING, "Warning"}, {LOG_WARNING, "Warning"},
{LOG_DEBUG, "Debug"}, {LOG_DEBUG, "Debug"},
{LOG_DC, "DC_Interface"}, {LOG_DC, "DC_Interface"},
{LOG_DTN, "DTN"},
{LOG_SURFACE, "Surface"}, {LOG_SURFACE, "Surface"},
{LOG_HW_HOTPLUG, "HW_Hotplug"}, {LOG_HW_HOTPLUG, "HW_Hotplug"},
{LOG_HW_LINK_TRAINING, "HW_LKTN"}, {LOG_HW_LINK_TRAINING, "HW_LKTN"},
...@@ -60,7 +61,7 @@ static const struct dc_log_type_info log_type_info_tbl[] = { ...@@ -60,7 +61,7 @@ static const struct dc_log_type_info log_type_info_tbl[] = {
{LOG_EVENT_LINK_LOSS, "LinkLoss"}, {LOG_EVENT_LINK_LOSS, "LinkLoss"},
{LOG_EVENT_UNDERFLOW, "Underflow"}, {LOG_EVENT_UNDERFLOW, "Underflow"},
{LOG_IF_TRACE, "InterfaceTrace"}, {LOG_IF_TRACE, "InterfaceTrace"},
{LOG_DTN, "DTN"}, {LOG_PERF_TRACE, "PerfTrace"},
{LOG_DISPLAYSTATS, "DisplayStats"} {LOG_DISPLAYSTATS, "DisplayStats"}
}; };
...@@ -128,8 +129,45 @@ uint32_t dal_logger_destroy(struct dal_logger **logger) ...@@ -128,8 +129,45 @@ uint32_t dal_logger_destroy(struct dal_logger **logger)
} }
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
void dm_logger_append_heading(struct log_entry *entry)
{
int j;
for (j = 0; j < NUM_ELEMENTS(log_type_info_tbl); j++) {
const struct dc_log_type_info *info = &log_type_info_tbl[j];
if (info->type == entry->type)
dm_logger_append(entry, "[%s]\t", info->name);
}
}
/* Print everything unread existing in log_buffer to debug console*/
void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn)
{
char *string_start = &logger->log_buffer[logger->buffer_read_offset];
if (should_warn)
dm_output_to_console(
"---------------- FLUSHING LOG BUFFER ----------------\n");
while (logger->buffer_read_offset < logger->buffer_write_offset) {
if (logger->log_buffer[logger->buffer_read_offset] == '\0') {
dm_output_to_console("%s", string_start);
string_start = logger->log_buffer + logger->buffer_read_offset + 1;
}
logger->buffer_read_offset++;
}
if (should_warn)
dm_output_to_console(
"-------------- END FLUSHING LOG BUFFER --------------\n\n");
}
/* ------------------------------------------------------------------------ */
/* Warning: Be careful that 'msg' is null terminated and the total size is
* less than DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE (256) including '\0'
*/
static bool dal_logger_should_log( static bool dal_logger_should_log(
struct dal_logger *logger, struct dal_logger *logger,
enum dc_log_type log_type) enum dc_log_type log_type)
...@@ -159,26 +197,6 @@ static void log_to_debug_console(struct log_entry *entry) ...@@ -159,26 +197,6 @@ static void log_to_debug_console(struct log_entry *entry)
} }
} }
/* Print everything unread existing in log_buffer to debug console*/
void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn)
{
char *string_start = &logger->log_buffer[logger->buffer_read_offset];
if (should_warn)
dm_output_to_console(
"---------------- FLUSHING LOG BUFFER ----------------\n");
while (logger->buffer_read_offset < logger->buffer_write_offset) {
if (logger->log_buffer[logger->buffer_read_offset] == '\0') {
dm_output_to_console("%s", string_start);
string_start = logger->log_buffer + logger->buffer_read_offset + 1;
}
logger->buffer_read_offset++;
}
if (should_warn)
dm_output_to_console(
"-------------- END FLUSHING LOG BUFFER --------------\n\n");
}
static void log_to_internal_buffer(struct log_entry *entry) static void log_to_internal_buffer(struct log_entry *entry)
{ {
...@@ -229,19 +247,6 @@ static void log_to_internal_buffer(struct log_entry *entry) ...@@ -229,19 +247,6 @@ static void log_to_internal_buffer(struct log_entry *entry)
} }
} }
static void log_heading(struct log_entry *entry)
{
int j;
for (j = 0; j < NUM_ELEMENTS(log_type_info_tbl); j++) {
const struct dc_log_type_info *info = &log_type_info_tbl[j];
if (info->type == entry->type)
dm_logger_append(entry, "[%s]\t", info->name);
}
}
static void append_entry( static void append_entry(
struct log_entry *entry, struct log_entry *entry,
char *buffer, char *buffer,
...@@ -259,11 +264,7 @@ static void append_entry( ...@@ -259,11 +264,7 @@ static void append_entry(
entry->buf_offset += buf_size; entry->buf_offset += buf_size;
} }
/* ------------------------------------------------------------------------ */
/* Warning: Be careful that 'msg' is null terminated and the total size is
* less than DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE (256) including '\0'
*/
void dm_logger_write( void dm_logger_write(
struct dal_logger *logger, struct dal_logger *logger,
enum dc_log_type log_type, enum dc_log_type log_type,
...@@ -287,7 +288,7 @@ void dm_logger_write( ...@@ -287,7 +288,7 @@ void dm_logger_write(
entry.type = log_type; entry.type = log_type;
log_heading(&entry); dm_logger_append_heading(&entry);
size = dm_log_to_buffer( size = dm_log_to_buffer(
buffer, LOG_MAX_LINE_SIZE - 1, msg, args); buffer, LOG_MAX_LINE_SIZE - 1, msg, args);
...@@ -372,7 +373,7 @@ void dm_logger_open( ...@@ -372,7 +373,7 @@ void dm_logger_open(
logger->open_count++; logger->open_count++;
log_heading(entry); dm_logger_append_heading(entry);
} }
void dm_logger_close(struct log_entry *entry) void dm_logger_close(struct log_entry *entry)
......
...@@ -169,6 +169,22 @@ static bool create_links( ...@@ -169,6 +169,22 @@ static bool create_links(
return false; return false;
} }
/**
*****************************************************************************
* Function: dc_stream_adjust_vmin_vmax
*
* @brief
* Looks up the pipe context of dc_stream_state and updates the
* vertical_total_min and vertical_total_max of the DRR, Dynamic Refresh
* Rate, which is a power-saving feature that targets reducing panel
* refresh rate while the screen is static
*
* @param [in] dc: dc reference
* @param [in] stream: Initial dc stream state
* @param [in] adjust: Updated parameters for vertical_total_min and
* vertical_total_max
*****************************************************************************
*/
bool dc_stream_adjust_vmin_vmax(struct dc *dc, bool dc_stream_adjust_vmin_vmax(struct dc *dc,
struct dc_stream_state **streams, int num_streams, struct dc_stream_state **streams, int num_streams,
int vmin, int vmax) int vmin, int vmax)
...@@ -465,6 +481,7 @@ static bool construct(struct dc *dc, ...@@ -465,6 +481,7 @@ static bool construct(struct dc *dc,
dc_ctx->driver_context = init_params->driver; dc_ctx->driver_context = init_params->driver;
dc_ctx->dc = dc; dc_ctx->dc = dc;
dc_ctx->asic_id = init_params->asic_id; dc_ctx->asic_id = init_params->asic_id;
dc_ctx->dc_sink_id_count = 0;
dc->ctx = dc_ctx; dc->ctx = dc_ctx;
dc->current_state = dc_create_state(); dc->current_state = dc_create_state();
...@@ -1548,7 +1565,7 @@ struct dc_sink *dc_link_add_remote_sink( ...@@ -1548,7 +1565,7 @@ struct dc_sink *dc_link_add_remote_sink(
struct dc_sink *dc_sink; struct dc_sink *dc_sink;
enum dc_edid_status edid_status; enum dc_edid_status edid_status;
if (len > MAX_EDID_BUFFER_SIZE) { if (len > DC_MAX_EDID_BUFFER_SIZE) {
dm_error("Max EDID buffer size breached!\n"); dm_error("Max EDID buffer size breached!\n");
return NULL; return NULL;
} }
......
...@@ -1861,28 +1861,6 @@ static enum dc_status enable_link( ...@@ -1861,28 +1861,6 @@ static enum dc_status enable_link(
break; break;
} }
if (pipe_ctx->stream_res.audio && status == DC_OK) {
struct dc *core_dc = pipe_ctx->stream->ctx->dc;
/* notify audio driver for audio modes of monitor */
struct pp_smu_funcs_rv *pp_smu = core_dc->res_pool->pp_smu;
unsigned int i, num_audio = 1;
for (i = 0; i < MAX_PIPES; i++) {
/*current_state not updated yet*/
if (core_dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL)
num_audio++;
}
pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio);
if (num_audio == 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL)
/*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
pp_smu->set_pme_wa_enable(&pp_smu->pp_smu);
/* un-mute audio */
/* TODO: audio should be per stream rather than per link */
pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
pipe_ctx->stream_res.stream_enc, false);
}
return status; return status;
} }
...@@ -2415,6 +2393,8 @@ void core_link_enable_stream( ...@@ -2415,6 +2393,8 @@ void core_link_enable_stream(
} }
} }
core_dc->hwss.enable_audio_stream(pipe_ctx);
/* turn off otg test pattern if enable */ /* turn off otg test pattern if enable */
pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
...@@ -2453,6 +2433,22 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) ...@@ -2453,6 +2433,22 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
core_dc->hwss.set_avmute(pipe_ctx, enable); core_dc->hwss.set_avmute(pipe_ctx, enable);
} }
/**
*****************************************************************************
* Function: dc_link_enable_hpd_filter
*
* @brief
* If enable is true, programs HPD filter on associated HPD line using
* delay_on_disconnect/delay_on_connect values dependent on
* link->connector_signal
*
* If enable is false, programs HPD filter on associated HPD line with no
* delays on connect or disconnect
*
* @param [in] link: pointer to the dc link
* @param [in] enable: boolean specifying whether to enable hbd
*****************************************************************************
*/
void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) void dc_link_enable_hpd_filter(struct dc_link *link, bool enable)
{ {
struct gpio *hpd; struct gpio *hpd;
......
...@@ -1647,22 +1647,26 @@ static enum dc_status read_hpd_rx_irq_data( ...@@ -1647,22 +1647,26 @@ static enum dc_status read_hpd_rx_irq_data(
irq_data->raw, irq_data->raw,
sizeof(union hpd_irq_data)); sizeof(union hpd_irq_data));
else { else {
/* Read 2 bytes at this location,... */ /* Read 14 bytes in a single read and then copy only the required fields.
* This is more efficient than doing it in two separate AUX reads. */
uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1];
retval = core_link_read_dpcd( retval = core_link_read_dpcd(
link, link,
DP_SINK_COUNT_ESI, DP_SINK_COUNT_ESI,
irq_data->raw, tmp,
2); sizeof(tmp));
if (retval != DC_OK) if (retval != DC_OK)
return retval; return retval;
/* ... then read remaining 4 at the other location */ irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
retval = core_link_read_dpcd( irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
link, irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
DP_LANE0_1_STATUS_ESI, irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
&irq_data->raw[2], irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
4); irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
} }
return retval; return retval;
...@@ -2305,6 +2309,7 @@ static bool retrieve_link_cap(struct dc_link *link) ...@@ -2305,6 +2309,7 @@ static bool retrieve_link_cap(struct dc_link *link)
{ {
uint8_t dpcd_data[DP_ADAPTER_CAP - DP_DPCD_REV + 1]; uint8_t dpcd_data[DP_ADAPTER_CAP - DP_DPCD_REV + 1];
struct dp_device_vendor_id sink_id;
union down_stream_port_count down_strm_port_count; union down_stream_port_count down_strm_port_count;
union edp_configuration_cap edp_config_cap; union edp_configuration_cap edp_config_cap;
union dp_downstream_port_present ds_port = { 0 }; union dp_downstream_port_present ds_port = { 0 };
...@@ -2391,6 +2396,17 @@ static bool retrieve_link_cap(struct dc_link *link) ...@@ -2391,6 +2396,17 @@ static bool retrieve_link_cap(struct dc_link *link)
&link->dpcd_caps.sink_count.raw, &link->dpcd_caps.sink_count.raw,
sizeof(link->dpcd_caps.sink_count.raw)); sizeof(link->dpcd_caps.sink_count.raw));
/* read sink ieee oui */
core_link_read_dpcd(link,
DP_SINK_OUI,
(uint8_t *)(&sink_id),
sizeof(sink_id));
link->dpcd_caps.sink_dev_id =
(sink_id.ieee_oui[0] << 16) +
(sink_id.ieee_oui[1] << 8) +
(sink_id.ieee_oui[2]);
/* Connectivity log: detection */ /* Connectivity log: detection */
CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
......
...@@ -522,13 +522,12 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx) ...@@ -522,13 +522,12 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
} }
} }
static void calculate_recout(struct pipe_ctx *pipe_ctx, struct view *recout_skip) static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full)
{ {
const struct dc_plane_state *plane_state = pipe_ctx->plane_state; const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
const struct dc_stream_state *stream = pipe_ctx->stream; const struct dc_stream_state *stream = pipe_ctx->stream;
struct rect surf_src = plane_state->src_rect; struct rect surf_src = plane_state->src_rect;
struct rect surf_clip = plane_state->clip_rect; struct rect surf_clip = plane_state->clip_rect;
int recout_full_x, recout_full_y;
bool pri_split = pipe_ctx->bottom_pipe && bool pri_split = pipe_ctx->bottom_pipe &&
pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state; pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state;
bool sec_split = pipe_ctx->top_pipe && bool sec_split = pipe_ctx->top_pipe &&
...@@ -600,17 +599,19 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct view *recout_skip ...@@ -600,17 +599,19 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct view *recout_skip
* * 1/ stream scaling ratio) - (surf surf_src offset * 1/ full scl * * 1/ stream scaling ratio) - (surf surf_src offset * 1/ full scl
* ratio) * ratio)
*/ */
recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x) recout_full->x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
* stream->dst.width / stream->src.width - * stream->dst.width / stream->src.width -
surf_src.x * plane_state->dst_rect.width / surf_src.width surf_src.x * plane_state->dst_rect.width / surf_src.width
* stream->dst.width / stream->src.width; * stream->dst.width / stream->src.width;
recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y) recout_full->y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
* stream->dst.height / stream->src.height - * stream->dst.height / stream->src.height -
surf_src.y * plane_state->dst_rect.height / surf_src.height surf_src.y * plane_state->dst_rect.height / surf_src.height
* stream->dst.height / stream->src.height; * stream->dst.height / stream->src.height;
recout_skip->width = pipe_ctx->plane_res.scl_data.recout.x - recout_full_x; recout_full->width = plane_state->dst_rect.width
recout_skip->height = pipe_ctx->plane_res.scl_data.recout.y - recout_full_y; * stream->dst.width / stream->src.width;
recout_full->height = plane_state->dst_rect.height
* stream->dst.height / stream->src.height;
} }
static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
...@@ -662,7 +663,7 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) ...@@ -662,7 +663,7 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.scl_data.ratios.vert_c, 19); pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
} }
static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *recout_skip) static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct rect *recout_full)
{ {
struct scaler_data *data = &pipe_ctx->plane_res.scl_data; struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
struct rect src = pipe_ctx->plane_state->src_rect; struct rect src = pipe_ctx->plane_state->src_rect;
...@@ -680,15 +681,14 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r ...@@ -680,15 +681,14 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r
flip_vert_scan_dir = true; flip_vert_scan_dir = true;
else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
flip_horz_scan_dir = true; flip_horz_scan_dir = true;
if (pipe_ctx->plane_state->horizontal_mirror)
flip_horz_scan_dir = !flip_horz_scan_dir;
if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
rect_swap_helper(&src); rect_swap_helper(&src);
rect_swap_helper(&data->viewport_c); rect_swap_helper(&data->viewport_c);
rect_swap_helper(&data->viewport); rect_swap_helper(&data->viewport);
} } else if (pipe_ctx->plane_state->horizontal_mirror)
flip_horz_scan_dir = !flip_horz_scan_dir;
/* /*
* Init calculated according to formula: * Init calculated according to formula:
...@@ -708,10 +708,9 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r ...@@ -708,10 +708,9 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r
data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int( data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int(
dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19); dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19);
if (!flip_horz_scan_dir) {
/* Adjust for viewport end clip-off */ /* Adjust for viewport end clip-off */
if ((data->viewport.x + data->viewport.width) < (src.x + src.width) && !flip_horz_scan_dir) { if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) {
int vp_clip = src.x + src.width - data->viewport.width - data->viewport.x; int vp_clip = src.x + src.width - data->viewport.width - data->viewport.x;
int int_part = dc_fixpt_floor( int int_part = dc_fixpt_floor(
dc_fixpt_sub(data->inits.h, data->ratios.horz)); dc_fixpt_sub(data->inits.h, data->ratios.horz));
...@@ -719,15 +718,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r ...@@ -719,15 +718,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r
int_part = int_part > 0 ? int_part : 0; int_part = int_part > 0 ? int_part : 0;
data->viewport.width += int_part < vp_clip ? int_part : vp_clip; data->viewport.width += int_part < vp_clip ? int_part : vp_clip;
} }
if ((data->viewport.y + data->viewport.height) < (src.y + src.height) && !flip_vert_scan_dir) { if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) {
int vp_clip = src.y + src.height - data->viewport.height - data->viewport.y;
int int_part = dc_fixpt_floor(
dc_fixpt_sub(data->inits.v, data->ratios.vert));
int_part = int_part > 0 ? int_part : 0;
data->viewport.height += int_part < vp_clip ? int_part : vp_clip;
}
if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div && !flip_horz_scan_dir) {
int vp_clip = (src.x + src.width) / vpc_div - int vp_clip = (src.x + src.width) / vpc_div -
data->viewport_c.width - data->viewport_c.x; data->viewport_c.width - data->viewport_c.x;
int int_part = dc_fixpt_floor( int int_part = dc_fixpt_floor(
...@@ -736,22 +727,13 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r ...@@ -736,22 +727,13 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r
int_part = int_part > 0 ? int_part : 0; int_part = int_part > 0 ? int_part : 0;
data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip; data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip;
} }
if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div && !flip_vert_scan_dir) {
int vp_clip = (src.y + src.height) / vpc_div -
data->viewport_c.height - data->viewport_c.y;
int int_part = dc_fixpt_floor(
dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c));
int_part = int_part > 0 ? int_part : 0;
data->viewport_c.height += int_part < vp_clip ? int_part : vp_clip;
}
/* Adjust for non-0 viewport offset */ /* Adjust for non-0 viewport offset */
if (data->viewport.x && !flip_horz_scan_dir) { if (data->viewport.x) {
int int_part; int int_part;
data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int( data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int(
data->ratios.horz, recout_skip->width)); data->ratios.horz, data->recout.x - recout_full->x));
int_part = dc_fixpt_floor(data->inits.h) - data->viewport.x; int_part = dc_fixpt_floor(data->inits.h) - data->viewport.x;
if (int_part < data->taps.h_taps) { if (int_part < data->taps.h_taps) {
int int_adj = data->viewport.x >= (data->taps.h_taps - int_part) ? int int_adj = data->viewport.x >= (data->taps.h_taps - int_part) ?
...@@ -768,11 +750,11 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r ...@@ -768,11 +750,11 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r
data->inits.h = dc_fixpt_add_int(data->inits.h, int_part); data->inits.h = dc_fixpt_add_int(data->inits.h, int_part);
} }
if (data->viewport_c.x && !flip_horz_scan_dir) { if (data->viewport_c.x) {
int int_part; int int_part;
data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int( data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int(
data->ratios.horz_c, recout_skip->width)); data->ratios.horz_c, data->recout.x - recout_full->x));
int_part = dc_fixpt_floor(data->inits.h_c) - data->viewport_c.x; int_part = dc_fixpt_floor(data->inits.h_c) - data->viewport_c.x;
if (int_part < data->taps.h_taps_c) { if (int_part < data->taps.h_taps_c) {
int int_adj = data->viewport_c.x >= (data->taps.h_taps_c - int_part) ? int int_adj = data->viewport_c.x >= (data->taps.h_taps_c - int_part) ?
...@@ -788,12 +770,111 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r ...@@ -788,12 +770,111 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r
data->inits.h_c.value &= 0xffffffff; data->inits.h_c.value &= 0xffffffff;
data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part); data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part);
} }
} else {
/* Adjust for non-0 viewport offset */
if (data->viewport.x) {
int int_part = dc_fixpt_floor(
dc_fixpt_sub(data->inits.h, data->ratios.horz));
int_part = int_part > 0 ? int_part : 0;
data->viewport.width += int_part < data->viewport.x ? int_part : data->viewport.x;
data->viewport.x -= int_part < data->viewport.x ? int_part : data->viewport.x;
}
if (data->viewport_c.x) {
int int_part = dc_fixpt_floor(
dc_fixpt_sub(data->inits.h_c, data->ratios.horz_c));
int_part = int_part > 0 ? int_part : 0;
data->viewport_c.width += int_part < data->viewport_c.x ? int_part : data->viewport_c.x;
data->viewport_c.x -= int_part < data->viewport_c.x ? int_part : data->viewport_c.x;
}
/* Adjust for viewport end clip-off */
if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) {
int int_part;
int end_offset = src.x + src.width
- data->viewport.x - data->viewport.width;
/*
* this is init if vp had no offset, keep in mind this is from the
* right side of vp due to scan direction
*/
data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int(
data->ratios.horz, data->recout.x - recout_full->x));
/*
* this is the difference between first pixel of viewport available to read
* and init position, takning into account scan direction
*/
int_part = dc_fixpt_floor(data->inits.h) - end_offset;
if (int_part < data->taps.h_taps) {
int int_adj = end_offset >= (data->taps.h_taps - int_part) ?
(data->taps.h_taps - int_part) : end_offset;
data->viewport.width += int_adj;
int_part += int_adj;
} else if (int_part > data->taps.h_taps) {
data->viewport.width += int_part - data->taps.h_taps;
int_part = data->taps.h_taps;
}
data->inits.h.value &= 0xffffffff;
data->inits.h = dc_fixpt_add_int(data->inits.h, int_part);
}
if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) {
int int_part;
int end_offset = (src.x + src.width) / vpc_div
- data->viewport_c.x - data->viewport_c.width;
/*
* this is init if vp had no offset, keep in mind this is from the
* right side of vp due to scan direction
*/
data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int(
data->ratios.horz_c, data->recout.x - recout_full->x));
/*
* this is the difference between first pixel of viewport available to read
* and init position, takning into account scan direction
*/
int_part = dc_fixpt_floor(data->inits.h_c) - end_offset;
if (int_part < data->taps.h_taps_c) {
int int_adj = end_offset >= (data->taps.h_taps_c - int_part) ?
(data->taps.h_taps_c - int_part) : end_offset;
data->viewport_c.width += int_adj;
int_part += int_adj;
} else if (int_part > data->taps.h_taps_c) {
data->viewport_c.width += int_part - data->taps.h_taps_c;
int_part = data->taps.h_taps_c;
}
data->inits.h_c.value &= 0xffffffff;
data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part);
}
}
if (!flip_vert_scan_dir) {
/* Adjust for viewport end clip-off */
if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) {
int vp_clip = src.y + src.height - data->viewport.height - data->viewport.y;
int int_part = dc_fixpt_floor(
dc_fixpt_sub(data->inits.v, data->ratios.vert));
int_part = int_part > 0 ? int_part : 0;
data->viewport.height += int_part < vp_clip ? int_part : vp_clip;
}
if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) {
int vp_clip = (src.y + src.height) / vpc_div -
data->viewport_c.height - data->viewport_c.y;
int int_part = dc_fixpt_floor(
dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c));
int_part = int_part > 0 ? int_part : 0;
data->viewport_c.height += int_part < vp_clip ? int_part : vp_clip;
}
if (data->viewport.y && !flip_vert_scan_dir) { /* Adjust for non-0 viewport offset */
if (data->viewport.y) {
int int_part; int int_part;
data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int( data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int(
data->ratios.vert, recout_skip->height)); data->ratios.vert, data->recout.y - recout_full->y));
int_part = dc_fixpt_floor(data->inits.v) - data->viewport.y; int_part = dc_fixpt_floor(data->inits.v) - data->viewport.y;
if (int_part < data->taps.v_taps) { if (int_part < data->taps.v_taps) {
int int_adj = data->viewport.y >= (data->taps.v_taps - int_part) ? int int_adj = data->viewport.y >= (data->taps.v_taps - int_part) ?
...@@ -810,11 +891,11 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r ...@@ -810,11 +891,11 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r
data->inits.v = dc_fixpt_add_int(data->inits.v, int_part); data->inits.v = dc_fixpt_add_int(data->inits.v, int_part);
} }
if (data->viewport_c.y && !flip_vert_scan_dir) { if (data->viewport_c.y) {
int int_part; int int_part;
data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int( data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int(
data->ratios.vert_c, recout_skip->height)); data->ratios.vert_c, data->recout.y - recout_full->y));
int_part = dc_fixpt_floor(data->inits.v_c) - data->viewport_c.y; int_part = dc_fixpt_floor(data->inits.v_c) - data->viewport_c.y;
if (int_part < data->taps.v_taps_c) { if (int_part < data->taps.v_taps_c) {
int int_adj = data->viewport_c.y >= (data->taps.v_taps_c - int_part) ? int int_adj = data->viewport_c.y >= (data->taps.v_taps_c - int_part) ?
...@@ -830,6 +911,84 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r ...@@ -830,6 +911,84 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r
data->inits.v_c.value &= 0xffffffff; data->inits.v_c.value &= 0xffffffff;
data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part); data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part);
} }
} else {
/* Adjust for non-0 viewport offset */
if (data->viewport.y) {
int int_part = dc_fixpt_floor(
dc_fixpt_sub(data->inits.v, data->ratios.vert));
int_part = int_part > 0 ? int_part : 0;
data->viewport.height += int_part < data->viewport.y ? int_part : data->viewport.y;
data->viewport.y -= int_part < data->viewport.y ? int_part : data->viewport.y;
}
if (data->viewport_c.y) {
int int_part = dc_fixpt_floor(
dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c));
int_part = int_part > 0 ? int_part : 0;
data->viewport_c.height += int_part < data->viewport_c.y ? int_part : data->viewport_c.y;
data->viewport_c.y -= int_part < data->viewport_c.y ? int_part : data->viewport_c.y;
}
/* Adjust for viewport end clip-off */
if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) {
int int_part;
int end_offset = src.y + src.height
- data->viewport.y - data->viewport.height;
/*
* this is init if vp had no offset, keep in mind this is from the
* right side of vp due to scan direction
*/
data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int(
data->ratios.vert, data->recout.y - recout_full->y));
/*
* this is the difference between first pixel of viewport available to read
* and init position, taking into account scan direction
*/
int_part = dc_fixpt_floor(data->inits.v) - end_offset;
if (int_part < data->taps.v_taps) {
int int_adj = end_offset >= (data->taps.v_taps - int_part) ?
(data->taps.v_taps - int_part) : end_offset;
data->viewport.height += int_adj;
int_part += int_adj;
} else if (int_part > data->taps.v_taps) {
data->viewport.height += int_part - data->taps.v_taps;
int_part = data->taps.v_taps;
}
data->inits.v.value &= 0xffffffff;
data->inits.v = dc_fixpt_add_int(data->inits.v, int_part);
}
if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) {
int int_part;
int end_offset = (src.y + src.height) / vpc_div
- data->viewport_c.y - data->viewport_c.height;
/*
* this is init if vp had no offset, keep in mind this is from the
* right side of vp due to scan direction
*/
data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int(
data->ratios.vert_c, data->recout.y - recout_full->y));
/*
* this is the difference between first pixel of viewport available to read
* and init position, taking into account scan direction
*/
int_part = dc_fixpt_floor(data->inits.v_c) - end_offset;
if (int_part < data->taps.v_taps_c) {
int int_adj = end_offset >= (data->taps.v_taps_c - int_part) ?
(data->taps.v_taps_c - int_part) : end_offset;
data->viewport_c.height += int_adj;
int_part += int_adj;
} else if (int_part > data->taps.v_taps_c) {
data->viewport_c.height += int_part - data->taps.v_taps_c;
int_part = data->taps.v_taps_c;
}
data->inits.v_c.value &= 0xffffffff;
data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part);
}
}
/* Interlaced inits based on final vert inits */ /* Interlaced inits based on final vert inits */
data->inits.v_bot = dc_fixpt_add(data->inits.v, data->ratios.vert); data->inits.v_bot = dc_fixpt_add(data->inits.v, data->ratios.vert);
...@@ -846,7 +1005,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) ...@@ -846,7 +1005,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
{ {
const struct dc_plane_state *plane_state = pipe_ctx->plane_state; const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
struct view recout_skip = { 0 }; struct rect recout_full = { 0 };
bool res = false; bool res = false;
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
/* Important: scaling ratio calculation requires pixel format, /* Important: scaling ratio calculation requires pixel format,
...@@ -866,7 +1025,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) ...@@ -866,7 +1025,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
if (pipe_ctx->plane_res.scl_data.viewport.height < 16 || pipe_ctx->plane_res.scl_data.viewport.width < 16) if (pipe_ctx->plane_res.scl_data.viewport.height < 16 || pipe_ctx->plane_res.scl_data.viewport.width < 16)
return false; return false;
calculate_recout(pipe_ctx, &recout_skip); calculate_recout(pipe_ctx, &recout_full);
/** /**
* Setting line buffer pixel depth to 24bpp yields banding * Setting line buffer pixel depth to 24bpp yields banding
...@@ -910,7 +1069,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) ...@@ -910,7 +1069,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
if (res) if (res)
/* May need to re-check lb size after this in some obscure scenario */ /* May need to re-check lb size after this in some obscure scenario */
calculate_inits_and_adj_vp(pipe_ctx, &recout_skip); calculate_inits_and_adj_vp(pipe_ctx, &recout_full);
DC_LOG_SCALER( DC_LOG_SCALER(
"%s: Viewport:\nheight:%d width:%d x:%d " "%s: Viewport:\nheight:%d width:%d x:%d "
...@@ -2347,7 +2506,8 @@ static void set_hdr_static_info_packet( ...@@ -2347,7 +2506,8 @@ static void set_hdr_static_info_packet(
{ {
/* HDR Static Metadata info packet for HDR10 */ /* HDR Static Metadata info packet for HDR10 */
if (!stream->hdr_static_metadata.valid) if (!stream->hdr_static_metadata.valid ||
stream->use_dynamic_meta)
return; return;
*info_packet = stream->hdr_static_metadata; *info_packet = stream->hdr_static_metadata;
......
...@@ -53,6 +53,10 @@ static bool construct(struct dc_sink *sink, const struct dc_sink_init_data *init ...@@ -53,6 +53,10 @@ static bool construct(struct dc_sink *sink, const struct dc_sink_init_data *init
sink->dongle_max_pix_clk = init_params->dongle_max_pix_clk; sink->dongle_max_pix_clk = init_params->dongle_max_pix_clk;
sink->converter_disable_audio = init_params->converter_disable_audio; sink->converter_disable_audio = init_params->converter_disable_audio;
sink->dc_container_id = NULL; sink->dc_container_id = NULL;
sink->sink_id = init_params->link->ctx->dc_sink_id_count;
// increment dc_sink_id_count because we don't want two sinks with same ID
// unless they are actually the same
init_params->link->ctx->dc_sink_id_count++;
return true; return true;
} }
......
...@@ -84,6 +84,17 @@ struct dc_plane_state *dc_create_plane_state(struct dc *dc) ...@@ -84,6 +84,17 @@ struct dc_plane_state *dc_create_plane_state(struct dc *dc)
return plane_state; return plane_state;
} }
/**
*****************************************************************************
* Function: dc_plane_get_status
*
* @brief
* Looks up the pipe context of plane_state and updates the pending status
* of the pipe context. Then returns plane_state->status
*
* @param [in] plane_state: pointer to the plane_state to get the status of
*****************************************************************************
*/
const struct dc_plane_status *dc_plane_get_status( const struct dc_plane_status *dc_plane_get_status(
const struct dc_plane_state *plane_state) const struct dc_plane_state *plane_state)
{ {
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include "inc/compressor.h" #include "inc/compressor.h"
#include "dml/display_mode_lib.h" #include "dml/display_mode_lib.h"
#define DC_VER "3.1.44" #define DC_VER "3.1.47"
#define MAX_SURFACES 3 #define MAX_SURFACES 3
#define MAX_STREAMS 6 #define MAX_STREAMS 6
...@@ -68,6 +68,7 @@ struct dc_caps { ...@@ -68,6 +68,7 @@ struct dc_caps {
uint32_t max_planes; uint32_t max_planes;
uint32_t max_downscale_ratio; uint32_t max_downscale_ratio;
uint32_t i2c_speed_in_khz; uint32_t i2c_speed_in_khz;
uint32_t dmdata_alloc_size;
unsigned int max_cursor_size; unsigned int max_cursor_size;
unsigned int max_video_width; unsigned int max_video_width;
int linear_pitch_alignment; int linear_pitch_alignment;
...@@ -288,9 +289,7 @@ struct dc { ...@@ -288,9 +289,7 @@ struct dc {
bool apply_edp_fast_boot_optimization; bool apply_edp_fast_boot_optimization;
/* FBC compressor */ /* FBC compressor */
#if defined(CONFIG_DRM_AMD_DC_FBC)
struct compressor *fbc_compressor; struct compressor *fbc_compressor;
#endif
}; };
enum frame_buffer_mode { enum frame_buffer_mode {
...@@ -358,6 +357,7 @@ enum dc_transfer_func_type { ...@@ -358,6 +357,7 @@ enum dc_transfer_func_type {
TF_TYPE_PREDEFINED, TF_TYPE_PREDEFINED,
TF_TYPE_DISTRIBUTED_POINTS, TF_TYPE_DISTRIBUTED_POINTS,
TF_TYPE_BYPASS, TF_TYPE_BYPASS,
TF_TYPE_HWPWL
}; };
struct dc_transfer_func_distributed_points { struct dc_transfer_func_distributed_points {
...@@ -377,16 +377,21 @@ enum dc_transfer_func_predefined { ...@@ -377,16 +377,21 @@ enum dc_transfer_func_predefined {
TRANSFER_FUNCTION_PQ, TRANSFER_FUNCTION_PQ,
TRANSFER_FUNCTION_LINEAR, TRANSFER_FUNCTION_LINEAR,
TRANSFER_FUNCTION_UNITY, TRANSFER_FUNCTION_UNITY,
TRANSFER_FUNCTION_HLG,
TRANSFER_FUNCTION_HLG12
}; };
struct dc_transfer_func { struct dc_transfer_func {
struct kref refcount; struct kref refcount;
struct dc_transfer_func_distributed_points tf_pts;
enum dc_transfer_func_type type; enum dc_transfer_func_type type;
enum dc_transfer_func_predefined tf; enum dc_transfer_func_predefined tf;
/* FP16 1.0 reference level in nits, default is 80 nits, only for PQ*/ /* FP16 1.0 reference level in nits, default is 80 nits, only for PQ*/
uint32_t sdr_ref_white_level; uint32_t sdr_ref_white_level;
struct dc_context *ctx; struct dc_context *ctx;
union {
struct pwl_params pwl;
struct dc_transfer_func_distributed_points tf_pts;
};
}; };
/* /*
...@@ -661,9 +666,13 @@ struct dc_sink { ...@@ -661,9 +666,13 @@ struct dc_sink {
struct dc_link *link; struct dc_link *link;
struct dc_context *ctx; struct dc_context *ctx;
uint32_t sink_id;
/* private to dc_sink.c */ /* private to dc_sink.c */
// refcount must be the last member in dc_sink, since we want the
// sink structure to be logically cloneable up to (but not including)
// refcount
struct kref refcount; struct kref refcount;
}; };
void dc_sink_retain(struct dc_sink *sink); void dc_sink_retain(struct dc_sink *sink);
......
...@@ -25,6 +25,65 @@ ...@@ -25,6 +25,65 @@
#ifndef DC_DDC_TYPES_H_ #ifndef DC_DDC_TYPES_H_
#define DC_DDC_TYPES_H_ #define DC_DDC_TYPES_H_
enum aux_transaction_type {
AUX_TRANSACTION_TYPE_DP,
AUX_TRANSACTION_TYPE_I2C
};
enum i2caux_transaction_action {
I2CAUX_TRANSACTION_ACTION_I2C_WRITE = 0x00,
I2CAUX_TRANSACTION_ACTION_I2C_READ = 0x10,
I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST = 0x20,
I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT = 0x40,
I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT = 0x50,
I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT = 0x60,
I2CAUX_TRANSACTION_ACTION_DP_WRITE = 0x80,
I2CAUX_TRANSACTION_ACTION_DP_READ = 0x90
};
enum aux_channel_operation_result {
AUX_CHANNEL_OPERATION_SUCCEEDED,
AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN,
AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY,
AUX_CHANNEL_OPERATION_FAILED_TIMEOUT,
AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON
};
struct aux_request_transaction_data {
enum aux_transaction_type type;
enum i2caux_transaction_action action;
/* 20-bit AUX channel transaction address */
uint32_t address;
/* delay, in 100-microsecond units */
uint8_t delay;
uint32_t length;
uint8_t *data;
};
enum aux_transaction_reply {
AUX_TRANSACTION_REPLY_AUX_ACK = 0x00,
AUX_TRANSACTION_REPLY_AUX_NACK = 0x01,
AUX_TRANSACTION_REPLY_AUX_DEFER = 0x02,
AUX_TRANSACTION_REPLY_I2C_ACK = 0x00,
AUX_TRANSACTION_REPLY_I2C_NACK = 0x10,
AUX_TRANSACTION_REPLY_I2C_DEFER = 0x20,
AUX_TRANSACTION_REPLY_HPD_DISCON = 0x40,
AUX_TRANSACTION_REPLY_INVALID = 0xFF
};
struct aux_reply_transaction_data {
enum aux_transaction_reply status;
uint32_t length;
uint8_t *data;
};
struct i2c_payload { struct i2c_payload {
bool write; bool write;
uint8_t address; uint8_t address;
...@@ -109,7 +168,7 @@ struct ddc_service { ...@@ -109,7 +168,7 @@ struct ddc_service {
uint32_t address; uint32_t address;
uint32_t edid_buf_len; uint32_t edid_buf_len;
uint8_t edid_buf[MAX_EDID_BUFFER_SIZE]; uint8_t edid_buf[DC_MAX_EDID_BUFFER_SIZE];
}; };
#endif /* DC_DDC_TYPES_H_ */ #endif /* DC_DDC_TYPES_H_ */
...@@ -430,7 +430,7 @@ union test_request { ...@@ -430,7 +430,7 @@ union test_request {
struct { struct {
uint8_t LINK_TRAINING :1; uint8_t LINK_TRAINING :1;
uint8_t LINK_TEST_PATTRN :1; uint8_t LINK_TEST_PATTRN :1;
uint8_t EDID_REAT :1; uint8_t EDID_READ :1;
uint8_t PHY_TEST_PATTERN :1; uint8_t PHY_TEST_PATTERN :1;
uint8_t AUDIO_TEST_PATTERN :1; uint8_t AUDIO_TEST_PATTERN :1;
uint8_t RESERVED :1; uint8_t RESERVED :1;
...@@ -443,7 +443,8 @@ union test_response { ...@@ -443,7 +443,8 @@ union test_response {
struct { struct {
uint8_t ACK :1; uint8_t ACK :1;
uint8_t NO_ACK :1; uint8_t NO_ACK :1;
uint8_t RESERVED :6; uint8_t EDID_CHECKSUM_WRITE:1;
uint8_t RESERVED :5;
} bits; } bits;
uint8_t raw; uint8_t raw;
}; };
......
...@@ -567,25 +567,25 @@ struct scaling_taps { ...@@ -567,25 +567,25 @@ struct scaling_taps {
}; };
enum dc_timing_standard { enum dc_timing_standard {
TIMING_STANDARD_UNDEFINED, DC_TIMING_STANDARD_UNDEFINED,
TIMING_STANDARD_DMT, DC_TIMING_STANDARD_DMT,
TIMING_STANDARD_GTF, DC_TIMING_STANDARD_GTF,
TIMING_STANDARD_CVT, DC_TIMING_STANDARD_CVT,
TIMING_STANDARD_CVT_RB, DC_TIMING_STANDARD_CVT_RB,
TIMING_STANDARD_CEA770, DC_TIMING_STANDARD_CEA770,
TIMING_STANDARD_CEA861, DC_TIMING_STANDARD_CEA861,
TIMING_STANDARD_HDMI, DC_TIMING_STANDARD_HDMI,
TIMING_STANDARD_TV_NTSC, DC_TIMING_STANDARD_TV_NTSC,
TIMING_STANDARD_TV_NTSC_J, DC_TIMING_STANDARD_TV_NTSC_J,
TIMING_STANDARD_TV_PAL, DC_TIMING_STANDARD_TV_PAL,
TIMING_STANDARD_TV_PAL_M, DC_TIMING_STANDARD_TV_PAL_M,
TIMING_STANDARD_TV_PAL_CN, DC_TIMING_STANDARD_TV_PAL_CN,
TIMING_STANDARD_TV_SECAM, DC_TIMING_STANDARD_TV_SECAM,
TIMING_STANDARD_EXPLICIT, DC_TIMING_STANDARD_EXPLICIT,
/*!< For explicit timings from EDID, VBIOS, etc.*/ /*!< For explicit timings from EDID, VBIOS, etc.*/
TIMING_STANDARD_USER_OVERRIDE, DC_TIMING_STANDARD_USER_OVERRIDE,
/*!< For mode timing override by user*/ /*!< For mode timing override by user*/
TIMING_STANDARD_MAX DC_TIMING_STANDARD_MAX
}; };
enum dc_color_depth { enum dc_color_depth {
......
...@@ -59,6 +59,9 @@ struct dc_stream_state { ...@@ -59,6 +59,9 @@ struct dc_stream_state {
struct freesync_context freesync_ctx; struct freesync_context freesync_ctx;
struct dc_info_packet hdr_static_metadata; struct dc_info_packet hdr_static_metadata;
PHYSICAL_ADDRESS_LOC dmdata_address;
bool use_dynamic_meta;
struct dc_transfer_func *out_transfer_func; struct dc_transfer_func *out_transfer_func;
struct colorspace_transform gamut_remap_matrix; struct colorspace_transform gamut_remap_matrix;
struct dc_csc_transform csc_color_matrix; struct dc_csc_transform csc_color_matrix;
...@@ -299,9 +302,4 @@ bool dc_stream_get_crtc_position(struct dc *dc, ...@@ -299,9 +302,4 @@ bool dc_stream_get_crtc_position(struct dc *dc,
unsigned int *v_pos, unsigned int *v_pos,
unsigned int *nom_v_pos); unsigned int *nom_v_pos);
void dc_stream_set_static_screen_events(struct dc *dc,
struct dc_stream_state **stream,
int num_streams,
const struct dc_static_screen_events *events);
#endif /* DC_STREAM_H_ */ #endif /* DC_STREAM_H_ */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册