diff options
author | Dave Airlie <airlied@redhat.com> | 2016-05-06 14:17:22 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-05-06 14:17:22 +1000 |
commit | a64424d722504926f3375bc4887976e3bfe3a01d (patch) | |
tree | abf5419151be98a8520e30b1ae7935127a678796 /drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | |
parent | 0552f7651bc233e5407ab06ba97a9d7c25e19580 (diff) | |
parent | 84fae133f0ccc974a425eee21101f5644bd8d14d (diff) |
Merge branch 'drm-next-4.7' of git://people.freedesktop.org/~agd5f/linux into drm-next
This is the first big radeon/amdgpu pull request for 4.7. Highlights:
- Polaris support in amdgpu
Current display stack on par with other asics, for advanced features DAL is required
Power management support
Support for GFX, Compute, SDMA, UVD, VCE
- VCE and UVD init/fini cleanup in radeon
- GPUVM improvements
- Scheduler improvements
- Clockgating improvements
- Powerplay improvements
- TTM changes to support driver specific LRU update mechanism
- Radeon support for new Mesa features
- ASYNC pageflip support for radeon
- Lots of bug fixes and code cleanups
* 'drm-next-4.7' of git://people.freedesktop.org/~agd5f/linux: (180 commits)
drm/amdgpu: Replace rcu_assign_pointer() with RCU_INIT_POINTER()
drm/amdgpu: use drm_mode_vrefresh() rather than mode->vrefresh
drm/amdgpu/uvd6: add bypass support for fiji (v3)
drm/amdgpu/fiji: set UVD CG state when enabling UVD DPM (v2)
drm/powerplay: add missing clockgating callback for tonga
drm/amdgpu: Constify some tables
drm/amd/powerplay: Delete dead struct declaration
drm/amd/powerplay/hwmgr: don't add invalid voltage
drm/amd/powerplay/hwmgr: prevent VDDC from exceeding 2V
MAINTAINERS: Remove unneded wildcard for the Radeon/AMDGPU drivers
drm/radeon: add cayman VM support for append packet.
drm/amd/amdgpu: Add debugfs entries for smc/didt/pcie
drm/amd/amdgpu: Drop print_status callbacks.
drm/amd/powerplay: revise reading/writing pptable on Polaris10
drm/amd/powerplay: revise reading/writing pptable on Tonga
drm/amd/powerplay: revise reading/writing pptable on Fiji
drm/amd/powerplay: revise caching the soft pptable and add it's size
drm/amd/powerplay: add dpm force multiple levels on cz/tonga/fiji/polaris (v2)
drm/amd/powerplay: fix fan speed percent setting error on Polaris10
drm/amd/powerplay: fix bug dpm can't work when resume back on Polaris
...
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_device.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 259 |
1 files changed, 241 insertions, 18 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 612117478b57..8f037e5e08fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -59,6 +59,8 @@ static const char *amdgpu_asic_name[] = { "FIJI", "CARRIZO", "STONEY", + "POLARIS10", + "POLARIS11", "LAST", }; @@ -942,15 +944,11 @@ static void amdgpu_check_arguments(struct amdgpu_device *adev) } if (amdgpu_gart_size != -1) { - /* gtt size must be power of two and greater or equal to 32M */ + /* gtt size must be greater or equal to 32M */ if (amdgpu_gart_size < 32) { dev_warn(adev->dev, "gart size (%d) too small\n", amdgpu_gart_size); amdgpu_gart_size = -1; - } else if (!amdgpu_check_pot_argument(amdgpu_gart_size)) { - dev_warn(adev->dev, "gart size (%d) must be a power of 2\n", - amdgpu_gart_size); - amdgpu_gart_size = -1; } } @@ -1150,6 +1148,8 @@ static int amdgpu_early_init(struct amdgpu_device *adev) case CHIP_TOPAZ: case CHIP_TONGA: case CHIP_FIJI: + case CHIP_POLARIS11: + case CHIP_POLARIS10: case CHIP_CARRIZO: case CHIP_STONEY: if (adev->asic_type == CHIP_CARRIZO || adev->asic_type == CHIP_STONEY) @@ -1338,14 +1338,23 @@ static int amdgpu_suspend(struct amdgpu_device *adev) { int i, r; + /* ungate SMC block first */ + r = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_SMC, + AMD_CG_STATE_UNGATE); + if (r) { + DRM_ERROR("set_clockgating_state(ungate) SMC failed %d\n",r); + } + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_block_status[i].valid) continue; /* ungate blocks so that suspend can properly shut them down */ - r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev, - AMD_CG_STATE_UNGATE); - if (r) { - DRM_ERROR("set_clockgating_state(ungate) %d failed %d\n", i, r); + if (i != AMD_IP_BLOCK_TYPE_SMC) { + r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev, + AMD_CG_STATE_UNGATE); + if (r) { + DRM_ERROR("set_clockgating_state(ungate) %d failed %d\n", i, r); + } } /* XXX handle errors */ r = adev->ip_blocks[i].funcs->suspend(adev); @@ -2013,7 +2022,7 @@ void amdgpu_get_pcie_info(struct amdgpu_device *adev) * Debugfs */ int amdgpu_debugfs_add_files(struct amdgpu_device *adev, - struct drm_info_list *files, + const struct drm_info_list *files, unsigned nfiles) { unsigned i; @@ -2125,32 +2134,246 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf, return result; } +static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = f->f_inode->i_private; + ssize_t result = 0; + int r; + + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + + while (size) { + uint32_t value; + + value = RREG32_PCIE(*pos >> 2); + r = put_user(value, (uint32_t *)buf); + if (r) + return r; + + result += 4; + buf += 4; + *pos += 4; + size -= 4; + } + + return result; +} + +static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = f->f_inode->i_private; + ssize_t result = 0; + int r; + + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + + while (size) { + uint32_t value; + + r = get_user(value, (uint32_t *)buf); + if (r) + return r; + + WREG32_PCIE(*pos >> 2, value); + + result += 4; + buf += 4; + *pos += 4; + size -= 4; + } + + return result; +} + +static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = f->f_inode->i_private; + ssize_t result = 0; + int r; + + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + + while (size) { + uint32_t value; + + value = RREG32_DIDT(*pos >> 2); + r = put_user(value, (uint32_t *)buf); + if (r) + return r; + + result += 4; + buf += 4; + *pos += 4; + size -= 4; + } + + return result; +} + +static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = f->f_inode->i_private; + ssize_t result = 0; + int r; + + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + + while (size) { + uint32_t value; + + r = get_user(value, (uint32_t *)buf); + if (r) + return r; + + WREG32_DIDT(*pos >> 2, value); + + result += 4; + buf += 4; + *pos += 4; + size -= 4; + } + + return result; +} + +static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = f->f_inode->i_private; + ssize_t result = 0; + int r; + + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + + while (size) { + uint32_t value; + + value = RREG32_SMC(*pos >> 2); + r = put_user(value, (uint32_t *)buf); + if (r) + return r; + + result += 4; + buf += 4; + *pos += 4; + size -= 4; + } + + return result; +} + +static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = f->f_inode->i_private; + ssize_t result = 0; + int r; + + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + + while (size) { + uint32_t value; + + r = get_user(value, (uint32_t *)buf); + if (r) + return r; + + WREG32_SMC(*pos >> 2, value); + + result += 4; + buf += 4; + *pos += 4; + size -= 4; + } + + return result; +} + static const struct file_operations amdgpu_debugfs_regs_fops = { .owner = THIS_MODULE, .read = amdgpu_debugfs_regs_read, .write = amdgpu_debugfs_regs_write, .llseek = default_llseek }; +static const struct file_operations amdgpu_debugfs_regs_didt_fops = { + .owner = THIS_MODULE, + .read = amdgpu_debugfs_regs_didt_read, + .write = amdgpu_debugfs_regs_didt_write, + .llseek = default_llseek +}; +static const struct file_operations amdgpu_debugfs_regs_pcie_fops = { + .owner = THIS_MODULE, + .read = amdgpu_debugfs_regs_pcie_read, + .write = amdgpu_debugfs_regs_pcie_write, + .llseek = default_llseek +}; +static const struct file_operations amdgpu_debugfs_regs_smc_fops = { + .owner = THIS_MODULE, + .read = amdgpu_debugfs_regs_smc_read, + .write = amdgpu_debugfs_regs_smc_write, + .llseek = default_llseek +}; + +static const struct file_operations *debugfs_regs[] = { + &amdgpu_debugfs_regs_fops, + &amdgpu_debugfs_regs_didt_fops, + &amdgpu_debugfs_regs_pcie_fops, + &amdgpu_debugfs_regs_smc_fops, +}; + +static const char *debugfs_regs_names[] = { + "amdgpu_regs", + "amdgpu_regs_didt", + "amdgpu_regs_pcie", + "amdgpu_regs_smc", +}; static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) { struct drm_minor *minor = adev->ddev->primary; struct dentry *ent, *root = minor->debugfs_root; + unsigned i, j; + + for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { + ent = debugfs_create_file(debugfs_regs_names[i], + S_IFREG | S_IRUGO, root, + adev, debugfs_regs[i]); + if (IS_ERR(ent)) { + for (j = 0; j < i; j++) { + debugfs_remove(adev->debugfs_regs[i]); + adev->debugfs_regs[i] = NULL; + } + return PTR_ERR(ent); + } - ent = debugfs_create_file("amdgpu_regs", S_IFREG | S_IRUGO, root, - adev, &amdgpu_debugfs_regs_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); - i_size_write(ent->d_inode, adev->rmmio_size); - adev->debugfs_regs = ent; + if (!i) + i_size_write(ent->d_inode, adev->rmmio_size); + adev->debugfs_regs[i] = ent; + } return 0; } static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev) { - debugfs_remove(adev->debugfs_regs); - adev->debugfs_regs = NULL; + unsigned i; + + for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { + if (adev->debugfs_regs[i]) { + debugfs_remove(adev->debugfs_regs[i]); + adev->debugfs_regs[i] = NULL; + } + } } int amdgpu_debugfs_init(struct drm_minor *minor) |