Commit a8a7cf02 authored by Dave Airlie's avatar Dave Airlie

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

for amdgpu separately next week.  Highlights for radeon:
- VCE1 support
- Bug fixes and misc cleanups

* 'drm-next-4.2' of git://people.freedesktop.org/~agd5f/linux:
  radeon: Deinline indirect register accessor functions
  drm/radeon: Fix max_vblank_count value for current display engines
  drm/radeon: stop using addr to check for BO move
  drm/radeon: clean up radeon_audio_enable
  drm/radeon: take the mode_config mutex when dealing with hpds (v2)
  drm/radeon: make dpcd parameters const
  drm/radeon: Use DECLARE_BITMAP
  drm/radeon/tn/si: enable/disable vce cg when encoding v2
  drm/radeon: add support for vce 1.0 clock gating
  drm/radeon: add VCE 1.0 support v4
  drm/radeon/dpm: add vce support for SI
  drm/radeon/dpm: add vce dpm support for TN
  drm/radeon: implement tn_set_vce_clocks
  drm/radeon: implement si_set_vce_clocks v2
  drm/radeon: allow some more VCE firmware versions
  drm/radeon: rework VCE FW size calculation
  drm/radeon: add a GPU reset counter queryable by userspace
parents c6e7e4bb 9e5acbc2
......@@ -253,7 +253,7 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_LEVEL_3
#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPH_LEVEL_3
static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
static void dp_get_adjust_train(const u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count,
u8 train_set[4])
{
......@@ -311,7 +311,7 @@ static int dp_get_max_dp_pix_clock(int link_rate,
/***** radeon specific DP functions *****/
int radeon_dp_get_max_link_rate(struct drm_connector *connector,
u8 dpcd[DP_DPCD_SIZE])
const u8 dpcd[DP_DPCD_SIZE])
{
int max_link_rate;
......@@ -328,7 +328,7 @@ int radeon_dp_get_max_link_rate(struct drm_connector *connector,
* if the max lane# < low rate lane# then use max lane# instead.
*/
static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
u8 dpcd[DP_DPCD_SIZE],
const u8 dpcd[DP_DPCD_SIZE],
int pix_clock)
{
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
......@@ -347,7 +347,7 @@ static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
}
static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
u8 dpcd[DP_DPCD_SIZE],
const u8 dpcd[DP_DPCD_SIZE],
int pix_clock)
{
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
......
......@@ -174,6 +174,31 @@ int cik_get_allowed_info_register(struct radeon_device *rdev,
}
}
/*
* Indirect registers accessor
*/
u32 cik_didt_rreg(struct radeon_device *rdev, u32 reg)
{
unsigned long flags;
u32 r;
spin_lock_irqsave(&rdev->didt_idx_lock, flags);
WREG32(CIK_DIDT_IND_INDEX, (reg));
r = RREG32(CIK_DIDT_IND_DATA);
spin_unlock_irqrestore(&rdev->didt_idx_lock, flags);
return r;
}
void cik_didt_wreg(struct radeon_device *rdev, u32 reg, u32 v)
{
unsigned long flags;
spin_lock_irqsave(&rdev->didt_idx_lock, flags);
WREG32(CIK_DIDT_IND_INDEX, (reg));
WREG32(CIK_DIDT_IND_DATA, (v));
spin_unlock_irqrestore(&rdev->didt_idx_lock, flags);
}
/* get temperature in millidegrees */
int ci_get_temp(struct radeon_device *rdev)
{
......
......@@ -35,6 +35,75 @@
#include "evergreen_blit_shaders.h"
#include "radeon_ucode.h"
/*
* Indirect registers accessor
*/
u32 eg_cg_rreg(struct radeon_device *rdev, u32 reg)
{
unsigned long flags;
u32 r;
spin_lock_irqsave(&rdev->cg_idx_lock, flags);
WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
r = RREG32(EVERGREEN_CG_IND_DATA);
spin_unlock_irqrestore(&rdev->cg_idx_lock, flags);
return r;
}
void eg_cg_wreg(struct radeon_device *rdev, u32 reg, u32 v)
{
unsigned long flags;
spin_lock_irqsave(&rdev->cg_idx_lock, flags);
WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
WREG32(EVERGREEN_CG_IND_DATA, (v));
spin_unlock_irqrestore(&rdev->cg_idx_lock, flags);
}
u32 eg_pif_phy0_rreg(struct radeon_device *rdev, u32 reg)
{
unsigned long flags;
u32 r;
spin_lock_irqsave(&rdev->pif_idx_lock, flags);
WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff));
r = RREG32(EVERGREEN_PIF_PHY0_DATA);
spin_unlock_irqrestore(&rdev->pif_idx_lock, flags);
return r;
}
void eg_pif_phy0_wreg(struct radeon_device *rdev, u32 reg, u32 v)
{
unsigned long flags;
spin_lock_irqsave(&rdev->pif_idx_lock, flags);
WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff));
WREG32(EVERGREEN_PIF_PHY0_DATA, (v));
spin_unlock_irqrestore(&rdev->pif_idx_lock, flags);
}
u32 eg_pif_phy1_rreg(struct radeon_device *rdev, u32 reg)
{
unsigned long flags;
u32 r;
spin_lock_irqsave(&rdev->pif_idx_lock, flags);
WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff));
r = RREG32(EVERGREEN_PIF_PHY1_DATA);
spin_unlock_irqrestore(&rdev->pif_idx_lock, flags);
return r;
}
void eg_pif_phy1_wreg(struct radeon_device *rdev, u32 reg, u32 v)
{
unsigned long flags;
spin_lock_irqsave(&rdev->pif_idx_lock, flags);
WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff));
WREG32(EVERGREEN_PIF_PHY1_DATA, (v));
spin_unlock_irqrestore(&rdev->pif_idx_lock, flags);
}
static const u32 crtc_offsets[6] =
{
EVERGREEN_CRTC0_REGISTER_OFFSET,
......
......@@ -36,6 +36,31 @@
#include "radeon_ucode.h"
#include "clearstate_cayman.h"
/*
* Indirect registers accessor
*/
u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg)
{
unsigned long flags;
u32 r;
spin_lock_irqsave(&rdev->smc_idx_lock, flags);
WREG32(TN_SMC_IND_INDEX_0, (reg));
r = RREG32(TN_SMC_IND_DATA_0);
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
return r;
}
void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v)
{
unsigned long flags;
spin_lock_irqsave(&rdev->smc_idx_lock, flags);
WREG32(TN_SMC_IND_INDEX_0, (reg));
WREG32(TN_SMC_IND_DATA_0, (v));
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
}
static const u32 tn_rlc_save_restore_register_list[] =
{
0x98fc,
......@@ -2041,6 +2066,25 @@ static int cayman_startup(struct radeon_device *rdev)
if (r)
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
if (rdev->family == CHIP_ARUBA) {
r = radeon_vce_resume(rdev);
if (!r)
r = vce_v1_0_resume(rdev);
if (!r)
r = radeon_fence_driver_start_ring(rdev,
TN_RING_TYPE_VCE1_INDEX);
if (!r)
r = radeon_fence_driver_start_ring(rdev,
TN_RING_TYPE_VCE2_INDEX);
if (r) {
dev_err(rdev->dev, "VCE init error (%d).\n", r);
rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
}
}
r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
......@@ -2118,6 +2162,19 @@ static int cayman_startup(struct radeon_device *rdev)
DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
}
ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
if (ring->ring_size)
r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0);
ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
if (ring->ring_size)
r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0);
if (!r)
r = vce_v1_0_init(rdev);
else if (r != -ENOENT)
DRM_ERROR("radeon: failed initializing VCE (%d).\n", r);
r = radeon_ib_pool_init(rdev);
if (r) {
dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
......@@ -2273,6 +2330,19 @@ int cayman_init(struct radeon_device *rdev)
r600_ring_init(rdev, ring, 4096);
}
if (rdev->family == CHIP_ARUBA) {
r = radeon_vce_init(rdev);
if (!r) {
ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 4096);
ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 4096);
}
}
rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024);
......@@ -2326,6 +2396,7 @@ void cayman_fini(struct radeon_device *rdev)
radeon_irq_kms_fini(rdev);
uvd_v1_0_fini(rdev);
radeon_uvd_fini(rdev);
radeon_vce_fini(rdev);
cayman_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
......@@ -2554,3 +2625,34 @@ void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
radeon_ring_write(ring, 0x0);
}
int tn_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk)
{
struct atom_clock_dividers dividers;
int r, i;
r = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
ecclk, false, &dividers);
if (r)
return r;
for (i = 0; i < 100; i++) {
if (RREG32(CG_ECLK_STATUS) & ECLK_STATUS)
break;
mdelay(10);
}
if (i == 100)
return -ETIMEDOUT;
WREG32_P(CG_ECLK_CNTL, dividers.post_div, ~(ECLK_DIR_CNTL_EN|ECLK_DIVIDER_MASK));
for (i = 0; i < 100; i++) {
if (RREG32(CG_ECLK_STATUS) & ECLK_STATUS)
break;
mdelay(10);
}
if (i == 100)
return -ETIMEDOUT;
return 0;
}
......@@ -46,6 +46,13 @@
#define DMIF_ADDR_CONFIG 0xBD4
/* fusion vce clocks */
#define CG_ECLK_CNTL 0x620
# define ECLK_DIVIDER_MASK 0x7f
# define ECLK_DIR_CNTL_EN (1 << 8)
#define CG_ECLK_STATUS 0x624
# define ECLK_STATUS (1 << 0)
/* DCE6 only */
#define DMIF_ADDR_CALC 0xC00
......
......@@ -4090,6 +4090,28 @@ int r100_init(struct radeon_device *rdev)
return 0;
}
uint32_t r100_mm_rreg_slow(struct radeon_device *rdev, uint32_t reg)
{
unsigned long flags;
uint32_t ret;
spin_lock_irqsave(&rdev->mmio_idx_lock, flags);
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA);
spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags);
return ret;
}
void r100_mm_wreg_slow(struct radeon_device *rdev, uint32_t reg, uint32_t v)
{
unsigned long flags;
spin_lock_irqsave(&rdev->mmio_idx_lock, flags);
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA);
spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags);
}
u32 r100_io_rreg(struct radeon_device *rdev, u32 reg)
{
if (reg < rdev->rio_mem_size)
......
......@@ -49,6 +49,31 @@
* tell. (Jerome Glisse)
*/
/*
* Indirect registers accessor
*/
uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg)
{
unsigned long flags;
uint32_t r;
spin_lock_irqsave(&rdev->pcie_idx_lock, flags);
WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask));
r = RREG32(RADEON_PCIE_DATA);
spin_unlock_irqrestore(&rdev->pcie_idx_lock, flags);
return r;
}
void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
{
unsigned long flags;
spin_lock_irqsave(&rdev->pcie_idx_lock, flags);
WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask));
WREG32(RADEON_PCIE_DATA, (v));
spin_unlock_irqrestore(&rdev->pcie_idx_lock, flags);
}
/*
* rv370,rv380 PCIE GART
*/
......
......@@ -108,6 +108,53 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev);
extern int evergreen_rlc_resume(struct radeon_device *rdev);
extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev);
/*
* Indirect registers accessor
*/
u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg)
{
unsigned long flags;
u32 r;
spin_lock_irqsave(&rdev->rcu_idx_lock, flags);
WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
r = RREG32(R600_RCU_DATA);
spin_unlock_irqrestore(&rdev->rcu_idx_lock, flags);
return r;
}
void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v)
{
unsigned long flags;
spin_lock_irqsave(&rdev->rcu_idx_lock, flags);
WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
WREG32(R600_RCU_DATA, (v));
spin_unlock_irqrestore(&rdev->rcu_idx_lock, flags);
}
u32 r600_uvd_ctx_rreg(struct radeon_device *rdev, u32 reg)
{
unsigned long flags;
u32 r;
spin_lock_irqsave(&rdev->uvd_idx_lock, flags);
WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff));
r = RREG32(R600_UVD_CTX_DATA);
spin_unlock_irqrestore(&rdev->uvd_idx_lock, flags);
return r;
}
void r600_uvd_ctx_wreg(struct radeon_device *rdev, u32 reg, u32 v)
{
unsigned long flags;
spin_lock_irqsave(&rdev->uvd_idx_lock, flags);
WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff));
WREG32(R600_UVD_CTX_DATA, (v));
spin_unlock_irqrestore(&rdev->uvd_idx_lock, flags);
}
/**
* r600_get_allowed_info_register - fetch the register for the info ioctl
*
......
This diff is collapsed.
......@@ -1761,6 +1761,19 @@ static struct radeon_asic cayman_asic = {
},
};
static struct radeon_asic_ring trinity_vce_ring = {
.ib_execute = &radeon_vce_ib_execute,
.emit_fence = &radeon_vce_fence_emit,
.emit_semaphore = &radeon_vce_semaphore_emit,
.cs_parse = &radeon_vce_cs_parse,
.ring_test = &radeon_vce_ring_test,
.ib_test = &radeon_vce_ib_test,
.is_lockup = &radeon_ring_test_lockup,
.get_rptr = &vce_v1_0_get_rptr,
.get_wptr = &vce_v1_0_get_wptr,
.set_wptr = &vce_v1_0_set_wptr,
};
static struct radeon_asic trinity_asic = {
.init = &cayman_init,
.fini = &cayman_fini,
......@@ -1794,6 +1807,8 @@ static struct radeon_asic trinity_asic = {
[R600_RING_TYPE_DMA_INDEX] = &cayman_dma_ring,
[CAYMAN_RING_TYPE_DMA1_INDEX] = &cayman_dma_ring,
[R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring,
[TN_RING_TYPE_VCE1_INDEX] = &trinity_vce_ring,
[TN_RING_TYPE_VCE2_INDEX] = &trinity_vce_ring,
},
.irq = {
.set = &evergreen_irq_set,
......@@ -1838,6 +1853,7 @@ static struct radeon_asic trinity_asic = {
.set_pcie_lanes = NULL,
.set_clock_gating = NULL,
.set_uvd_clocks = &sumo_set_uvd_clocks,
.set_vce_clocks = &tn_set_vce_clocks,
.get_temperature = &tn_get_temp,
},
.dpm = {
......@@ -1929,6 +1945,8 @@ static struct radeon_asic si_asic = {
[R600_RING_TYPE_DMA_INDEX] = &si_dma_ring,
[CAYMAN_RING_TYPE_DMA1_INDEX] = &si_dma_ring,
[R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring,
[TN_RING_TYPE_VCE1_INDEX] = &trinity_vce_ring,
[TN_RING_TYPE_VCE2_INDEX] = &trinity_vce_ring,
},
.irq = {
.set = &si_irq_set,
......@@ -1973,6 +1991,7 @@ static struct radeon_asic si_asic = {
.set_pcie_lanes = &r600_set_pcie_lanes,
.set_clock_gating = NULL,
.set_uvd_clocks = &si_set_uvd_clocks,
.set_vce_clocks = &si_set_vce_clocks,
.get_temperature = &si_get_temp,
},
.dpm = {
......@@ -2436,6 +2455,8 @@ int radeon_asic_init(struct radeon_device *rdev)
/* set num crtcs */
rdev->num_crtc = 4;
rdev->has_uvd = true;
rdev->cg_flags =
RADEON_CG_SUPPORT_VCE_MGCG;
break;
case CHIP_TAHITI:
case CHIP_PITCAIRN:
......
......@@ -694,6 +694,7 @@ int trinity_dpm_force_performance_level(struct radeon_device *rdev,
void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev);
u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev);
int tn_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk);
/* DCE6 - SI */
void dce6_bandwidth_update(struct radeon_device *rdev);
......@@ -745,6 +746,7 @@ void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
u32 si_get_xclk(struct radeon_device *rdev);
uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev);
int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
int si_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk);
int si_get_temp(struct radeon_device *rdev);
int si_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val);
......@@ -970,10 +972,14 @@ uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev,
struct radeon_ring *ring);
void vce_v1_0_set_wptr(struct radeon_device *rdev,
struct radeon_ring *ring);
int vce_v1_0_load_fw(struct radeon_device *rdev, uint32_t *data);
unsigned vce_v1_0_bo_size(struct radeon_device *rdev);
int vce_v1_0_resume(struct radeon_device *rdev);
int vce_v1_0_init(struct radeon_device *rdev);
int vce_v1_0_start(struct radeon_device *rdev);
/* vce v2.0 */
unsigned vce_v2_0_bo_size(struct radeon_device *rdev);
int vce_v2_0_resume(struct radeon_device *rdev);
#endif
......@@ -242,6 +242,13 @@ static struct radeon_audio_funcs dce6_dp_funcs = {
.dpms = evergreen_dp_enable,
};
static void radeon_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin, u8 enable_mask)
{
if (rdev->audio.funcs->enable)
rdev->audio.funcs->enable(rdev, pin, enable_mask);
}
static void radeon_audio_interface_init(struct radeon_device *rdev)
{
if (ASIC_IS_DCE6(rdev)) {
......@@ -307,7 +314,7 @@ int radeon_audio_init(struct radeon_device *rdev)
/* disable audio. it will be set up later */
for (i = 0; i < rdev->audio.num_pins; i++)
radeon_audio_enable(rdev, &rdev->audio.pin[i], false);
radeon_audio_enable(rdev, &rdev->audio.pin[i], 0);
return 0;
}
......@@ -443,13 +450,6 @@ static void radeon_audio_select_pin(struct drm_encoder *encoder)
radeon_encoder->audio->select_pin(encoder);
}
void radeon_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin, u8 enable_mask)
{
if (rdev->audio.funcs->enable)
rdev->audio.funcs->enable(rdev, pin, enable_mask);
}
void radeon_audio_detect(struct drm_connector *connector,
enum drm_connector_status status)
{
......@@ -505,7 +505,7 @@ void radeon_audio_fini(struct radeon_device *rdev)
return;
for (i = 0; i < rdev->audio.num_pins; i++)
radeon_audio_enable(rdev, &rdev->audio.pin[i], false);
radeon_audio_enable(rdev, &rdev->audio.pin[i], 0);
rdev->audio.enabled = false;
}
......
......@@ -74,8 +74,6 @@ u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev,
void radeon_audio_endpoint_wreg(struct radeon_device *rdev,
u32 offset, u32 reg, u32 v);
struct r600_audio_pin *radeon_audio_get_pin(struct drm_encoder *encoder);
void radeon_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin, u8 enable_mask);
void radeon_audio_fini(struct radeon_device *rdev);
void radeon_audio_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode);
......
......@@ -1725,6 +1725,8 @@ int radeon_gpu_reset(struct radeon_device *rdev)
return 0;
}
atomic_inc(&rdev->gpu_reset_counter);
radeon_save_bios_scratch_regs(rdev);
/* block TTM */
resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
......
......@@ -90,9 +90,10 @@
* CS to GPU on >= r600
* 2.41.0 - evergreen/cayman: Add SET_BASE/DRAW_INDIRECT command parsing support
* 2.42.0 - Add VCE/VUI (Video Usability Information) support
* 2.43.0 - RADEON_INFO_GPU_RESET_COUNTER
*/
#define KMS_DRIVER_MAJOR 2
#define KMS_DRIVER_MINOR 42
#define KMS_DRIVER_MINOR 43
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
......
......@@ -79,10 +79,12 @@ static void radeon_hotplug_work_func(struct work_struct *work)
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
mutex_lock(&mode_config->mutex);
if (mode_config->num_connector) {
list_for_each_entry(connector, &mode_config->connector_list, head)
radeon_connector_hotplug(connector);
}
mutex_unlock(&mode_config->mutex);
/* Just fire off a uevent and let userspace tell us what to do */
drm_helper_hpd_irq_event(dev);
}
......@@ -143,7 +145,13 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
*/
int radeon_driver_irq_postinstall_kms(struct drm_device *dev)
{
dev->max_vblank_count = 0x001fffff;
struct radeon_device *rdev = dev->dev_private;
if (ASIC_IS_AVIVO(rdev))
dev->max_vblank_count = 0x00ffffff;
else
dev->max_vblank_count = 0x001fffff;
return 0;
}
......
......@@ -576,6 +576,9 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file
if (radeon_get_allowed_info_register(rdev, *value, value))
return -EINVAL;
break;
case RADEON_INFO_GPU_RESET_COUNTER:
*value = atomic_read(&rdev->gpu_reset_counter);
break;
default:
DRM_DEBUG_KMS("Invalid request %d\n", info->request);
return -EINVAL;
......
......@@ -754,7 +754,7 @@ extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
struct drm_connector *connector);
int radeon_dp_get_max_link_rate(struct drm_connector *connector,
u8 *dpcd);
const u8 *dpcd);
extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
u8 power_state);
extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
......
......@@ -38,8 +38,10 @@
#define VCE_IDLE_TIMEOUT_MS 1000
/* Firmware Names */
#define FIRMWARE_TAHITI "radeon/TAHITI_vce.bin"
#define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin"
MODULE_FIRMWARE(FIRMWARE_TAHITI);
MODULE_FIRMWARE(FIRMWARE_BONAIRE);
static void radeon_vce_idle_work_handler(struct work_struct *work);
......@@ -63,6 +65,14 @@ int radeon_vce_init(struct radeon_device *rdev)
INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler);
switch (rdev->family) {
case CHIP_TAHITI:
case CHIP_PITCAIRN:
case CHIP_VERDE:
case CHIP_OLAND:
case CHIP_ARUBA:
fw_name = FIRMWARE_TAHITI;
break;
case CHIP_BONAIRE:
case CHIP_KAVERI:
case CHIP_KABINI:
......@@ -118,13 +128,17 @@ int radeon_vce_init(struct radeon_device *rdev)
rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8);
/* we can only work with this fw version for now */
if (rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8)))
if ((rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) &&
(rdev->vce.fw_version != ((50 << 24) | (0 << 16) | (1 << 8))) &&
(rdev->vce.fw_version != ((50 << 24) | (1 << 16) | (2 << 8))))
return -EINVAL;
/* allocate firmware, stack and heap BO */
size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size) +
RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE;
if (rdev->family < CHIP_BONAIRE)
size = vce_v1_0_bo_size(rdev);
else
size = vce_v2_0_bo_size(rdev);
r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL,
&rdev->vce.vcpu_bo);
......@@ -225,13 +239,17 @@ int radeon_vce_resume(struct radeon_device *rdev)
return r;
}
memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size);
memset(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo));
if (rdev->family < CHIP_BONAIRE)
r = vce_v1_0_load_fw(rdev, cpu_addr);
else
memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size);
radeon_bo_kunmap(rdev->vce.vcpu_bo);
radeon_bo_unreserve(rdev->vce.vcpu_bo);
return 0;
return r;
}
/**
......
......@@ -331,7 +331,6 @@ struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev,
bo_va->it.start = 0;
bo_va->it.last = 0;
bo_va->flags = 0;
bo_va->addr = 0;
bo_va->ref_count = 1;
INIT_LIST_HEAD(&bo_va->bo_list);
INIT_LIST_HEAD(&bo_va->vm_status);
......@@ -491,9 +490,11 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
}
if (bo_va->it.start || bo_va->it.last) {
if (bo_va->addr) {
spin_lock(&vm->status_lock);
if (list_empty(&bo_va->vm_status)) {
/* add a clone of the bo_va to clear the old address */
struct radeon_bo_va *tmp;
spin_unlock(&vm->status_lock);
tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL);
if (!tmp) {
mutex_unlock(&vm->mutex);
......@@ -502,14 +503,11 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
tmp->it.start = bo_va->it.start;
tmp->it.last = bo_va->it.last;
tmp->vm = vm;
tmp->addr = bo_va->addr;
tmp->bo = radeon_bo_ref(bo_va->bo);
spin_lock(&vm->status_lock);
list_add(&tmp->vm_status, &vm->freed);
spin_unlock(&vm->status_lock);
bo_va->addr = 0;
}
spin_unlock(&vm->status_lock);
interval_tree_remove(&bo_va->it, &vm->va);
bo_va->it.start = 0;
......@@ -520,10 +518,12 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
bo_va->it.start = soffset;
bo_va->it.last = eoffset - 1;
interval_tree_insert(&bo_va->it, &vm->va);
spin_lock(&vm->status_lock);
list_add(&bo_va->vm_status, &vm->cleared);
spin_unlock(&vm->status_lock);
}
bo_va->flags = flags;
bo_va->addr = 0;
soffset >>= radeon_vm_block_size;
eoffset >>= radeon_vm_block_size;
......@@ -921,7 +921,16 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
}
spin_lock(&vm->status_lock);
list_del_init(&bo_va->vm_status);
if (mem) {
if (list_empty(&bo_va->vm_status)) {
spin_unlock(&vm->status_lock);
return 0;
}
list_del_init(&bo_va->vm_status);
} else {
list_del(&bo_va->vm_status);
list_add(&bo_va->vm_status, &vm->cleared);
}
spin_unlock(&vm->status_lock);
bo_va->flags &= ~RADEON_VM_PAGE_VALID;
......@@ -947,10 +956,6 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
addr = 0;
}
if (addr == bo_va->addr)
return 0;
bo_va->addr = addr;
trace_radeon_vm_bo_update(bo_va);
nptes = bo_va->it.last - bo_va->it.start + 1;
......@@ -1038,7 +1043,7 @@ int radeon_vm_clear_freed(struct radeon_device *rdev,
struct radeon_vm *vm)
{
struct radeon_bo_va *bo_va;
int r;
int r = 0;
spin_lock(&vm->status_lock);
while (!list_empty(&vm->freed)) {
......@@ -1049,14 +1054,15 @@ int radeon_vm_clear_freed(struct radeon_device *rdev,
r = radeon_vm_bo_update(rdev, bo_va, NULL);
radeon_bo_unref(&bo_va->bo);
radeon_fence_unref(&bo_va->last_pt_update);
spin_lock(&vm->status_lock);
list_del(&bo_va->vm_status);
kfree(bo_va);
if (r)
return r;
break;
spin_lock(&vm->status_lock);
}
spin_unlock(&vm->status_lock);
return 0;
return r;
}
......@@ -1114,14 +1120,14 @@ void radeon_vm_bo_rmv(struct radeon_device *rdev,
mutex_lock(&vm->mutex);
if (bo_va->it.start || bo_va->it.last)
interval_tree_remove(&bo_va->it, &vm->va);
spin_lock(&vm->status_lock);
list_del(&bo_va->vm_status);
if (bo_va->addr) {
spin_lock(&vm->status_lock);
if (list_empty(&bo_va->vm_status)) {
bo_va->bo = radeon_bo_ref(bo_va->bo);
list_add(&bo_va->vm_status, &vm->freed);
} else {
radeon_fence_unref(&bo_va->last_pt_update);
list_del(&bo_va->vm_status);
kfree(bo_va);
}
spin_unlock(&vm->status_lock);
......@@ -1144,12 +1150,10 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev,
struct radeon_bo_va *bo_va;
list_for_each_entry(bo_va, &bo->va, bo_list) {
if (bo_va->addr) {
spin_lock(&bo_va->vm->status_lock);
list_del(&bo_va->vm_status);
spin_lock(&bo_va->vm->status_lock);
if (list_empty(&bo_va->vm_status))
list_add(&bo_va->vm_status, &bo_va->vm->invalidated);
spin_unlock(&bo_va->vm->status_lock);
}
spin_unlock(&bo_va->vm->status_lock);
}
}
......@@ -1179,6 +1183,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
spin_lock_init(&vm->status_lock);
INIT_LIST_HEAD(&vm->invalidated);
INIT_LIST_HEAD(&vm->freed);
INIT_LIST_HEAD(&vm->cleared);
pd_size = radeon_vm_directory_size(rdev);
pd_entries = radeon_vm_num_pdes(rdev);
......
......@@ -6907,6 +6907,22 @@ static int si_startup(struct radeon_device *rdev)
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
}
r = radeon_vce_resume(rdev);
if (!r) {
r = vce_v1_0_resume(rdev);
if (!r)
r = radeon_fence_driver_start_ring(rdev,
TN_RING_TYPE_VCE1_INDEX);
if (!r)
r = radeon_fence_driver_start_ring(rdev,
TN_RING_TYPE_VCE2_INDEX);
}
if (r) {
dev_err(rdev->dev, "VCE init error (%d).\n", r);
rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
}
/* Enable IRQ */
if (!rdev->irq.installed) {
r = radeon_irq_kms_init(rdev);
......@@ -6975,6 +6991,23 @@ static int si_startup(struct radeon_device *rdev)
}
}
r = -ENOENT;
ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
if (ring->ring_size)
r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
VCE_CMD_NO_OP);
ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
if (ring->ring_size)
r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
VCE_CMD_NO_OP);
if (!r)
r = vce_v1_0_init(rdev);
else if (r != -ENOENT)
DRM_ERROR("radeon: failed initializing VCE (%d).\n", r);
r = radeon_ib_pool_init(rdev);
if (r) {
dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
......@@ -7033,6 +7066,7 @@ int si_suspend(struct radeon_device *rdev)
if (rdev->has_uvd) {
uvd_v1_0_fini(rdev);
radeon_uvd_suspend(rdev);
radeon_vce_suspend(rdev);
}
si_fini_pg(rdev);
si_fini_cg(rdev);
......@@ -7140,6 +7174,17 @@ int si_init(struct radeon_device *rdev)
}
}
r = radeon_vce_init(rdev);
if (!r) {
ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 4096);
ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 4096);
}
rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024);
......@@ -7191,6 +7236,7 @@ void si_fini(struct radeon_device *rdev)
if (rdev->has_uvd) {
uvd_v1_0_fini(rdev);
radeon_uvd_fini(rdev);
radeon_vce_fini(rdev);
}
si_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
......@@ -7675,3 +7721,124 @@ static void si_program_aspm(struct radeon_device *rdev)
}
}
}
int si_vce_send_vcepll_ctlreq(struct radeon_device *rdev)
{
unsigned i;
/* make sure VCEPLL_CTLREQ is deasserted */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK);
mdelay(10);
/* assert UPLL_CTLREQ */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK);
/* wait for CTLACK and CTLACK2 to get asserted */
for (i = 0; i < 100; ++i) {
uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK;
if ((RREG32_SMC(CG_VCEPLL_FUNC_CNTL) & mask) == mask)
break;
mdelay(10);
}
/* deassert UPLL_CTLREQ */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK);
if (i == 100) {
DRM_ERROR("Timeout setting UVD clocks!\n");
return -ETIMEDOUT;
}
return 0;
}
int si_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk)
{
unsigned fb_div = 0, evclk_div = 0, ecclk_div = 0;
int r;
/* bypass evclk and ecclk with bclk */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_2,
EVCLK_SRC_SEL(1) | ECCLK_SRC_SEL(1),
~(EVCLK_SRC_SEL_MASK | ECCLK_SRC_SEL_MASK));
/* put PLL in bypass mode */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_BYPASS_EN_MASK,
~VCEPLL_BYPASS_EN_MASK);
if (!evclk || !ecclk) {
/* keep the Bypass mode, put PLL to sleep */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_SLEEP_MASK,
~VCEPLL_SLEEP_MASK);
return 0;
}
r = radeon_uvd_calc_upll_dividers(rdev, evclk, ecclk, 125000, 250000,
16384, 0x03FFFFFF, 0, 128, 5,
&fb_div, &evclk_div, &ecclk_div);
if (r)
return r;
/* set RESET_ANTI_MUX to 0 */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_5, 0, ~RESET_ANTI_MUX_MASK);
/* set VCO_MODE to 1 */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_VCO_MODE_MASK,
~VCEPLL_VCO_MODE_MASK);
/* toggle VCEPLL_SLEEP to 1 then back to 0 */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_SLEEP_MASK,
~VCEPLL_SLEEP_MASK);
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_SLEEP_MASK);
/* deassert VCEPLL_RESET */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_RESET_MASK);
mdelay(1);
r = si_vce_send_vcepll_ctlreq(rdev);
if (r)
return r;
/* assert VCEPLL_RESET again */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_RESET_MASK, ~VCEPLL_RESET_MASK);
/* disable spread spectrum. */
WREG32_SMC_P(CG_VCEPLL_SPREAD_SPECTRUM, 0, ~SSEN_MASK);
/* set feedback divider */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_3, VCEPLL_FB_DIV(fb_div), ~VCEPLL_FB_DIV_MASK);
/* set ref divider to 0 */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_REF_DIV_MASK);
/* set PDIV_A and PDIV_B */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_2,
VCEPLL_PDIV_A(evclk_div) | VCEPLL_PDIV_B(ecclk_div),
~(VCEPLL_PDIV_A_MASK | VCEPLL_PDIV_B_MASK));
/* give the PLL some time to settle */
mdelay(15);
/* deassert PLL_RESET */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_RESET_MASK);
mdelay(15);
/* switch from bypass mode to normal mode */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_BYPASS_EN_MASK);
r = si_vce_send_vcepll_ctlreq(rdev);
if (r)
return r;
/* switch VCLK and DCLK selection */
WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_2,
EVCLK_SRC_SEL(16) | ECCLK_SRC_SEL(16),
~(EVCLK_SRC_SEL_MASK | ECCLK_SRC_SEL_MASK));
mdelay(100);
return 0;
}
......@@ -1740,6 +1740,7 @@ struct ni_power_info *ni_get_pi(struct radeon_device *rdev);
struct ni_ps *ni_get_ps(struct radeon_ps *rps);
extern int si_mc_load_microcode(struct radeon_device *rdev);
extern void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable);
static int si_populate_voltage_value(struct radeon_device *rdev,
const struct atom_voltage_table *table,
......@@ -2928,6 +2929,56 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = {
{ 0, 0, 0, 0 },
};
static u16 si_get_lower_of_leakage_and_vce_voltage(struct radeon_device *rdev,
u16 vce_voltage)
{
u16 highest_leakage = 0;
struct si_power_info *si_pi = si_get_pi(rdev);
int i;
for (i = 0; i < si_pi->leakage_voltage.count; i++){
if (highest_leakage < si_pi->leakage_voltage.entries[i].voltage)
highest_leakage = si_pi->leakage_voltage.entries[i].voltage;
}
if (si_pi->leakage_voltage.count && (highest_leakage < vce_voltage))
return highest_leakage;
return vce_voltage;
}
static int si_get_vce_clock_voltage(struct radeon_device *rdev,
u32 evclk, u32 ecclk, u16 *voltage)
{
u32 i;
int ret = -EINVAL;
struct radeon_vce_clock_voltage_dependency_table *table =
&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
if (((evclk == 0) && (ecclk == 0)) ||
(table && (table->count == 0))) {
*voltage = 0;
return 0;
}
for (i = 0; i < table->count; i++) {
if ((evclk <= table->entries[i].evclk) &&
(ecclk <= table->entries[i].ecclk)) {
*voltage = table->entries[i].v;
ret = 0;
break;
}
}
/* if no match return the highest voltage */
if (ret)
*voltage = table->entries[table->count - 1].v;
*voltage = si_get_lower_of_leakage_and_vce_voltage(rdev, *voltage);
return ret;
}
static void si_apply_state_adjust_rules(struct radeon_device *rdev,
struct radeon_ps *rps)
{
......@@ -2936,7 +2987,7 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
bool disable_mclk_switching = false;
bool disable_sclk_switching = false;
u32 mclk, sclk;
u16 vddc, vddci;
u16 vddc, vddci, min_vce_voltage = 0;
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
u32 max_sclk = 0, max_mclk = 0;
int i;
......@@ -2955,6 +3006,16 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
++p;
}
if (rps->vce_active) {
rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
si_get_vce_clock_voltage(rdev, rps->evclk, rps->ecclk,
&min_vce_voltage);
} else {
rps->evclk = 0;
rps->ecclk = 0;
}
if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
ni_dpm_vblank_too_short(rdev))
disable_mclk_switching = true;
......@@ -3035,6 +3096,13 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
vddc = ps->performance_levels[0].vddc;
}
if (rps->vce_active) {
if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
if (mclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk)
mclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk;
}
/* adjusted low state */
ps->performance_levels[0].sclk = sclk;
ps->performance_levels[0].mclk = mclk;
......@@ -3084,6 +3152,8 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
&ps->performance_levels[i]);
for (i = 0; i < ps->performance_level_count; i++) {
if (ps->performance_levels[i].vddc < min_vce_voltage)
ps->performance_levels[i].vddc = min_vce_voltage;
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
ps->performance_levels[i].sclk,
max_limits->vddc, &ps->performance_levels[i].vddc);
......@@ -3110,7 +3180,6 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
if (ps->performance_levels[i].vddc > rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc)
ps->dc_compatible = false;
}
}
#if 0
......@@ -5859,6 +5928,21 @@ static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev,
}
}
static void si_set_vce_clock(struct radeon_device *rdev,
struct radeon_ps *new_rps,
struct radeon_ps *old_rps)
{
if ((old_rps->evclk != new_rps->evclk) ||
(old_rps->ecclk != new_rps->ecclk)) {
/* turn the clocks on when encoding, off otherwise */
if (new_rps->evclk || new_rps->ecclk)
vce_v1_0_enable_mgcg(rdev, false);
else
vce_v1_0_enable_mgcg(rdev, true);
radeon_set_vce_clocks(rdev, new_rps->evclk, new_rps->ecclk);
}
}
void si_dpm_setup_asic(struct radeon_device *rdev)
{
int r;
......@@ -6547,6 +6631,7 @@ int si_dpm_set_power_state(struct radeon_device *rdev)
return ret;
}
ni_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
si_set_vce_clock(rdev, new_ps, old_ps);
if (eg_pi->pcie_performance_request)
si_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
ret = si_set_power_state_conditionally_enable_ulv(rdev, new_ps);
......@@ -6793,6 +6878,21 @@ static int si_parse_power_table(struct radeon_device *rdev)
power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
}
rdev->pm.dpm.num_ps = state_array->ucNumEntries;
/* fill in the vce power states */
for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
u32 sclk, mclk;
clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
clock_info = (union pplib_clock_info *)
&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
sclk |= clock_info->si.ucEngineClockHigh << 16;
mclk = le16_to_cpu(clock_info->si.usMemoryClockLow);
mclk |= clock_info->si.ucMemoryClockHigh << 16;
rdev->pm.dpm.vce_states[i].sclk = sclk;
rdev->pm.dpm.vce_states[i].mclk = mclk;
}
return 0;
}
......@@ -6837,10 +6937,11 @@ int si_dpm_init(struct radeon_device *rdev)
if (ret)
return ret;
ret = si_parse_power_table(rdev);
ret = r600_parse_extended_power_table(rdev);
if (ret)
return ret;
ret = r600_parse_extended_power_table(rdev);
ret = si_parse_power_table(rdev);
if (ret)
return ret;
......
......@@ -1879,6 +1879,7 @@
#define VCE_VCPU_CACHE_SIZE1 0x20030
#define VCE_VCPU_CACHE_OFFSET2 0x20034
#define VCE_VCPU_CACHE_SIZE2 0x20038
#define VCE_VCPU_SCRATCH7 0x200dc
#define VCE_SOFT_RESET 0x20120
#define VCE_ECPU_SOFT_RESET (1 << 0)
#define VCE_FME_SOFT_RESET (1 << 2)
......@@ -1893,6 +1894,7 @@
#define VCE_RB_RPTR 0x2018c
#define VCE_RB_WPTR 0x20190
#define VCE_CLOCK_GATING_A 0x202f8
# define CGC_DYN_CLOCK_MODE (1 << 16)
#define VCE_CLOCK_GATING_B 0x202fc
#define VCE_UENC_CLOCK_GATING 0x205bc
#define VCE_UENC_REG_CLOCK_GATING 0x205c0
......@@ -1917,4 +1919,31 @@
#define VCE_CMD_IB_AUTO 0x00000005
#define VCE_CMD_SEMAPHORE 0x00000006
/* discrete vce clocks */
#define CG_VCEPLL_FUNC_CNTL 0xc0030600
# define VCEPLL_RESET_MASK 0x00000001
# define VCEPLL_SLEEP_MASK 0x00000002
# define VCEPLL_BYPASS_EN_MASK 0x00000004
# define VCEPLL_CTLREQ_MASK 0x00000008
# define VCEPLL_VCO_MODE_MASK 0x00000600
# define VCEPLL_REF_DIV_MASK 0x003F0000
# define VCEPLL_CTLACK_MASK 0x40000000
# define VCEPLL_CTLACK2_MASK 0x80000000
#define CG_VCEPLL_FUNC_CNTL_2 0xc0030601
# define VCEPLL_PDIV_A(x) ((x) << 0)
# define VCEPLL_PDIV_A_MASK 0x0000007F
# define VCEPLL_PDIV_B(x) ((x) << 8)
# define VCEPLL_PDIV_B_MASK 0x00007F00
# define EVCLK_SRC_SEL(x) ((x) << 20)
# define EVCLK_SRC_SEL_MASK 0x01F00000
# define ECCLK_SRC_SEL(x) ((x) << 25)
# define ECCLK_SRC_SEL_MASK 0x3E000000
#define CG_VCEPLL_FUNC_CNTL_3 0xc0030602
# define VCEPLL_FB_DIV(x) ((x) << 0)
# define VCEPLL_FB_DIV_MASK 0x01FFFFFF
#define CG_VCEPLL_FUNC_CNTL_4 0xc0030603
#define CG_VCEPLL_FUNC_CNTL_5 0xc0030604
#define CG_VCEPLL_SPREAD_SPECTRUM 0xc0030606
# define VCEPLL_SSEN_MASK 0x00000001
#endif
......@@ -336,6 +336,7 @@ static const u32 trinity_override_mgpg_sequences[] =
0x00000204, 0x00000000,
};
extern void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable);
static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
const u32 *seq, u32 count);
static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev);
......@@ -985,6 +986,21 @@ static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev
trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
}
static void trinity_set_vce_clock(struct radeon_device *rdev,
struct radeon_ps *new_rps,
struct radeon_ps *old_rps)
{
if ((old_rps->evclk != new_rps->evclk) ||
(old_rps->ecclk != new_rps->ecclk)) {
/* turn the clocks on when encoding, off otherwise */
if (new_rps->evclk || new_rps->ecclk)
vce_v1_0_enable_mgcg(rdev, false);
else
vce_v1_0_enable_mgcg(rdev, true);
radeon_set_vce_clocks(rdev, new_rps->evclk, new_rps->ecclk);
}
}
static void trinity_program_ttt(struct radeon_device *rdev)
{
struct trinity_power_info *pi = trinity_get_pi(rdev);
......@@ -1246,6 +1262,7 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev)
trinity_force_level_0(rdev);
trinity_unforce_levels(rdev);
trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
trinity_set_vce_clock(rdev, new_ps, old_ps);
}
trinity_release_mutex(rdev);
......@@ -1483,7 +1500,35 @@ static void trinity_adjust_uvd_state(struct radeon_device *rdev,
}
}
static int trinity_get_vce_clock_voltage(struct radeon_device *rdev,
u32 evclk, u32 ecclk, u16 *voltage)
{
u32 i;
int ret = -EINVAL;
struct radeon_vce_clock_voltage_dependency_table *table =
&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
if (((evclk == 0) && (ecclk == 0)) ||
(table && (table->count == 0))) {
*voltage = 0;
return 0;
}
for (i = 0; i < table->count; i++) {
if ((evclk <= table->entries[i].evclk) &&
(ecclk <= table->entries[i].ecclk)) {
*voltage = table->entries[i].v;
ret = 0;
break;
}
}
/* if no match return the highest voltage */
if (ret)
*voltage = table->entries[table->count - 1].v;
return ret;
}
static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
struct radeon_ps *new_rps,
......@@ -1496,6 +1541,7 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
u32 i;
u16 min_vce_voltage;
bool force_high;
u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
......@@ -1504,6 +1550,14 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
trinity_adjust_uvd_state(rdev, new_rps);
if (new_rps->vce_active) {
new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
} else {
new_rps->evclk = 0;
new_rps->ecclk = 0;
}
for (i = 0; i < ps->num_levels; i++) {
if (ps->levels[i].vddc_index < min_voltage)
ps->levels[i].vddc_index = min_voltage;
......@@ -1512,6 +1566,17 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
ps->levels[i].sclk =
trinity_get_valid_engine_clock(rdev, min_sclk);
/* patch in vce limits */
if (new_rps->vce_active) {
/* sclk */
if (ps->levels[i].sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
ps->levels[i].sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
/* vddc */
trinity_get_vce_clock_voltage(rdev, new_rps->evclk, new_rps->ecclk, &min_vce_voltage);
if (ps->levels[i].vddc_index < min_vce_voltage)
ps->levels[i].vddc_index = min_vce_voltage;
}
ps->levels[i].ds_divider_index =
sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
......@@ -1733,6 +1798,19 @@ static int trinity_parse_power_table(struct radeon_device *rdev)
power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
}
rdev->pm.dpm.num_ps = state_array->ucNumEntries;
/* fill in the vce power states */
for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
u32 sclk;
clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
clock_info = (union pplib_clock_info *)
&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
sclk |= clock_info->sumo.ucEngineClockHigh << 16;
rdev->pm.dpm.vce_states[i].sclk = sclk;
rdev->pm.dpm.vce_states[i].mclk = 0;
}
return 0;
}
......@@ -1914,6 +1992,10 @@ int trinity_dpm_init(struct radeon_device *rdev)
if (ret)
return ret;
ret = r600_parse_extended_power_table(rdev);
if (ret)
return ret;
ret = trinity_parse_power_table(rdev);
if (ret)
return ret;
......@@ -2000,6 +2082,7 @@ void trinity_dpm_fini(struct radeon_device *rdev)
}
kfree(rdev->pm.dpm.ps);
kfree(rdev->pm.dpm.priv);
r600_free_extended_power_table(rdev);
}
u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
......
......@@ -31,6 +31,23 @@
#include "radeon_asic.h"
#include "sid.h"
#define VCE_V1_0_FW_SIZE (256 * 1024)
#define VCE_V1_0_STACK_SIZE (64 * 1024)
#define VCE_V1_0_DATA_SIZE (7808 * (RADEON_MAX_VCE_HANDLES + 1))
struct vce_v1_0_fw_signature
{
int32_t off;
uint32_t len;
int32_t num;
struct {
uint32_t chip_id;
uint32_t keyselect;
uint32_t nonce[4];
uint32_t sigval[4];
} val[8];
};
/**
* vce_v1_0_get_rptr - get read pointer
*
......@@ -82,6 +99,186 @@ void vce_v1_0_set_wptr(struct radeon_device *rdev,
WREG32(VCE_RB_WPTR2, ring->wptr);
}
void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable)
{
u32 tmp;
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_VCE_MGCG)) {
tmp = RREG32(VCE_CLOCK_GATING_A);
tmp |= CGC_DYN_CLOCK_MODE;
WREG32(VCE_CLOCK_GATING_A, tmp);
tmp = RREG32(VCE_UENC_CLOCK_GATING);
tmp &= ~0x1ff000;
tmp |= 0xff800000;
WREG32(VCE_UENC_CLOCK_GATING, tmp);
tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
tmp &= ~0x3ff;
WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
} else {
tmp = RREG32(VCE_CLOCK_GATING_A);
tmp &= ~CGC_DYN_CLOCK_MODE;
WREG32(VCE_CLOCK_GATING_A, tmp);
tmp = RREG32(VCE_UENC_CLOCK_GATING);
tmp |= 0x1ff000;
tmp &= ~0xff800000;
WREG32(VCE_UENC_CLOCK_GATING, tmp);
tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
tmp |= 0x3ff;
WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
}
}
static void vce_v1_0_init_cg(struct radeon_device *rdev)
{
u32 tmp;
tmp = RREG32(VCE_CLOCK_GATING_A);
tmp |= CGC_DYN_CLOCK_MODE;
WREG32(VCE_CLOCK_GATING_A, tmp);
tmp = RREG32(VCE_CLOCK_GATING_B);
tmp |= 0x1e;
tmp &= ~0xe100e1;
WREG32(VCE_CLOCK_GATING_B, tmp);
tmp = RREG32(VCE_UENC_CLOCK_GATING);
tmp &= ~0xff9ff000;
WREG32(VCE_UENC_CLOCK_GATING, tmp);
tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
tmp &= ~0x3ff;
WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
}
int vce_v1_0_load_fw(struct radeon_device *rdev, uint32_t *data)
{
struct vce_v1_0_fw_signature *sign = (void*)rdev->vce_fw->data;
uint32_t chip_id;
int i;
switch (rdev->family) {
case CHIP_TAHITI:
chip_id = 0x01000014;
break;
case CHIP_VERDE:
chip_id = 0x01000015;
break;
case CHIP_PITCAIRN:
case CHIP_OLAND:
chip_id = 0x01000016;
break;
case CHIP_ARUBA:
chip_id = 0x01000017;
break;
default:
return -EINVAL;
}
for (i = 0; i < sign->num; ++i) {
if (sign->val[i].chip_id == chip_id)
break;
}
if (i == sign->num)
return -EINVAL;
data += (256 - 64) / 4;
data[0] = sign->val[i].nonce[0];
data[1] = sign->val[i].nonce[1];
data[2] = sign->val[i].nonce[2];
data[3] = sign->val[i].nonce[3];
data[4] = sign->len + 64;
memset(&data[5], 0, 44);
memcpy(&data[16], &sign[1], rdev->vce_fw->size - sizeof(*sign));
data += data[4] / 4;
data[0] = sign->val[i].sigval[0];
data[1] = sign->val[i].sigval[1];
data[2] = sign->val[i].sigval[2];
data[3] = sign->val[i].sigval[3];
rdev->vce.keyselect = sign->val[i].keyselect;
return 0;
}
unsigned vce_v1_0_bo_size(struct radeon_device *rdev)
{
WARN_ON(VCE_V1_0_FW_SIZE < rdev->vce_fw->size);
return VCE_V1_0_FW_SIZE + VCE_V1_0_STACK_SIZE + VCE_V1_0_DATA_SIZE;
}
int vce_v1_0_resume(struct radeon_device *rdev)
{
uint64_t addr = rdev->vce.gpu_addr;
uint32_t size;
int i;
WREG32_P(VCE_CLOCK_GATING_A, 0, ~(1 << 16));
WREG32_P(VCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
WREG32_P(VCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
WREG32(VCE_CLOCK_GATING_B, 0);
WREG32_P(VCE_LMI_FW_PERIODIC_CTRL, 0x4, ~0x4);
WREG32(VCE_LMI_CTRL, 0x00398000);
WREG32_P(VCE_LMI_CACHE_CTRL, 0x0, ~0x1);
WREG32(VCE_LMI_SWAP_CNTL, 0);
WREG32(VCE_LMI_SWAP_CNTL1, 0);
WREG32(VCE_LMI_VM_CTRL, 0);
WREG32(VCE_VCPU_SCRATCH7, RADEON_MAX_VCE_HANDLES);
addr += 256;
size = VCE_V1_0_FW_SIZE;
WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff);
WREG32(VCE_VCPU_CACHE_SIZE0, size);
addr += size;
size = VCE_V1_0_STACK_SIZE;
WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff);
WREG32(VCE_VCPU_CACHE_SIZE1, size);
addr += size;
size = VCE_V1_0_DATA_SIZE;
WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff);
WREG32(VCE_VCPU_CACHE_SIZE2, size);
WREG32_P(VCE_LMI_CTRL2, 0x0, ~0x100);
WREG32(VCE_LMI_FW_START_KEYSEL, rdev->vce.keyselect);
for (i = 0; i < 10; ++i) {
mdelay(10);
if (RREG32(VCE_FW_REG_STATUS) & VCE_FW_REG_STATUS_DONE)
break;
}
if (i == 10)
return -ETIMEDOUT;
if (!(RREG32(VCE_FW_REG_STATUS) & VCE_FW_REG_STATUS_PASS))
return -EINVAL;
for (i = 0; i < 10; ++i) {
mdelay(10);
if (!(RREG32(VCE_FW_REG_STATUS) & VCE_FW_REG_STATUS_BUSY))
break;
}
if (i == 10)
return -ETIMEDOUT;
vce_v1_0_init_cg(rdev);
return 0;
}
/**
* vce_v1_0_start - start VCE block
*
......
......@@ -31,6 +31,10 @@
#include "radeon_asic.h"
#include "cikd.h"
#define VCE_V2_0_FW_SIZE (256 * 1024)
#define VCE_V2_0_STACK_SIZE (64 * 1024)
#define VCE_V2_0_DATA_SIZE (23552 * RADEON_MAX_VCE_HANDLES)
static void vce_v2_0_set_sw_cg(struct radeon_device *rdev, bool gated)
{
u32 tmp;
......@@ -140,6 +144,12 @@ static void vce_v2_0_init_cg(struct radeon_device *rdev)
WREG32(VCE_CLOCK_GATING_B, tmp);
}
unsigned vce_v2_0_bo_size(struct radeon_device *rdev)
{
WARN_ON(rdev->vce_fw->size > VCE_V2_0_FW_SIZE);
return VCE_V2_0_FW_SIZE + VCE_V2_0_STACK_SIZE + VCE_V2_0_DATA_SIZE;
}
int vce_v2_0_resume(struct radeon_device *rdev)
{
uint64_t addr = rdev->vce.gpu_addr;
......@@ -159,17 +169,17 @@ int vce_v2_0_resume(struct radeon_device *rdev)
WREG32(VCE_LMI_VCPU_CACHE_40BIT_BAR, addr >> 8);
addr &= 0xff;
size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size);
size = VCE_V2_0_FW_SIZE;
WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff);
WREG32(VCE_VCPU_CACHE_SIZE0, size);
addr += size;
size = RADEON_VCE_STACK_SIZE;
size = VCE_V2_0_STACK_SIZE;
WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff);
WREG32(VCE_VCPU_CACHE_SIZE1, size);
addr += size;
size = RADEON_VCE_HEAP_SIZE;
size = VCE_V2_0_DATA_SIZE;
WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff);
WREG32(VCE_VCPU_CACHE_SIZE2, size);
......
......@@ -1038,6 +1038,7 @@ struct drm_radeon_cs {
#define RADEON_INFO_CURRENT_GPU_SCLK 0x22
#define RADEON_INFO_CURRENT_GPU_MCLK 0x23
#define RADEON_INFO_READ_REG 0x24
#define RADEON_INFO_GPU_RESET_COUNTER 0x25
struct drm_radeon_info {
uint32_t request;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment